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,98 @@
|
|
|
1
|
+
# 2. Lifecycle and effects
|
|
2
|
+
|
|
3
|
+
English | [中文](02-lifecycle-and-effects.zh.md)
|
|
4
|
+
|
|
5
|
+
A Cordis plugin can be unloaded by a config edit, hot reload, explicit disposal, or loss of a required service. Registrations made through Cordis APIs are effects and are undone when their owning plugin unloads; resources managed outside those APIs must be wrapped in `ctx.effect()`.
|
|
6
|
+
|
|
7
|
+
## Effects
|
|
8
|
+
|
|
9
|
+
For a resource Cordis does not already manage — a timer, a connection, a watcher — wrap it in `ctx.effect()` and return a disposer:
|
|
10
|
+
|
|
11
|
+
Create `lifecycle.ts` in `tmp/cordis-tutorial`:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
15
|
+
|
|
16
|
+
export const name = 'lifecycle-demo'
|
|
17
|
+
|
|
18
|
+
function heartbeat(ctx: Context) {
|
|
19
|
+
console.log('heartbeat plugin loading')
|
|
20
|
+
ctx.effect(() => {
|
|
21
|
+
const timer = setInterval(() => console.log('tick'), 200)
|
|
22
|
+
return () => {
|
|
23
|
+
clearInterval(timer)
|
|
24
|
+
console.log('heartbeat cleaned up')
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function apply(ctx: Context) {
|
|
30
|
+
// Mount a child plugin and keep its fiber to dispose it later.
|
|
31
|
+
const fiber = ctx.plugin(heartbeat)
|
|
32
|
+
// The demo timer is itself an effect: if THIS plugin is unloaded first,
|
|
33
|
+
// the pending callback is cancelled instead of firing on a dead app.
|
|
34
|
+
ctx.effect(() => {
|
|
35
|
+
const timer = setTimeout(async () => {
|
|
36
|
+
await fiber.dispose()
|
|
37
|
+
console.log('disposed')
|
|
38
|
+
process.exit(0)
|
|
39
|
+
}, 700)
|
|
40
|
+
return () => clearTimeout(timer)
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Point `cordis.yml` at it:
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
- name: './lifecycle.ts'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Run (`node --import tsx ../../vendor/cordis/bin.js`) and you get:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
heartbeat plugin loading
|
|
55
|
+
tick
|
|
56
|
+
tick
|
|
57
|
+
tick
|
|
58
|
+
heartbeat cleaned up
|
|
59
|
+
disposed
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Three things to notice:
|
|
63
|
+
|
|
64
|
+
- `ctx.plugin(heartbeat)` mounts a function **from code** as a plugin — the same operation the YAML loader performs for each config entry. A function plugin needs no `apply` method: Cordis calls the function directly and uses its name only for diagnostics. An `apply` method is required only for the object form, `ctx.plugin({ apply(ctx) { /* ... */ } })`. The call returns a **fiber**, the runtime handle for one loaded plugin instance.
|
|
65
|
+
- The effect body runs during load; the disposer it returns runs during unload. You never call the disposer yourself for a plugin-lifetime resource.
|
|
66
|
+
- `fiber.dispose()` resolves after all of the plugin's cleanup — including async disposers — has finished, and recursively unloads any child plugins it mounted.
|
|
67
|
+
|
|
68
|
+
## The fiber state machine
|
|
69
|
+
|
|
70
|
+
Every loaded plugin instance owns a fiber that moves through these states:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED
|
|
74
|
+
↘ FAILED
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- **PENDING** — declared, but a required service (chapter 3) is not available yet.
|
|
78
|
+
- **LOADING / ACTIVE** — `apply` is running / has completed.
|
|
79
|
+
- **FAILED** — `apply` or config validation threw.
|
|
80
|
+
- **UNLOADING / DISPOSED** — disposers are running / everything is torn down.
|
|
81
|
+
|
|
82
|
+
You will meet PENDING again in [chapter 6](06-composition-and-hmr.md), where it is the usual answer to "why does my plugin print nothing?".
|
|
83
|
+
|
|
84
|
+
## What is already an effect
|
|
85
|
+
|
|
86
|
+
You rarely write `ctx.effect()` yourself, because the built-in registration APIs are effects already:
|
|
87
|
+
|
|
88
|
+
- `ctx.on(event, listener)` — the listener is removed on unload ([chapter 4](04-events.md)).
|
|
89
|
+
- `ctx.plugin(child)` — the child is disposed with its parent.
|
|
90
|
+
- Service registrations are effects. Harness registries such as `ctx.tools.register(...)` also attach their returned disposers to the calling plugin, so they unwind automatically ([chapter 7](07-into-the-harness.md)).
|
|
91
|
+
|
|
92
|
+
For a resource Cordis does not manage, acquire it inside `ctx.effect()` and return a disposer that releases it. Cordis then invokes that release during unloading, including hot reload.
|
|
93
|
+
|
|
94
|
+
One ordering caveat: disposers start in reverse registration order, but multiple **async** disposers run concurrently. If teardown steps must run in sequence, keep them in one disposer and await them there.
|
|
95
|
+
|
|
96
|
+
Next: [Services](03-services.md) — how plugins share capabilities.
|
|
97
|
+
|
|
98
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# 2. 生命周期与 effect
|
|
2
|
+
|
|
3
|
+
[English](02-lifecycle-and-effects.md) | 中文
|
|
4
|
+
|
|
5
|
+
Cordis 插件可能因修改配置、热重载、显式资源释放或所需服务消失而卸载。通过 Cordis API 建立的注册属于 effect,会在所属插件卸载时撤销;在这些 API 之外管理的资源必须包装在 `ctx.effect()` 中。
|
|
6
|
+
|
|
7
|
+
## Effect
|
|
8
|
+
|
|
9
|
+
对于 Cordis 尚未管理的资源,例如定时器、连接或 watcher,应将其包装在 `ctx.effect()` 中并返回 disposer(资源释放函数):
|
|
10
|
+
|
|
11
|
+
创建 `lifecycle.ts`,将它放在 `tmp/cordis-tutorial` 中:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
15
|
+
|
|
16
|
+
export const name = 'lifecycle-demo'
|
|
17
|
+
|
|
18
|
+
function heartbeat(ctx: Context) {
|
|
19
|
+
console.log('heartbeat plugin loading')
|
|
20
|
+
ctx.effect(() => {
|
|
21
|
+
const timer = setInterval(() => console.log('tick'), 200)
|
|
22
|
+
return () => {
|
|
23
|
+
clearInterval(timer)
|
|
24
|
+
console.log('heartbeat cleaned up')
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function apply(ctx: Context) {
|
|
30
|
+
// Mount a child plugin and keep its fiber to dispose it later.
|
|
31
|
+
const fiber = ctx.plugin(heartbeat)
|
|
32
|
+
// The demo timer is itself an effect: if THIS plugin is unloaded first,
|
|
33
|
+
// the pending callback is cancelled instead of firing on a dead app.
|
|
34
|
+
ctx.effect(() => {
|
|
35
|
+
const timer = setTimeout(async () => {
|
|
36
|
+
await fiber.dispose()
|
|
37
|
+
console.log('disposed')
|
|
38
|
+
process.exit(0)
|
|
39
|
+
}, 700)
|
|
40
|
+
return () => clearTimeout(timer)
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
让 `cordis.yml` 指向该文件:
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
- name: './lifecycle.ts'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
运行(`node --import tsx ../../vendor/cordis/bin.js`)后会得到:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
heartbeat plugin loading
|
|
55
|
+
tick
|
|
56
|
+
tick
|
|
57
|
+
tick
|
|
58
|
+
heartbeat cleaned up
|
|
59
|
+
disposed
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
请留意三点:
|
|
63
|
+
|
|
64
|
+
- `ctx.plugin(heartbeat)` 会把一个**来自代码**的函数挂载为插件,这与 YAML loader 为每个配置项执行的操作相同。函数插件不需要 `apply` 方法:Cordis 会直接调用该函数,其名称只用于诊断。只有对象形态才要求 `apply` 方法,例如 `ctx.plugin({ apply(ctx) { /* ... */ } })`。调用会返回一个 **fiber**,即一个已加载插件实例的运行时句柄。
|
|
65
|
+
- effect 主体在加载期间运行;它返回的 disposer 在卸载期间运行。对于生命周期与插件一致的资源,你绝不需要自行调用 disposer。
|
|
66
|
+
- `fiber.dispose()` 会等该插件的所有清理工作(包括异步 disposer)完成后才结束,并递归卸载它挂载的所有子插件。
|
|
67
|
+
|
|
68
|
+
## Fiber 状态机
|
|
69
|
+
|
|
70
|
+
每个已加载插件实例都拥有一个 fiber,并在以下状态之间转换:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED
|
|
74
|
+
↘ FAILED
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- **PENDING**:已经声明,但所需服务(第 3 章)尚不可用。
|
|
78
|
+
- **LOADING / ACTIVE**:`apply` 正在运行/已经完成。
|
|
79
|
+
- **FAILED**:`apply` 或配置校验抛出异常。
|
|
80
|
+
- **UNLOADING / DISPOSED**:disposer 正在运行/一切均已拆除。
|
|
81
|
+
|
|
82
|
+
你会在[第 6 章](06-composition-and-hmr.md)再次遇到 PENDING,它通常就是「为什么我的插件没有输出」的答案。
|
|
83
|
+
|
|
84
|
+
## 已经属于 effect 的操作
|
|
85
|
+
|
|
86
|
+
你很少需要亲自编写 `ctx.effect()`,因为内置注册 API 本身已经是 effect:
|
|
87
|
+
|
|
88
|
+
- `ctx.on(event, listener)`:监听器会在卸载时移除([第 4 章](04-events.md))。
|
|
89
|
+
- `ctx.plugin(child)`:子插件会随父插件一同 dispose(资源释放)。
|
|
90
|
+
- 服务注册属于 effect。`ctx.tools.register(...)` 等 harness 注册表也会把返回的 disposer 附着到调用插件上,因此会自动撤销([第 7 章](07-into-the-harness.md))。
|
|
91
|
+
|
|
92
|
+
对于 Cordis 不管理的资源,应在 `ctx.effect()` 内获取它,并返回用于释放资源的 disposer。此后 Cordis 会在卸载期间调用该释放逻辑,热重载时也不例外。
|
|
93
|
+
|
|
94
|
+
有一项顺序注意事项:disposer 会按注册顺序的逆序启动,但多个**异步** disposer 会并发运行。如果拆除步骤必须按顺序执行,请把它们放在同一个 disposer 中,并在其中依次等待每步完成。
|
|
95
|
+
|
|
96
|
+
下一章:[服务](03-services.md):插件如何共享功能。
|
|
97
|
+
|
|
98
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write docs/cordis-tutorial/03-services.md
|
|
5
|
+
03-services.md: ebfc400dbbc701a3c164c7d30c371dec879d7d73
|
|
6
|
+
03-services.zh.md: fcfd8be7f7fe654a4f4943cf591b5ab7bfc27fc6
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# 3. Services
|
|
2
|
+
|
|
3
|
+
English | [中文](03-services.zh.md)
|
|
4
|
+
|
|
5
|
+
A **service** is a named capability one plugin provides and other plugins consume through `ctx`. In the harness, `ctx.tools`, `ctx.llm`, and `ctx.agents` are services. A consumer names the capability, such as `'tools'`, rather than importing its provider, so configuration can select a provider without changing the consumer.
|
|
6
|
+
|
|
7
|
+
## Provide a service
|
|
8
|
+
|
|
9
|
+
Create `greeter.ts` in `tmp/cordis-tutorial`:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { Service, type Context } from '@deepseek-ai/cordis'
|
|
13
|
+
|
|
14
|
+
declare module '@deepseek-ai/cordis' {
|
|
15
|
+
interface Context {
|
|
16
|
+
greeter: GreeterService
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class GreeterService extends Service {
|
|
21
|
+
constructor(ctx: Context) {
|
|
22
|
+
super(ctx, 'greeter')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
greet(who: string) {
|
|
26
|
+
return `Hello, ${who}!`
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const name = 'greeter'
|
|
31
|
+
|
|
32
|
+
export function apply(ctx: Context) {
|
|
33
|
+
ctx.plugin(GreeterService)
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Two pieces work together:
|
|
38
|
+
|
|
39
|
+
- **Runtime**: `super(ctx, 'greeter')` registers the instance under the name `greeter`. From then on, any plugin can reach it as `ctx.greeter`. The registration is an effect — unloading the provider removes the service.
|
|
40
|
+
- **Compile time**: the `declare module '@deepseek-ai/cordis'` block is TypeScript declaration merging. It adds `greeter` to the `Context` interface so `ctx.greeter` typechecks everywhere. It generates no code; without it the service still works at runtime, but consumers lose type safety.
|
|
41
|
+
|
|
42
|
+
A `Service` subclass is itself a plugin (the class form from chapter 1), so `ctx.plugin(GreeterService)` mounts it like any other.
|
|
43
|
+
|
|
44
|
+
## Consume a service with `inject`
|
|
45
|
+
|
|
46
|
+
Create `consumer.ts`:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
50
|
+
|
|
51
|
+
export const name = 'consumer'
|
|
52
|
+
export const inject = ['greeter']
|
|
53
|
+
|
|
54
|
+
export function apply(ctx: Context) {
|
|
55
|
+
console.log(ctx.greeter.greet('world'))
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`inject` lists the services this plugin requires. Cordis holds the plugin in PENDING until every listed service exists, so inside `apply`, `ctx.greeter` is guaranteed ready. Load order in `cordis.yml` does not matter — dependencies, not file order, decide when plugins start.
|
|
60
|
+
|
|
61
|
+
Compose and run:
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
- name: './greeter.ts'
|
|
65
|
+
- name: './consumer.ts'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
Hello, world!
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Swap the two lines in `cordis.yml` and rerun: same output. Try removing `./greeter.ts` entirely: the consumer stays PENDING and prints nothing — no crash, no partial run. A PENDING fiber does not keep Node's event loop alive either, so a composition with nothing else running exits 0 silently. [Chapter 6](06-composition-and-hmr.md) shows how to diagnose that state.
|
|
73
|
+
|
|
74
|
+
## Dependencies are tracked after load
|
|
75
|
+
|
|
76
|
+
`inject` is not a one-shot boot check. If a required service disappears while the app runs — its provider was unloaded or hot-replaced — every dependent plugin is unloaded too, and loads again when the service returns. Combined with effects ([chapter 2](02-lifecycle-and-effects.md)), this prevents a running consumer from retaining a reference to an unavailable service: its own registrations are unwound when the dependency disappears.
|
|
77
|
+
|
|
78
|
+
This is also why service replacement works in config: unload the `dsh-bash-local` entry, mount a different `shell` provider, and every plugin injecting `'shell'` cleanly restarts against the new implementation.
|
|
79
|
+
|
|
80
|
+
## Optional dependencies
|
|
81
|
+
|
|
82
|
+
`inject` is for hard requirements. For a capability the plugin can live without, skip `inject` and probe at the use site:
|
|
83
|
+
|
|
84
|
+
```ts ignore-check
|
|
85
|
+
export function apply(ctx: Context) {
|
|
86
|
+
// undefined when no provider is loaded; the plugin still runs.
|
|
87
|
+
const greeter = ctx.get('greeter')
|
|
88
|
+
console.log(greeter?.greet('maybe') ?? 'no greeter available')
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Naming
|
|
93
|
+
|
|
94
|
+
Service names live in one flat namespace per application. Prefix or namespace your own services distinctively (the harness claims plain names like `tools` and `llm`); the generated `cordis-surface` regions on the [subsystem pages](../subsystems/core.md) list every name the harness registers.
|
|
95
|
+
|
|
96
|
+
Next: [Events](04-events.md) — communication without a shared service.
|
|
97
|
+
|
|
98
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# 3. 服务
|
|
2
|
+
|
|
3
|
+
[English](03-services.md) | 中文
|
|
4
|
+
|
|
5
|
+
**服务**是一个插件提供、其他插件通过 `ctx` 消费的具名能力。在 harness 中,`ctx.tools`、`ctx.llm` 和 `ctx.agents` 都是服务。消费方只指定 `'tools'` 之类的能力,而不导入其提供方,因此配置可以选择提供方,无需修改消费方。
|
|
6
|
+
|
|
7
|
+
## 提供服务
|
|
8
|
+
|
|
9
|
+
创建 `greeter.ts`,将它放在 `tmp/cordis-tutorial` 中:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { Service, type Context } from '@deepseek-ai/cordis'
|
|
13
|
+
|
|
14
|
+
declare module '@deepseek-ai/cordis' {
|
|
15
|
+
interface Context {
|
|
16
|
+
greeter: GreeterService
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class GreeterService extends Service {
|
|
21
|
+
constructor(ctx: Context) {
|
|
22
|
+
super(ctx, 'greeter')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
greet(who: string) {
|
|
26
|
+
return `Hello, ${who}!`
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const name = 'greeter'
|
|
31
|
+
|
|
32
|
+
export function apply(ctx: Context) {
|
|
33
|
+
ctx.plugin(GreeterService)
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
两部分协同工作:
|
|
38
|
+
|
|
39
|
+
- **运行时**:`super(ctx, 'greeter')` 以名称 `greeter` 注册该实例。此后,任何插件都可以通过 `ctx.greeter` 访问它。注册属于 effect,卸载提供方时会移除该服务。
|
|
40
|
+
- **编译时**:`declare module '@deepseek-ai/cordis'` 块使用 TypeScript 声明合并,把 `greeter` 加入 `Context` 接口,使 `ctx.greeter` 在各处都能通过类型检查。它不会生成代码;没有该声明时,服务在运行时仍能工作,但消费方会失去类型安全。
|
|
41
|
+
|
|
42
|
+
`Service` 子类本身就是插件(第 1 章介绍的类形态),因此 `ctx.plugin(GreeterService)` 会像挂载其他插件一样挂载它。
|
|
43
|
+
|
|
44
|
+
## 使用 `inject` 消费服务
|
|
45
|
+
|
|
46
|
+
创建 `consumer.ts`:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
50
|
+
|
|
51
|
+
export const name = 'consumer'
|
|
52
|
+
export const inject = ['greeter']
|
|
53
|
+
|
|
54
|
+
export function apply(ctx: Context) {
|
|
55
|
+
console.log(ctx.greeter.greet('world'))
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`inject` 列出该插件需要的服务。Cordis 会让插件保持 PENDING,直到列出的每项服务都存在,因此在 `apply` 内可以保证 `ctx.greeter` 已经就绪。`cordis.yml` 中的加载顺序无关紧要:决定插件何时启动的是依赖关系,而不是文件顺序。
|
|
60
|
+
|
|
61
|
+
组合并运行:
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
- name: './greeter.ts'
|
|
65
|
+
- name: './consumer.ts'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
Hello, world!
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
交换 `cordis.yml` 中两行的顺序后重新运行,输出仍然相同。尝试彻底移除 `./greeter.ts`:消费方会保持 PENDING,不输出任何内容,既不崩溃,也不会只运行一部分。处于 PENDING 的 fiber 也不会让 Node 的事件循环保持活跃,因此如果组合中没有其他运行项,进程会静默地以状态码 0 退出。[第 6 章](06-composition-and-hmr.md)介绍如何诊断这种状态。
|
|
73
|
+
|
|
74
|
+
## 加载后仍会跟踪依赖关系
|
|
75
|
+
|
|
76
|
+
`inject` 并非一次性的启动检查。如果应用运行期间所需服务消失,例如提供方被卸载或热替换,每个依赖插件也会随之卸载,并在服务恢复后再次加载。结合 effect([第 2 章](02-lifecycle-and-effects.md)),这能防止运行中的消费方保留对不可用服务的引用:依赖消失时,它自己的注册也会撤销。
|
|
77
|
+
|
|
78
|
+
这也是配置中可以替换服务的原因:卸载 Cordis 配置项 `dsh-bash-local`,挂载另一个 `shell` 提供方,所有注入 `'shell'` 的插件都会重新启动并使用新实现。
|
|
79
|
+
|
|
80
|
+
## 可选依赖
|
|
81
|
+
|
|
82
|
+
`inject` 用于硬性依赖。如果某项功能缺失时插件仍可运行,请跳过 `inject`,并在使用处探测:
|
|
83
|
+
|
|
84
|
+
```ts ignore-check
|
|
85
|
+
export function apply(ctx: Context) {
|
|
86
|
+
// undefined when no provider is loaded; the plugin still runs.
|
|
87
|
+
const greeter = ctx.get('greeter')
|
|
88
|
+
console.log(greeter?.greet('maybe') ?? 'no greeter available')
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 命名
|
|
93
|
+
|
|
94
|
+
每个应用中的服务名称共用一个扁平命名空间。请为自有服务添加有辨识度的前缀或命名空间(harness 已占用 `tools` 和 `llm` 等普通名称);[子系统页面](../subsystems/core.md)上生成的 `cordis-surface` 区块列出 harness 注册的每个名称。
|
|
95
|
+
|
|
96
|
+
下一章:[事件](04-events.md):无需共享服务即可通信。
|
|
97
|
+
|
|
98
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write docs/cordis-tutorial/04-events.md
|
|
5
|
+
04-events.md: db911b9a06d7304d73030a2020de3d465fde2f9c
|
|
6
|
+
04-events.zh.md: e72c94e8548a6ac621f9a020db81910bcf22b541
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# 4. Events
|
|
2
|
+
|
|
3
|
+
English | [中文](04-events.zh.md)
|
|
4
|
+
|
|
5
|
+
Services support direct calls; **events** let a plugin announce something without knowing which plugins listen. The harness uses events for interactions such as tool results, model requests, and approval decisions.
|
|
6
|
+
|
|
7
|
+
## Declare, emit, listen
|
|
8
|
+
|
|
9
|
+
Create `stats.ts` in `tmp/cordis-tutorial` — a service that counts things and announces each change:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { Service, type Context } from '@deepseek-ai/cordis'
|
|
13
|
+
|
|
14
|
+
declare module '@deepseek-ai/cordis' {
|
|
15
|
+
interface Context {
|
|
16
|
+
stats: StatsService
|
|
17
|
+
}
|
|
18
|
+
interface Events {
|
|
19
|
+
'stats/report'(name: string, count: number): void
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class StatsService extends Service {
|
|
24
|
+
private counts = new Map<string, number>()
|
|
25
|
+
|
|
26
|
+
constructor(ctx: Context) {
|
|
27
|
+
super(ctx, 'stats')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
bump(name: string) {
|
|
31
|
+
const next = (this.counts.get(name) ?? 0) + 1
|
|
32
|
+
this.counts.set(name, next)
|
|
33
|
+
this.ctx.emit('stats/report', name, next)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const name = 'stats'
|
|
38
|
+
|
|
39
|
+
export function apply(ctx: Context) {
|
|
40
|
+
ctx.plugin(StatsService)
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The `interface Events` merge is the event-system twin of the `interface Context` merge from chapter 3: it declares the event name and its listener signature, so `ctx.emit` and `ctx.on` are fully typed. The `namespace/action` naming convention keeps the flat event namespace readable.
|
|
45
|
+
|
|
46
|
+
Create `reporter.ts`:
|
|
47
|
+
|
|
48
|
+
```ts ignore-check
|
|
49
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
50
|
+
import type {} from './stats.ts'
|
|
51
|
+
|
|
52
|
+
export const name = 'reporter'
|
|
53
|
+
export const inject = ['stats']
|
|
54
|
+
|
|
55
|
+
export function apply(ctx: Context) {
|
|
56
|
+
ctx.on('stats/report', (name, count) => {
|
|
57
|
+
console.log(`[stats] ${name} -> ${count}`)
|
|
58
|
+
})
|
|
59
|
+
ctx.stats.bump('tool_call')
|
|
60
|
+
ctx.stats.bump('tool_call')
|
|
61
|
+
ctx.stats.bump('prompt')
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The `import type {} from './stats.ts'` line imports nothing at runtime; it exists so TypeScript sees the declaration merges. Compose and run:
|
|
66
|
+
|
|
67
|
+
```yaml
|
|
68
|
+
- name: './stats.ts'
|
|
69
|
+
- name: './reporter.ts'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
[stats] tool_call -> 1
|
|
74
|
+
[stats] tool_call -> 2
|
|
75
|
+
[stats] prompt -> 1
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Because `ctx.on()` is an effect, the listener disappears with the plugin — no manual `removeListener` bookkeeping, ever.
|
|
79
|
+
|
|
80
|
+
## Dispatch modes
|
|
81
|
+
|
|
82
|
+
`emit` is one of five dispatch modes. Which one an event uses is part of its contract — it decides whether listeners can return values, run concurrently, or short-circuit each other:
|
|
83
|
+
|
|
84
|
+
| Mode | Call | Semantics |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| emit | `ctx.emit(name, ...args)` | Synchronous broadcast; returned promises and values are not awaited or collected. |
|
|
87
|
+
| parallel | `await ctx.parallel(name, ...args)` | All listeners run concurrently; awaited together. |
|
|
88
|
+
| serial | `await ctx.serial(name, ...args)` | Listeners run in order, awaited; the first non-`null`/`false`/`undefined` return wins and stops the rest. |
|
|
89
|
+
| bail | `ctx.bail(name, ...args)` | Synchronous version of serial. |
|
|
90
|
+
| waterfall | `ctx.waterfall(name, ...args, next)` | Around-middleware; see below. |
|
|
91
|
+
|
|
92
|
+
Every harness event documents its mode in the generated reference on its owning [subsystem page](../subsystems/core.md).
|
|
93
|
+
|
|
94
|
+
## Waterfall: transform or short-circuit
|
|
95
|
+
|
|
96
|
+
Waterfall is the mode that powers interception. Each listener receives the arguments plus a `next()` continuation; it can transform what `next()` returns, or return without calling `next()` and short-circuit the rest of the chain — what the Cordis docs call the veto. Create `waterfall-demo.ts`:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
100
|
+
|
|
101
|
+
declare module '@deepseek-ai/cordis' {
|
|
102
|
+
interface Events {
|
|
103
|
+
'demo/transform'(input: string, next: () => Promise<string>): Promise<string>
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const name = 'waterfall-demo'
|
|
108
|
+
|
|
109
|
+
export function apply(ctx: Context) {
|
|
110
|
+
// Listener 1: wrap the downstream result.
|
|
111
|
+
ctx.on('demo/transform', async (input, next) => {
|
|
112
|
+
const downstream = await next()
|
|
113
|
+
return downstream.toUpperCase()
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
// Listener 2: short-circuit when it owns the decision.
|
|
117
|
+
ctx.on('demo/transform', async (input, next) => {
|
|
118
|
+
if (input.includes('blocked')) return '** blocked **'
|
|
119
|
+
return next()
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
void (async () => {
|
|
123
|
+
console.log(await ctx.waterfall('demo/transform', 'hello', async () => 'hello'))
|
|
124
|
+
console.log(await ctx.waterfall('demo/transform', 'blocked words', async () => 'blocked words'))
|
|
125
|
+
})()
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Point `cordis.yml` at just this file and run:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
HELLO
|
|
133
|
+
** BLOCKED **
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Walk through the second line: listener 1 runs first, calls `next()`, which invokes listener 2; listener 2 sees `blocked` and returns without calling `next()` — the innermost default (the function passed to `ctx.waterfall`) never runs — and listener 1 uppercases the replacement message on the way out.
|
|
137
|
+
|
|
138
|
+
The discipline that follows: **a waterfall listener that only observes or annotates must call `next()`**; returning without it is a deliberate short-circuit. Forgetting `next()` in a logging listener silently swallows the default behavior for everyone downstream. It is a standing rule of this repository ([waterfall semantics](../cordis-primer.md#cordis-waterfall-semantics)).
|
|
139
|
+
|
|
140
|
+
The harness uses waterfalls for decisions that cooperating plugins may wrap or answer: [`agent/request`](../subsystems/core.md#agentrequest--waterfall) lets a plugin replace the model-call config, and [`approval/request`](../subsystems/approval.md#approvalrequest--waterfall) lets a policy answer instead of the user.
|
|
141
|
+
|
|
142
|
+
Next: [Configuration](05-config.md) — plugin options from `cordis.yml`.
|
|
143
|
+
|
|
144
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|