dsh-plugin-guide 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE.md +26 -0
- package/README.es.md +139 -0
- package/README.hi.md +138 -0
- package/README.md +165 -0
- package/README.pt.md +139 -0
- package/README.zh-CN.md +164 -0
- package/SKILL.md +69 -0
- package/cordis.patch.yml +4 -0
- package/guide/links.md +92 -0
- package/guide/plugin-dev-guide.md +429 -0
- package/guide/quick-reference.es.md +176 -0
- package/guide/quick-reference.hi.md +176 -0
- package/guide/quick-reference.md +176 -0
- package/guide/quick-reference.pt.md +176 -0
- package/guide/quick-reference.zh-CN.md +175 -0
- package/index.js +58 -0
- package/package.json +83 -0
- package/references/community-ecosystem.md +201 -0
- package/references/community-repo-deep-dive.md +695 -0
- package/references/cordis-paper-and-community.md +326 -0
- package/references/harness-repo.md +654 -0
- package/references/official-docs/AGENTS.md +149 -0
- package/references/official-docs/BENCHMARK.md +3 -0
- package/references/official-docs/CLAUDE.md +1 -0
- package/references/official-docs/CONTRIBUTING.i18n.yaml +6 -0
- package/references/official-docs/CONTRIBUTING.md +23 -0
- package/references/official-docs/CONTRIBUTING.zh.md +23 -0
- package/references/official-docs/LICENSE +21 -0
- package/references/official-docs/README.i18n.yaml +6 -0
- package/references/official-docs/README.md +35 -0
- package/references/official-docs/README.zh.md +74 -0
- package/references/official-docs/SNAPSHOT.md +16 -0
- package/references/official-docs/THIRD_PARTY_NOTICES.md +192 -0
- package/references/official-docs/docs/AGENTS.md +75 -0
- package/references/official-docs/docs/agent-lifecycle.i18n.yaml +6 -0
- package/references/official-docs/docs/agent-lifecycle.md +82 -0
- package/references/official-docs/docs/agent-lifecycle.zh.md +84 -0
- package/references/official-docs/docs/api-gateway.i18n.yaml +6 -0
- package/references/official-docs/docs/api-gateway.md +164 -0
- package/references/official-docs/docs/api-gateway.zh.md +164 -0
- package/references/official-docs/docs/architecture.i18n.yaml +6 -0
- package/references/official-docs/docs/architecture.md +129 -0
- package/references/official-docs/docs/architecture.zh.md +133 -0
- package/references/official-docs/docs/capability-seams.i18n.yaml +6 -0
- package/references/official-docs/docs/capability-seams.md +471 -0
- package/references/official-docs/docs/capability-seams.zh.md +473 -0
- package/references/official-docs/docs/config-catalog.i18n.yaml +6 -0
- package/references/official-docs/docs/config-catalog.md +3151 -0
- package/references/official-docs/docs/config-catalog.zh.md +3152 -0
- package/references/official-docs/docs/cookbook/adding-a-conversation-node.i18n.yaml +6 -0
- package/references/official-docs/docs/cookbook/adding-a-conversation-node.md +233 -0
- package/references/official-docs/docs/cookbook/adding-a-conversation-node.zh.md +233 -0
- package/references/official-docs/docs/cookbook/adding-a-package.i18n.yaml +6 -0
- package/references/official-docs/docs/cookbook/adding-a-package.md +118 -0
- package/references/official-docs/docs/cookbook/adding-a-package.zh.md +118 -0
- package/references/official-docs/docs/cookbook/adding-a-tool.i18n.yaml +6 -0
- package/references/official-docs/docs/cookbook/adding-a-tool.md +94 -0
- package/references/official-docs/docs/cookbook/adding-a-tool.zh.md +96 -0
- package/references/official-docs/docs/cookbook/adding-a-vendored-package.i18n.yaml +6 -0
- package/references/official-docs/docs/cookbook/adding-a-vendored-package.md +59 -0
- package/references/official-docs/docs/cookbook/adding-a-vendored-package.zh.md +59 -0
- package/references/official-docs/docs/cookbook/adding-an-llm-adapter.i18n.yaml +6 -0
- package/references/official-docs/docs/cookbook/adding-an-llm-adapter.md +43 -0
- package/references/official-docs/docs/cookbook/adding-an-llm-adapter.zh.md +43 -0
- package/references/official-docs/docs/cookbook/extension-cookbook.i18n.yaml +6 -0
- package/references/official-docs/docs/cookbook/extension-cookbook.md +129 -0
- package/references/official-docs/docs/cookbook/extension-cookbook.zh.md +131 -0
- package/references/official-docs/docs/cookbook/maintaining-dsh-code-review.i18n.yaml +6 -0
- package/references/official-docs/docs/cookbook/maintaining-dsh-code-review.md +64 -0
- package/references/official-docs/docs/cookbook/maintaining-dsh-code-review.zh.md +64 -0
- package/references/official-docs/docs/cookbook/responding-to-pr-review-on-a-stack.i18n.yaml +6 -0
- package/references/official-docs/docs/cookbook/responding-to-pr-review-on-a-stack.md +32 -0
- package/references/official-docs/docs/cookbook/responding-to-pr-review-on-a-stack.zh.md +32 -0
- package/references/official-docs/docs/cordis-api/context.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-api/context.md +364 -0
- package/references/official-docs/docs/cordis-api/context.zh.md +366 -0
- package/references/official-docs/docs/cordis-api/events.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-api/events.md +207 -0
- package/references/official-docs/docs/cordis-api/events.zh.md +209 -0
- package/references/official-docs/docs/cordis-api/fiber.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-api/fiber.md +375 -0
- package/references/official-docs/docs/cordis-api/fiber.zh.md +377 -0
- package/references/official-docs/docs/cordis-api/inherited.md +39 -0
- package/references/official-docs/docs/cordis-api/registry.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-api/registry.md +152 -0
- package/references/official-docs/docs/cordis-api/registry.zh.md +154 -0
- package/references/official-docs/docs/cordis-api/service.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-api/service.md +102 -0
- package/references/official-docs/docs/cordis-api/service.zh.md +104 -0
- package/references/official-docs/docs/cordis-primer.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-primer.md +44 -0
- package/references/official-docs/docs/cordis-primer.zh.md +50 -0
- package/references/official-docs/docs/cordis-tutorial/01-first-plugin.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-tutorial/01-first-plugin.md +95 -0
- package/references/official-docs/docs/cordis-tutorial/01-first-plugin.zh.md +95 -0
- package/references/official-docs/docs/cordis-tutorial/02-lifecycle-and-effects.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-tutorial/02-lifecycle-and-effects.md +98 -0
- package/references/official-docs/docs/cordis-tutorial/02-lifecycle-and-effects.zh.md +98 -0
- package/references/official-docs/docs/cordis-tutorial/03-services.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-tutorial/03-services.md +98 -0
- package/references/official-docs/docs/cordis-tutorial/03-services.zh.md +98 -0
- package/references/official-docs/docs/cordis-tutorial/04-events.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-tutorial/04-events.md +144 -0
- package/references/official-docs/docs/cordis-tutorial/04-events.zh.md +144 -0
- package/references/official-docs/docs/cordis-tutorial/05-config.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-tutorial/05-config.md +84 -0
- package/references/official-docs/docs/cordis-tutorial/05-config.zh.md +84 -0
- package/references/official-docs/docs/cordis-tutorial/06-composition-and-hmr.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-tutorial/06-composition-and-hmr.md +113 -0
- package/references/official-docs/docs/cordis-tutorial/06-composition-and-hmr.zh.md +113 -0
- package/references/official-docs/docs/cordis-tutorial/07-into-the-harness.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-tutorial/07-into-the-harness.md +107 -0
- package/references/official-docs/docs/cordis-tutorial/07-into-the-harness.zh.md +107 -0
- package/references/official-docs/docs/cordis-tutorial/index.i18n.yaml +6 -0
- package/references/official-docs/docs/cordis-tutorial/index.md +60 -0
- package/references/official-docs/docs/cordis-tutorial/index.zh.md +62 -0
- package/references/official-docs/docs/defensive-patterns.i18n.yaml +6 -0
- package/references/official-docs/docs/defensive-patterns.md +33 -0
- package/references/official-docs/docs/defensive-patterns.zh.md +33 -0
- package/references/official-docs/docs/development.i18n.yaml +6 -0
- package/references/official-docs/docs/development.md +171 -0
- package/references/official-docs/docs/development.zh.md +171 -0
- package/references/official-docs/docs/event-producer-consumer.i18n.yaml +6 -0
- package/references/official-docs/docs/event-producer-consumer.md +76 -0
- package/references/official-docs/docs/event-producer-consumer.zh.md +78 -0
- package/references/official-docs/docs/glossary.i18n.yaml +6 -0
- package/references/official-docs/docs/glossary.md +45 -0
- package/references/official-docs/docs/glossary.zh.md +45 -0
- package/references/official-docs/docs/graph-atlas.i18n.yaml +6 -0
- package/references/official-docs/docs/graph-atlas.md +24 -0
- package/references/official-docs/docs/graph-atlas.zh.md +26 -0
- package/references/official-docs/docs/i18n/README.i18n.yaml +6 -0
- package/references/official-docs/docs/i18n/README.md +60 -0
- package/references/official-docs/docs/i18n/README.zh.md +60 -0
- package/references/official-docs/docs/i18n/style-samples.md +87 -0
- package/references/official-docs/docs/i18n/terminology.md +214 -0
- package/references/official-docs/docs/i18n/translation-prompt.md +263 -0
- package/references/official-docs/docs/i18n/translation-rules.i18n.yaml +6 -0
- package/references/official-docs/docs/i18n/translation-rules.md +69 -0
- package/references/official-docs/docs/i18n/translation-rules.zh.md +69 -0
- package/references/official-docs/docs/module-graph.i18n.yaml +6 -0
- package/references/official-docs/docs/module-graph.md +1638 -0
- package/references/official-docs/docs/module-graph.zh.md +1640 -0
- package/references/official-docs/docs/persistence-catalog.i18n.yaml +6 -0
- package/references/official-docs/docs/persistence-catalog.md +944 -0
- package/references/official-docs/docs/persistence-catalog.zh.md +946 -0
- package/references/official-docs/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml +6 -0
- package/references/official-docs/docs/postmortem/0001-acp-default-export-drops-inject.md +113 -0
- package/references/official-docs/docs/postmortem/0001-acp-default-export-drops-inject.zh.md +113 -0
- package/references/official-docs/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml +6 -0
- package/references/official-docs/docs/postmortem/0002-js-expression-disabled-filesystem-tools.md +47 -0
- package/references/official-docs/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +47 -0
- package/references/official-docs/docs/postmortem/0003-web-agent-gui-feedback-loop.i18n.yaml +6 -0
- package/references/official-docs/docs/postmortem/0003-web-agent-gui-feedback-loop.md +53 -0
- package/references/official-docs/docs/postmortem/0003-web-agent-gui-feedback-loop.zh.md +53 -0
- package/references/official-docs/docs/postmortem/0004-landlock-partial-notice-misclassified-child-failures.i18n.yaml +6 -0
- package/references/official-docs/docs/postmortem/0004-landlock-partial-notice-misclassified-child-failures.md +55 -0
- package/references/official-docs/docs/postmortem/0004-landlock-partial-notice-misclassified-child-failures.zh.md +55 -0
- package/references/official-docs/docs/postmortem/README.i18n.yaml +6 -0
- package/references/official-docs/docs/postmortem/README.md +18 -0
- package/references/official-docs/docs/postmortem/README.zh.md +18 -0
- package/references/official-docs/docs/rescope.i18n.yaml +6 -0
- package/references/official-docs/docs/rescope.md +53 -0
- package/references/official-docs/docs/rescope.zh.md +53 -0
- package/references/official-docs/docs/subsystems/README.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/README.md +55 -0
- package/references/official-docs/docs/subsystems/README.zh.md +55 -0
- package/references/official-docs/docs/subsystems/approval.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/approval.md +170 -0
- package/references/official-docs/docs/subsystems/approval.zh.md +170 -0
- package/references/official-docs/docs/subsystems/attachment.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/attachment.md +115 -0
- package/references/official-docs/docs/subsystems/attachment.zh.md +115 -0
- package/references/official-docs/docs/subsystems/client-modules.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/client-modules.md +118 -0
- package/references/official-docs/docs/subsystems/client-modules.zh.md +118 -0
- package/references/official-docs/docs/subsystems/code-runtime.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/code-runtime.md +191 -0
- package/references/official-docs/docs/subsystems/code-runtime.zh.md +191 -0
- package/references/official-docs/docs/subsystems/commands.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/commands.md +187 -0
- package/references/official-docs/docs/subsystems/commands.zh.md +187 -0
- package/references/official-docs/docs/subsystems/compaction.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/compaction.md +238 -0
- package/references/official-docs/docs/subsystems/compaction.zh.md +238 -0
- package/references/official-docs/docs/subsystems/core.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/core.md +1070 -0
- package/references/official-docs/docs/subsystems/core.zh.md +1078 -0
- package/references/official-docs/docs/subsystems/credentials.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/credentials.md +133 -0
- package/references/official-docs/docs/subsystems/credentials.zh.md +133 -0
- package/references/official-docs/docs/subsystems/extensions.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/extensions.md +364 -0
- package/references/official-docs/docs/subsystems/extensions.zh.md +364 -0
- package/references/official-docs/docs/subsystems/feedback.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/feedback.md +266 -0
- package/references/official-docs/docs/subsystems/feedback.zh.md +266 -0
- package/references/official-docs/docs/subsystems/filesystem.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/filesystem.md +495 -0
- package/references/official-docs/docs/subsystems/filesystem.zh.md +495 -0
- package/references/official-docs/docs/subsystems/goal.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/goal.md +277 -0
- package/references/official-docs/docs/subsystems/goal.zh.md +277 -0
- package/references/official-docs/docs/subsystems/invariants.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/invariants.md +88 -0
- package/references/official-docs/docs/subsystems/invariants.zh.md +88 -0
- package/references/official-docs/docs/subsystems/jobs.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/jobs.md +290 -0
- package/references/official-docs/docs/subsystems/jobs.zh.md +290 -0
- package/references/official-docs/docs/subsystems/llm-streaming.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/llm-streaming.md +888 -0
- package/references/official-docs/docs/subsystems/llm-streaming.zh.md +894 -0
- package/references/official-docs/docs/subsystems/lsp.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/lsp.md +202 -0
- package/references/official-docs/docs/subsystems/lsp.zh.md +202 -0
- package/references/official-docs/docs/subsystems/permission-presets.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/permission-presets.md +131 -0
- package/references/official-docs/docs/subsystems/permission-presets.zh.md +131 -0
- package/references/official-docs/docs/subsystems/persistence.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/persistence.md +385 -0
- package/references/official-docs/docs/subsystems/persistence.zh.md +385 -0
- package/references/official-docs/docs/subsystems/plan.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/plan.md +87 -0
- package/references/official-docs/docs/subsystems/plan.zh.md +87 -0
- package/references/official-docs/docs/subsystems/sandbox.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/sandbox.md +218 -0
- package/references/official-docs/docs/subsystems/sandbox.zh.md +218 -0
- package/references/official-docs/docs/subsystems/schedule.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/schedule.md +186 -0
- package/references/official-docs/docs/subsystems/schedule.zh.md +186 -0
- package/references/official-docs/docs/subsystems/scope.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/scope.md +59 -0
- package/references/official-docs/docs/subsystems/scope.zh.md +59 -0
- package/references/official-docs/docs/subsystems/session-projection.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/session-projection.md +262 -0
- package/references/official-docs/docs/subsystems/session-projection.zh.md +262 -0
- package/references/official-docs/docs/subsystems/session-query.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/session-query.md +495 -0
- package/references/official-docs/docs/subsystems/session-query.zh.md +495 -0
- package/references/official-docs/docs/subsystems/session-reference.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/session-reference.md +108 -0
- package/references/official-docs/docs/subsystems/session-reference.zh.md +108 -0
- package/references/official-docs/docs/subsystems/session-telemetry.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/session-telemetry.md +194 -0
- package/references/official-docs/docs/subsystems/session-telemetry.zh.md +194 -0
- package/references/official-docs/docs/subsystems/session-title.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/session-title.md +204 -0
- package/references/official-docs/docs/subsystems/session-title.zh.md +204 -0
- package/references/official-docs/docs/subsystems/session.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/session.md +849 -0
- package/references/official-docs/docs/subsystems/session.zh.md +851 -0
- package/references/official-docs/docs/subsystems/settings.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/settings.md +310 -0
- package/references/official-docs/docs/subsystems/settings.zh.md +310 -0
- package/references/official-docs/docs/subsystems/shell.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/shell.md +303 -0
- package/references/official-docs/docs/subsystems/shell.zh.md +303 -0
- package/references/official-docs/docs/subsystems/skills.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/skills.md +331 -0
- package/references/official-docs/docs/subsystems/skills.zh.md +331 -0
- package/references/official-docs/docs/subsystems/spill.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/spill.md +117 -0
- package/references/official-docs/docs/subsystems/spill.zh.md +117 -0
- package/references/official-docs/docs/subsystems/storage.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/storage.md +229 -0
- package/references/official-docs/docs/subsystems/storage.zh.md +229 -0
- package/references/official-docs/docs/subsystems/subagent.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/subagent.md +734 -0
- package/references/official-docs/docs/subsystems/subagent.zh.md +736 -0
- package/references/official-docs/docs/subsystems/subprocess.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/subprocess.md +324 -0
- package/references/official-docs/docs/subsystems/subprocess.zh.md +324 -0
- package/references/official-docs/docs/subsystems/system-prompt.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/system-prompt.md +207 -0
- package/references/official-docs/docs/subsystems/system-prompt.zh.md +207 -0
- package/references/official-docs/docs/subsystems/terminal.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/terminal.md +184 -0
- package/references/official-docs/docs/subsystems/terminal.zh.md +184 -0
- package/references/official-docs/docs/subsystems/token-meter.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/token-meter.md +90 -0
- package/references/official-docs/docs/subsystems/token-meter.zh.md +90 -0
- package/references/official-docs/docs/subsystems/tools.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/tools.md +720 -0
- package/references/official-docs/docs/subsystems/tools.zh.md +720 -0
- package/references/official-docs/docs/subsystems/typert.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/typert.md +336 -0
- package/references/official-docs/docs/subsystems/typert.zh.md +336 -0
- package/references/official-docs/docs/subsystems/user-questions.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/user-questions.md +178 -0
- package/references/official-docs/docs/subsystems/user-questions.zh.md +178 -0
- package/references/official-docs/docs/subsystems/web-server.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/web-server.md +108 -0
- package/references/official-docs/docs/subsystems/web-server.zh.md +108 -0
- package/references/official-docs/docs/subsystems/web.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/web.md +199 -0
- package/references/official-docs/docs/subsystems/web.zh.md +199 -0
- package/references/official-docs/docs/subsystems/workflow.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/workflow.md +278 -0
- package/references/official-docs/docs/subsystems/workflow.zh.md +278 -0
- package/references/official-docs/docs/subsystems/workspace.i18n.yaml +6 -0
- package/references/official-docs/docs/subsystems/workspace.md +228 -0
- package/references/official-docs/docs/subsystems/workspace.zh.md +228 -0
- package/references/official-docs/docs/testing.i18n.yaml +6 -0
- package/references/official-docs/docs/testing.md +49 -0
- package/references/official-docs/docs/testing.zh.md +49 -0
- package/references/official-docs/docs/tool-catalog.i18n.yaml +6 -0
- package/references/official-docs/docs/tool-catalog.md +1873 -0
- package/references/official-docs/docs/tool-catalog.zh.md +1878 -0
- package/references/official-docs/docs/tool-execution-pipeline.i18n.yaml +6 -0
- package/references/official-docs/docs/tool-execution-pipeline.md +62 -0
- package/references/official-docs/docs/tool-execution-pipeline.zh.md +64 -0
- package/references/official-docs/docs/user/develop/basic/config.i18n.yaml +6 -0
- package/references/official-docs/docs/user/develop/basic/config.md +106 -0
- package/references/official-docs/docs/user/develop/basic/config.zh.md +106 -0
- package/references/official-docs/docs/user/develop/basic/index.i18n.yaml +6 -0
- package/references/official-docs/docs/user/develop/basic/index.md +144 -0
- package/references/official-docs/docs/user/develop/basic/index.zh.md +144 -0
- package/references/official-docs/docs/user/develop/basic/publish.i18n.yaml +6 -0
- package/references/official-docs/docs/user/develop/basic/publish.md +183 -0
- package/references/official-docs/docs/user/develop/basic/publish.zh.md +183 -0
- package/references/official-docs/docs/user/develop/basic/tool.i18n.yaml +6 -0
- package/references/official-docs/docs/user/develop/basic/tool.md +52 -0
- package/references/official-docs/docs/user/develop/basic/tool.zh.md +52 -0
- package/references/official-docs/docs/user/develop/framework/events.i18n.yaml +6 -0
- package/references/official-docs/docs/user/develop/framework/events.md +143 -0
- package/references/official-docs/docs/user/develop/framework/events.zh.md +143 -0
- package/references/official-docs/docs/user/develop/framework/index.i18n.yaml +6 -0
- package/references/official-docs/docs/user/develop/framework/index.md +137 -0
- package/references/official-docs/docs/user/develop/framework/index.zh.md +137 -0
- package/references/official-docs/docs/user/develop/framework/service.i18n.yaml +6 -0
- package/references/official-docs/docs/user/develop/framework/service.md +148 -0
- package/references/official-docs/docs/user/develop/framework/service.zh.md +150 -0
- package/references/official-docs/docs/user/develop/practice/index.i18n.yaml +6 -0
- package/references/official-docs/docs/user/develop/practice/index.md +155 -0
- package/references/official-docs/docs/user/develop/practice/index.zh.md +155 -0
- package/references/official-docs/docs/user/develop/practice/llm-adapter.i18n.yaml +6 -0
- package/references/official-docs/docs/user/develop/practice/llm-adapter.md +188 -0
- package/references/official-docs/docs/user/develop/practice/llm-adapter.zh.md +188 -0
- package/references/official-docs/docs/user/guide/index.i18n.yaml +6 -0
- package/references/official-docs/docs/user/guide/index.md +30 -0
- package/references/official-docs/docs/user/guide/index.zh.md +30 -0
- package/references/official-docs/docs/user/guide/providers-custom-form.png +0 -0
- package/references/official-docs/docs/user/guide/providers-custom-form.zh.png +0 -0
- package/references/official-docs/docs/user/guide/providers-models-page.png +0 -0
- package/references/official-docs/docs/user/guide/providers-models-page.zh.png +0 -0
- package/references/official-docs/docs/user/guide/providers.i18n.yaml +6 -0
- package/references/official-docs/docs/user/guide/providers.md +98 -0
- package/references/official-docs/docs/user/guide/providers.zh.md +98 -0
- package/references/official-docs/docs/user/guide/python-sdk.i18n.yaml +6 -0
- package/references/official-docs/docs/user/guide/python-sdk.md +104 -0
- package/references/official-docs/docs/user/guide/python-sdk.zh.md +104 -0
- package/references/official-docs/docs/user/index.i18n.yaml +6 -0
- package/references/official-docs/docs/user/index.md +11 -0
- package/references/official-docs/docs/user/index.zh.md +11 -0
- package/references/official-docs/docs/web-styling.i18n.yaml +6 -0
- package/references/official-docs/docs/web-styling.md +25 -0
- package/references/official-docs/docs/web-styling.zh.md +25 -0
- package/references/official-docs/examples/AGENTS.md +20 -0
- package/references/official-docs/packages/AGENTS.md +27 -0
- package/references/official-docs/packages/README.md +69 -0
- package/references/official-docs/vendor/README.md +60 -0
- package/references/official-docs/website-docs.ts +524 -0
- package/references/sources.md +137 -0
- package/references/upstream-cordis.md +594 -0
- package/references/website-pages.md +668 -0
- package/scripts/archive-discussions.ps1 +154 -0
- package/scripts/download-community-articles.ps1 +188 -0
- package/scripts/download-community-repos.ps1 +232 -0
- package/scripts/download-sources.ps1 +195 -0
- package/scripts/gen-topic-snapshot.ps1 +91 -0
- package/scripts/install-skill.ps1 +63 -0
- package/scripts/sync-official-docs.ps1 +130 -0
- package/scripts/verify-kit.ps1 +191 -0
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
# Cordis 框架调研
|
|
2
|
+
|
|
3
|
+
> **归档更正(2026-08-13 下载复核)**:本报告撰写时子代理沙箱禁网,未验证 cordis.io。知识库下载脚本实测:`https://cordis.io/` 返回 **308 永久重定向到自身**(curl 跟随即死循环;`www.`/`http` 变体亦不可达)——该站点当前无法访问或已改址。上游权威以 **GitHub 仓库**(`downloads/github/cordis/`:README、package.json、仓库树、全部 md 文档)+ **DSH vendored 源码**(`vendor/cordis/src/*`)为准;cordis.js.org 是否 301 至 cordis.io 仍标 [unverified]。
|
|
4
|
+
|
|
5
|
+
> 目标读者:DeepSeek Harness 插件开发者。本文为 Cordis 插件框架(https://github.com/cordiverse/cordis)的基础知识调研,作为 DSH 插件开发的知识底座。
|
|
6
|
+
>
|
|
7
|
+
> 语言约定:中文叙述,保留英文技术术语(`ctx.effect`、`Service`、`Fiber`、`waterfall`、`inject` 等)。
|
|
8
|
+
>
|
|
9
|
+
> 标注约定:每条事实尽量给出**精确 URL**。凡无法通过一手来源(源码 / 官方文档 / 仓库元数据)核实的论断,标注 **[unverified]**。
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 0. 关键结论先行(务必先读)
|
|
14
|
+
|
|
15
|
+
Cordis 存在**两个明显不同的 API 谱系**,调研时必须区分,否则会混淆:
|
|
16
|
+
|
|
17
|
+
| 谱系 | 版本 | 代表 API | 状态 |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| **经典 Cordis**(Koishi 时代) | `cordis` v1–v3,`@cordisjs/core` v3 | `ctx.scope`、`ctx.select`、`ctx.using`、`ctx.provide/inject/get/set`、`ctx.effect/on/root/plugin`;`ctx.loader`(`@koishijs/loader`)、`ctx.registry`(`@koishijs/registry`) | 历史版本,npm 上仍可查(`cordis` 1.5.2 / 2.1.1 / 2.3.1,`@cordisjs/core` 3.17.7) |
|
|
20
|
+
| **Cordis v4(重写版)** | `cordis` 4.x,即 DSH 所 vendored 的版本 | `ctx.effect/on/root/plugin/inject`、`ctx.get/set/provide`、`ctx.extend/isolate/intercept`(取代 `scope/select`)、`ctx.registry`(内置)、`ctx.reflect/fiber/events/logger`、`ctx.mixin/accessor`;`ctx.loader` 来自 `@cordisjs/plugin-loader`(loader 本身已是插件) | 当前上游 master 与 DSH 使用 |
|
|
21
|
+
|
|
22
|
+
**这是本调研最重要的一个事实**:用户问题清单里的 `ctx.scope` 与 `ctx.select/selector` 属于**经典谱系**;DSH 所 vendored 的 v4 已经用 `ctx.extend()` / `ctx.isolate()` / `ctx.intercept()` 取代了它们。`ctx.loader` 在 v4 不再是核心内置,而是 `@cordisjs/plugin-loader` 提供的一个 **Service**(见 §5)。`ctx.registry` 在 v4 变为核心内置(`ctx.registry` 永远存在),不再需要单独安装 registry 包。
|
|
23
|
+
|
|
24
|
+
- 上游仓库:https://github.com/cordiverse/cordis ,仓库描述为 "Meta-Framework of Spatiotemporal Composability"(时空可组合性的元框架)。作者为 Shigma(Koishi 作者)。
|
|
25
|
+
- 上游论文仓库:https://github.com/cordiverse/paper —— "A Programming Paradigm for Spatiotemporal Composability"(《一种时空可组合性的编程范式》)。
|
|
26
|
+
- 官方文档站:https://cordis.io/ (当前,v4 API;例如 https://cordis.io/zh-CN/api/core/context.html 、https://cordis.io/zh-CN/api/std/loader.html 、https://cordis.io/zh-CN/guide/starter/config.html )。经典文档站为 https://koishi.js.org/ (Koishi 文档中的 Context 页,如 https://koishi.js.org/api/core/context.html )以及更早的 cordis.js.org。
|
|
27
|
+
- DSH 对 Cordis 的 vendored 快照与本地文档(一手、权威):
|
|
28
|
+
- vendor 源码与同步清单:https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/README.md
|
|
29
|
+
- 概念入门:https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-primer.md
|
|
30
|
+
- API 参考(生成式):`docs/cordis-api/{context,events,fiber,registry,service,inherited}.md`
|
|
31
|
+
- 动手教程:`docs/cordis-tutorial/01…07`
|
|
32
|
+
- 术语表:https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/glossary.md
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 1. 核心插件范式:一切皆插件(Everything is a Plugin)
|
|
37
|
+
|
|
38
|
+
### 1.1 为什么“一切皆插件”
|
|
39
|
+
|
|
40
|
+
Cordis 的定义性观点是:**应用完全由插件组合而成**。DSH 的 `AGENTS.md` 第一句即是 "DeepSeek Harness is a plugin-based agent harness on vendored Cordis: **everything is a plugin**"。上游将其提炼为“时空可组合性(Spatiotemporal Composability)”:一个应用 = 若干插件(空间维度,谁和谁并存)在时间轴上的挂载/卸载(时间维度,何时生效)。
|
|
41
|
+
|
|
42
|
+
由此得到三个推论(见 DSH `docs/cordis-primer.md` 的 “Cordis In Five Ideas”):
|
|
43
|
+
|
|
44
|
+
1. **插件是一个实现 Service 的对象**:可以是带 `inject` / `apply(ctx)` 字段的函数,也可以是 `Service` 子类(其生命周期由 Cordis 挂载进当前 context)。
|
|
45
|
+
2. **context 是服务的仓库**:服务通过稳定键 `ctx.<key>`(如 `ctx.tools`、`ctx.llm`、`ctx.sessions`)被声明;其它插件**通过键名而非 import 具体实现**来获取服务。
|
|
46
|
+
3. **依赖通过 `inject` 声明**:插件列出所需服务,并在这些服务存在前一直等待,因此**加载顺序由服务依赖表达,而非手工 boot 序列**。
|
|
47
|
+
|
|
48
|
+
这意味着:没有“框架引导代码(bootstrap glue)”——插件只描述它贡献什么,`cordis.yml` 负责组合出整个应用。DSH 教程第一章的表述:“There is no framework bootstrap code in your file: a plugin describes what it contributes, and `cordis.yml` composes the application.”(https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-tutorial/01-first-plugin.md)
|
|
49
|
+
|
|
50
|
+
### 1.2 插件 = 函数(或类 / 对象),可返回 disposer
|
|
51
|
+
|
|
52
|
+
`ctx.plugin()` 接受三种插件形态(vendored 源码 `vendor/cordis/src/registry.ts`,`Plugin` 类型):
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
// 1. 函数插件:直接调用 callback(ctx, config)
|
|
56
|
+
export function apply(ctx: Context, config: Config) { /* ... */ }
|
|
57
|
+
|
|
58
|
+
// 2. 对象插件:带 apply(ctx, config) 方法
|
|
59
|
+
export const objectPlugin = {
|
|
60
|
+
name: 'object-plugin',
|
|
61
|
+
apply(ctx: Context, config: Config) { /* ... */ },
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 3. 类插件:Service 子类,用 new (ctx, config) 构造
|
|
65
|
+
export class MyService extends Service {
|
|
66
|
+
constructor(ctx: Context) { super(ctx, 'myService') }
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- 函数插件最常见的形态是**具名导出 `apply`**(loader 从模块读取 `apply`),但 `ctx.plugin(fn)` 直接接受函数本身。
|
|
71
|
+
- 插件可以返回一个 **disposer**(或 disposer 的数组/迭代器/async 迭代器,见 §2.1 的 `Effect`),在插件卸载时释放资源——这正是“插件 = `function(ctx) → disposer`”这一经典表述的准确含义。注意:v4 中 disposer 的登记被统一收敛进 `ctx.effect()`(见 §2.1),插件主体(`apply`)的返回值与 `ctx.effect` 的执行体共享同一套 `Effect` 形状处理逻辑(`vendor/cordis/src/fiber.ts` 的 `Effect` 类型与 `_execute`)。
|
|
72
|
+
|
|
73
|
+
### 1.3 Fiber:一个已加载插件实例的运行时句柄
|
|
74
|
+
|
|
75
|
+
`ctx.plugin()` 返回一个 **Fiber**(同时是 thenable,`await fiber` 等待其完成加载):
|
|
76
|
+
|
|
77
|
+
- 状态机(`vendor/cordis/src/fiber.ts` 的 `FiberState`):`PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED`,旁路 `FAILED`。
|
|
78
|
+
- `PENDING`:已声明,但某个 `inject` 的服务尚不可用。
|
|
79
|
+
- `LOADING / ACTIVE`:`apply` 正在执行 / 已执行完成。
|
|
80
|
+
- `FAILED`:`apply` 或 config 校验抛错。
|
|
81
|
+
- `UNLOADING / DISPOSED`:disposer 正在运行 / 全部拆除。
|
|
82
|
+
- `fiber.uid`:registry 内唯一 id,根 fiber 为 `0`,dispose 后为 `null`。
|
|
83
|
+
- `fiber.dispose()`:卸载插件,resolve 时全部清理(含 async disposer)已结束,并**递归卸载其挂载的子插件**。
|
|
84
|
+
- `fiber.restart()` / `fiber.update(config)`:按当前/新 config 重载。
|
|
85
|
+
- `fiber.getEffects()`:返回当前效果的 `EffectMeta` 诊断树。
|
|
86
|
+
- `fiber.name`:展示名,取自最近的具名祖先,否则 `'root'`。
|
|
87
|
+
|
|
88
|
+
教程第二章(https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-tutorial/02-lifecycle-and-effects.md )给出完整状态机与示例。
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 2. Context API
|
|
93
|
+
|
|
94
|
+
`Context` 是核心对象:一切 service / event / 生命周期 API 都经 `ctx` 到达。运行时 `Context` 是一个 **Proxy**:普通属性读取走 service 解析器(`ReflectService.handler`),而 `extend()` / `isolate()` / `intercept()` 派生作用域子 context,**不修改父 context**(`vendor/cordis/src/context.ts`)。
|
|
95
|
+
|
|
96
|
+
### 2.1 生命周期与 effect
|
|
97
|
+
|
|
98
|
+
- `ctx.effect(execute, label?)`:登记一个带清理语义的副作用。`execute` 立即执行,产生的 disposer 被收集,并在「返回的 disposer 被调用」或「所属 fiber 卸载」二者先发生时运行。**disposer 以注册逆序运行**;可以是 async(卸载时 await 它们)。执行体返回形状 `Effect`:
|
|
99
|
+
- 单个 disposer `() => T`
|
|
100
|
+
- 一个 disposer 的 `Promise`
|
|
101
|
+
- (async)可迭代的多个 disposer——**generator effect 每 yield 一个 disposer 就立即登记一个**
|
|
102
|
+
- 在已 dispose 的 fiber 上调用会抛 `CordisError('INACTIVE_EFFECT')`;返回非法形状抛 `TypeError`。
|
|
103
|
+
- `ctx.fiber`:当前 fiber(拥有此 context 的插件实例)。`ctx.effect()` 委托给它。
|
|
104
|
+
- **disposer 逆序执行、多个 async disposer 并发**:教程第二章明确提醒“如果拆除步骤必须顺序执行,把它们放进同一个 disposer 并在此 await”(https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-tutorial/02-lifecycle-and-effects.md )。
|
|
105
|
+
|
|
106
|
+
> **经典谱系对照**:`ctx.effect()` 在经典 Cordis 中即存在,语义一致(“返回 disposer,随插件卸载而回收”)。v4 额外把 `ctx.on()`、`ctx.plugin()`、`ctx.provide()` 等全部实现为 effect(见下),即 AGENTS.md 的 “**Registrations are effects**”。
|
|
107
|
+
|
|
108
|
+
### 2.2 作用域派生(v4 取代 scope/select 的机制)
|
|
109
|
+
|
|
110
|
+
- `ctx.extend(meta?)`:创建继承当前 scope 的子 context,叠加额外元数据;子 context 原型继承父的所有属性,`meta` 自有属性遮蔽继承项;**父不受影响**。
|
|
111
|
+
- `ctx.isolate(name, label?)`:为服务 `name` 创建独立服务作用域的子 context。在该子 context 之下,对服务 `name` 的读写解析到新 label 而非父的 label,因此可在不影响父作用域的前提下提供不同实现。传相同 `label` 给两次 `isolate()` 会**合并这两个作用域**(默认 label 是全新 symbol)。
|
|
112
|
+
- `ctx.intercept(name, config)`:为在其下启动的插件追加服务专属 intercept config(见 §3.3)。该 config 会被 merge 进服务的解析后 config(祖先条目优先,见 `Service[symbols.resolveConfig]`);父 context 不受影响。
|
|
113
|
+
|
|
114
|
+
> **`ctx.scope` / `ctx.select` 的说明**:这是**经典 Cordis(v2/v3)**的作用域 API——`ctx.scope` 派生隔离作用域、`ctx.select(name)` 创建在所选服务作用域中运行的选择器。它们在 v4 被 `extend/isolate/intercept` 取代。本文在 vendored v4 源码(`vendor/cordis/src/context.ts`)中**未找到** `scope`/`select` 属性(grep 仅命中注释里的普通英文 “scope”),因此 DSH 实际使用的 v4 无此二者。经典 API 的精确语义请以 Koishi 文档为准(https://koishi.js.org/api/core/context.html 、https://deepwiki.com/koishijs/koishi/2.1-context );下文对该二 API 的转述标注 **[unverified]**:`ctx.scope` 创建隔离作用域(服务提供在作用域内隔离),`ctx.select(name)` 返回一个可在选中服务作用域中消费/提供该服务的 `Selection` 对象(用于隔离多个同名服务的实例)。另有提交 `feat: support ctx.inject(), deprecate ctx.using()`(https://github.com/cordiverse/cordis/commit/b5cd65aa27a18b90aeb6c8f036570cf1a374277a )表明经典 `ctx.using()` 被 `ctx.inject()` 取代。**[unverified 部分如上]**
|
|
115
|
+
|
|
116
|
+
### 2.3 环境句柄与混合成员
|
|
117
|
+
|
|
118
|
+
`ctx` 上的环境句柄(`vendor/cordis/src/context.ts` 的 `Context` 接口):
|
|
119
|
+
|
|
120
|
+
- `ctx.root`:应用根 context(每个子 context 共享它)。标注 `@experimental`。
|
|
121
|
+
- `ctx.events`:事件总线 `EventsService`,其方法也 mixin 到 `ctx`(`ctx.on/emit/…`)。
|
|
122
|
+
- `ctx.logger`:日志服务 `LoggerService`,可 `ctx.logger(name)` 生成具名 logger,也可直接 `ctx.logger.info(...)`。
|
|
123
|
+
- `ctx.registry`:插件注册表 `RegistryService`,其方法 mixin 到 `ctx`(`ctx.plugin/inject`)。
|
|
124
|
+
- `ctx.reflect`:反射层 `ReflectService`,支撑 context proxy 与 `ctx.get/provide/…`。
|
|
125
|
+
- `ctx.baseUrl?`:解析相对插件/模块 specifier 的 base URL(运行时设定)。
|
|
126
|
+
- 静态符号:`Context.effect / filter / isolate / intercept`(对应 `symbols.effect/filter/isolate/intercept`,键为 `Symbol.for('cordis.*')`)。`Context.is(value)` 跨 realm/多份 cordis 判定是否为 context(以全局 symbol 品牌,而非 `instanceof`)。
|
|
127
|
+
|
|
128
|
+
`ctx` 上由 `ReflectService` mixin 出的方法(`vendor/cordis/src/reflect.ts` 构造器):
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
this.mixin('reflect', ['get', 'set', 'provide', 'accessor', 'mixin'])
|
|
132
|
+
this.mixin('fiber', ['runtime', 'effect'])
|
|
133
|
+
this.mixin('registry', ['inject', 'plugin'])
|
|
134
|
+
this.mixin('events', ['on', 'once', 'parallel', 'emit', 'serial', 'bail', 'waterfall'])
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- `ctx.get(name, strict?)`:无需 inject 直接从 store 读服务;`strict=true`(默认)只返回 provider fiber 当前 ACTIVE 的实现,否则可能返回 `undefined`。这是“可选依赖”的读取方式。
|
|
138
|
+
- `ctx.set(name, value)`:覆写某已提供服务的值;**只有提供该服务的 fiber 才能 set**,set 未提供名抛错。
|
|
139
|
+
- `ctx.provide(name, value)`:以当前 fiber 为所有者登记一个服务实现;fiber ACTIVE 后对同 isolation 作用域的依赖方可见;disposer 运行或 fiber 卸载时注销(唤醒依赖方)。同作用域重名抛错。
|
|
140
|
+
- `ctx.accessor(name, { get, set? })`:定义由 get/set 钩子支撑的计算型 context 属性;随 fiber 卸载移除。
|
|
141
|
+
- `ctx.mixin(name, keys)` / `ctx.mixin(source, keys)`:把服务成员直接暴露到 `ctx`(如 `ctx.on` 转发到 `ctx.events.on`,方法绑定到该服务);随 fiber 卸载移除。
|
|
142
|
+
|
|
143
|
+
> 来源(一手):https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-api/context.md 与 `vendor/cordis/src/{context,reflect}.ts`。
|
|
144
|
+
|
|
145
|
+
### 2.4 scope forking 与 dispose 语义小结
|
|
146
|
+
|
|
147
|
+
- “作用域分叉(scope forking)”在 v4 = `extend()` 派生原型子 context;服务隔离 = `isolate()`;配置拦截 = `intercept()`。三者都不改动父 context(copy-on-write 原型链)。
|
|
148
|
+
- 事件监听过滤也通过 context 实现:每个 context 可携带一个 **listener filter**(`Context.filter` symbol,`ctx[Context.filter]`),每次事件分发都会查询它(见 §4.4)。
|
|
149
|
+
- dispose 语义:所有注册都是 effect;卸载按 fiber 为单位,disposer 逆序、async 并发;子插件随父插件递归卸载。
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 3. Services(服务)
|
|
154
|
+
|
|
155
|
+
### 3.1 服务定义与提供
|
|
156
|
+
|
|
157
|
+
- 基类 `Service`(`vendor/cordis/src/service.ts`):在 `ctx` 上暴露具名 API 的抽象基类。子类在构造器调用 `super(ctx, name)`——服务**立即注册**,并随所属 fiber 自动移除。
|
|
158
|
+
- `super(ctx, name)` 内部调用 `ctx.reflect.provide(name, this, this[Service.check])`(`service.ts` 构造器),等价于 `ctx.provide(name, value)`。
|
|
159
|
+
- `name ??= this.constructor['provide']`:服务名默认取静态 `provide` 字段。
|
|
160
|
+
- 若服务带 `[Service.invoke]` 执行体,则实例变为**可调用对象**(如 `ctx.logger()`)。
|
|
161
|
+
- 消费方通过 `inject` 或 `ctx.get(name)` 获取;类型上通过 `declare module '@deepseek-ai/cordis' { interface Context { <key>: <Type> } }` 的 **declaration merging** 把键加进 `Context` 接口(编译期,无运行时代码)。
|
|
162
|
+
|
|
163
|
+
DSH 教程第三章的完整例子(https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-tutorial/03-services.md ):
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import { Service, type Context } from '@deepseek-ai/cordis'
|
|
167
|
+
|
|
168
|
+
declare module '@deepseek-ai/cordis' {
|
|
169
|
+
interface Context { greeter: GreeterService }
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export class GreeterService extends Service {
|
|
173
|
+
constructor(ctx: Context) { super(ctx, 'greeter') }
|
|
174
|
+
greet(who: string) { return `Hello, ${who}!` }
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export const name = 'greeter'
|
|
178
|
+
export function apply(ctx: Context) { ctx.plugin(GreeterService) }
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
消费方:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
export const name = 'consumer'
|
|
185
|
+
export const inject = ['greeter']
|
|
186
|
+
export function apply(ctx: Context) { console.log(ctx.greeter.greet('world')) }
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### 3.2 `inject`:声明依赖
|
|
190
|
+
|
|
191
|
+
- `inject` 有数组/对象两种形式(`Inject` 类型,`vendor/cordis/src/registry.ts`):数组形式仅请求服务;对象形式把每个服务名映射到可选 intercept config。
|
|
192
|
+
- `ctx.inject(deps, callback)` 是 `ctx.plugin({ inject, apply: callback })` 的简写:当所需服务可用时执行 callback,且**每当所需服务变化时卸载并重跑**。
|
|
193
|
+
- **依赖在加载后仍被跟踪**:若所需服务在运行中消失(其 provider 被卸载或被热替换),所有依赖方插件也会被卸载,并在服务恢复时重新加载——从而避免运行中的消费者持有不可用服务的引用。这也是“服务替换”可配置化的基础。
|
|
194
|
+
- 可选依赖:不用 `inject`,在 `apply` 内部用 `ctx.get(name)`(返回 `undefined` 表示未提供)。
|
|
195
|
+
|
|
196
|
+
### 3.3 intercept(配置拦截 / provider 无关的服务配置)
|
|
197
|
+
|
|
198
|
+
- `inject` 的对象形式 / `ctx.intercept(name, config)` / loader entry 的 `intercept` 字段,都会把一段 config 合并进该服务在插件 context 下的“解析后 config”。
|
|
199
|
+
- 合并规则(`Service[symbols.resolveConfig]`):祖先条目优先(更靠近根的条目先合并),`base` 前置、`head` 后置;服务若声明 `Config.merge` 则用其合并,否则浅 `Object.assign`。
|
|
200
|
+
- 典型用途:loader 服务自身声明 `Loader.Intercept = { await?: boolean }`,让依赖 `loader` 的插件在 loader entries 尚在加载时保持 PENDING(`vendor/loader/src/index.ts` 的 `[Service.check]`)。
|
|
201
|
+
|
|
202
|
+
### 3.4 隔离状态 vs 共享状态
|
|
203
|
+
|
|
204
|
+
- 默认:同一服务名在一个作用域内**唯一**(同作用域重名 `provide` 抛错 `service "x" has been registered at <fiber>`)。
|
|
205
|
+
- 隔离通过 `ctx.isolate(name)` 或 loader 的 `isolate` entry 字段实现:不同 label 各持一份实现。
|
|
206
|
+
- Loader 层有 `LocalRealm`(entry 本地隔离,label 后缀 `#<id>`)与 `GlobalRealm`(具名共享隔离,label 后缀 `@<label>`)两种 realm(`vendor/loader/src/config/isolate.ts`)。`isolate: { shell: true }` = 每个 entry 本地隔离;`isolate: { shell: 'shared-label' }` = 同一 label 的 entry 共享同一隔离实例。
|
|
207
|
+
- DSH 文档的服务隔离示例(https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/framework/service.md#service-isolation ):两个 group 各自 `isolate: { shell: true }`,则 `plugin-a` 与 `plugin-b` 各看到自己组的 Bash 实例(如 `timeoutMs` 5000 vs 60000),互不影响。
|
|
208
|
+
|
|
209
|
+
### 3.5 `Service` 的静态符号(扩展点)
|
|
210
|
+
|
|
211
|
+
`vendor/cordis/src/service.ts` 定义:`Service.init`(类插件构造后运行实例方法)、`Service.check`(传给 `ctx.provide` 的可用性谓词)、`Service.config`(phantom intercept-config 类型参数)、`Service.invoke`(使服务可调用的调用体,如 `ctx.logger()`)、`Service.extend`(派生扩展服务实例)、`Service.tracker`(context 追踪元数据)、`Service.resolveConfig`(上文 intercept 解析)。这些符号键均为 `Symbol.for('cordis.*')`(`vendor/cordis/src/utils.ts`)。
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## 4. Events(事件)
|
|
216
|
+
|
|
217
|
+
### 4.1 五种 dispatch mode
|
|
218
|
+
|
|
219
|
+
`vendor/cordis/src/events.ts` 定义 `DispatchMode` 与五个方法(也 mixin 到 `ctx`):
|
|
220
|
+
|
|
221
|
+
| Mode | 调用 | 语义 |
|
|
222
|
+
|---|---|---|
|
|
223
|
+
| `emit` | `ctx.emit(name, ...args)` | 同步广播;忽略返回值,不 await 返回的 promise |
|
|
224
|
+
| `parallel` | `await ctx.parallel(name, ...args)` | 所有监听器并发执行,一起 await(`Promise.allSettled`,有错抛 `AggregateError`) |
|
|
225
|
+
| `serial` | `await ctx.serial(name, ...args)` | 按注册顺序 await;第一个非 `null/false/undefined`(bail)返回并停止后续 |
|
|
226
|
+
| `bail` | `ctx.bail(name, ...args)` | `serial` 的同步版 |
|
|
227
|
+
| `waterfall` | `ctx.waterfall(name, ...args, next)` | around-middleware,见 §4.3 |
|
|
228
|
+
|
|
229
|
+
dispatch mode 是事件公开契约的一部分。DSH 约定新事件用 `@mode` JSDoc 标签标注,供生成目录核对声明与分发点(`docs/cordis-primer.md`)。
|
|
230
|
+
|
|
231
|
+
### 4.2 类型化事件(declaration merging)
|
|
232
|
+
|
|
233
|
+
- 事件名经 TypeScript **declaration merging** 声明:`declare module '@deepseek-ai/cordis' { interface Events { 'stats/report'(name: string, count: number): void } }`。
|
|
234
|
+
- 然后 `ctx.emit('stats/report', ...)`、`ctx.on('stats/report', (name, count) => ...)` 全类型化。
|
|
235
|
+
- 命名约定 `namespace/action`(教程第四章,https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-tutorial/04-events.md )。DSH 的 AGENTS.md 进一步要求:事件 JSDoc 需 `@mode` 与 payload `@param`;作用域键缺 payload 时需 `@dshScopeScan unsupported`。
|
|
236
|
+
|
|
237
|
+
### 4.3 waterfall 语义(拦截与短路的机制)
|
|
238
|
+
|
|
239
|
+
`ctx.waterfall(name, ...args, next)`:每个监听器收到 `(...args, next)`。调用 `next()` 委派给下一个监听器(最终是内置行为);不调用 `next()` 即**否决(veto)短路**剩余链条。`next()` 的返回值沿链回传,监听器可包装/替换它。
|
|
240
|
+
|
|
241
|
+
纪律(DSH `docs/cordis-primer.md` 与 AGENTS.md):**只观察/注解的 waterfall 监听器必须调用 `next()`**;不调用即刻意短路。DSH 用 waterfall 实现可包装/回答的决策点(如 `agent/request` 替换模型调用配置、`approval/request` 由策略代为回答)。
|
|
242
|
+
|
|
243
|
+
### 4.4 hooks 与过滤(topic selection / event bus 语义)
|
|
244
|
+
|
|
245
|
+
- `ctx.on(name, listener, options?)`:登记监听器,返回 disposer;`options` 可为布尔(`prepend` 简写)或 `EventOptions { prepend?, global? }`。
|
|
246
|
+
- `ctx.once(name, listener, options?)`:首调后自 dispose。
|
|
247
|
+
- `prepend: true`:把监听器插入到同事件已有监听器之前。
|
|
248
|
+
- `global: true`:忽略 context filter 检查(见下)。
|
|
249
|
+
- **过滤(topic selection)**:`EventsService.dispatch()` 在解析监听器时执行过滤——`const filter = thisArg?.[Context.filter]`,然后 `.filter(hook => hook.global || !filter || filter.call(thisArg, hook.ctx))`。即:
|
|
250
|
+
- 分发方法的第一个参数可以是显式 `thisArg`(作为监听器的 `this`,同时用于过滤)。
|
|
251
|
+
- 若 `thisArg` 携带 `[Context.filter]`(一个 `(listenerCtx) => boolean`),则只有 `global` 监听器或通过 filter 的监听器收到事件。
|
|
252
|
+
- 这就是 DSH 的“作用域过滤分发(scoped dispatch)”在 Cordis 层的机制底座:事件针对某 agent 活动时,以该 agent 的 scope carrier 作为 `thisArg` 分发,filter 只放行无标签监听器与主题自身监听器(见 `docs/glossary.md` 的 `agent-scope`)。
|
|
253
|
+
- **事件总线语义**:监听器随所属 fiber 自动 dispose(`register()` 内部就是 `ctx.fiber.effect(...)`,返回 `() => this.unregister(...)`)。`internal/` 前缀事件为框架内部事件。
|
|
254
|
+
|
|
255
|
+
### 4.5 内置框架事件(`internal/*`)
|
|
256
|
+
|
|
257
|
+
`vendor/cordis/src/events.ts` 的 `Events` 接口:`internal/plugin`(fiber 创建 / uid 清除)、`internal/status`(fiber 状态变化)、`internal/config`(waterfall,注入激活后解析原始 config)、`internal/service`(服务绑定拦截钩子,无核心 producer)、`internal/update`(waterfall,应用 fiber config 更新,跳过 `next()` 否决)、`internal/get`(waterfall,经 context proxy 读服务)、`internal/set`(waterfall,写服务)、`internal/listener`(bail,监听器注册拦截,非空返回替代注册)、`internal/dispatch`(非 internal 事件分发前的诊断)。
|
|
258
|
+
|
|
259
|
+
DSH 的 `docs/cordis-api/inherited.md` 还列出 loader/hmr 增补事件:`exit`、`loader/config-update`、`loader/entry-init`、`loader/partial-dispose`、`loader/patch-context`、`hmr/change`、`hmr/reload`。
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 5. Loader 与配置(cordis.yml)
|
|
264
|
+
|
|
265
|
+
### 5.1 Loader 是插件,提供 `ctx.loader` 服务
|
|
266
|
+
|
|
267
|
+
关键提交:`feat(loader): loader as a cordis plugin`(https://github.com/cordiverse/cordis/commit/fd408a422375972b4ff02a9647063919d055b133 )。v4 中 loader 是 `@cordisjs/plugin-loader`(DSH 里为 `@deepseek-ai/cordis-plugin-loader`),一个 `Service`,通过 `declare module` 增补 `interface Context { loader: Loader }`(`vendor/loader/src/index.ts`)。挂载方式:
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
import { Context } from 'cordis'
|
|
271
|
+
import Loader from '@cordisjs/plugin-loader'
|
|
272
|
+
const root = new Context()
|
|
273
|
+
await root.plugin(Loader, { baseUrl: import.meta.url })
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Loader 核心 API(`vendor/loader/README.md`):
|
|
277
|
+
|
|
278
|
+
| API | 作用 |
|
|
279
|
+
|---|---|
|
|
280
|
+
| `loader.create(options, parent?, position?)` | 新增并启动 entry |
|
|
281
|
+
| `loader.update(id, options, parent?, position?)` | 更新/移动/重启 entry |
|
|
282
|
+
| `loader.remove(id)` | 停止并删除 entry |
|
|
283
|
+
| `loader.resolve(id)` | 按 id(含嵌套 `a:b`)解析 entry |
|
|
284
|
+
| `loader.resolveGroup(id)` | 解析根组或嵌套组 |
|
|
285
|
+
| `loader.await()` | 等待挂起的 import 与 fiber 重载 |
|
|
286
|
+
| `loader.locate(fiber?)` | 返回拥有某 fiber 的 entry id |
|
|
287
|
+
|
|
288
|
+
`@cordisjs/plugin-include` 提供文件后端的 loader tree(读写 YAML/JSON),是 `cordis.yml` 的落地实现。
|
|
289
|
+
|
|
290
|
+
### 5.2 cordis.yml 的 schema(entry list)
|
|
291
|
+
|
|
292
|
+
`cordis.yml` 是**顶层数组**,每个元素是一个 entry(`EntryOptions`,`vendor/loader/src/config/entry.ts`):
|
|
293
|
+
|
|
294
|
+
| 字段 | 说明 |
|
|
295
|
+
|---|---|
|
|
296
|
+
| `id` | 所在 entry tree 内的稳定 id(用于 diff/更新/删除) |
|
|
297
|
+
| `name` | 被 import 的模块 specifier(相对路径或 npm 包名) |
|
|
298
|
+
| `config` | 传给插件的配置 |
|
|
299
|
+
| `group` | 标记为嵌套组,其 `config` 是子 entry 列表 |
|
|
300
|
+
| `disabled` | 停止该 entry 及其后代,但不删除 |
|
|
301
|
+
| `inject` | 为该 entry 追加所需服务或 intercept config |
|
|
302
|
+
| `intercept` / `isolate` | 服务配置拦截 / 服务隔离(由 loader 的 isolate 子插件增补,`vendor/loader/src/config/isolate.ts`) |
|
|
303
|
+
|
|
304
|
+
最小示例(`vendor/include/README.md`):
|
|
305
|
+
|
|
306
|
+
```yaml
|
|
307
|
+
- id: timer
|
|
308
|
+
name: '@cordisjs/plugin-timer'
|
|
309
|
+
- id: app
|
|
310
|
+
name: ./plugins/app
|
|
311
|
+
config:
|
|
312
|
+
message: hello
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Include 插件 config:`path`(YAML/JSON 路径,相对 `ctx.baseUrl` 解析)、`initial`(文件缺失时写入的初始列表)、`patches`(读后应用的运行时补丁)、`enableLogs`(loader 日志开关)。文件缺失且无 `initial` 时抛错;有 `initial` 则写出后回读。
|
|
316
|
+
|
|
317
|
+
### 5.3 插件解析(plugin resolution)
|
|
318
|
+
|
|
319
|
+
`EntryTree.import(name)`(`vendor/loader/src/config/tree.ts`):
|
|
320
|
+
|
|
321
|
+
1. `name` 以 `cordis:` 开头 → 读 `ctx.loader.builtins[name.slice(7)]`(内置)。
|
|
322
|
+
2. 否则,若存在 Node 内部模块 loader(`ModuleLoader.fromInternal()`,经 `node-addon-require-builtin` 或 `--expose-internals` 取得,兼容 Node 22/23 v1 与 Node 24+ v2 形状),用 `internal.import(name, baseUrl, {})`。
|
|
323
|
+
3. 否则,`name` 以 `.` 开头 → `import(new URL(name, baseUrl).href)`(相对 base URL);否则 `import(name)`(裸包名)。
|
|
324
|
+
|
|
325
|
+
模块导出经 `Loader.unwrapExports()` 归一化 ESM/CJS/default 导出形状(`exports.default ?? exports`,处理 `__esModule`)。DSH 约定 Raw/Web `cordis.yml` 裸插件必须出现在其 resolver manifest 的 `dependencies` 中(由 `verify-cordis-config` 强制)。
|
|
326
|
+
|
|
327
|
+
### 5.4 `!!js` 计算表达式
|
|
328
|
+
|
|
329
|
+
- `@cordisjs/plugin-include` 用 js-yaml 的 `Type('tag:yaml.org,2002:js')` 把 `!!js` 标量解析为 `{ __jsExpr: '<expr>' }`(`vendor/include/src/index.ts` 的 `JsExpr` / `entryListSchema`)。
|
|
330
|
+
- Loader 在 entry 激活、声明注入已激活之后,对 entry 的 `config` 做 `interpolate(ctx, config)`——递归把 `__jsExpr` 节点替换为 `evaluate(ctx, expr)`(`new Function('ctx','expr','with(ctx){ return eval(expr) }')`,`vendor/loader/src/config/utils.ts`)。
|
|
331
|
+
- 用法(DSH 教程第五章,https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-tutorial/05-config.md ):
|
|
332
|
+
|
|
333
|
+
```yaml
|
|
334
|
+
- name: './config-demo.ts'
|
|
335
|
+
config:
|
|
336
|
+
greeting: !!js process.env.DEMO_GREETING ?? 'Hello'
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
- **DSH 扩展**:`disabled: !!js ...` 在每次挂载决策时对 loader context 求值(原始节点留在 options 里,写回保持 `!!js` 形式);`disabled` 是唯一被插值的元数据字段,其余元数据(`name/id/inject/…`)保持字面量。`!!js` 只作用于 `config` 与 entry 的 `disabled` 字段(DSH `docs/cordis-primer.md` “Loader Configuration”)。注意 `!!js`(双感叹号)而非 `!js`(AGENTS.md 强调 "allows `!!js` (never `!js`)")。
|
|
340
|
+
- Group/Include 作为“tree carrier”(声明 `EntryGroup.key`)保持自身 config 字面量,以便其嵌套行里的 `!!js` 在各行自己的 fiber 中惰性求值(`vendor/loader/src/index.ts` 的 `internal/config` 钩子)。
|
|
341
|
+
|
|
342
|
+
### 5.5 filters / patches(过滤与补丁)
|
|
343
|
+
|
|
344
|
+
- `@cordisjs/plugin-include` 的 `patches` 是对 entry 列表应用的**运行时补丁**(`PatchOptions`,`vendor/include/src/index.ts`):每个 patch 可 `id` 定位目标、`name` 校验(不匹配则警告跳过)、覆盖任意字段,或 `insert`(无 `id` 时追加到顶层;有 `id` 且目标是 group 时插入其子列表)。
|
|
345
|
+
- `applyEntryPatches(data, patches, warn)` 是导出的纯函数(DSH 本地修改 #11),供 `dsh --dump-config` 与挂载共用同一 patch 语义;输入永不被原地修改,结果为 detached clone;插入的行会被立即索引,以便**同一列表里后出现的 patch 可配置/禁用先前插入的行**。
|
|
346
|
+
- **排序/顺序**:entry **并发启动**,列表位置不保证加载顺序;顺序由服务依赖(`inject`)决定(教程第一章明确:“Entries start concurrently, so list position guarantees nothing… ordering comes from service dependencies, not from position in the file.”)。这对应 §6 的依赖解析。
|
|
347
|
+
|
|
348
|
+
### 5.6 groups(分组)
|
|
349
|
+
|
|
350
|
+
`@cordisjs/plugin-group`(DSH `@deepseek-ai/cordis-plugin-group`,默认导出 loader 的 `Group`):
|
|
351
|
+
|
|
352
|
+
```yaml
|
|
353
|
+
- id: tools
|
|
354
|
+
name: '@cordisjs/plugin-group'
|
|
355
|
+
group: true
|
|
356
|
+
config:
|
|
357
|
+
- id: logger
|
|
358
|
+
name: '@cordisjs/plugin-logger-console'
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
- 组自身永远视为启用;禁用组 entry 会阻止其子 entry 运行。
|
|
362
|
+
- 嵌套 entry id 用 `:` 分隔(`EntryTree.sep = ':'`),如上例为 `tools:logger`。
|
|
363
|
+
- 组作为**一个单元**加载/卸载;可 `isolate` 服务(§3.4)。
|
|
364
|
+
- 组更新是事务性的(DSH 本地修改 #8):候选并发启动、收集全部结果、失败时撤销新增并恢复旧条目。
|
|
365
|
+
|
|
366
|
+
### 5.7 config 校验
|
|
367
|
+
|
|
368
|
+
插件导出 `Config` 作为 **Standard Schema** 校验器(`@standard-schema/spec`),`RegistryService.plugin()` 在启动前用 `runtime.Config['~standard'].validate(config)` 校验,失败抛 `ValidationError`(`vendor/cordis/src/fiber.ts`)。DSH 用 Schemastery(`Schema.object(...)`)产出 schema。坏 config 使 fiber 进入 `FAILED`、加载失败,**绝不半配置启动**("fail loud")。同步校验仅支持(async 校验抛 `TypeError('Async config validation is not supported')`)。插件 `Config` 也可以是 `Transform`(`schema: true` + `Config: (S) => T`,把用户 config 转运行时 config)。
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## 6. Registry 与发现(Registry & discovery)
|
|
373
|
+
|
|
374
|
+
### 6.1 RegistryService(内置 `ctx.registry`)
|
|
375
|
+
|
|
376
|
+
`vendor/cordis/src/registry.ts`:`ctx.registry` 是核心内置(不再需要单独的 registry 包)。它规范化插件形态、跟踪插件 runtime、启动 fiber、提供对活跃插件 callback 的 map 式遍历:
|
|
377
|
+
|
|
378
|
+
- `registry.resolve(plugin)`:把三种形态解析为可执行 callback(`typeof plugin === 'function'` 直接返回;对象取其 `apply`)。
|
|
379
|
+
- `registry.get/has/delete(plugin)`:查/删 runtime;`delete` 会 dispose 该插件的所有 fiber 并移除 runtime(对应提交 `feat: use ctx.registry.delete() when removing plugins`,https://github.com/cordiverse/cordis/commit/99a7cc6f91c408d18e9165215f7d3afa052f5d1a )。
|
|
380
|
+
- `registry.size / keys() / values() / entries() / forEach()`:Map 式遍历已注册 runtime。
|
|
381
|
+
- `registry.plugin(plugin, config, getOuterStack?)`:创建(或复用)runtime,再在当前 context 启动新 fiber;非法形态或当前 fiber 已 dispose 抛错。
|
|
382
|
+
- 每个 `Plugin.Runtime` 记录:`name`、`fibers`(`DisposableList<Fiber>`)、`callback`(registry 身份键)、`Config`。一个插件 callback 的所有 fiber 共享一个 runtime。
|
|
383
|
+
|
|
384
|
+
### 6.2 插件名 / 身份
|
|
385
|
+
|
|
386
|
+
- 插件展示名 `name`(`Plugin.Base.name`,即 `export const name = ...` 或函数名),用于 fiber 诊断与 logger 名。`fiber.name` 继承最近具名祖先,否则 `'root'`。
|
|
387
|
+
- 提供名 `provide`(`Plugin.Base.provide`,字符串或数组)供 `Service` 与 loader 读取(声明“我提供哪些服务”)。
|
|
388
|
+
- 依赖声明 `inject`、intercept 消费声明 `intercept`(`Dict<boolean>`)。
|
|
389
|
+
- `@Inject(name, config?)` 装饰器:类上并入静态 `inject`;方法上延迟到服务可用时再调用。
|
|
390
|
+
|
|
391
|
+
### 6.3 依赖解析(dependency resolution)
|
|
392
|
+
|
|
393
|
+
`Fiber` 的依赖状态机(`vendor/cordis/src/fiber.ts`):
|
|
394
|
+
|
|
395
|
+
- 构造时把 `inject` 解析为 map(`Inject.resolve`),并为每条带 intercept config 的依赖挂到子 context 的 intercept。
|
|
396
|
+
- 发布 `internal/plugin` 通知**之后**才解析依赖(loader 可能在该通知中扩展 `inject`),对每个注入名 `_checkImpl(name)`(取当前 isolation label 下的 `Impl`,有 `check` 谓词则执行)。
|
|
397
|
+
- `_refresh()` 计算 epoch:所有注入服务的 `fiber.uid` 拼接;只要缺一个实现,epoch = `INACTIVE` → fiber 保持 `PENDING`。
|
|
398
|
+
- 服务变化经 `ReflectService.notify(names)` 广播:遍历 registry 所有 runtime/fiber,对注入这些名字的 fiber 重查实现并 `_refresh()`(触发 load/unload),并 emit `internal/service`(带 filter 限定作用域)。这正是“依赖方随服务增删自动重载”的机制。
|
|
399
|
+
- `ctx.get(name, strict=false)` 可绕过 inject 直接读(严格模式要求 provider ACTIVE)。
|
|
400
|
+
|
|
401
|
+
### 6.4 discovery(发现)
|
|
402
|
+
|
|
403
|
+
- 服务发现:消费者**不 import 具体实现**,通过 `ctx.<key>`(proxy 经 `internal/get` waterfall + 沿 fiber 链向上查 `fiber.store`)或 `ctx.get(name)` 解析。
|
|
404
|
+
- 插件发现:`ctx.registry.values()` 枚举所有 runtime/fiber(教程第六章用其诊断 PENDING 状态,https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-tutorial/06-composition-and-hmr.md )。
|
|
405
|
+
- 模块发现:loader 按 specifier 解析(§5.3),支持 `cordis:` 内置、Node 内部 loader、相对/裸 specifier。
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## 7. 典型示例(canonical code shapes)
|
|
410
|
+
|
|
411
|
+
以下均为 DSH 教程/源码中的规范形态(每段已在正文给出出处)。
|
|
412
|
+
|
|
413
|
+
### 7.1 最小函数插件 + cordis.yml
|
|
414
|
+
|
|
415
|
+
```ts
|
|
416
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
417
|
+
export const name = 'hello'
|
|
418
|
+
export function apply(ctx: Context) { console.log('hello from my first plugin') }
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
```yaml
|
|
422
|
+
- name: './hello.ts'
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### 7.2 带 effect 的资源与子插件
|
|
426
|
+
|
|
427
|
+
```ts
|
|
428
|
+
export function apply(ctx: Context) {
|
|
429
|
+
const fiber = ctx.plugin(heartbeat) // 从代码挂载子插件,返回 Fiber
|
|
430
|
+
ctx.effect(() => { // 外部资源包成 effect
|
|
431
|
+
const timer = setTimeout(async () => { await fiber.dispose(); process.exit(0) }, 700)
|
|
432
|
+
return () => clearTimeout(timer) // disposer:卸载时运行
|
|
433
|
+
})
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### 7.3 服务定义 + 消费者
|
|
438
|
+
|
|
439
|
+
见 §3.1(`GreeterService` / `consumer` 例子)。
|
|
440
|
+
|
|
441
|
+
### 7.4 类型化事件 + waterfall 短路
|
|
442
|
+
|
|
443
|
+
```ts
|
|
444
|
+
declare module '@deepseek-ai/cordis' {
|
|
445
|
+
interface Events { 'demo/transform'(input: string, next: () => Promise<string>): Promise<string> }
|
|
446
|
+
}
|
|
447
|
+
export function apply(ctx: Context) {
|
|
448
|
+
ctx.on('demo/transform', async (input, next) => (await next()).toUpperCase()) // 包装下游结果
|
|
449
|
+
ctx.on('demo/transform', async (input, next) => { // 决策短路
|
|
450
|
+
if (input.includes('blocked')) return '** blocked **'
|
|
451
|
+
return next()
|
|
452
|
+
})
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### 7.5 带 schema 的配置插件
|
|
457
|
+
|
|
458
|
+
```ts
|
|
459
|
+
import Schema from '@deepseek-ai/schemastery'
|
|
460
|
+
export interface Config { greeting: string; targets: string[] }
|
|
461
|
+
export const Config: Schema<Config> = Schema.object({
|
|
462
|
+
greeting: Schema.string().default('Hello'),
|
|
463
|
+
targets: Schema.array(String).default(['world']),
|
|
464
|
+
})
|
|
465
|
+
export function apply(ctx: Context, config: Config) { /* config 已完整校验 */ }
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### 7.6 上游 README 快速上手(vendored `vendor/cordis/README.md`)
|
|
469
|
+
|
|
470
|
+
```ts
|
|
471
|
+
import { Context, Service } from 'cordis'
|
|
472
|
+
declare module 'cordis' {
|
|
473
|
+
interface Context { counter: Counter }
|
|
474
|
+
interface Events { 'app/ready'(message: string): void }
|
|
475
|
+
}
|
|
476
|
+
class Counter extends Service {
|
|
477
|
+
value = 0
|
|
478
|
+
constructor(ctx: Context) { super(ctx, 'counter') }
|
|
479
|
+
next() { return ++this.value }
|
|
480
|
+
}
|
|
481
|
+
const greeter = Object.assign((ctx: Context) => {
|
|
482
|
+
ctx.on('app/ready', (message) => ctx.logger.info('%s #%d', message, ctx.counter.next()))
|
|
483
|
+
}, { inject: ['counter'] })
|
|
484
|
+
const root = new Context()
|
|
485
|
+
await root.plugin(Counter)
|
|
486
|
+
await root.plugin(greeter)
|
|
487
|
+
root.emit('app/ready', 'started')
|
|
488
|
+
await root.fiber.dispose()
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### 7.7 HMR 组合
|
|
492
|
+
|
|
493
|
+
```yaml
|
|
494
|
+
- id: logger
|
|
495
|
+
name: '@deepseek-ai/cordis-plugin-logger-console'
|
|
496
|
+
- id: timer
|
|
497
|
+
name: '@deepseek-ai/cordis-plugin-timer'
|
|
498
|
+
- id: hmr
|
|
499
|
+
name: '@deepseek-ai/cordis-plugin-hmr'
|
|
500
|
+
config:
|
|
501
|
+
root: ['.']
|
|
502
|
+
- id: hello
|
|
503
|
+
name: './hello.ts'
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
## 8. Cordis → DeepSeek Harness 概念映射
|
|
509
|
+
|
|
510
|
+
DSH 是“vendored Cordis 上的、基于插件的 agent harness”,因此 Cordis 概念被大量直接复用并加了领域约定。
|
|
511
|
+
|
|
512
|
+
### 8.1 vendoring 与 rescope
|
|
513
|
+
|
|
514
|
+
- DSH 将 Cordis 及其基础库**源码 vendored** 进 `vendor/`(不再依赖 npm),以便“完全拥有框架层(可审计、可打补丁、可钉版本)”(https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/README.md )。
|
|
515
|
+
- 全部改名为 `@deepseek-ai` scope:`cordis` → `@deepseek-ai/cordis`;`@cordisjs/plugin-<x>` → `@deepseek-ai/cordis-plugin-<x>`。目录名与版本号不变。
|
|
516
|
+
- 上游 SHA(manifest):`cordis` 4.0.0-rc.7(package.json 显示 4.0.1)、`@cordisjs/plugin-loader` 1.0.0-rc.5 来自 https://github.com/cordiverse/cordis @ `56b3d4f725681cf4556c1a8695a709cc3b6eed74`;`include` 1.0.4 / `group` 1.0.0 / `timer` 1.1.2 / `hmr` 1.0.15 / `logger-console` 1.0.0 来自 https://github.com/deepseek-harness/cordis @ `abb0a307cb1d3b0947f455d590cf5ba922d4caa4`(**08-14 核查:该 fork 仓库已 404**);`cosmokit` 1.8.1、`schemastery` 3.18.0。→ 注意:include/group/timer/hmr/logger-console 来自 **DSH 自己的 cordis fork**,core 与 loader 来自上游 cordiverse。
|
|
517
|
+
- 18 条本地修改记录在 `vendor/README.md`(生命周期加固、事务化 loader/include、`!!js`/`disabled` 插值、`@deepseek-ai` rescope 等)。
|
|
518
|
+
|
|
519
|
+
### 8.2 capability seam(能力接缝)= Service Definition / Provider / Consumer
|
|
520
|
+
|
|
521
|
+
DSH 把“可替换能力”建模为三角色(`docs/glossary.md` 的 `capability-seam`):
|
|
522
|
+
|
|
523
|
+
- **Service Definition**:拥有 `ctx.<key>` 与词汇类型的 Cordis `Service`(抽象类如 `ShellExecutor`,或具体 registry 如 `WebRuntime`,**从不是 TS `interface`**)。
|
|
524
|
+
- **Service Providers**:提供该服务的一个或多个实现。
|
|
525
|
+
- **Consumers**:`inject` 该服务的消费方。
|
|
526
|
+
|
|
527
|
+
典型:`packages/shell` = `dsh-shell`(Service Definition)、`dsh-bash-local` / `dsh-bash-sandbox`(providers)、`dsh-tool-bash`(Consumer)。一个包可同时拥有多个角色(`dsh-llm` 同时拥有 Service Definition 与 Consumer)。AGENTS.md 强调:“能力接缝 = Service Definition / Service Provider / Consumer 三角色,**永远完整、绝不止一个角色**;仅当角色独立演化时才拆分”。这直接落地了 Cordis 的 §3(服务)与 §1(一切皆插件)。
|
|
528
|
+
|
|
529
|
+
### 8.3 “scope”一词的两义(易混淆)
|
|
530
|
+
|
|
531
|
+
DSH 在 Cordis 之上复用“scope”但含义不同(`docs/glossary.md` 的 `agent-scope`):
|
|
532
|
+
|
|
533
|
+
- Cordis v4 的 `ctx.isolate`/作用域 = 服务实例隔离(§2.2、§3.4)。
|
|
534
|
+
- DSH 的 **agent-scope** = 按 agent 的注册可见性(全局 vs 归属某 scope key),其分发过滤机制正是 Cordis 事件系统的 `thisArg` + `Context.filter`(§4.4),与经典 Cordis 的 `ctx.scope`(隔离作用域)**不是一回事**。DSH 的 `ctx.fiber`/`ctx.isolate` 才是 Cordis 原生隔离,agent-scope 是 DSH 自建概念。
|
|
535
|
+
|
|
536
|
+
### 8.4 事件与注册约定(AGENTS.md 落地 Cordis)
|
|
537
|
+
|
|
538
|
+
- “**Registrations are effects**”:一切贡献都经 `ctx.effect()` / `ctx.on()`;registry 的 `register()` 返回 disposer。
|
|
539
|
+
- “**Waterfall listeners MUST call `next()`**”:来自 Cordis 的 waterfall 语义(§4.3)。
|
|
540
|
+
- 类型化事件用 declaration merging + 可合并扩展的 map;事件 JSDoc 需 `@mode` 与 payload `@param`。
|
|
541
|
+
- “**Switch on discriminant tags**”:闭包联合用 `assertNever`,可合并扩展联合落入文档化默认分支。
|
|
542
|
+
- “**Model-visible ⟺ logged**”:凡到达模型请求的内容必须可由 session log 重建——这是 DSH 在 Cordis 事件系统之上的持久化不变量。
|
|
543
|
+
- 服务方法公开文档化参数与返回值;`SessionEventMap` 成员默认 required-on-read。
|
|
544
|
+
|
|
545
|
+
### 8.5 DSH 直接复用 Cordis 的位置
|
|
546
|
+
|
|
547
|
+
- `docs/cordis-primer.md`:DSH 自己的“Cordis 五条理念”浓缩。
|
|
548
|
+
- `docs/cordis-api/*`:由 `scripts/gen-cordis-catalog.ts` 从 vendored 源码生成、`verify-cordis-catalog` 校验的 API 参考。
|
|
549
|
+
- `docs/cordis-tutorial/01…07`:逐步教程,第 7 章把 Cordis 范式接到真实 harness 服务(`ctx.tools.register(defineTool(...))`、`tools/result` 事件、`inject: ['tools']`)。
|
|
550
|
+
- 启动器 `vendor/cordis/bin.js`:创建 root `Context` + 挂载 Loader + 读 `./cordis.yml`。
|
|
551
|
+
- 示例叶子 `examples/**/cordis.yml`(如 `examples/headless-agent/cordis.yml`)即完整应用组合。
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## 9. 来源列表(Source list)
|
|
556
|
+
|
|
557
|
+
### 上游(cordiverse)
|
|
558
|
+
|
|
559
|
+
1. cordiverse/cordis 仓库:https://github.com/cordiverse/cordis
|
|
560
|
+
2. cordiverse/paper(《一种时空可组合性的编程范式》):https://github.com/cordiverse/paper
|
|
561
|
+
3. Cordis 文档站(当前 v4 API):https://cordis.io/ ;Context API:https://cordis.io/zh-CN/api/core/context.html ;Loader(实验性):https://cordis.io/zh-CN/api/std/loader.html ;配置:https://cordis.io/zh-CN/guide/starter/config.html
|
|
562
|
+
4. 关键提交:loader 变为插件 https://github.com/cordiverse/cordis/commit/fd408a422375972b4ff02a9647063919d055b133 ;`ctx.inject()` 取代 `ctx.using()` https://github.com/cordiverse/cordis/commit/b5cd65aa27a18b90aeb6c8f036570cf1a374277a ;`ctx.registry.delete()` 移除插件 https://github.com/cordiverse/cordis/commit/99a7cc6f91c408d18e9165215f7d3afa052f5d1a ;`ctx.collect()` https://github.com/cordiverse/cordis/commit/3649a2a51815c359521bdc7037142d84f7e6f021 ;events `this` 参数 https://github.com/cordiverse/cordis/commit/e99a3444884eaa3722543d7af105fe9090b6b41a ;services and mixins https://github.com/cordiverse/cordis/commit/86ea62d5b9e4ead60175ee2b7b6409ffb24e8361 ;lifecycle→events 重命名 https://github.com/cordiverse/cordis/commit/15a8c3de50f9e8dcec24074a12a4980591dcbd80 ;traceable object https://github.com/cordiverse/cordis/commit/90257b25bedb88cb9db94c8b005b0737f01a7f8c
|
|
563
|
+
5. cordiverse/webui(Cordis App 的 WebUI):https://github.com/cordiverse/webui
|
|
564
|
+
|
|
565
|
+
### 经典 Cordis / Koishi(用于谱系对照)
|
|
566
|
+
|
|
567
|
+
6. Koishi Context API(含经典 `ctx.scope`/`ctx.select` 语义):https://koishi.js.org/api/core/context.html ;raw:https://raw.githubusercontent.com/koishijs/koishi/15bb8ba9d48aea26dfd4b4d559322c6bc0d4755d/docs/api/core/context.md
|
|
568
|
+
7. DeepWiki 对 Koishi Context 的梳理:https://deepwiki.com/koishijs/koishi/2.1-context
|
|
569
|
+
8. Koishi 论坛“关于服务与依赖”:https://forum.koishi.xyz/t/topic/3246/2
|
|
570
|
+
9. npm 版本线索:`cordis` https://socket.dev/npm/package/cordis/overview/2.3.1 (及 1.5.2 / 2.1.1)、`@cordisjs/core` https://socket.dev/npm/package/@cordisjs/core/overview/3.17.7
|
|
571
|
+
|
|
572
|
+
### DeepSeek Harness(vendored 源码 + 本地文档,一手权威)
|
|
573
|
+
|
|
574
|
+
10. vendoring 清单与 SHA:https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/README.md
|
|
575
|
+
11. 概念入门:https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-primer.md (中文版 cordis-primer.zh.md)
|
|
576
|
+
12. API 参考:https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-api/context.md 、.../events.md 、.../fiber.md 、.../registry.md 、.../service.md 、.../inherited.md
|
|
577
|
+
13. 教程:https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-tutorial/01-first-plugin.md (02-lifecycle-and-effects / 03-services / 04-events / 05-config / 06-composition-and-hmr / 07-into-the-harness)
|
|
578
|
+
14. 服务与依赖(含服务隔离):https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/framework/service.md
|
|
579
|
+
15. 术语表:https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/glossary.md
|
|
580
|
+
16. vendored 源码(本地读,路径即 GitHub 对应路径):`vendor/cordis/src/{context,events,fiber,logger,reflect,registry,service,utils,index}.ts`、`vendor/loader/src/{index,internal}.ts`、`vendor/loader/src/config/{entry,group,isolate,tree,utils}.ts`、`vendor/include/src/index.ts`、`vendor/group/src/index.ts`、`vendor/{cordis,loader,include,group}/README.md`
|
|
581
|
+
|
|
582
|
+
### 其它
|
|
583
|
+
|
|
584
|
+
17. Standard Schema 规范:https://standardschema.dev/
|
|
585
|
+
18. Schemastery:https://github.com/shigma/schemastery
|
|
586
|
+
19. 社区综述(DSH 第三方文章,非官方):https://www.cnblogs.com/sing1ee/p/22455466
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
## 附:无法核实项清单
|
|
591
|
+
|
|
592
|
+
- **经典 Cordis `ctx.scope` / `ctx.select` / `ctx.using` 的精确签名与语义**:未能抓取 koishi.js.org 原文(沙箱禁网),仅能据 Koishi Context 页标题与历史提交推断其存在与被取代关系;具体签名与行为标注 **[unverified]**。
|
|
593
|
+
- **cordis.js.org 是否仍在线 / 是否 301 至 cordis.io**:未能访问验证,**[unverified]**(搜索仅返回 cordis.io 与 koishi.js.org 两处当前在线文档)。
|
|
594
|
+
- **上游 master 的 README 与 docs 目录结构**:以 vendored 快照(pin 于上述 SHA)为准;上游 master 可能已继续演进,**[unverified]**。
|