dsh-plugin-guide 0.3.41 → 0.4.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 +0 -0
- package/NOTICE.md +8 -23
- package/PRIVACY.md +11 -0
- package/README-zh.md +45 -418
- package/README.md +50 -435
- package/SKILL.md +41 -99
- package/STANDARDS.md +14 -5
- package/cordis.patch.yml +0 -0
- package/docs/boost.md +75 -0
- package/docs/entry.md +60 -0
- package/docs/flow.md +57 -0
- package/docs/levels.md +76 -0
- package/icon.svg +0 -0
- package/index.js +7 -24
- package/locale/en.json +2 -2
- package/locale/zh.json +2 -2
- package/package.json +29 -78
- package/README-es.md +0 -453
- package/README-hi.md +0 -453
- package/README-pt.md +0 -453
- package/bin/dsh-plugin-dev.js +0 -6
- package/data/facts.json +0 -66
- package/data/seams/index.json +0 -397
- package/data/standards.json +0 -300
- package/dist/dsh-plugin-dev.js +0 -2261
- package/guide/choosing-a-plugin.md +0 -412
- package/guide/choosing-a-plugin.zh-CN.md +0 -414
- package/guide/family-toolchain.md +0 -260
- package/guide/links.md +0 -112
- package/guide/migration-0.2.md +0 -275
- package/guide/plugin-dev-guide.md +0 -629
- package/guide/quick-reference.es.md +0 -185
- package/guide/quick-reference.hi.md +0 -185
- package/guide/quick-reference.md +0 -185
- package/guide/quick-reference.pt.md +0 -185
- package/guide/quick-reference.zh-CN.md +0 -184
- package/guide/release-engineering.md +0 -198
- package/guide/release-engineering.zh-CN.md +0 -198
- package/guide/standards.md +0 -141
- package/guide/standards.zh-CN.md +0 -141
- package/guide/unfixed-issues.md +0 -155
- package/guide/version-matrix.md +0 -309
- package/guide/when-to-retire-a-plugin.md +0 -127
- package/guide/when-to-retire-a-plugin.zh-CN.md +0 -127
- package/index.d.ts +0 -32
- package/references/cli-positioning-decision.md +0 -78
- package/references/community-ecosystem.md +0 -202
- package/references/community-repo-deep-dive.md +0 -660
- package/references/cordis-paper-and-community.md +0 -326
- package/references/dev-resource-landscape.md +0 -294
- package/references/harness-repo.md +0 -673
- package/references/mirror-scope-decision.md +0 -79
- package/references/official-docs/AGENTS.md +0 -185
- package/references/official-docs/BENCHMARK.md +0 -3
- package/references/official-docs/CLAUDE.md +0 -1
- package/references/official-docs/CONTRIBUTING.i18n.yaml +0 -7
- package/references/official-docs/CONTRIBUTING.md +0 -23
- package/references/official-docs/CONTRIBUTING.zh.md +0 -23
- package/references/official-docs/LICENSE +0 -21
- package/references/official-docs/README.i18n.yaml +0 -34
- package/references/official-docs/README.md +0 -35
- package/references/official-docs/README.zh.md +0 -96
- package/references/official-docs/SNAPSHOT.md +0 -14
- package/references/official-docs/THIRD_PARTY_NOTICES.md +0 -304
- package/references/official-docs/docs/AGENTS.md +0 -77
- package/references/official-docs/docs/agent-lifecycle.i18n.yaml +0 -10
- package/references/official-docs/docs/agent-lifecycle.md +0 -91
- package/references/official-docs/docs/agent-lifecycle.zh.md +0 -93
- package/references/official-docs/docs/api-gateway.i18n.yaml +0 -31
- package/references/official-docs/docs/api-gateway.md +0 -172
- package/references/official-docs/docs/api-gateway.zh.md +0 -178
- package/references/official-docs/docs/architecture.i18n.yaml +0 -37
- package/references/official-docs/docs/architecture.md +0 -165
- package/references/official-docs/docs/architecture.zh.md +0 -169
- package/references/official-docs/docs/capability-seams.i18n.yaml +0 -10
- package/references/official-docs/docs/capability-seams.md +0 -714
- package/references/official-docs/docs/capability-seams.zh.md +0 -716
- package/references/official-docs/docs/cli-help.i18n.yaml +0 -34
- package/references/official-docs/docs/cli-help.md +0 -203
- package/references/official-docs/docs/cli-help.zh.md +0 -205
- package/references/official-docs/docs/config-catalog.i18n.yaml +0 -19
- package/references/official-docs/docs/config-catalog.md +0 -4801
- package/references/official-docs/docs/config-catalog.zh.md +0 -4803
- package/references/official-docs/docs/cookbook/adding-a-package.i18n.yaml +0 -28
- package/references/official-docs/docs/cookbook/adding-a-package.md +0 -170
- package/references/official-docs/docs/cookbook/adding-a-package.zh.md +0 -170
- package/references/official-docs/docs/cookbook/adding-a-plugin-preview.i18n.yaml +0 -22
- package/references/official-docs/docs/cookbook/adding-a-plugin-preview.md +0 -52
- package/references/official-docs/docs/cookbook/adding-a-plugin-preview.zh.md +0 -52
- package/references/official-docs/docs/cookbook/adding-a-remote-api.i18n.yaml +0 -25
- package/references/official-docs/docs/cookbook/adding-a-remote-api.md +0 -197
- package/references/official-docs/docs/cookbook/adding-a-remote-api.zh.md +0 -197
- package/references/official-docs/docs/cookbook/adding-a-session-format-version.i18n.yaml +0 -40
- package/references/official-docs/docs/cookbook/adding-a-session-format-version.md +0 -153
- package/references/official-docs/docs/cookbook/adding-a-session-format-version.zh.md +0 -153
- package/references/official-docs/docs/cookbook/adding-a-settings-card.i18n.yaml +0 -22
- package/references/official-docs/docs/cookbook/adding-a-settings-card.md +0 -72
- package/references/official-docs/docs/cookbook/adding-a-settings-card.zh.md +0 -72
- package/references/official-docs/docs/cookbook/adding-a-tool.i18n.yaml +0 -31
- package/references/official-docs/docs/cookbook/adding-a-tool.md +0 -101
- package/references/official-docs/docs/cookbook/adding-a-tool.zh.md +0 -103
- package/references/official-docs/docs/cookbook/adding-a-vendored-package.i18n.yaml +0 -19
- package/references/official-docs/docs/cookbook/adding-a-vendored-package.md +0 -59
- package/references/official-docs/docs/cookbook/adding-a-vendored-package.zh.md +0 -59
- package/references/official-docs/docs/cookbook/adding-an-llm-adapter.i18n.yaml +0 -19
- package/references/official-docs/docs/cookbook/adding-an-llm-adapter.md +0 -43
- package/references/official-docs/docs/cookbook/adding-an-llm-adapter.zh.md +0 -43
- package/references/official-docs/docs/cookbook/extension-cookbook.i18n.yaml +0 -25
- package/references/official-docs/docs/cookbook/extension-cookbook.md +0 -132
- package/references/official-docs/docs/cookbook/extension-cookbook.zh.md +0 -136
- package/references/official-docs/docs/cookbook/maintaining-dsh-code-review.i18n.yaml +0 -22
- package/references/official-docs/docs/cookbook/maintaining-dsh-code-review.md +0 -64
- package/references/official-docs/docs/cookbook/maintaining-dsh-code-review.zh.md +0 -64
- package/references/official-docs/docs/cookbook/responding-to-pr-review-on-a-stack.i18n.yaml +0 -16
- package/references/official-docs/docs/cookbook/responding-to-pr-review-on-a-stack.md +0 -32
- package/references/official-docs/docs/cookbook/responding-to-pr-review-on-a-stack.zh.md +0 -32
- package/references/official-docs/docs/cookbook/reviewing-persistence-type-changes.i18n.yaml +0 -31
- package/references/official-docs/docs/cookbook/reviewing-persistence-type-changes.md +0 -122
- package/references/official-docs/docs/cookbook/reviewing-persistence-type-changes.zh.md +0 -122
- package/references/official-docs/docs/cordis-api/context.i18n.yaml +0 -73
- package/references/official-docs/docs/cordis-api/context.md +0 -364
- package/references/official-docs/docs/cordis-api/context.zh.md +0 -366
- package/references/official-docs/docs/cordis-api/events.i18n.yaml +0 -37
- package/references/official-docs/docs/cordis-api/events.md +0 -207
- package/references/official-docs/docs/cordis-api/events.zh.md +0 -209
- package/references/official-docs/docs/cordis-api/fiber.i18n.yaml +0 -76
- package/references/official-docs/docs/cordis-api/fiber.md +0 -375
- package/references/official-docs/docs/cordis-api/fiber.zh.md +0 -377
- package/references/official-docs/docs/cordis-api/inherited.md +0 -38
- package/references/official-docs/docs/cordis-api/registry.i18n.yaml +0 -22
- package/references/official-docs/docs/cordis-api/registry.md +0 -152
- package/references/official-docs/docs/cordis-api/registry.zh.md +0 -154
- package/references/official-docs/docs/cordis-api/service.i18n.yaml +0 -37
- package/references/official-docs/docs/cordis-api/service.md +0 -102
- package/references/official-docs/docs/cordis-api/service.zh.md +0 -104
- package/references/official-docs/docs/cordis-primer.i18n.yaml +0 -22
- package/references/official-docs/docs/cordis-primer.md +0 -45
- package/references/official-docs/docs/cordis-primer.zh.md +0 -51
- package/references/official-docs/docs/cordis-tutorial/01-first-plugin.i18n.yaml +0 -22
- package/references/official-docs/docs/cordis-tutorial/01-first-plugin.md +0 -95
- package/references/official-docs/docs/cordis-tutorial/01-first-plugin.zh.md +0 -95
- package/references/official-docs/docs/cordis-tutorial/02-lifecycle-and-effects.i18n.yaml +0 -16
- package/references/official-docs/docs/cordis-tutorial/02-lifecycle-and-effects.md +0 -98
- package/references/official-docs/docs/cordis-tutorial/02-lifecycle-and-effects.zh.md +0 -98
- package/references/official-docs/docs/cordis-tutorial/03-services.i18n.yaml +0 -22
- package/references/official-docs/docs/cordis-tutorial/03-services.md +0 -98
- package/references/official-docs/docs/cordis-tutorial/03-services.zh.md +0 -98
- package/references/official-docs/docs/cordis-tutorial/04-events.i18n.yaml +0 -16
- package/references/official-docs/docs/cordis-tutorial/04-events.md +0 -144
- package/references/official-docs/docs/cordis-tutorial/04-events.zh.md +0 -144
- package/references/official-docs/docs/cordis-tutorial/05-config.i18n.yaml +0 -19
- package/references/official-docs/docs/cordis-tutorial/05-config.md +0 -111
- package/references/official-docs/docs/cordis-tutorial/05-config.zh.md +0 -111
- package/references/official-docs/docs/cordis-tutorial/06-composition-and-hmr.i18n.yaml +0 -16
- package/references/official-docs/docs/cordis-tutorial/06-composition-and-hmr.md +0 -113
- package/references/official-docs/docs/cordis-tutorial/06-composition-and-hmr.zh.md +0 -113
- package/references/official-docs/docs/cordis-tutorial/07-into-the-harness.i18n.yaml +0 -19
- package/references/official-docs/docs/cordis-tutorial/07-into-the-harness.md +0 -108
- package/references/official-docs/docs/cordis-tutorial/07-into-the-harness.zh.md +0 -108
- package/references/official-docs/docs/cordis-tutorial/index.i18n.yaml +0 -16
- package/references/official-docs/docs/cordis-tutorial/index.md +0 -60
- package/references/official-docs/docs/cordis-tutorial/index.zh.md +0 -62
- package/references/official-docs/docs/deepseek-llm-api-wire-extensions.i18n.yaml +0 -34
- package/references/official-docs/docs/deepseek-llm-api-wire-extensions.md +0 -162
- package/references/official-docs/docs/deepseek-llm-api-wire-extensions.zh.md +0 -162
- package/references/official-docs/docs/defensive-patterns/README.i18n.yaml +0 -10
- package/references/official-docs/docs/defensive-patterns/README.md +0 -25
- package/references/official-docs/docs/defensive-patterns/README.zh.md +0 -27
- package/references/official-docs/docs/defensive-patterns/client-components.i18n.yaml +0 -46
- package/references/official-docs/docs/defensive-patterns/client-components.md +0 -493
- package/references/official-docs/docs/defensive-patterns/client-components.zh.md +0 -495
- package/references/official-docs/docs/defensive-patterns/conversation-and-session.i18n.yaml +0 -31
- package/references/official-docs/docs/defensive-patterns/conversation-and-session.md +0 -316
- package/references/official-docs/docs/defensive-patterns/conversation-and-session.zh.md +0 -316
- package/references/official-docs/docs/defensive-patterns/general.i18n.yaml +0 -52
- package/references/official-docs/docs/defensive-patterns/general.md +0 -222
- package/references/official-docs/docs/defensive-patterns/general.zh.md +0 -252
- package/references/official-docs/docs/defensive-patterns/package-surface.i18n.yaml +0 -28
- package/references/official-docs/docs/defensive-patterns/package-surface.md +0 -231
- package/references/official-docs/docs/defensive-patterns/package-surface.zh.md +0 -231
- package/references/official-docs/docs/defensive-patterns/remote-and-api.i18n.yaml +0 -16
- package/references/official-docs/docs/defensive-patterns/remote-and-api.md +0 -115
- package/references/official-docs/docs/defensive-patterns/remote-and-api.zh.md +0 -115
- package/references/official-docs/docs/dependency-catalog.json +0 -7312
- package/references/official-docs/docs/development.i18n.yaml +0 -49
- package/references/official-docs/docs/development.md +0 -214
- package/references/official-docs/docs/development.zh.md +0 -221
- package/references/official-docs/docs/event-producer-consumer.i18n.yaml +0 -13
- package/references/official-docs/docs/event-producer-consumer.md +0 -110
- package/references/official-docs/docs/event-producer-consumer.zh.md +0 -112
- package/references/official-docs/docs/experimental-persistence-catalog.i18n.yaml +0 -10
- package/references/official-docs/docs/experimental-persistence-catalog.md +0 -17
- package/references/official-docs/docs/experimental-persistence-catalog.zh.md +0 -17
- package/references/official-docs/docs/glossary.i18n.yaml +0 -25
- package/references/official-docs/docs/glossary.md +0 -46
- package/references/official-docs/docs/glossary.zh.md +0 -46
- package/references/official-docs/docs/graph-atlas.i18n.yaml +0 -10
- package/references/official-docs/docs/graph-atlas.md +0 -22
- package/references/official-docs/docs/graph-atlas.zh.md +0 -24
- package/references/official-docs/docs/i18n/README.i18n.yaml +0 -19
- package/references/official-docs/docs/i18n/README.md +0 -69
- package/references/official-docs/docs/i18n/README.zh.md +0 -71
- package/references/official-docs/docs/i18n/style-samples.md +0 -87
- package/references/official-docs/docs/i18n/terminology.md +0 -215
- package/references/official-docs/docs/i18n/translation-prompt.md +0 -263
- package/references/official-docs/docs/i18n/translation-rules.i18n.yaml +0 -28
- package/references/official-docs/docs/i18n/translation-rules.md +0 -69
- package/references/official-docs/docs/i18n/translation-rules.zh.md +0 -69
- package/references/official-docs/docs/module-graph.i18n.yaml +0 -10
- package/references/official-docs/docs/module-graph.md +0 -1776
- package/references/official-docs/docs/module-graph.zh.md +0 -1778
- package/references/official-docs/docs/persistence-catalog.i18n.yaml +0 -2152
- package/references/official-docs/docs/persistence-catalog.md +0 -9140
- package/references/official-docs/docs/persistence-catalog.zh.md +0 -9142
- package/references/official-docs/docs/persistence-changes/2026-09-11-initial.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-09-11-initial.md +0 -280
- package/references/official-docs/docs/persistence-changes/2026-09-11-initial.schema.json +0 -13557
- package/references/official-docs/docs/persistence-changes/2026-09-11-initial.zh.md +0 -280
- package/references/official-docs/docs/persistence-changes/2026-09-12-auto-review-error-metadata.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-09-12-auto-review-error-metadata.md +0 -52
- package/references/official-docs/docs/persistence-changes/2026-09-12-auto-review-error-metadata.schema.json +0 -910
- package/references/official-docs/docs/persistence-changes/2026-09-12-auto-review-error-metadata.zh.md +0 -52
- package/references/official-docs/docs/persistence-changes/2026-09-13-working-directory.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-09-13-working-directory.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-09-13-working-directory.schema.json +0 -76
- package/references/official-docs/docs/persistence-changes/2026-09-13-working-directory.zh.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-09-14-image-offload.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-09-14-image-offload.md +0 -96
- package/references/official-docs/docs/persistence-changes/2026-09-14-image-offload.schema.json +0 -8478
- package/references/official-docs/docs/persistence-changes/2026-09-14-image-offload.zh.md +0 -96
- package/references/official-docs/docs/persistence-changes/2026-09-14-workspace-changes-event.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-09-14-workspace-changes-event.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-09-14-workspace-changes-event.schema.json +0 -72
- package/references/official-docs/docs/persistence-changes/2026-09-14-workspace-changes-event.zh.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-09-16-session-format-v4.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-09-16-session-format-v4.md +0 -120
- package/references/official-docs/docs/persistence-changes/2026-09-16-session-format-v4.schema.json +0 -16212
- package/references/official-docs/docs/persistence-changes/2026-09-16-session-format-v4.zh.md +0 -120
- package/references/official-docs/docs/persistence-changes/2026-09-18-schedule-optional-title.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-09-18-schedule-optional-title.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-09-18-schedule-optional-title.schema.json +0 -302
- package/references/official-docs/docs/persistence-changes/2026-09-18-schedule-optional-title.zh.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-09-19-external-subagent-catalog.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-09-19-external-subagent-catalog.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-09-19-external-subagent-catalog.schema.json +0 -290
- package/references/official-docs/docs/persistence-changes/2026-09-19-external-subagent-catalog.zh.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-09-20-unknown-child-catalog.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-09-20-unknown-child-catalog.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-09-20-unknown-child-catalog.schema.json +0 -250
- package/references/official-docs/docs/persistence-changes/2026-09-20-unknown-child-catalog.zh.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-09-21-user-question-reply.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-09-21-user-question-reply.md +0 -60
- package/references/official-docs/docs/persistence-changes/2026-09-21-user-question-reply.schema.json +0 -11405
- package/references/official-docs/docs/persistence-changes/2026-09-21-user-question-reply.zh.md +0 -60
- package/references/official-docs/docs/persistence-changes/2026-09-30-job-session-lifecycle.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-09-30-job-session-lifecycle.md +0 -52
- package/references/official-docs/docs/persistence-changes/2026-09-30-job-session-lifecycle.schema.json +0 -297
- package/references/official-docs/docs/persistence-changes/2026-09-30-job-session-lifecycle.zh.md +0 -52
- package/references/official-docs/docs/persistence-changes/2026-10-05-ptc-operation-metadata.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-10-05-ptc-operation-metadata.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-10-05-ptc-operation-metadata.schema.json +0 -457
- package/references/official-docs/docs/persistence-changes/2026-10-05-ptc-operation-metadata.zh.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-10-05-working-directory-attribution.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-10-05-working-directory-attribution.md +0 -60
- package/references/official-docs/docs/persistence-changes/2026-10-05-working-directory-attribution.schema.json +0 -11474
- package/references/official-docs/docs/persistence-changes/2026-10-05-working-directory-attribution.zh.md +0 -60
- package/references/official-docs/docs/persistence-changes/2026-10-07-title-reasoning-effort.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-10-07-title-reasoning-effort.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-10-07-title-reasoning-effort.schema.json +0 -2990
- package/references/official-docs/docs/persistence-changes/2026-10-07-title-reasoning-effort.zh.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-10-13-deepseek-search-thinking.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-10-13-deepseek-search-thinking.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-10-13-deepseek-search-thinking.schema.json +0 -231
- package/references/official-docs/docs/persistence-changes/2026-10-13-deepseek-search-thinking.zh.md +0 -48
- package/references/official-docs/docs/persistence-changes/2026-10-13-user-rpc-principal.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/2026-10-13-user-rpc-principal.md +0 -60
- package/references/official-docs/docs/persistence-changes/2026-10-13-user-rpc-principal.schema.json +0 -11559
- package/references/official-docs/docs/persistence-changes/2026-10-13-user-rpc-principal.zh.md +0 -60
- package/references/official-docs/docs/persistence-changes/README.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/README.md +0 -90
- package/references/official-docs/docs/persistence-changes/README.zh.md +0 -90
- package/references/official-docs/docs/persistence-changes/finalized/v4.json +0 -379
- package/references/official-docs/docs/persistence-changes/historical-formats/README.i18n.yaml +0 -28
- package/references/official-docs/docs/persistence-changes/historical-formats/README.md +0 -75
- package/references/official-docs/docs/persistence-changes/historical-formats/README.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/historical-formats/v0.i18n.yaml +0 -1285
- package/references/official-docs/docs/persistence-changes/historical-formats/v0.md +0 -5105
- package/references/official-docs/docs/persistence-changes/historical-formats/v0.schema.json +0 -49308
- package/references/official-docs/docs/persistence-changes/historical-formats/v0.zh.md +0 -5105
- package/references/official-docs/docs/persistence-changes/historical-formats/v1.i18n.yaml +0 -1285
- package/references/official-docs/docs/persistence-changes/historical-formats/v1.md +0 -5107
- package/references/official-docs/docs/persistence-changes/historical-formats/v1.schema.json +0 -49411
- package/references/official-docs/docs/persistence-changes/historical-formats/v1.zh.md +0 -5107
- package/references/official-docs/docs/persistence-changes/historical-formats/v2.i18n.yaml +0 -1345
- package/references/official-docs/docs/persistence-changes/historical-formats/v2.md +0 -5362
- package/references/official-docs/docs/persistence-changes/historical-formats/v2.schema.json +0 -56466
- package/references/official-docs/docs/persistence-changes/historical-formats/v2.zh.md +0 -5362
- package/references/official-docs/docs/persistence-changes/historical-formats/v3.i18n.yaml +0 -1441
- package/references/official-docs/docs/persistence-changes/historical-formats/v3.md +0 -5634
- package/references/official-docs/docs/persistence-changes/historical-formats/v3.schema.json +0 -61307
- package/references/official-docs/docs/persistence-changes/historical-formats/v3.zh.md +0 -5634
- package/references/official-docs/docs/persistence-changes/releases/README.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/README.md +0 -103
- package/references/official-docs/docs/persistence-changes/releases/README.zh.md +0 -103
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.1.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.1.md +0 -201
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.1.schema.json +0 -39868
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.1.zh.md +0 -201
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.2.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.2.md +0 -261
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.2.schema.json +0 -43342
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.2.zh.md +0 -261
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.3.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.3.md +0 -126
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.3.schema.json +0 -19452
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.3.zh.md +0 -126
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.4.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.4.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.4.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.4.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.5.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.5.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.5.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.0.1-rc.5.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.1.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.1.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.1.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.1.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.2.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.2.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.2.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.2.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.3.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.3.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.3.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.3.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.5.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.5.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.5.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.5.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.6.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.6.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.6.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.6.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.7.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.7.md +0 -82
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.7.schema.json +0 -5320
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.7.zh.md +0 -82
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.8.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.8.md +0 -110
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.8.schema.json +0 -21258
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.0-rc.8.zh.md +0 -110
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.1-rc.1.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.1-rc.1.md +0 -82
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.1-rc.1.schema.json +0 -417
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.1-rc.1.zh.md +0 -82
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.1-rc.2.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.1-rc.2.md +0 -119
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.1-rc.2.schema.json +0 -29672
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.1-rc.2.zh.md +0 -119
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.1.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.1.md +0 -295
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.1.schema.json +0 -48429
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.1.zh.md +0 -295
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.2.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.2.md +0 -286
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.2.schema.json +0 -49347
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.2.zh.md +0 -286
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.3.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.3.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.3.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.3.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.4.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.4.md +0 -95
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.4.schema.json +0 -17642
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.4.zh.md +0 -95
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.5.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.5.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.5.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-alpha.5.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-rc.1.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-rc.1.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-rc.1.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.2-rc.1.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.3-alpha.1.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.3-alpha.1.md +0 -154
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.3-alpha.1.schema.json +0 -38678
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.3-alpha.1.zh.md +0 -154
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.3-alpha.2.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.3-alpha.2.md +0 -86
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.3-alpha.2.schema.json +0 -783
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.3-alpha.2.zh.md +0 -86
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-alpha.1.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-alpha.1.md +0 -139
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-alpha.1.schema.json +0 -24597
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-alpha.1.zh.md +0 -139
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-alpha.2.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-alpha.2.md +0 -95
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-alpha.2.schema.json +0 -2132
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-alpha.2.zh.md +0 -95
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-rc.1.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-rc.1.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-rc.1.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-rc.1.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-rc.2.i18n.yaml +0 -31
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-rc.2.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-rc.2.schema.json +0 -5
- package/references/official-docs/docs/persistence-changes/releases/dsh-v0.1.5-rc.2.zh.md +0 -75
- package/references/official-docs/docs/persistence-changes/releases/manifest.json +0 -162
- package/references/official-docs/docs/persistence-schema.json +0 -26177
- package/references/official-docs/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml +0 -34
- package/references/official-docs/docs/postmortem/0001-acp-default-export-drops-inject.md +0 -113
- package/references/official-docs/docs/postmortem/0001-acp-default-export-drops-inject.zh.md +0 -113
- package/references/official-docs/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml +0 -28
- package/references/official-docs/docs/postmortem/0002-js-expression-disabled-filesystem-tools.md +0 -47
- package/references/official-docs/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +0 -47
- package/references/official-docs/docs/postmortem/0003-web-agent-gui-feedback-loop.i18n.yaml +0 -28
- package/references/official-docs/docs/postmortem/0003-web-agent-gui-feedback-loop.md +0 -53
- package/references/official-docs/docs/postmortem/0003-web-agent-gui-feedback-loop.zh.md +0 -53
- package/references/official-docs/docs/postmortem/0004-landlock-partial-notice-misclassified-child-failures.i18n.yaml +0 -28
- package/references/official-docs/docs/postmortem/0004-landlock-partial-notice-misclassified-child-failures.md +0 -55
- package/references/official-docs/docs/postmortem/0004-landlock-partial-notice-misclassified-child-failures.zh.md +0 -55
- package/references/official-docs/docs/postmortem/README.i18n.yaml +0 -7
- package/references/official-docs/docs/postmortem/README.md +0 -18
- package/references/official-docs/docs/postmortem/README.zh.md +0 -18
- package/references/official-docs/docs/rescope.i18n.yaml +0 -19
- package/references/official-docs/docs/rescope.md +0 -53
- package/references/official-docs/docs/rescope.zh.md +0 -53
- package/references/official-docs/docs/session-format-status.i18n.yaml +0 -28
- package/references/official-docs/docs/session-format-status.md +0 -63
- package/references/official-docs/docs/session-format-status.zh.md +0 -63
- package/references/official-docs/docs/subsystems/README.i18n.yaml +0 -7
- package/references/official-docs/docs/subsystems/README.md +0 -76
- package/references/official-docs/docs/subsystems/README.zh.md +0 -76
- package/references/official-docs/docs/subsystems/agent-team.i18n.yaml +0 -22
- package/references/official-docs/docs/subsystems/agent-team.md +0 -231
- package/references/official-docs/docs/subsystems/agent-team.zh.md +0 -231
- package/references/official-docs/docs/subsystems/approval.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/approval.md +0 -170
- package/references/official-docs/docs/subsystems/approval.zh.md +0 -170
- package/references/official-docs/docs/subsystems/attachment.i18n.yaml +0 -13
- package/references/official-docs/docs/subsystems/attachment.md +0 -361
- package/references/official-docs/docs/subsystems/attachment.zh.md +0 -361
- package/references/official-docs/docs/subsystems/boot.i18n.yaml +0 -16
- package/references/official-docs/docs/subsystems/boot.md +0 -447
- package/references/official-docs/docs/subsystems/boot.zh.md +0 -447
- package/references/official-docs/docs/subsystems/browser-use.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/browser-use.md +0 -67
- package/references/official-docs/docs/subsystems/browser-use.zh.md +0 -67
- package/references/official-docs/docs/subsystems/claude-code-mods.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/claude-code-mods.md +0 -146
- package/references/official-docs/docs/subsystems/claude-code-mods.zh.md +0 -146
- package/references/official-docs/docs/subsystems/client-modules.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/client-modules.md +0 -198
- package/references/official-docs/docs/subsystems/client-modules.zh.md +0 -198
- package/references/official-docs/docs/subsystems/client-resources.i18n.yaml +0 -22
- package/references/official-docs/docs/subsystems/client-resources.md +0 -92
- package/references/official-docs/docs/subsystems/client-resources.zh.md +0 -92
- package/references/official-docs/docs/subsystems/commands.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/commands.md +0 -223
- package/references/official-docs/docs/subsystems/commands.zh.md +0 -223
- package/references/official-docs/docs/subsystems/compaction.i18n.yaml +0 -22
- package/references/official-docs/docs/subsystems/compaction.md +0 -284
- package/references/official-docs/docs/subsystems/compaction.zh.md +0 -284
- package/references/official-docs/docs/subsystems/computer-use.i18n.yaml +0 -16
- package/references/official-docs/docs/subsystems/computer-use.md +0 -59
- package/references/official-docs/docs/subsystems/computer-use.zh.md +0 -59
- package/references/official-docs/docs/subsystems/conversation.i18n.yaml +0 -31
- package/references/official-docs/docs/subsystems/conversation.md +0 -301
- package/references/official-docs/docs/subsystems/conversation.zh.md +0 -303
- package/references/official-docs/docs/subsystems/core.i18n.yaml +0 -37
- package/references/official-docs/docs/subsystems/core.md +0 -1113
- package/references/official-docs/docs/subsystems/core.zh.md +0 -1125
- package/references/official-docs/docs/subsystems/credentials.i18n.yaml +0 -25
- package/references/official-docs/docs/subsystems/credentials.md +0 -493
- package/references/official-docs/docs/subsystems/credentials.zh.md +0 -493
- package/references/official-docs/docs/subsystems/deliverables.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/deliverables.md +0 -178
- package/references/official-docs/docs/subsystems/deliverables.zh.md +0 -178
- package/references/official-docs/docs/subsystems/extensions.i18n.yaml +0 -7
- package/references/official-docs/docs/subsystems/extensions.md +0 -384
- package/references/official-docs/docs/subsystems/extensions.zh.md +0 -384
- package/references/official-docs/docs/subsystems/feedback.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/feedback.md +0 -400
- package/references/official-docs/docs/subsystems/feedback.zh.md +0 -400
- package/references/official-docs/docs/subsystems/filesystem.i18n.yaml +0 -34
- package/references/official-docs/docs/subsystems/filesystem.md +0 -530
- package/references/official-docs/docs/subsystems/filesystem.zh.md +0 -530
- package/references/official-docs/docs/subsystems/goal.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/goal.md +0 -313
- package/references/official-docs/docs/subsystems/goal.zh.md +0 -313
- package/references/official-docs/docs/subsystems/jobs.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/jobs.md +0 -554
- package/references/official-docs/docs/subsystems/jobs.zh.md +0 -554
- package/references/official-docs/docs/subsystems/llm-streaming.i18n.yaml +0 -49
- package/references/official-docs/docs/subsystems/llm-streaming.md +0 -1196
- package/references/official-docs/docs/subsystems/llm-streaming.zh.md +0 -1202
- package/references/official-docs/docs/subsystems/lsp.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/lsp.md +0 -202
- package/references/official-docs/docs/subsystems/lsp.zh.md +0 -202
- package/references/official-docs/docs/subsystems/mcp.i18n.yaml +0 -34
- package/references/official-docs/docs/subsystems/mcp.md +0 -139
- package/references/official-docs/docs/subsystems/mcp.zh.md +0 -139
- package/references/official-docs/docs/subsystems/office-to-pdf.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/office-to-pdf.md +0 -87
- package/references/official-docs/docs/subsystems/office-to-pdf.zh.md +0 -87
- package/references/official-docs/docs/subsystems/otel.i18n.yaml +0 -7
- package/references/official-docs/docs/subsystems/otel.md +0 -44
- package/references/official-docs/docs/subsystems/otel.zh.md +0 -44
- package/references/official-docs/docs/subsystems/permission-presets.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/permission-presets.md +0 -167
- package/references/official-docs/docs/subsystems/permission-presets.zh.md +0 -167
- package/references/official-docs/docs/subsystems/persistence.i18n.yaml +0 -37
- package/references/official-docs/docs/subsystems/persistence.md +0 -418
- package/references/official-docs/docs/subsystems/persistence.zh.md +0 -418
- package/references/official-docs/docs/subsystems/plan.i18n.yaml +0 -22
- package/references/official-docs/docs/subsystems/plan.md +0 -87
- package/references/official-docs/docs/subsystems/plan.zh.md +0 -87
- package/references/official-docs/docs/subsystems/product-telemetry.i18n.yaml +0 -10
- package/references/official-docs/docs/subsystems/product-telemetry.md +0 -81
- package/references/official-docs/docs/subsystems/product-telemetry.zh.md +0 -81
- package/references/official-docs/docs/subsystems/ptc-runtime.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/ptc-runtime.md +0 -250
- package/references/official-docs/docs/subsystems/ptc-runtime.zh.md +0 -250
- package/references/official-docs/docs/subsystems/sandbox.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/sandbox.md +0 -221
- package/references/official-docs/docs/subsystems/sandbox.zh.md +0 -221
- package/references/official-docs/docs/subsystems/schedule.i18n.yaml +0 -40
- package/references/official-docs/docs/subsystems/schedule.md +0 -550
- package/references/official-docs/docs/subsystems/schedule.zh.md +0 -550
- package/references/official-docs/docs/subsystems/scope.i18n.yaml +0 -16
- package/references/official-docs/docs/subsystems/scope.md +0 -59
- package/references/official-docs/docs/subsystems/scope.zh.md +0 -61
- package/references/official-docs/docs/subsystems/session-projection.i18n.yaml +0 -16
- package/references/official-docs/docs/subsystems/session-projection.md +0 -356
- package/references/official-docs/docs/subsystems/session-projection.zh.md +0 -356
- package/references/official-docs/docs/subsystems/session-query.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/session-query.md +0 -511
- package/references/official-docs/docs/subsystems/session-query.zh.md +0 -511
- package/references/official-docs/docs/subsystems/session-reference.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/session-reference.md +0 -224
- package/references/official-docs/docs/subsystems/session-reference.zh.md +0 -224
- package/references/official-docs/docs/subsystems/session-telemetry.i18n.yaml +0 -22
- package/references/official-docs/docs/subsystems/session-telemetry.md +0 -212
- package/references/official-docs/docs/subsystems/session-telemetry.zh.md +0 -212
- package/references/official-docs/docs/subsystems/session-title.i18n.yaml +0 -16
- package/references/official-docs/docs/subsystems/session-title.md +0 -213
- package/references/official-docs/docs/subsystems/session-title.zh.md +0 -213
- package/references/official-docs/docs/subsystems/session.i18n.yaml +0 -70
- package/references/official-docs/docs/subsystems/session.md +0 -1339
- package/references/official-docs/docs/subsystems/session.zh.md +0 -1343
- package/references/official-docs/docs/subsystems/settings.i18n.yaml +0 -13
- package/references/official-docs/docs/subsystems/settings.md +0 -155
- package/references/official-docs/docs/subsystems/settings.zh.md +0 -155
- package/references/official-docs/docs/subsystems/shell.i18n.yaml +0 -25
- package/references/official-docs/docs/subsystems/shell.md +0 -314
- package/references/official-docs/docs/subsystems/shell.zh.md +0 -314
- package/references/official-docs/docs/subsystems/sidebar-right.i18n.yaml +0 -37
- package/references/official-docs/docs/subsystems/sidebar-right.md +0 -160
- package/references/official-docs/docs/subsystems/sidebar-right.zh.md +0 -160
- package/references/official-docs/docs/subsystems/skills.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/skills.md +0 -352
- package/references/official-docs/docs/subsystems/skills.zh.md +0 -352
- package/references/official-docs/docs/subsystems/slots.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/slots.md +0 -200
- package/references/official-docs/docs/subsystems/slots.zh.md +0 -204
- package/references/official-docs/docs/subsystems/spill.i18n.yaml +0 -16
- package/references/official-docs/docs/subsystems/spill.md +0 -124
- package/references/official-docs/docs/subsystems/spill.zh.md +0 -124
- package/references/official-docs/docs/subsystems/ssh.i18n.yaml +0 -22
- package/references/official-docs/docs/subsystems/ssh.md +0 -146
- package/references/official-docs/docs/subsystems/ssh.zh.md +0 -146
- package/references/official-docs/docs/subsystems/storage.i18n.yaml +0 -25
- package/references/official-docs/docs/subsystems/storage.md +0 -259
- package/references/official-docs/docs/subsystems/storage.zh.md +0 -259
- package/references/official-docs/docs/subsystems/subagent.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/subagent.md +0 -686
- package/references/official-docs/docs/subsystems/subagent.zh.md +0 -688
- package/references/official-docs/docs/subsystems/subprocess.i18n.yaml +0 -31
- package/references/official-docs/docs/subsystems/subprocess.md +0 -321
- package/references/official-docs/docs/subsystems/subprocess.zh.md +0 -321
- package/references/official-docs/docs/subsystems/system-prompt.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/system-prompt.md +0 -254
- package/references/official-docs/docs/subsystems/system-prompt.zh.md +0 -254
- package/references/official-docs/docs/subsystems/terminal.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/terminal.md +0 -184
- package/references/official-docs/docs/subsystems/terminal.zh.md +0 -184
- package/references/official-docs/docs/subsystems/todo.i18n.yaml +0 -13
- package/references/official-docs/docs/subsystems/todo.md +0 -32
- package/references/official-docs/docs/subsystems/todo.zh.md +0 -32
- package/references/official-docs/docs/subsystems/token-meter.i18n.yaml +0 -13
- package/references/official-docs/docs/subsystems/token-meter.md +0 -106
- package/references/official-docs/docs/subsystems/token-meter.zh.md +0 -106
- package/references/official-docs/docs/subsystems/tools.i18n.yaml +0 -25
- package/references/official-docs/docs/subsystems/tools.md +0 -747
- package/references/official-docs/docs/subsystems/tools.zh.md +0 -747
- package/references/official-docs/docs/subsystems/translation.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/translation.md +0 -103
- package/references/official-docs/docs/subsystems/translation.zh.md +0 -103
- package/references/official-docs/docs/subsystems/typert.i18n.yaml +0 -25
- package/references/official-docs/docs/subsystems/typert.md +0 -690
- package/references/official-docs/docs/subsystems/typert.zh.md +0 -690
- package/references/official-docs/docs/subsystems/user-questions.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/user-questions.md +0 -307
- package/references/official-docs/docs/subsystems/user-questions.zh.md +0 -307
- package/references/official-docs/docs/subsystems/voice-input.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/voice-input.md +0 -164
- package/references/official-docs/docs/subsystems/voice-input.zh.md +0 -164
- package/references/official-docs/docs/subsystems/web-client.i18n.yaml +0 -37
- package/references/official-docs/docs/subsystems/web-client.md +0 -100
- package/references/official-docs/docs/subsystems/web-client.zh.md +0 -100
- package/references/official-docs/docs/subsystems/web-server.i18n.yaml +0 -16
- package/references/official-docs/docs/subsystems/web-server.md +0 -302
- package/references/official-docs/docs/subsystems/web-server.zh.md +0 -302
- package/references/official-docs/docs/subsystems/web.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/web.md +0 -206
- package/references/official-docs/docs/subsystems/web.zh.md +0 -206
- package/references/official-docs/docs/subsystems/webhook.i18n.yaml +0 -19
- package/references/official-docs/docs/subsystems/webhook.md +0 -70
- package/references/official-docs/docs/subsystems/webhook.zh.md +0 -70
- package/references/official-docs/docs/subsystems/workflow.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/workflow.md +0 -278
- package/references/official-docs/docs/subsystems/workflow.zh.md +0 -278
- package/references/official-docs/docs/subsystems/working-directory.i18n.yaml +0 -13
- package/references/official-docs/docs/subsystems/working-directory.md +0 -64
- package/references/official-docs/docs/subsystems/working-directory.zh.md +0 -64
- package/references/official-docs/docs/subsystems/workspace.i18n.yaml +0 -28
- package/references/official-docs/docs/subsystems/workspace.md +0 -647
- package/references/official-docs/docs/subsystems/workspace.zh.md +0 -647
- package/references/official-docs/docs/subsystems/worktrees.i18n.yaml +0 -13
- package/references/official-docs/docs/subsystems/worktrees.md +0 -76
- package/references/official-docs/docs/subsystems/worktrees.zh.md +0 -76
- package/references/official-docs/docs/testing.i18n.yaml +0 -34
- package/references/official-docs/docs/testing.md +0 -55
- package/references/official-docs/docs/testing.zh.md +0 -55
- package/references/official-docs/docs/tool-catalog.i18n.yaml +0 -331
- package/references/official-docs/docs/tool-catalog.md +0 -2824
- package/references/official-docs/docs/tool-catalog.zh.md +0 -2832
- package/references/official-docs/docs/tool-execution-pipeline.i18n.yaml +0 -10
- package/references/official-docs/docs/tool-execution-pipeline.md +0 -65
- package/references/official-docs/docs/tool-execution-pipeline.zh.md +0 -67
- package/references/official-docs/docs/ui-radius.i18n.yaml +0 -31
- package/references/official-docs/docs/ui-radius.md +0 -117
- package/references/official-docs/docs/ui-radius.zh.md +0 -117
- package/references/official-docs/docs/upgrade-guide/v0.1.7-rc.2/schedule-optional-bundle/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.1.7-rc.2/schedule-optional-bundle/guide.md +0 -22
- package/references/official-docs/docs/upgrade-guide/v0.1.7-rc.2/schedule-optional-bundle/guide.zh.md +0 -22
- package/references/official-docs/docs/upgrade-guide/v0.1.7-rc.2/transcript-view-legacy-normal/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.1.7-rc.2/transcript-view-legacy-normal/guide.md +0 -25
- package/references/official-docs/docs/upgrade-guide/v0.1.7-rc.2/transcript-view-legacy-normal/guide.zh.md +0 -25
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/account-sign-in-errors/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/account-sign-in-errors/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/account-sign-in-errors/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/bundled-python-tests/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/bundled-python-tests/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/bundled-python-tests/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/primary-runtime-python-aliases/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/primary-runtime-python-aliases/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/primary-runtime-python-aliases/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/remove-runtime-invariants/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/remove-runtime-invariants/guide.md +0 -23
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/remove-runtime-invariants/guide.zh.md +0 -23
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/schedule-bundle-retired/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/schedule-bundle-retired/guide.md +0 -22
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/schedule-bundle-retired/guide.zh.md +0 -22
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/subpath-plugin-display-manifest/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/subpath-plugin-display-manifest/guide.md +0 -27
- package/references/official-docs/docs/upgrade-guide/v0.2.0-rc.2/subpath-plugin-display-manifest/guide.zh.md +0 -27
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/deepseek-model-discovery/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/deepseek-model-discovery/guide.md +0 -17
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/deepseek-model-discovery/guide.zh.md +0 -17
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/desktop-test-auth-popup/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/desktop-test-auth-popup/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/desktop-test-auth-popup/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/experimental-package-composition/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/experimental-package-composition/guide.md +0 -28
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/experimental-package-composition/guide.zh.md +0 -28
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/instruction-home-override/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/instruction-home-override/guide.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/instruction-home-override/guide.zh.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/job-id-identity/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/job-id-identity/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/job-id-identity/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/jsonl-persistence-plugin/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/jsonl-persistence-plugin/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/jsonl-persistence-plugin/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/mock-messages-events/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/mock-messages-events/guide.md +0 -17
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/mock-messages-events/guide.zh.md +0 -17
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/native-subagent-bundle-tools/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/native-subagent-bundle-tools/guide.md +0 -31
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/native-subagent-bundle-tools/guide.zh.md +0 -31
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/new-session-generations/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/new-session-generations/guide.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/new-session-generations/guide.zh.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/plugin-option-placement/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/plugin-option-placement/guide.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/plugin-option-placement/guide.zh.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/python-optional-resources/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/python-optional-resources/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/python-optional-resources/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/python-ptc-sandbox/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/python-ptc-sandbox/guide.md +0 -21
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/python-ptc-sandbox/guide.zh.md +0 -21
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/session-title-adapters/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/session-title-adapters/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/session-title-adapters/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/session-title-provider-strategy/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/session-title-provider-strategy/guide.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/session-title-provider-strategy/guide.zh.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/ssh-helper-launch/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/ssh-helper-launch/guide.md +0 -19
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/ssh-helper-launch/guide.zh.md +0 -19
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/subagent-activations/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/subagent-activations/guide.md +0 -59
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/subagent-activations/guide.zh.md +0 -59
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/subagent-preset-composition/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/subagent-preset-composition/guide.md +0 -21
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/subagent-preset-composition/guide.zh.md +0 -21
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.md +0 -21
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.zh.md +0 -21
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/terminal-command-labels/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/terminal-command-labels/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/terminal-command-labels/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/tool-presentation-mode/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/tool-presentation-mode/guide.md +0 -21
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/tool-presentation-mode/guide.zh.md +0 -21
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/web-listener-trust-config/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/web-listener-trust-config/guide.md +0 -36
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/web-listener-trust-config/guide.zh.md +0 -36
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/working-directory/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/working-directory/guide.md +0 -25
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.1/working-directory/guide.zh.md +0 -25
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/deepseek-account-identity-watch/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/deepseek-account-identity-watch/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/deepseek-account-identity-watch/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/deepseek-account-model-catalog/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/deepseek-account-model-catalog/guide.md +0 -27
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/deepseek-account-model-catalog/guide.zh.md +0 -27
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/desktop-font-size-shortcuts/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/desktop-font-size-shortcuts/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/desktop-font-size-shortcuts/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/from-default-profile-replaces-target/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/from-default-profile-replaces-target/guide.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/from-default-profile-replaces-target/guide.zh.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/operator-connect/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/operator-connect/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/operator-connect/guide.zh.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/pi-ai-azure-provider/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/pi-ai-azure-provider/guide.md +0 -19
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/pi-ai-azure-provider/guide.zh.md +0 -19
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/pi-ai-model-discovery/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/pi-ai-model-discovery/guide.md +0 -17
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/pi-ai-model-discovery/guide.zh.md +0 -17
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/plugin-install-over-installed/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/plugin-install-over-installed/guide.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/plugin-install-over-installed/guide.zh.md +0 -20
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/sdk-minimal-image-compaction/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/sdk-minimal-image-compaction/guide.md +0 -32
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/sdk-minimal-image-compaction/guide.zh.md +0 -32
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/stored-credentials-precedence/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/stored-credentials-precedence/guide.md +0 -25
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.2/stored-credentials-precedence/guide.zh.md +0 -25
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.3/plugin-engines-dsh/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.3/plugin-engines-dsh/guide.md +0 -21
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.3/plugin-engines-dsh/guide.zh.md +0 -21
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.4/account-notification-fields/guide.i18n.yaml +0 -16
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.4/account-notification-fields/guide.md +0 -18
- package/references/official-docs/docs/upgrade-guide/v0.2.1-alpha.4/account-notification-fields/guide.zh.md +0 -18
- package/references/official-docs/docs/user/develop/basic/config.i18n.yaml +0 -28
- package/references/official-docs/docs/user/develop/basic/config.md +0 -106
- package/references/official-docs/docs/user/develop/basic/config.zh.md +0 -106
- package/references/official-docs/docs/user/develop/basic/index.i18n.yaml +0 -37
- package/references/official-docs/docs/user/develop/basic/index.md +0 -144
- package/references/official-docs/docs/user/develop/basic/index.zh.md +0 -144
- package/references/official-docs/docs/user/develop/basic/publish.i18n.yaml +0 -31
- package/references/official-docs/docs/user/develop/basic/publish.md +0 -191
- package/references/official-docs/docs/user/develop/basic/publish.zh.md +0 -191
- package/references/official-docs/docs/user/develop/basic/tool.i18n.yaml +0 -16
- package/references/official-docs/docs/user/develop/basic/tool.md +0 -52
- package/references/official-docs/docs/user/develop/basic/tool.zh.md +0 -52
- package/references/official-docs/docs/user/develop/framework/events.i18n.yaml +0 -46
- package/references/official-docs/docs/user/develop/framework/events.md +0 -143
- package/references/official-docs/docs/user/develop/framework/events.zh.md +0 -143
- package/references/official-docs/docs/user/develop/framework/index.i18n.yaml +0 -31
- package/references/official-docs/docs/user/develop/framework/index.md +0 -137
- package/references/official-docs/docs/user/develop/framework/index.zh.md +0 -137
- package/references/official-docs/docs/user/develop/framework/service.i18n.yaml +0 -40
- package/references/official-docs/docs/user/develop/framework/service.md +0 -148
- package/references/official-docs/docs/user/develop/framework/service.zh.md +0 -150
- package/references/official-docs/docs/user/develop/practice/dynamic-cordis.i18n.yaml +0 -10
- package/references/official-docs/docs/user/develop/practice/dynamic-cordis.md +0 -15
- package/references/official-docs/docs/user/develop/practice/dynamic-cordis.zh.md +0 -15
- package/references/official-docs/docs/user/develop/practice/index.i18n.yaml +0 -46
- package/references/official-docs/docs/user/develop/practice/index.md +0 -155
- package/references/official-docs/docs/user/develop/practice/index.zh.md +0 -155
- package/references/official-docs/docs/user/develop/practice/llm-adapter.i18n.yaml +0 -34
- package/references/official-docs/docs/user/develop/practice/llm-adapter.md +0 -189
- package/references/official-docs/docs/user/develop/practice/llm-adapter.zh.md +0 -189
- package/references/official-docs/docs/user/guide/github-review.i18n.yaml +0 -25
- package/references/official-docs/docs/user/guide/github-review.md +0 -99
- package/references/official-docs/docs/user/guide/github-review.zh.md +0 -99
- package/references/official-docs/docs/user/guide/index.i18n.yaml +0 -19
- package/references/official-docs/docs/user/guide/index.md +0 -31
- package/references/official-docs/docs/user/guide/index.zh.md +0 -31
- package/references/official-docs/docs/user/guide/mcp-memory.i18n.yaml +0 -37
- package/references/official-docs/docs/user/guide/mcp-memory.md +0 -101
- package/references/official-docs/docs/user/guide/mcp-memory.zh.md +0 -101
- package/references/official-docs/docs/user/guide/network-proxy.i18n.yaml +0 -25
- package/references/official-docs/docs/user/guide/network-proxy.md +0 -85
- package/references/official-docs/docs/user/guide/network-proxy.zh.md +0 -85
- package/references/official-docs/docs/user/guide/plugin-market.i18n.yaml +0 -34
- package/references/official-docs/docs/user/guide/plugin-market.md +0 -148
- package/references/official-docs/docs/user/guide/plugin-market.zh.md +0 -148
- 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 +0 -40
- package/references/official-docs/docs/user/guide/providers.md +0 -227
- package/references/official-docs/docs/user/guide/providers.zh.md +0 -227
- package/references/official-docs/docs/user/guide/public-deployments.i18n.yaml +0 -19
- package/references/official-docs/docs/user/guide/public-deployments.md +0 -37
- package/references/official-docs/docs/user/guide/public-deployments.zh.md +0 -37
- package/references/official-docs/docs/user/guide/python-sdk.i18n.yaml +0 -28
- package/references/official-docs/docs/user/guide/python-sdk.md +0 -185
- package/references/official-docs/docs/user/guide/python-sdk.zh.md +0 -185
- package/references/official-docs/docs/user/guide/schedule.i18n.yaml +0 -31
- package/references/official-docs/docs/user/guide/schedule.md +0 -79
- package/references/official-docs/docs/user/guide/schedule.zh.md +0 -79
- package/references/official-docs/docs/user/index.i18n.yaml +0 -10
- package/references/official-docs/docs/user/index.md +0 -11
- package/references/official-docs/docs/user/index.zh.md +0 -11
- package/references/official-docs/docs/web-styling.i18n.yaml +0 -19
- package/references/official-docs/docs/web-styling.md +0 -39
- package/references/official-docs/docs/web-styling.zh.md +0 -39
- package/references/official-docs/packages/AGENTS.md +0 -29
- package/references/official-docs/packages/README.md +0 -117
- package/references/official-docs/vendor/README.md +0 -73
- package/references/official-docs/website-docs.ts +0 -591
- package/references/official-plugin-dev-skill.md +0 -124
- package/references/sources.md +0 -143
- package/references/upstream-cordis.md +0 -594
- package/references/website-pages.md +0 -673
- package/scripts/archive-discussions.ps1 +0 -162
- package/scripts/build-llms-full.mjs +0 -73
- package/scripts/check-docs-drift-detail.mjs +0 -145
- package/scripts/check-docs-drift.ps1 +0 -55
- package/scripts/check-facts.mjs +0 -162
- package/scripts/check-ps1-bom.mjs +0 -68
- package/scripts/check-readme-parity.mjs +0 -149
- package/scripts/check-readme-sync.mjs +0 -96
- package/scripts/download-community-articles.ps1 +0 -188
- package/scripts/download-community-repos.ps1 +0 -232
- package/scripts/download-sources.ps1 +0 -195
- package/scripts/gen-topic-snapshot.ps1 +0 -91
- package/scripts/install-skill.ps1 +0 -63
- package/scripts/measure-mirror-references.mjs +0 -117
- package/scripts/sync-official-docs.ps1 +0 -138
- package/scripts/verify-artifacts.mjs +0 -145
- package/scripts/verify-kit.ps1 +0 -197
- package/templates/js/LICENSE +0 -15
- package/templates/js/README-es.md +0 -46
- package/templates/js/README-hi.md +0 -46
- package/templates/js/README-pt.md +0 -46
- package/templates/js/README-zh.md +0 -46
- package/templates/js/README.md +0 -46
- package/templates/js/cordis.patch.yml +0 -10
- package/templates/js/icon.svg +0 -4
- package/templates/js/index.js +0 -38
- package/templates/js/locale/en.json +0 -6
- package/templates/js/locale/zh.json +0 -6
- package/templates/js/package.json +0 -49
- package/templates/js/tests/index.test.js +0 -12
- package/templates/ts/LICENSE +0 -15
- package/templates/ts/README-es.md +0 -48
- package/templates/ts/README-hi.md +0 -48
- package/templates/ts/README-pt.md +0 -48
- package/templates/ts/README-zh.md +0 -48
- package/templates/ts/README.md +0 -48
- package/templates/ts/cordis.patch.yml +0 -10
- package/templates/ts/icon.svg +0 -4
- package/templates/ts/locale/en.json +0 -6
- package/templates/ts/locale/zh.json +0 -6
- package/templates/ts/package.json +0 -58
- package/templates/ts/src/config.ts +0 -12
- package/templates/ts/src/index.ts +0 -36
- package/templates/ts/tests/index.test.ts +0 -12
- package/templates/ts/tsconfig.json +0 -17
- package/templates/ts/tsdown.config.mjs +0 -21
- package/templates/ts/vitest.config.ts +0 -8
package/dist/dsh-plugin-dev.js
DELETED
|
@@ -1,2261 +0,0 @@
|
|
|
1
|
-
import { dirname, join, resolve } from "node:path";
|
|
2
|
-
import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { spawn } from "node:child_process";
|
|
6
|
-
|
|
7
|
-
//#region src/cli/lib/args.ts
|
|
8
|
-
const LONG_ALIASES = {
|
|
9
|
-
help: "help",
|
|
10
|
-
version: "version"
|
|
11
|
-
};
|
|
12
|
-
/** Raised for a malformed or unrecognised argument. */
|
|
13
|
-
var UsageError = class extends Error {};
|
|
14
|
-
/**
|
|
15
|
-
* Parse an argv slice (without the node/script prefix) into positionals and flags.
|
|
16
|
-
*
|
|
17
|
-
* `allowed` is the set of long flag names the caller accepts (aliases included).
|
|
18
|
-
* Passing it turns an unrecognised flag into a `UsageError` instead of a silently
|
|
19
|
-
* ignored one: `dsh-plugin-dev check --stirct` used to parse the typo, check
|
|
20
|
-
* nothing extra, and exit 0 — a gate that can be disabled by a spelling mistake
|
|
21
|
-
* is worse than no gate, because CI stays green and everyone believes it ran.
|
|
22
|
-
*
|
|
23
|
-
* @param argv - process.argv.slice(2) style input.
|
|
24
|
-
* @param allowed - optional allowlist of accepted long flag names.
|
|
25
|
-
* @returns the parsed structure.
|
|
26
|
-
*/
|
|
27
|
-
function parseArgs(argv, allowed) {
|
|
28
|
-
const positionals = [];
|
|
29
|
-
const flags = {};
|
|
30
|
-
const permitted = allowed ? new Set(allowed) : void 0;
|
|
31
|
-
const assertAllowed = (key) => {
|
|
32
|
-
if (permitted && !permitted.has(key)) {
|
|
33
|
-
const known = [...permitted].sort().join(", ");
|
|
34
|
-
throw new UsageError(`unknown option "--${key}" (accepted: ${known})`);
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
for (let i = 0; i < argv.length; i++) {
|
|
38
|
-
const arg = argv[i];
|
|
39
|
-
if (arg === "--") {
|
|
40
|
-
positionals.push(...argv.slice(i + 1));
|
|
41
|
-
break;
|
|
42
|
-
}
|
|
43
|
-
if (arg.startsWith("--")) {
|
|
44
|
-
const body = arg.slice(2);
|
|
45
|
-
const eq = body.indexOf("=");
|
|
46
|
-
if (eq >= 0) {
|
|
47
|
-
const key = body.slice(0, eq);
|
|
48
|
-
assertAllowed(LONG_ALIASES[key] ?? key);
|
|
49
|
-
setFlag(flags, key, body.slice(eq + 1));
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
const key = body;
|
|
53
|
-
assertAllowed(LONG_ALIASES[key] ?? key);
|
|
54
|
-
const next = argv[i + 1];
|
|
55
|
-
if (next !== void 0 && !next.startsWith("-")) {
|
|
56
|
-
setFlag(flags, key, next);
|
|
57
|
-
i++;
|
|
58
|
-
} else setFlag(flags, key, true);
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
if (arg.startsWith("-") && arg.length > 1) {
|
|
62
|
-
for (const ch of arg.slice(1)) {
|
|
63
|
-
assertAllowed(ch);
|
|
64
|
-
flags[ch] = true;
|
|
65
|
-
}
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
positionals.push(arg);
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
positionals,
|
|
72
|
-
flags
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
function setFlag(flags, key, value) {
|
|
76
|
-
const canonical = LONG_ALIASES[key] ?? key;
|
|
77
|
-
flags[canonical] = value;
|
|
78
|
-
}
|
|
79
|
-
/** Read a flag as a string, returning the fallback when absent or boolean-true. */
|
|
80
|
-
function flagString(flags, key, fallback) {
|
|
81
|
-
const v = flags[key];
|
|
82
|
-
if (typeof v === "string") return v;
|
|
83
|
-
return fallback;
|
|
84
|
-
}
|
|
85
|
-
/** Read a flag as a boolean. */
|
|
86
|
-
function flagBool(flags, key) {
|
|
87
|
-
return flags[key] === true || flags[key] === "true";
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
//#endregion
|
|
91
|
-
//#region src/cli/lib/fs.ts
|
|
92
|
-
/** Fixed temp-dir marker prefix; a security invariant, not a tunable. */
|
|
93
|
-
const TEMP_PREFIX = "dsh-pd-";
|
|
94
|
-
const createdTempDirs = /* @__PURE__ */ new Set();
|
|
95
|
-
/**
|
|
96
|
-
* Create a fresh temporary directory under the OS temp root and track it so only
|
|
97
|
-
* this process can clean it up.
|
|
98
|
-
* @param label - short label embedded in the directory name for diagnostics.
|
|
99
|
-
* @returns the absolute path of the new directory.
|
|
100
|
-
*/
|
|
101
|
-
function createTempDir(label) {
|
|
102
|
-
const dir = mkdtempSync(join(tmpdir(), `${TEMP_PREFIX}${label}-`));
|
|
103
|
-
createdTempDirs.add(resolve(dir));
|
|
104
|
-
return dir;
|
|
105
|
-
}
|
|
106
|
-
/** Remove every still-tracked temp directory (best-effort teardown). */
|
|
107
|
-
function cleanupAllTempDirs() {
|
|
108
|
-
for (const dir of [...createdTempDirs]) {
|
|
109
|
-
try {
|
|
110
|
-
rmSync(dir, {
|
|
111
|
-
recursive: true,
|
|
112
|
-
force: true
|
|
113
|
-
});
|
|
114
|
-
} catch {}
|
|
115
|
-
createdTempDirs.delete(dir);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
/** Read a UTF-8 file, returning `undefined` when it does not exist. */
|
|
119
|
-
function readFileIfExists(path) {
|
|
120
|
-
try {
|
|
121
|
-
return readFileSync(path, "utf8");
|
|
122
|
-
} catch {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
/** Read a JSON file as a structured value, returning `undefined` when absent. */
|
|
127
|
-
function readJsonIfExists(path) {
|
|
128
|
-
const text = readFileIfExists(path);
|
|
129
|
-
if (text === void 0) return void 0;
|
|
130
|
-
try {
|
|
131
|
-
return JSON.parse(text);
|
|
132
|
-
} catch {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
/** Write a UTF-8 file, creating parent directories as needed. */
|
|
137
|
-
function writeFileDeep(path, content) {
|
|
138
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
139
|
-
writeFileSync(path, content, "utf8");
|
|
140
|
-
}
|
|
141
|
-
/** True when the path exists and is a regular file. */
|
|
142
|
-
function isFile(path) {
|
|
143
|
-
try {
|
|
144
|
-
return statSync(path).isFile();
|
|
145
|
-
} catch {
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
/** True when the path exists and is a directory. */
|
|
150
|
-
function isDir(path) {
|
|
151
|
-
try {
|
|
152
|
-
return statSync(path).isDirectory();
|
|
153
|
-
} catch {
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
//#endregion
|
|
159
|
-
//#region src/cli/templates.ts
|
|
160
|
-
/**
|
|
161
|
-
* The canonical `@deepseek-ai/dsh-*` peer range, single-sourced here and
|
|
162
|
-
* substituted into every scaffolded package.json through the
|
|
163
|
-
* `{{dshPeerRange}}` placeholder. Keep it identical to the canonical range in
|
|
164
|
-
* `dsh-plugin-kit/data/peer-range.json`: one clause per prerelease tuple is
|
|
165
|
-
* required by semver's prerelease rule, and the `-0` floor covers the whole
|
|
166
|
-
* tuple (never a bare `>=0.2.0` form, which semver's prerelease rule would
|
|
167
|
-
* reject for `0.2.1-alpha.1`).
|
|
168
|
-
*
|
|
169
|
-
* The 0.2 line is load-bearing: `dsh` enforces peer ranges at install time and
|
|
170
|
-
* rejects any plugin whose declared range excludes the running runtime, so a
|
|
171
|
-
* range that stops at 0.1.x makes every scaffolded plugin uninstallable on a
|
|
172
|
-
* 0.2.x harness (`installation rejected: ... is incompatible with dsh <runtime>`).
|
|
173
|
-
*/
|
|
174
|
-
const DSH_PEER_RANGE = ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-0 <0.2.0 || >=0.1.7-0 <0.2.0 || >=0.2.0-0 <0.3.0 || >=0.2.1-0 <0.3.0";
|
|
175
|
-
/**
|
|
176
|
-
* The DSH release this scaffold was last verified against, single-sourced here
|
|
177
|
-
* and substituted into template prose through the `{{dshBaseline}}` placeholder.
|
|
178
|
-
*
|
|
179
|
-
* Keep it in step with `guide/version-matrix.md` §1 and the root README
|
|
180
|
-
* compatibility table. It is deliberately a *prerelease*: DSH has no stable
|
|
181
|
-
* line (every published version and GitHub release carries `-alpha.N`/`-rc.N`),
|
|
182
|
-
* so a scaffold that claimed a stable baseline would be lying.
|
|
183
|
-
*/
|
|
184
|
-
const DSH_BASELINE = "0.2.1-alpha.2";
|
|
185
|
-
/** Resolve the templates root: env override first, then candidate walks. */
|
|
186
|
-
function resolveTemplatesRoot() {
|
|
187
|
-
const env = process.env.DSH_PLUGIN_DEV_TEMPLATES;
|
|
188
|
-
if (env) return resolve(env);
|
|
189
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
190
|
-
const candidates = [
|
|
191
|
-
join(here, "..", "..", "templates"),
|
|
192
|
-
join(here, "..", "templates"),
|
|
193
|
-
join(here, "templates")
|
|
194
|
-
];
|
|
195
|
-
for (const candidate of candidates) if (existsSync(join(candidate, "ts")) && existsSync(join(candidate, "js"))) return resolve(candidate);
|
|
196
|
-
throw new Error("templates directory not found; set DSH_PLUGIN_DEV_TEMPLATES to its path");
|
|
197
|
-
}
|
|
198
|
-
/** Recursively list relative file paths under a directory. */
|
|
199
|
-
function walkFiles(dir, base = "") {
|
|
200
|
-
const out = [];
|
|
201
|
-
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
202
|
-
const rel = base ? `${base}/${entry.name}` : entry.name;
|
|
203
|
-
if (entry.isDirectory()) out.push(...walkFiles(join(dir, entry.name), rel));
|
|
204
|
-
else out.push(rel);
|
|
205
|
-
}
|
|
206
|
-
return out;
|
|
207
|
-
}
|
|
208
|
-
/** Substitute placeholders in template text. */
|
|
209
|
-
function renderTemplate(text, context) {
|
|
210
|
-
return text.replaceAll("{{pkgName}}", context.pkgName).replaceAll("{{name}}", context.name).replaceAll("{{version}}", context.version).replaceAll("{{year}}", context.year).replaceAll("{{dshPeerRange}}", DSH_PEER_RANGE).replaceAll("{{dshBaseline}}", DSH_BASELINE);
|
|
211
|
-
}
|
|
212
|
-
/** Render every file of a language template. */
|
|
213
|
-
function renderScaffold(lang, context) {
|
|
214
|
-
const root = join(resolveTemplatesRoot(), lang);
|
|
215
|
-
return walkFiles(root).sort().map((rel) => {
|
|
216
|
-
return {
|
|
217
|
-
relativePath: rel,
|
|
218
|
-
content: renderTemplate(readFileSync(join(root, rel), "utf8"), context)
|
|
219
|
-
};
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
/** Write rendered files under a target directory. */
|
|
223
|
-
function writeScaffold(targetDir, files) {
|
|
224
|
-
for (const file of files) writeFileDeep(join(targetDir, file.relativePath), file.content);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
//#endregion
|
|
228
|
-
//#region src/cli/meta.ts
|
|
229
|
-
/** Resolve the installed package root (parent of the templates directory). */
|
|
230
|
-
function resolvePackageRoot() {
|
|
231
|
-
return dirname(resolveTemplatesRoot());
|
|
232
|
-
}
|
|
233
|
-
/** Read the installed package version, falling back to a placeholder. */
|
|
234
|
-
function readCliVersion() {
|
|
235
|
-
return readJsonIfExists(join(resolvePackageRoot(), "package.json"))?.version ?? "0.0.0";
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
//#endregion
|
|
239
|
-
//#region src/cli/lib/report.ts
|
|
240
|
-
/** Aggregate a list of checks into a report, deriving `ok` from errors. */
|
|
241
|
-
function buildReport(target, version, checks) {
|
|
242
|
-
const summary = {
|
|
243
|
-
passed: checks.filter((c) => c.status === "pass").length,
|
|
244
|
-
failed: checks.filter((c) => c.status === "fail").length,
|
|
245
|
-
warned: checks.filter((c) => c.status === "warn").length,
|
|
246
|
-
skipped: checks.filter((c) => c.status === "skip").length
|
|
247
|
-
};
|
|
248
|
-
return {
|
|
249
|
-
schemaVersion: 1,
|
|
250
|
-
cli: "dsh-plugin-dev",
|
|
251
|
-
version,
|
|
252
|
-
target,
|
|
253
|
-
ok: summary.failed === 0,
|
|
254
|
-
summary,
|
|
255
|
-
checks
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
/** Render a check list as a human-readable line-oriented report. */
|
|
259
|
-
function renderHuman(report) {
|
|
260
|
-
const lines = [];
|
|
261
|
-
lines.push(`target: ${report.target}`);
|
|
262
|
-
lines.push(`result: ${report.ok ? "OK" : "FAILED"} (${report.summary.passed} passed, ${report.summary.failed} failed, ${report.summary.warned} warned, ${report.summary.skipped} skipped)`);
|
|
263
|
-
lines.push("");
|
|
264
|
-
for (const check of report.checks) {
|
|
265
|
-
const icon = check.status === "pass" ? "✓" : check.status === "fail" ? "✗" : check.status === "warn" ? "!" : "-";
|
|
266
|
-
lines.push(`${icon} [${check.id}] (${check.severity}/${check.kind}) ${check.message}`);
|
|
267
|
-
lines.push(` skill: ${check.skillRef.file} ${check.skillRef.section} — ${check.skillRef.heading}`);
|
|
268
|
-
for (const detail of check.detail ?? []) lines.push(` ${detail}`);
|
|
269
|
-
}
|
|
270
|
-
return lines.join("\n");
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
//#endregion
|
|
274
|
-
//#region src/cli/skill-sections.ts
|
|
275
|
-
/** Canonical skill citation for one check id. */
|
|
276
|
-
const SKILL_SECTIONS = {
|
|
277
|
-
"patch-valid": {
|
|
278
|
-
file: "guide/plugin-dev-guide.md",
|
|
279
|
-
section: "§2.2",
|
|
280
|
-
heading: "三个概念、三种清单(package.json 的 `dsh` 键)"
|
|
281
|
-
},
|
|
282
|
-
"patch-ids-unique": {
|
|
283
|
-
file: "guide/plugin-dev-guide.md",
|
|
284
|
-
section: "§2.3",
|
|
285
|
-
heading: "配置分层顺序(后层覆盖前层,逐行按 `id` 整段替换 config)"
|
|
286
|
-
},
|
|
287
|
-
"manifest-bundle-patch": {
|
|
288
|
-
file: "guide/plugin-dev-guide.md",
|
|
289
|
-
section: "§2.2",
|
|
290
|
-
heading: "三个概念、三种清单(package.json 的 `dsh` 键)"
|
|
291
|
-
},
|
|
292
|
-
"manifest-main": {
|
|
293
|
-
file: "guide/plugin-dev-guide.md",
|
|
294
|
-
section: "§7.3",
|
|
295
|
-
heading: "常见坑清单"
|
|
296
|
-
},
|
|
297
|
-
"manifest-peers": {
|
|
298
|
-
file: "guide/plugin-dev-guide.md",
|
|
299
|
-
section: "§7.3",
|
|
300
|
-
heading: "常见坑清单"
|
|
301
|
-
},
|
|
302
|
-
"manifest-engines": {
|
|
303
|
-
file: "guide/plugin-dev-guide.md",
|
|
304
|
-
section: "§8",
|
|
305
|
-
heading: "规范与质量门禁(对插件作者的实际影响)"
|
|
306
|
-
},
|
|
307
|
-
"manifest-files": {
|
|
308
|
-
file: "guide/plugin-dev-guide.md",
|
|
309
|
-
section: "§7.1",
|
|
310
|
-
heading: "从 GitHub 安装的 build-script 坑"
|
|
311
|
-
},
|
|
312
|
-
"manifest-package-manager": {
|
|
313
|
-
file: "guide/plugin-dev-guide.md",
|
|
314
|
-
section: "§8",
|
|
315
|
-
heading: "规范与质量门禁(对插件作者的实际影响)"
|
|
316
|
-
},
|
|
317
|
-
"display-meta": {
|
|
318
|
-
file: "guide/plugin-dev-guide.md",
|
|
319
|
-
section: "§7.0.1",
|
|
320
|
-
heading: "展示元数据与图标(0.2 世代新增的硬性交付项)"
|
|
321
|
-
},
|
|
322
|
-
"readme-five-langs": {
|
|
323
|
-
file: "guide/plugin-dev-guide.md",
|
|
324
|
-
section: "§8",
|
|
325
|
-
heading: "规范与质量门禁(对插件作者的实际影响)"
|
|
326
|
-
},
|
|
327
|
-
"readme-consistency": {
|
|
328
|
-
file: "guide/plugin-dev-guide.md",
|
|
329
|
-
section: "§8",
|
|
330
|
-
heading: "规范与质量门禁(对插件作者的实际影响)"
|
|
331
|
-
},
|
|
332
|
-
"redline-persona-role": {
|
|
333
|
-
file: "guide/plugin-dev-guide.md",
|
|
334
|
-
section: "§3.7",
|
|
335
|
-
heading: "仓库级红线(写进 AGENTS.md,违反会挂门禁)"
|
|
336
|
-
},
|
|
337
|
-
"redline-waterfall-next": {
|
|
338
|
-
file: "guide/plugin-dev-guide.md",
|
|
339
|
-
section: "§3.5",
|
|
340
|
-
heading: "事件(Events)"
|
|
341
|
-
},
|
|
342
|
-
"redline-no-hardcoded-tunables": {
|
|
343
|
-
file: "guide/plugin-dev-guide.md",
|
|
344
|
-
section: "§3.6",
|
|
345
|
-
heading: "配置(Config)"
|
|
346
|
-
},
|
|
347
|
-
"redline-effect-registration": {
|
|
348
|
-
file: "guide/plugin-dev-guide.md",
|
|
349
|
-
section: "§3.3",
|
|
350
|
-
heading: "注册即 effect"
|
|
351
|
-
},
|
|
352
|
-
"redline-async-apply-registration": {
|
|
353
|
-
file: "guide/plugin-dev-guide.md",
|
|
354
|
-
section: "§3.3.1",
|
|
355
|
-
heading: "async `apply()` 的注册顺序(最容易写成静默缺陷的一条)"
|
|
356
|
-
}
|
|
357
|
-
};
|
|
358
|
-
/** Fallback citation for any check id not in the table. */
|
|
359
|
-
function skillRefFor(id) {
|
|
360
|
-
return SKILL_SECTIONS[id] ?? {
|
|
361
|
-
file: "guide/plugin-dev-guide.md",
|
|
362
|
-
section: "§10",
|
|
363
|
-
heading: "从零到发布的标准路径"
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
//#endregion
|
|
368
|
-
//#region src/cli/lib/yaml.ts
|
|
369
|
-
/**
|
|
370
|
-
* Parse a YAML subset document.
|
|
371
|
-
* @param text - raw YAML text.
|
|
372
|
-
* @returns the parsed value; an empty document is `null`.
|
|
373
|
-
*/
|
|
374
|
-
function parseYaml(text) {
|
|
375
|
-
const lines = tokenize(text);
|
|
376
|
-
return new Parser(lines).parseValue();
|
|
377
|
-
}
|
|
378
|
-
/** True when the value is a mapping. */
|
|
379
|
-
function isObject(value) {
|
|
380
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
381
|
-
}
|
|
382
|
-
/** True when the value is a sequence. */
|
|
383
|
-
function isArray(value) {
|
|
384
|
-
return Array.isArray(value);
|
|
385
|
-
}
|
|
386
|
-
function tokenize(text) {
|
|
387
|
-
const out = [];
|
|
388
|
-
const lines = text.split(/\r?\n/);
|
|
389
|
-
for (let n = 0; n < lines.length; n++) {
|
|
390
|
-
const stripped = stripComment(lines[n]);
|
|
391
|
-
if (stripped.trim() === "") continue;
|
|
392
|
-
out.push({
|
|
393
|
-
indent: stripped.length - stripped.trimStart().length,
|
|
394
|
-
text: stripped.trim(),
|
|
395
|
-
num: n + 1
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
return out;
|
|
399
|
-
}
|
|
400
|
-
function stripComment(line) {
|
|
401
|
-
let single = false;
|
|
402
|
-
let double = false;
|
|
403
|
-
for (let i = 0; i < line.length; i++) {
|
|
404
|
-
const c = line[i];
|
|
405
|
-
if (single) {
|
|
406
|
-
if (c === "'") single = false;
|
|
407
|
-
continue;
|
|
408
|
-
}
|
|
409
|
-
if (double) {
|
|
410
|
-
if (c === "\\") {
|
|
411
|
-
i++;
|
|
412
|
-
continue;
|
|
413
|
-
}
|
|
414
|
-
if (c === "\"") double = false;
|
|
415
|
-
continue;
|
|
416
|
-
}
|
|
417
|
-
if (c === "'") single = true;
|
|
418
|
-
else if (c === "\"") double = true;
|
|
419
|
-
else if (c === "#") return line.slice(0, i);
|
|
420
|
-
}
|
|
421
|
-
return line;
|
|
422
|
-
}
|
|
423
|
-
var Parser = class {
|
|
424
|
-
lines;
|
|
425
|
-
pos = 0;
|
|
426
|
-
constructor(lines) {
|
|
427
|
-
this.lines = lines;
|
|
428
|
-
}
|
|
429
|
-
parseValue() {
|
|
430
|
-
if (this.pos >= this.lines.length) return null;
|
|
431
|
-
const line = this.lines[this.pos];
|
|
432
|
-
if (isSeqItem(line.text)) return this.parseSequence(line.indent);
|
|
433
|
-
if (isMappingStart(line.text)) return this.parseMapping(line.indent);
|
|
434
|
-
this.pos++;
|
|
435
|
-
return parseScalar(line.text);
|
|
436
|
-
}
|
|
437
|
-
parseSequence(indent) {
|
|
438
|
-
const arr = [];
|
|
439
|
-
while (this.pos < this.lines.length && this.lines[this.pos].indent === indent && isSeqItem(this.lines[this.pos].text)) {
|
|
440
|
-
const text = this.lines[this.pos].text;
|
|
441
|
-
if (text === "-") {
|
|
442
|
-
this.pos++;
|
|
443
|
-
arr.push(this.parseValue());
|
|
444
|
-
continue;
|
|
445
|
-
}
|
|
446
|
-
const rest = text.slice(2);
|
|
447
|
-
if (rest === "") {
|
|
448
|
-
this.pos++;
|
|
449
|
-
arr.push(this.parseValue());
|
|
450
|
-
} else if (isMappingStart(rest)) arr.push(this.parseInlineMapping(rest, indent));
|
|
451
|
-
else {
|
|
452
|
-
this.pos++;
|
|
453
|
-
arr.push(parseScalar(rest));
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
return arr;
|
|
457
|
-
}
|
|
458
|
-
parseInlineMapping(firstEntry, seqIndent) {
|
|
459
|
-
const map = {};
|
|
460
|
-
let entry = firstEntry;
|
|
461
|
-
const keyIndent = seqIndent + 2;
|
|
462
|
-
while (true) {
|
|
463
|
-
const split = splitKeyValue(entry);
|
|
464
|
-
if (split.value === "") {
|
|
465
|
-
this.pos++;
|
|
466
|
-
map[split.key] = this.parseValue();
|
|
467
|
-
} else {
|
|
468
|
-
this.pos++;
|
|
469
|
-
map[split.key] = parseScalar(split.value);
|
|
470
|
-
}
|
|
471
|
-
const next = this.lines[this.pos];
|
|
472
|
-
if (next && next.indent === keyIndent && !isSeqItem(next.text) && isMappingStart(next.text)) entry = next.text;
|
|
473
|
-
else break;
|
|
474
|
-
}
|
|
475
|
-
return map;
|
|
476
|
-
}
|
|
477
|
-
parseMapping(indent) {
|
|
478
|
-
const map = {};
|
|
479
|
-
while (this.pos < this.lines.length && this.lines[this.pos].indent === indent && isMappingStart(this.lines[this.pos].text) && !isSeqItem(this.lines[this.pos].text)) {
|
|
480
|
-
const entry = this.lines[this.pos].text;
|
|
481
|
-
const split = splitKeyValue(entry);
|
|
482
|
-
if (split.value === "") {
|
|
483
|
-
this.pos++;
|
|
484
|
-
map[split.key] = this.parseValue();
|
|
485
|
-
} else {
|
|
486
|
-
this.pos++;
|
|
487
|
-
map[split.key] = parseScalar(split.value);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
return map;
|
|
491
|
-
}
|
|
492
|
-
};
|
|
493
|
-
function isSeqItem(text) {
|
|
494
|
-
return text === "-" || text.startsWith("- ");
|
|
495
|
-
}
|
|
496
|
-
function isMappingStart(text) {
|
|
497
|
-
if (text.endsWith(":")) return true;
|
|
498
|
-
return text.includes(": ");
|
|
499
|
-
}
|
|
500
|
-
function splitKeyValue(text) {
|
|
501
|
-
for (let i = 0; i < text.length; i++) if (text[i] === ":" && (i + 1 >= text.length || text[i + 1] === " ")) return {
|
|
502
|
-
key: text.slice(0, i).trim(),
|
|
503
|
-
value: text.slice(i + 1).trim()
|
|
504
|
-
};
|
|
505
|
-
return {
|
|
506
|
-
key: text,
|
|
507
|
-
value: ""
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
function parseScalar(text) {
|
|
511
|
-
const t = text.trim();
|
|
512
|
-
if (t === "" || t === "~" || t === "null" || t === "Null" || t === "NULL") return null;
|
|
513
|
-
if (t === "true" || t === "True" || t === "TRUE") return true;
|
|
514
|
-
if (t === "false" || t === "False" || t === "FALSE") return false;
|
|
515
|
-
if (t.startsWith("'") && t.endsWith("'") && t.length >= 2) return t.slice(1, -1).replace(/''/g, "'");
|
|
516
|
-
if (t.startsWith("\"") && t.endsWith("\"") && t.length >= 2) return unescapeDouble(t.slice(1, -1));
|
|
517
|
-
if (/^-?\d+$/.test(t)) return Number.parseInt(t, 10);
|
|
518
|
-
if (/^-?\d+\.\d+$/.test(t)) return Number.parseFloat(t);
|
|
519
|
-
return t;
|
|
520
|
-
}
|
|
521
|
-
function unescapeDouble(text) {
|
|
522
|
-
return text.replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\r/g, "\r").replace(/\\0/g, "\0").replace(/\\"/g, "\"").replace(/\\\\/g, "\\");
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
//#endregion
|
|
526
|
-
//#region src/cli/commands/check.ts
|
|
527
|
-
/** Icon formats the harness accepts, and its per-file size ceiling. */
|
|
528
|
-
const ICON_EXTENSIONS = [
|
|
529
|
-
".svg",
|
|
530
|
-
".png",
|
|
531
|
-
".jpg",
|
|
532
|
-
".jpeg",
|
|
533
|
-
".webp"
|
|
534
|
-
];
|
|
535
|
-
const ICON_MAX_BYTES = 262144;
|
|
536
|
-
const README_LANGS = [
|
|
537
|
-
"README.md",
|
|
538
|
-
"README-zh.md",
|
|
539
|
-
"README-es.md",
|
|
540
|
-
"README-pt.md",
|
|
541
|
-
"README-hi.md"
|
|
542
|
-
];
|
|
543
|
-
const EXCLUDED_DIRS = /* @__PURE__ */ new Set([
|
|
544
|
-
"node_modules",
|
|
545
|
-
".git",
|
|
546
|
-
"dist",
|
|
547
|
-
"coverage",
|
|
548
|
-
"downloads",
|
|
549
|
-
"_check"
|
|
550
|
-
]);
|
|
551
|
-
/** Run every check and return the report plus a process exit code. */
|
|
552
|
-
function runCheck(options) {
|
|
553
|
-
const root = resolve(options.root);
|
|
554
|
-
const pkg = readJsonIfExists(join(root, "package.json"));
|
|
555
|
-
const checks = [
|
|
556
|
-
checkPatchValid(root, pkg),
|
|
557
|
-
checkPatchIdsUnique(root, pkg),
|
|
558
|
-
checkManifestBundlePatch(root, pkg),
|
|
559
|
-
checkManifestMain(root, pkg),
|
|
560
|
-
checkManifestPeers(root, pkg),
|
|
561
|
-
checkManifestEngines(root, pkg),
|
|
562
|
-
checkManifestFiles(root, pkg),
|
|
563
|
-
checkManifestPackageManager(root, pkg),
|
|
564
|
-
checkDisplayMeta(root, pkg),
|
|
565
|
-
checkReadmeFiveLangs(root),
|
|
566
|
-
checkReadmeConsistency(root),
|
|
567
|
-
checkRedlinePersonaRole(root),
|
|
568
|
-
checkRedlineWaterfallNext(root),
|
|
569
|
-
checkRedlineNoHardcodedTunables(root),
|
|
570
|
-
checkRedlineEffectRegistration(root),
|
|
571
|
-
checkRedlineAsyncApplyRegistration(root)
|
|
572
|
-
];
|
|
573
|
-
const report = buildReport(root, readCliVersion(), checks);
|
|
574
|
-
return {
|
|
575
|
-
report,
|
|
576
|
-
exitCode: report.summary.failed + (options.strict ? report.summary.warned : 0) > 0 ? 1 : 0
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
/** Render the report to the console in the requested format. */
|
|
580
|
-
function printCheckReport(report, format) {
|
|
581
|
-
if (format === "json") process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
582
|
-
else process.stdout.write(`${renderHuman(report)}\n`);
|
|
583
|
-
}
|
|
584
|
-
/** Every patch file a `dsh.bundle.patch` pointer names, in application order. */
|
|
585
|
-
function patchPaths(root, pkg) {
|
|
586
|
-
const pointer = pkg?.dsh?.bundle?.patch;
|
|
587
|
-
if (!pointer) return [];
|
|
588
|
-
return (Array.isArray(pointer) ? pointer : [pointer]).filter((entry) => typeof entry === "string" && entry !== "").map((entry) => resolve(root, entry));
|
|
589
|
-
}
|
|
590
|
-
/** The first patch file, for checks that only describe one file. */
|
|
591
|
-
function patchPath(root, pkg) {
|
|
592
|
-
return patchPaths(root, pkg)[0];
|
|
593
|
-
}
|
|
594
|
-
/**
|
|
595
|
-
* List real source files: the `src/` tree plus root-level JS/ESM entry files.
|
|
596
|
-
* Templates, tests, scripts, references, and generated directories are data or
|
|
597
|
-
* fixtures, never runtime source, so they are excluded from static scans.
|
|
598
|
-
*/
|
|
599
|
-
function listSourceFiles(root) {
|
|
600
|
-
const out = [];
|
|
601
|
-
let rootEntries;
|
|
602
|
-
try {
|
|
603
|
-
rootEntries = readdirSync(root);
|
|
604
|
-
} catch {
|
|
605
|
-
rootEntries = [];
|
|
606
|
-
}
|
|
607
|
-
for (const entry of rootEntries) if (/\.(js|mjs|cjs)$/.test(entry)) out.push(join(root, entry));
|
|
608
|
-
const walk = (dir) => {
|
|
609
|
-
let entries;
|
|
610
|
-
try {
|
|
611
|
-
entries = readdirSync(dir);
|
|
612
|
-
} catch {
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
for (const entry of entries) {
|
|
616
|
-
if (EXCLUDED_DIRS.has(entry)) continue;
|
|
617
|
-
const full = join(dir, entry);
|
|
618
|
-
let stat;
|
|
619
|
-
try {
|
|
620
|
-
stat = statSync(full);
|
|
621
|
-
} catch {
|
|
622
|
-
continue;
|
|
623
|
-
}
|
|
624
|
-
if (stat.isDirectory()) walk(full);
|
|
625
|
-
else if (stat.isFile() && /\.(ts|js|mjs|cjs)$/.test(entry)) out.push(full);
|
|
626
|
-
}
|
|
627
|
-
};
|
|
628
|
-
walk(join(root, "src"));
|
|
629
|
-
return out;
|
|
630
|
-
}
|
|
631
|
-
function readText(path) {
|
|
632
|
-
try {
|
|
633
|
-
return readFileSync(path, "utf8");
|
|
634
|
-
} catch {
|
|
635
|
-
return;
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
function collectedImports(sourceFiles) {
|
|
639
|
-
const imports = /* @__PURE__ */ new Set();
|
|
640
|
-
const re = /(?:from\s+|import\s+|import\s*\(\s*)['"](@deepseek-ai\/[^'"]+)['"]/g;
|
|
641
|
-
for (const file of sourceFiles) {
|
|
642
|
-
const text = readText(file);
|
|
643
|
-
if (!text) continue;
|
|
644
|
-
let match;
|
|
645
|
-
while ((match = re.exec(text)) !== null) imports.add(match[1]);
|
|
646
|
-
}
|
|
647
|
-
return imports;
|
|
648
|
-
}
|
|
649
|
-
function validatePatch(text) {
|
|
650
|
-
const errors = [];
|
|
651
|
-
const rows = [];
|
|
652
|
-
let value;
|
|
653
|
-
try {
|
|
654
|
-
value = parseYaml(text);
|
|
655
|
-
} catch (err) {
|
|
656
|
-
return {
|
|
657
|
-
errors: [`cannot parse YAML: ${err instanceof Error ? err.message : String(err)}`],
|
|
658
|
-
rows
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
if (value === null || value === void 0) return {
|
|
662
|
-
errors: ["empty document"],
|
|
663
|
-
rows
|
|
664
|
-
};
|
|
665
|
-
if (!isArray(value)) return {
|
|
666
|
-
errors: ["top level must be a YAML sequence of row verbs"],
|
|
667
|
-
rows
|
|
668
|
-
};
|
|
669
|
-
value.forEach((verbEntry, i) => {
|
|
670
|
-
if (!isObject(verbEntry)) {
|
|
671
|
-
errors.push(`entry ${i} must be a mapping like \`- insert:\``);
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
const verbs = Object.keys(verbEntry);
|
|
675
|
-
if (verbs.length !== 1) {
|
|
676
|
-
errors.push(`entry ${i} must have exactly one verb key (got ${verbs.length})`);
|
|
677
|
-
return;
|
|
678
|
-
}
|
|
679
|
-
const verb = verbs[0];
|
|
680
|
-
const rowsValue = verbEntry[verb];
|
|
681
|
-
if (!isArray(rowsValue)) {
|
|
682
|
-
errors.push(`entry ${i} verb \`${verb}\` must map to a sequence of rows`);
|
|
683
|
-
return;
|
|
684
|
-
}
|
|
685
|
-
rowsValue.forEach((row, r) => {
|
|
686
|
-
if (!isObject(row)) {
|
|
687
|
-
errors.push(`row ${i}.${r} must be a mapping`);
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
const id = row.id;
|
|
691
|
-
const name = row.name;
|
|
692
|
-
if (typeof id !== "string" || id === "") errors.push(`row ${i}.${r} is missing a string \`id\``);
|
|
693
|
-
if (verb === "insert" && (typeof name !== "string" || name === "")) errors.push(`row ${i}.${r} (insert) is missing a string \`name\``);
|
|
694
|
-
rows.push({
|
|
695
|
-
id: typeof id === "string" ? id : void 0,
|
|
696
|
-
name: typeof name === "string" ? name : void 0
|
|
697
|
-
});
|
|
698
|
-
});
|
|
699
|
-
});
|
|
700
|
-
return {
|
|
701
|
-
errors,
|
|
702
|
-
rows
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
|
-
function checkPatchValid(root, pkg) {
|
|
706
|
-
const ref = skillRefFor("patch-valid");
|
|
707
|
-
const path = patchPath(root, pkg);
|
|
708
|
-
if (!path) return {
|
|
709
|
-
id: "patch-valid",
|
|
710
|
-
severity: "warning",
|
|
711
|
-
kind: "deterministic",
|
|
712
|
-
status: "warn",
|
|
713
|
-
message: "no dsh.bundle.patch pointer; nothing to validate",
|
|
714
|
-
skillRef: ref
|
|
715
|
-
};
|
|
716
|
-
if (!isFile(path)) return {
|
|
717
|
-
id: "patch-valid",
|
|
718
|
-
severity: "error",
|
|
719
|
-
kind: "deterministic",
|
|
720
|
-
status: "fail",
|
|
721
|
-
message: `patch file not found: ${path}`,
|
|
722
|
-
skillRef: ref
|
|
723
|
-
};
|
|
724
|
-
const { errors } = validatePatch(readText(path) ?? "");
|
|
725
|
-
if (errors.length > 0) return {
|
|
726
|
-
id: "patch-valid",
|
|
727
|
-
severity: "error",
|
|
728
|
-
kind: "deterministic",
|
|
729
|
-
status: "fail",
|
|
730
|
-
message: "cordis.patch.yml is invalid",
|
|
731
|
-
skillRef: ref,
|
|
732
|
-
detail: errors
|
|
733
|
-
};
|
|
734
|
-
return {
|
|
735
|
-
id: "patch-valid",
|
|
736
|
-
severity: "error",
|
|
737
|
-
kind: "deterministic",
|
|
738
|
-
status: "pass",
|
|
739
|
-
message: "cordis.patch.yml parses and every row is well-formed",
|
|
740
|
-
skillRef: ref
|
|
741
|
-
};
|
|
742
|
-
}
|
|
743
|
-
function checkPatchIdsUnique(root, pkg) {
|
|
744
|
-
const ref = skillRefFor("patch-ids-unique");
|
|
745
|
-
const path = patchPath(root, pkg);
|
|
746
|
-
if (!path || !isFile(path)) return {
|
|
747
|
-
id: "patch-ids-unique",
|
|
748
|
-
severity: "error",
|
|
749
|
-
kind: "deterministic",
|
|
750
|
-
status: "skip",
|
|
751
|
-
message: "no patch file to check for duplicate ids",
|
|
752
|
-
skillRef: ref
|
|
753
|
-
};
|
|
754
|
-
const { rows } = validatePatch(readText(path) ?? "");
|
|
755
|
-
const seen = /* @__PURE__ */ new Map();
|
|
756
|
-
const dupes = [];
|
|
757
|
-
rows.forEach((row, i) => {
|
|
758
|
-
if (!row.id) return;
|
|
759
|
-
if (seen.has(row.id)) dupes.push(`id "${row.id}" repeated at row ${seen.get(row.id)} and row ${i}`);
|
|
760
|
-
else seen.set(row.id, i);
|
|
761
|
-
});
|
|
762
|
-
if (dupes.length > 0) return {
|
|
763
|
-
id: "patch-ids-unique",
|
|
764
|
-
severity: "error",
|
|
765
|
-
kind: "deterministic",
|
|
766
|
-
status: "fail",
|
|
767
|
-
message: "duplicate row ids in cordis.patch.yml",
|
|
768
|
-
skillRef: ref,
|
|
769
|
-
detail: dupes
|
|
770
|
-
};
|
|
771
|
-
return {
|
|
772
|
-
id: "patch-ids-unique",
|
|
773
|
-
severity: "error",
|
|
774
|
-
kind: "deterministic",
|
|
775
|
-
status: "pass",
|
|
776
|
-
message: `row ids are unique (${rows.length} rows)`,
|
|
777
|
-
skillRef: ref
|
|
778
|
-
};
|
|
779
|
-
}
|
|
780
|
-
function checkManifestBundlePatch(root, pkg) {
|
|
781
|
-
const ref = skillRefFor("manifest-bundle-patch");
|
|
782
|
-
const pointer = pkg?.dsh?.bundle?.patch;
|
|
783
|
-
if (!pointer) return {
|
|
784
|
-
id: "manifest-bundle-patch",
|
|
785
|
-
severity: "warning",
|
|
786
|
-
kind: "deterministic",
|
|
787
|
-
status: "warn",
|
|
788
|
-
message: "no dsh.bundle.patch declared (pure cordis plugin, no bundle layer)",
|
|
789
|
-
skillRef: ref
|
|
790
|
-
};
|
|
791
|
-
const paths = patchPaths(root, pkg);
|
|
792
|
-
if (paths.length === 0) return {
|
|
793
|
-
id: "manifest-bundle-patch",
|
|
794
|
-
severity: "error",
|
|
795
|
-
kind: "deterministic",
|
|
796
|
-
status: "fail",
|
|
797
|
-
message: "dsh.bundle.patch must be a file path or a list of file paths",
|
|
798
|
-
skillRef: ref
|
|
799
|
-
};
|
|
800
|
-
const missing = paths.filter((path) => !isFile(path));
|
|
801
|
-
const label = Array.isArray(pointer) ? pointer.join(", ") : pointer;
|
|
802
|
-
if (missing.length > 0) return {
|
|
803
|
-
id: "manifest-bundle-patch",
|
|
804
|
-
severity: "error",
|
|
805
|
-
kind: "deterministic",
|
|
806
|
-
status: "fail",
|
|
807
|
-
message: `dsh.bundle.patch points at a missing file: ${label}`,
|
|
808
|
-
skillRef: ref,
|
|
809
|
-
detail: missing.map((path) => `not found: ${path}`)
|
|
810
|
-
};
|
|
811
|
-
return {
|
|
812
|
-
id: "manifest-bundle-patch",
|
|
813
|
-
severity: "error",
|
|
814
|
-
kind: "deterministic",
|
|
815
|
-
status: "pass",
|
|
816
|
-
message: `dsh.bundle.patch resolves to ${label}`,
|
|
817
|
-
skillRef: ref
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
function checkManifestMain(root, pkg) {
|
|
821
|
-
const ref = skillRefFor("manifest-main");
|
|
822
|
-
const main = pkg?.main;
|
|
823
|
-
if (!main) return {
|
|
824
|
-
id: "manifest-main",
|
|
825
|
-
severity: "error",
|
|
826
|
-
kind: "deterministic",
|
|
827
|
-
status: "fail",
|
|
828
|
-
message: "package.json has no `main` entry",
|
|
829
|
-
skillRef: ref
|
|
830
|
-
};
|
|
831
|
-
if (!isFile(join(root, main))) return {
|
|
832
|
-
id: "manifest-main",
|
|
833
|
-
severity: "warning",
|
|
834
|
-
kind: "deterministic",
|
|
835
|
-
status: "warn",
|
|
836
|
-
message: `main entry not built yet: ${main} (run the build first)`,
|
|
837
|
-
skillRef: ref
|
|
838
|
-
};
|
|
839
|
-
return {
|
|
840
|
-
id: "manifest-main",
|
|
841
|
-
severity: "error",
|
|
842
|
-
kind: "deterministic",
|
|
843
|
-
status: "pass",
|
|
844
|
-
message: `main entry present: ${main}`,
|
|
845
|
-
skillRef: ref
|
|
846
|
-
};
|
|
847
|
-
}
|
|
848
|
-
function checkManifestPeers(root, pkg) {
|
|
849
|
-
const ref = skillRefFor("manifest-peers");
|
|
850
|
-
const peers = pkg?.peerDependencies ?? {};
|
|
851
|
-
const harnessImports = [...collectedImports(listSourceFiles(root))].filter((i) => i.startsWith("@deepseek-ai/"));
|
|
852
|
-
if (harnessImports.length === 0) return {
|
|
853
|
-
id: "manifest-peers",
|
|
854
|
-
severity: "info",
|
|
855
|
-
kind: "deterministic",
|
|
856
|
-
status: "pass",
|
|
857
|
-
message: "no @deepseek-ai/* packages imported; peers are optional",
|
|
858
|
-
skillRef: ref
|
|
859
|
-
};
|
|
860
|
-
const expected = {};
|
|
861
|
-
for (const imp of harnessImports) if (imp === "@deepseek-ai/cordis") expected[imp] = "^4.0.2";
|
|
862
|
-
else if (imp === "@deepseek-ai/schemastery") expected[imp] = "^3.18.2";
|
|
863
|
-
else if (imp.startsWith("@deepseek-ai/dsh-")) expected[imp] = DSH_PEER_RANGE;
|
|
864
|
-
const problems = [];
|
|
865
|
-
for (const [pkgName, range] of Object.entries(expected)) {
|
|
866
|
-
const declared = peers[pkgName];
|
|
867
|
-
if (!declared) problems.push(`imports ${pkgName} but declares no peerDependency`);
|
|
868
|
-
else if (declared !== range) problems.push(`peerDependency ${pkgName} should be "${range}", found "${declared}"`);
|
|
869
|
-
}
|
|
870
|
-
if (problems.length > 0) return {
|
|
871
|
-
id: "manifest-peers",
|
|
872
|
-
severity: "error",
|
|
873
|
-
kind: "deterministic",
|
|
874
|
-
status: "fail",
|
|
875
|
-
message: "harness imports without a matching peerDependency",
|
|
876
|
-
skillRef: ref,
|
|
877
|
-
detail: problems
|
|
878
|
-
};
|
|
879
|
-
return {
|
|
880
|
-
id: "manifest-peers",
|
|
881
|
-
severity: "error",
|
|
882
|
-
kind: "deterministic",
|
|
883
|
-
status: "pass",
|
|
884
|
-
message: `peerDependencies align with harness imports (${Object.keys(expected).length})`,
|
|
885
|
-
skillRef: ref
|
|
886
|
-
};
|
|
887
|
-
}
|
|
888
|
-
function checkManifestEngines(_root, pkg) {
|
|
889
|
-
const ref = skillRefFor("manifest-engines");
|
|
890
|
-
const node = pkg?.engines?.node;
|
|
891
|
-
if (!node) return {
|
|
892
|
-
id: "manifest-engines",
|
|
893
|
-
severity: "error",
|
|
894
|
-
kind: "deterministic",
|
|
895
|
-
status: "fail",
|
|
896
|
-
message: "package.json has no engines.node",
|
|
897
|
-
skillRef: ref
|
|
898
|
-
};
|
|
899
|
-
const has22 = /\b22\b/.test(node);
|
|
900
|
-
const has24 = /\b24\b/.test(node);
|
|
901
|
-
if (!has22 || !has24) return {
|
|
902
|
-
id: "manifest-engines",
|
|
903
|
-
severity: "error",
|
|
904
|
-
kind: "deterministic",
|
|
905
|
-
status: "fail",
|
|
906
|
-
message: `engines.node "${node}" should allow Node 22 and 24 (^22.19.0 || >=24.0.0)`,
|
|
907
|
-
skillRef: ref
|
|
908
|
-
};
|
|
909
|
-
return {
|
|
910
|
-
id: "manifest-engines",
|
|
911
|
-
severity: "error",
|
|
912
|
-
kind: "deterministic",
|
|
913
|
-
status: "pass",
|
|
914
|
-
message: `engines.node "${node}" covers Node 22 and 24`,
|
|
915
|
-
skillRef: ref
|
|
916
|
-
};
|
|
917
|
-
}
|
|
918
|
-
function checkManifestFiles(_root, pkg) {
|
|
919
|
-
const ref = skillRefFor("manifest-files");
|
|
920
|
-
const files = pkg?.files;
|
|
921
|
-
if (!files || files.length === 0) return {
|
|
922
|
-
id: "manifest-files",
|
|
923
|
-
severity: "warning",
|
|
924
|
-
kind: "deterministic",
|
|
925
|
-
status: "warn",
|
|
926
|
-
message: "no `files` whitelist; npm will publish everything",
|
|
927
|
-
skillRef: ref
|
|
928
|
-
};
|
|
929
|
-
const pointer = pkg?.dsh?.bundle?.patch;
|
|
930
|
-
const patchFiles = (Array.isArray(pointer) ? pointer : pointer ? [pointer] : ["cordis.patch.yml"]).map((entry) => entry.replace(/^\.\//, ""));
|
|
931
|
-
const main = pkg?.main;
|
|
932
|
-
const problems = [];
|
|
933
|
-
for (const patchFile of patchFiles) if (!files.includes(patchFile)) problems.push(`files whitelist is missing the patch file "${patchFile}"`);
|
|
934
|
-
if (main && !files.includes(main) && !files.some((f) => main.startsWith(`${f.replace(/\/$/, "")}/`))) problems.push(`files whitelist is missing the main entry "${main}"`);
|
|
935
|
-
const entryDir = main?.includes("/") ? main.slice(0, main.indexOf("/")) : void 0;
|
|
936
|
-
if (entryDir && (entryDir === "lib" || entryDir === "dist") && !files.includes(entryDir)) problems.push(`files whitelist has no built-artifact directory ("${entryDir}"), but main points into it`);
|
|
937
|
-
if (problems.length > 0) return {
|
|
938
|
-
id: "manifest-files",
|
|
939
|
-
severity: "error",
|
|
940
|
-
kind: "deterministic",
|
|
941
|
-
status: "fail",
|
|
942
|
-
message: "files whitelist incomplete",
|
|
943
|
-
skillRef: ref,
|
|
944
|
-
detail: problems
|
|
945
|
-
};
|
|
946
|
-
return {
|
|
947
|
-
id: "manifest-files",
|
|
948
|
-
severity: "error",
|
|
949
|
-
kind: "deterministic",
|
|
950
|
-
status: "pass",
|
|
951
|
-
message: "files whitelist includes patch, entry, and built artifacts",
|
|
952
|
-
skillRef: ref
|
|
953
|
-
};
|
|
954
|
-
}
|
|
955
|
-
function checkManifestPackageManager(_root, pkg) {
|
|
956
|
-
const ref = skillRefFor("manifest-package-manager");
|
|
957
|
-
const pm = pkg?.packageManager;
|
|
958
|
-
if (pm === "pnpm@11.7.0") return {
|
|
959
|
-
id: "manifest-package-manager",
|
|
960
|
-
severity: "warning",
|
|
961
|
-
kind: "deterministic",
|
|
962
|
-
status: "pass",
|
|
963
|
-
message: "packageManager pinned to pnpm@11.7.0",
|
|
964
|
-
skillRef: ref
|
|
965
|
-
};
|
|
966
|
-
if (pm) return {
|
|
967
|
-
id: "manifest-package-manager",
|
|
968
|
-
severity: "warning",
|
|
969
|
-
kind: "deterministic",
|
|
970
|
-
status: "warn",
|
|
971
|
-
message: `packageManager is "${pm}"; the family standard is pnpm@11.7.0`,
|
|
972
|
-
skillRef: ref
|
|
973
|
-
};
|
|
974
|
-
return {
|
|
975
|
-
id: "manifest-package-manager",
|
|
976
|
-
severity: "warning",
|
|
977
|
-
kind: "deterministic",
|
|
978
|
-
status: "warn",
|
|
979
|
-
message: "packageManager not pinned; add \"pnpm@11.7.0\" for reproducible installs",
|
|
980
|
-
skillRef: ref
|
|
981
|
-
};
|
|
982
|
-
}
|
|
983
|
-
/**
|
|
984
|
-
* Plugin Manager and Settings read display text and an icon without activating
|
|
985
|
-
* the plugin, so a package that runs but ships no metadata still looks broken to
|
|
986
|
-
* users. Passing this check is a packaging requirement, not a runtime feature.
|
|
987
|
-
*/
|
|
988
|
-
function checkDisplayMeta(root, pkg) {
|
|
989
|
-
const ref = skillRefFor("display-meta");
|
|
990
|
-
const problems = [];
|
|
991
|
-
const notes = [];
|
|
992
|
-
const localeExport = Object.keys(pkg?.exports ?? {}).find((key) => key.includes("locale"));
|
|
993
|
-
if (!localeExport) problems.push("no locale export; add { \"./locale/*.json\": \"./locale/*.json\" } and a locale file with meta.title/meta.description");
|
|
994
|
-
else {
|
|
995
|
-
const localeDir = join(root, "locale");
|
|
996
|
-
if (!isDirectory(localeDir)) problems.push(`exports "${localeExport}" but the locale/ directory is missing`);
|
|
997
|
-
else {
|
|
998
|
-
const files = readdirSync(localeDir).filter((f) => f.endsWith(".json"));
|
|
999
|
-
if (files.length === 0) problems.push("locale/ holds no .json files");
|
|
1000
|
-
if (!files.find((f) => f === "en.json")) problems.push("locale/en.json is missing (English is the required fallback)");
|
|
1001
|
-
for (const file of files.filter((f) => f === "en.json")) {
|
|
1002
|
-
const meta = readJsonIfExists(join(localeDir, file));
|
|
1003
|
-
const title = typeof meta?.meta?.title === "string" ? meta.meta.title.trim() : "";
|
|
1004
|
-
const description = typeof meta?.meta?.description === "string" ? meta.meta.description.trim() : "";
|
|
1005
|
-
if (title === "") problems.push(`locale/${file} has no meta.title`);
|
|
1006
|
-
if (description === "") problems.push(`locale/${file} has no meta.description`);
|
|
1007
|
-
}
|
|
1008
|
-
if (files.length === 1) notes.push("only locale/en.json present; add the user-facing languages too");
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
const manifestIcon = typeof pkg?.icon === "string" && pkg.icon !== "" ? pkg.icon : void 0;
|
|
1012
|
-
const iconExport = Object.keys(pkg?.exports ?? {}).find((key) => key === "./icon" || key.endsWith("/icon"));
|
|
1013
|
-
if (!manifestIcon && !iconExport) problems.push("no icon; publish an exported \"./icon\" (or a top-level package.json \"icon\")");
|
|
1014
|
-
if (manifestIcon) {
|
|
1015
|
-
const iconPath = resolve(root, manifestIcon);
|
|
1016
|
-
if (!isFile(iconPath)) problems.push(`package.json icon points at a missing file: ${manifestIcon}`);
|
|
1017
|
-
else {
|
|
1018
|
-
if (!ICON_EXTENSIONS.some((ext) => iconPath.toLowerCase().endsWith(ext))) problems.push(`icon must be SVG, PNG, JPEG or WebP: ${manifestIcon}`);
|
|
1019
|
-
const size = statSync(iconPath).size;
|
|
1020
|
-
if (size > ICON_MAX_BYTES) problems.push(`icon exceeds 256 KiB (${size} bytes): ${manifestIcon}`);
|
|
1021
|
-
if (size === 0) problems.push(`icon file is empty: ${manifestIcon}`);
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
if (iconExport && !manifestIcon) {
|
|
1025
|
-
const target = pkg?.exports?.[iconExport];
|
|
1026
|
-
if (typeof target === "string" && target !== "" && !ICON_EXTENSIONS.some((ext) => target.toLowerCase().endsWith(ext))) problems.push(`exported ${iconExport} must resolve to SVG, PNG, JPEG or WebP (got ${target})`);
|
|
1027
|
-
}
|
|
1028
|
-
if (problems.length > 0) return {
|
|
1029
|
-
id: "display-meta",
|
|
1030
|
-
severity: "warning",
|
|
1031
|
-
kind: "deterministic",
|
|
1032
|
-
status: "warn",
|
|
1033
|
-
message: "display metadata incomplete (Plugin Manager shows the raw id and default artwork)",
|
|
1034
|
-
skillRef: ref,
|
|
1035
|
-
detail: [...problems, ...notes]
|
|
1036
|
-
};
|
|
1037
|
-
return {
|
|
1038
|
-
id: "display-meta",
|
|
1039
|
-
severity: "warning",
|
|
1040
|
-
kind: "deterministic",
|
|
1041
|
-
status: "pass",
|
|
1042
|
-
message: "display metadata present (locale meta + exported icon)",
|
|
1043
|
-
skillRef: ref,
|
|
1044
|
-
...notes.length > 0 ? { detail: notes } : {}
|
|
1045
|
-
};
|
|
1046
|
-
}
|
|
1047
|
-
/** True when the path exists and is a directory. */
|
|
1048
|
-
function isDirectory(path) {
|
|
1049
|
-
try {
|
|
1050
|
-
return statSync(path).isDirectory();
|
|
1051
|
-
} catch {
|
|
1052
|
-
return false;
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
function checkReadmeFiveLangs(root) {
|
|
1056
|
-
const ref = skillRefFor("readme-five-langs");
|
|
1057
|
-
const missing = [];
|
|
1058
|
-
for (const lang of README_LANGS) {
|
|
1059
|
-
const path = join(root, lang);
|
|
1060
|
-
if (!isFile(path)) missing.push(lang);
|
|
1061
|
-
else if ((readText(path) ?? "").trim() === "") missing.push(`${lang} (empty)`);
|
|
1062
|
-
}
|
|
1063
|
-
const missingEn = missing.includes("README.md");
|
|
1064
|
-
const missingOthers = missing.filter((m) => m !== "README.md");
|
|
1065
|
-
if (missingEn) return {
|
|
1066
|
-
id: "readme-five-langs",
|
|
1067
|
-
severity: "error",
|
|
1068
|
-
kind: "deterministic",
|
|
1069
|
-
status: "fail",
|
|
1070
|
-
message: "README.md (English source) is missing",
|
|
1071
|
-
skillRef: ref,
|
|
1072
|
-
detail: missing
|
|
1073
|
-
};
|
|
1074
|
-
if (missingOthers.length > 0) return {
|
|
1075
|
-
id: "readme-five-langs",
|
|
1076
|
-
severity: "warning",
|
|
1077
|
-
kind: "deterministic",
|
|
1078
|
-
status: "warn",
|
|
1079
|
-
message: "five-language README incomplete",
|
|
1080
|
-
skillRef: ref,
|
|
1081
|
-
detail: missingOthers
|
|
1082
|
-
};
|
|
1083
|
-
return {
|
|
1084
|
-
id: "readme-five-langs",
|
|
1085
|
-
severity: "error",
|
|
1086
|
-
kind: "deterministic",
|
|
1087
|
-
status: "pass",
|
|
1088
|
-
message: "all five README languages present",
|
|
1089
|
-
skillRef: ref
|
|
1090
|
-
};
|
|
1091
|
-
}
|
|
1092
|
-
function headingsOf(text) {
|
|
1093
|
-
return text.split(/\r?\n/).filter((line) => line.startsWith("## ")).map((line) => line.slice(3).trim());
|
|
1094
|
-
}
|
|
1095
|
-
function checkReadmeConsistency(root) {
|
|
1096
|
-
const ref = skillRefFor("readme-consistency");
|
|
1097
|
-
const existing = README_LANGS.filter((lang) => isFile(join(root, lang)));
|
|
1098
|
-
if (existing.length < 2) return {
|
|
1099
|
-
id: "readme-consistency",
|
|
1100
|
-
severity: "warning",
|
|
1101
|
-
kind: "deterministic",
|
|
1102
|
-
status: "skip",
|
|
1103
|
-
message: "fewer than two READMEs; nothing to compare",
|
|
1104
|
-
skillRef: ref
|
|
1105
|
-
};
|
|
1106
|
-
const base = headingsOf(readText(join(root, "README.md")) ?? "");
|
|
1107
|
-
const mismatches = [];
|
|
1108
|
-
for (const lang of existing.slice(1)) {
|
|
1109
|
-
const headings = headingsOf(readText(join(root, lang)) ?? "");
|
|
1110
|
-
const missing = base.filter((h) => !headings.includes(h));
|
|
1111
|
-
if (missing.length > 0) mismatches.push(`${lang} is missing headings: ${missing.join(", ")}`);
|
|
1112
|
-
}
|
|
1113
|
-
if (mismatches.length > 0) return {
|
|
1114
|
-
id: "readme-consistency",
|
|
1115
|
-
severity: "warning",
|
|
1116
|
-
kind: "deterministic",
|
|
1117
|
-
status: "warn",
|
|
1118
|
-
message: "README headings drifted across languages",
|
|
1119
|
-
skillRef: ref,
|
|
1120
|
-
detail: mismatches
|
|
1121
|
-
};
|
|
1122
|
-
return {
|
|
1123
|
-
id: "readme-consistency",
|
|
1124
|
-
severity: "warning",
|
|
1125
|
-
kind: "deterministic",
|
|
1126
|
-
status: "pass",
|
|
1127
|
-
message: `README headings match across ${existing.length} languages`,
|
|
1128
|
-
skillRef: ref
|
|
1129
|
-
};
|
|
1130
|
-
}
|
|
1131
|
-
/**
|
|
1132
|
-
* Body of SKILL.md after its YAML frontmatter, or undefined when the file is
|
|
1133
|
-
* absent. Falls back to the whole text when there is no well-formed block.
|
|
1134
|
-
*
|
|
1135
|
-
* CRLF tolerance is load-bearing: without `.gitattributes`, a Windows checkout
|
|
1136
|
-
* (`core.autocrlf=true`) delivers CRLF while CI and the published tarball
|
|
1137
|
-
* deliver LF. An exact `startsWith('---\n')` guard therefore failed locally,
|
|
1138
|
-
* leaving the frontmatter in the "body" — so `redline-persona-role` judged the
|
|
1139
|
-
* `name:` line as the opening paragraph and emitted a false warning on every
|
|
1140
|
-
* local run while CI stayed green. Keep this in step with `index.js`.
|
|
1141
|
-
*/
|
|
1142
|
-
function skillBody(root) {
|
|
1143
|
-
const text = readText(join(root, "SKILL.md"));
|
|
1144
|
-
if (!text) return void 0;
|
|
1145
|
-
const open = /^---\r?\n/.exec(text);
|
|
1146
|
-
if (!open) return text;
|
|
1147
|
-
const rest = text.slice(open[0].length);
|
|
1148
|
-
const close = /\r?\n---[ \t]*(?:\r?\n|$)/.exec(rest);
|
|
1149
|
-
if (!close) return text;
|
|
1150
|
-
return rest.slice(close.index + close[0].length).replace(/^(?:[ \t]*\r?\n)+/, "");
|
|
1151
|
-
}
|
|
1152
|
-
function checkRedlinePersonaRole(root) {
|
|
1153
|
-
const ref = skillRefFor("redline-persona-role");
|
|
1154
|
-
const body = skillBody(root);
|
|
1155
|
-
const problems = [];
|
|
1156
|
-
if (body !== void 0) {
|
|
1157
|
-
const firstContentPara = body.split(/\r?\n\s*\r?\n/).find((p) => !/^\s*#/.test(p)) ?? "";
|
|
1158
|
-
const firstLine = firstContentPara.split(/\r?\n/)[0] ?? "";
|
|
1159
|
-
if (!/[.。?!]/.test(firstLine)) problems.push("SKILL.md instruction body does not open with a role sentence");
|
|
1160
|
-
else if (firstLine.length > 200) problems.push("SKILL.md opening role sentence is longer than 200 characters");
|
|
1161
|
-
if (firstContentPara.length > 600) problems.push("SKILL.md first paragraph is a wall of text; keep injected persona paragraphs short");
|
|
1162
|
-
}
|
|
1163
|
-
for (const file of listSourceFiles(root)) {
|
|
1164
|
-
const text = readText(file) ?? "";
|
|
1165
|
-
const re = /systemPrompt\.section\(\s*['"][^'"]*['"]\s*,\s*`([^`]+)`/g;
|
|
1166
|
-
let match;
|
|
1167
|
-
while ((match = re.exec(text)) !== null) if (match[1].length > 400) problems.push(`${relativePath(root, file)}: injected systemPrompt section is a wall of text`);
|
|
1168
|
-
}
|
|
1169
|
-
if (problems.length > 0) return {
|
|
1170
|
-
id: "redline-persona-role",
|
|
1171
|
-
severity: "warning",
|
|
1172
|
-
kind: "heuristic",
|
|
1173
|
-
status: "warn",
|
|
1174
|
-
message: "injected persona/prompt paragraphs should open with a short role sentence",
|
|
1175
|
-
skillRef: ref,
|
|
1176
|
-
detail: problems
|
|
1177
|
-
};
|
|
1178
|
-
if (body === void 0) return {
|
|
1179
|
-
id: "redline-persona-role",
|
|
1180
|
-
severity: "warning",
|
|
1181
|
-
kind: "heuristic",
|
|
1182
|
-
status: "skip",
|
|
1183
|
-
message: "no SKILL.md or systemPrompt section found to inspect",
|
|
1184
|
-
skillRef: ref
|
|
1185
|
-
};
|
|
1186
|
-
return {
|
|
1187
|
-
id: "redline-persona-role",
|
|
1188
|
-
severity: "warning",
|
|
1189
|
-
kind: "heuristic",
|
|
1190
|
-
status: "pass",
|
|
1191
|
-
message: "persona paragraphs open with a short role sentence",
|
|
1192
|
-
skillRef: ref
|
|
1193
|
-
};
|
|
1194
|
-
}
|
|
1195
|
-
function checkRedlineWaterfallNext(root) {
|
|
1196
|
-
const ref = skillRefFor("redline-waterfall-next");
|
|
1197
|
-
const flagged = [];
|
|
1198
|
-
for (const file of listSourceFiles(root)) {
|
|
1199
|
-
const text = readText(file) ?? "";
|
|
1200
|
-
if (!text.includes("waterfall")) continue;
|
|
1201
|
-
if (!text.includes("next")) flagged.push(`${relativePath(root, file)}: mentions waterfall but never calls next()`);
|
|
1202
|
-
}
|
|
1203
|
-
if (flagged.length > 0) return {
|
|
1204
|
-
id: "redline-waterfall-next",
|
|
1205
|
-
severity: "warning",
|
|
1206
|
-
kind: "heuristic",
|
|
1207
|
-
status: "warn",
|
|
1208
|
-
message: "possible waterfall listener missing next()",
|
|
1209
|
-
skillRef: ref,
|
|
1210
|
-
detail: flagged
|
|
1211
|
-
};
|
|
1212
|
-
if (!listSourceFiles(root).some((f) => (readText(f) ?? "").includes("waterfall"))) return {
|
|
1213
|
-
id: "redline-waterfall-next",
|
|
1214
|
-
severity: "warning",
|
|
1215
|
-
kind: "heuristic",
|
|
1216
|
-
status: "skip",
|
|
1217
|
-
message: "no waterfall listeners found",
|
|
1218
|
-
skillRef: ref
|
|
1219
|
-
};
|
|
1220
|
-
return {
|
|
1221
|
-
id: "redline-waterfall-next",
|
|
1222
|
-
severity: "warning",
|
|
1223
|
-
kind: "heuristic",
|
|
1224
|
-
status: "pass",
|
|
1225
|
-
message: "waterfall listeners call next()",
|
|
1226
|
-
skillRef: ref
|
|
1227
|
-
};
|
|
1228
|
-
}
|
|
1229
|
-
function checkRedlineNoHardcodedTunables(root) {
|
|
1230
|
-
const ref = skillRefFor("redline-no-hardcoded-tunables");
|
|
1231
|
-
const files = listSourceFiles(root);
|
|
1232
|
-
const plainObjectConfigs = [];
|
|
1233
|
-
const schemaConfigs = [];
|
|
1234
|
-
for (const file of files) {
|
|
1235
|
-
const text = readText(file) ?? "";
|
|
1236
|
-
if (/export\s+const\s+Config\s*=\s*\{/.test(text)) plainObjectConfigs.push(relativePath(root, file));
|
|
1237
|
-
if (/export\s+const\s+Config\s*=\s*Schema\./.test(text)) schemaConfigs.push(relativePath(root, file));
|
|
1238
|
-
}
|
|
1239
|
-
if (plainObjectConfigs.length > 0) return {
|
|
1240
|
-
id: "redline-no-hardcoded-tunables",
|
|
1241
|
-
severity: "error",
|
|
1242
|
-
kind: "heuristic",
|
|
1243
|
-
status: "fail",
|
|
1244
|
-
message: "Config is a plain object; it must be a Schemastery Schema",
|
|
1245
|
-
skillRef: ref,
|
|
1246
|
-
detail: plainObjectConfigs
|
|
1247
|
-
};
|
|
1248
|
-
if (schemaConfigs.length === 0) return {
|
|
1249
|
-
id: "redline-no-hardcoded-tunables",
|
|
1250
|
-
severity: "warning",
|
|
1251
|
-
kind: "heuristic",
|
|
1252
|
-
status: "skip",
|
|
1253
|
-
message: "no Config schema found to inspect",
|
|
1254
|
-
skillRef: ref
|
|
1255
|
-
};
|
|
1256
|
-
return {
|
|
1257
|
-
id: "redline-no-hardcoded-tunables",
|
|
1258
|
-
severity: "warning",
|
|
1259
|
-
kind: "heuristic",
|
|
1260
|
-
status: "pass",
|
|
1261
|
-
message: `Config uses Schemastery Schema (${schemaConfigs.length} file(s))`,
|
|
1262
|
-
skillRef: ref
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1265
|
-
function checkRedlineEffectRegistration(root) {
|
|
1266
|
-
const ref = skillRefFor("redline-effect-registration");
|
|
1267
|
-
const files = listSourceFiles(root);
|
|
1268
|
-
const manualTeardown = [];
|
|
1269
|
-
for (const file of files) {
|
|
1270
|
-
const text = readText(file) ?? "";
|
|
1271
|
-
if (/removeListener\(|removeAllListeners\(|\.off\(/.test(text)) manualTeardown.push(`${relativePath(root, file)}: manual event-listener teardown detected; registrations must be reversible via ctx.effect()/disposer`);
|
|
1272
|
-
}
|
|
1273
|
-
if (manualTeardown.length > 0) return {
|
|
1274
|
-
id: "redline-effect-registration",
|
|
1275
|
-
severity: "warning",
|
|
1276
|
-
kind: "heuristic",
|
|
1277
|
-
status: "warn",
|
|
1278
|
-
message: "possible non-effect manual teardown",
|
|
1279
|
-
skillRef: ref,
|
|
1280
|
-
detail: manualTeardown
|
|
1281
|
-
};
|
|
1282
|
-
return {
|
|
1283
|
-
id: "redline-effect-registration",
|
|
1284
|
-
severity: "warning",
|
|
1285
|
-
kind: "heuristic",
|
|
1286
|
-
status: "pass",
|
|
1287
|
-
message: "no manual teardown patterns detected",
|
|
1288
|
-
skillRef: ref
|
|
1289
|
-
};
|
|
1290
|
-
}
|
|
1291
|
-
/** Registration idioms that must never run after the first `await` of an async apply. */
|
|
1292
|
-
const ASYNC_APPLY_REGISTRATION = [
|
|
1293
|
-
["ctx.effect", /\bctx\.effect\s*\(/],
|
|
1294
|
-
["ctx.on", /\bctx\.on\s*\(/],
|
|
1295
|
-
["ctx.provide", /\bctx\.provide\s*\(/],
|
|
1296
|
-
["ctx.plugin", /\bctx\.plugin\s*\(/],
|
|
1297
|
-
["register()", /\.register\s*\(/]
|
|
1298
|
-
];
|
|
1299
|
-
/** Braces of the block whose `{` is at `openIdx`, skipping strings and comments. Returns the inner body or undefined. */
|
|
1300
|
-
function blockBody(text, openIdx) {
|
|
1301
|
-
let depth = 0;
|
|
1302
|
-
let quote = null;
|
|
1303
|
-
let lineComment = false;
|
|
1304
|
-
let blockComment = false;
|
|
1305
|
-
for (let i = openIdx; i < text.length; i++) {
|
|
1306
|
-
const ch = text[i];
|
|
1307
|
-
const next = text[i + 1];
|
|
1308
|
-
if (lineComment) {
|
|
1309
|
-
if (ch === "\n") lineComment = false;
|
|
1310
|
-
continue;
|
|
1311
|
-
}
|
|
1312
|
-
if (blockComment) {
|
|
1313
|
-
if (ch === "*" && next === "/") {
|
|
1314
|
-
blockComment = false;
|
|
1315
|
-
i++;
|
|
1316
|
-
}
|
|
1317
|
-
continue;
|
|
1318
|
-
}
|
|
1319
|
-
if (quote) {
|
|
1320
|
-
if (ch === "\\") {
|
|
1321
|
-
i++;
|
|
1322
|
-
continue;
|
|
1323
|
-
}
|
|
1324
|
-
if (ch === quote) quote = null;
|
|
1325
|
-
continue;
|
|
1326
|
-
}
|
|
1327
|
-
if (ch === "/" && next === "/") {
|
|
1328
|
-
lineComment = true;
|
|
1329
|
-
i++;
|
|
1330
|
-
continue;
|
|
1331
|
-
}
|
|
1332
|
-
if (ch === "/" && next === "*") {
|
|
1333
|
-
blockComment = true;
|
|
1334
|
-
i++;
|
|
1335
|
-
continue;
|
|
1336
|
-
}
|
|
1337
|
-
if (ch === "\"" || ch === "'" || ch === "`") {
|
|
1338
|
-
quote = ch;
|
|
1339
|
-
continue;
|
|
1340
|
-
}
|
|
1341
|
-
if (ch === "{") depth++;
|
|
1342
|
-
else if (ch === "}") {
|
|
1343
|
-
depth--;
|
|
1344
|
-
if (depth === 0) return text.slice(openIdx + 1, i);
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1348
|
-
/** Index just past the first top-level (brace-depth 0) `await` keyword, or -1. */
|
|
1349
|
-
function firstTopLevelAwait(body) {
|
|
1350
|
-
let depth = 0;
|
|
1351
|
-
let quote = null;
|
|
1352
|
-
let lineComment = false;
|
|
1353
|
-
let blockComment = false;
|
|
1354
|
-
for (let i = 0; i < body.length - 5; i++) {
|
|
1355
|
-
const ch = body[i];
|
|
1356
|
-
const next = body[i + 1];
|
|
1357
|
-
if (lineComment) {
|
|
1358
|
-
if (ch === "\n") lineComment = false;
|
|
1359
|
-
continue;
|
|
1360
|
-
}
|
|
1361
|
-
if (blockComment) {
|
|
1362
|
-
if (ch === "*" && next === "/") {
|
|
1363
|
-
blockComment = false;
|
|
1364
|
-
i++;
|
|
1365
|
-
}
|
|
1366
|
-
continue;
|
|
1367
|
-
}
|
|
1368
|
-
if (quote) {
|
|
1369
|
-
if (ch === "\\") {
|
|
1370
|
-
i++;
|
|
1371
|
-
continue;
|
|
1372
|
-
}
|
|
1373
|
-
if (ch === quote) quote = null;
|
|
1374
|
-
continue;
|
|
1375
|
-
}
|
|
1376
|
-
if (ch === "/" && next === "/") {
|
|
1377
|
-
lineComment = true;
|
|
1378
|
-
i++;
|
|
1379
|
-
continue;
|
|
1380
|
-
}
|
|
1381
|
-
if (ch === "/" && next === "*") {
|
|
1382
|
-
blockComment = true;
|
|
1383
|
-
i++;
|
|
1384
|
-
continue;
|
|
1385
|
-
}
|
|
1386
|
-
if (ch === "\"" || ch === "'" || ch === "`") {
|
|
1387
|
-
quote = ch;
|
|
1388
|
-
continue;
|
|
1389
|
-
}
|
|
1390
|
-
if (ch === "{") depth++;
|
|
1391
|
-
else if (ch === "}") depth--;
|
|
1392
|
-
else if (depth === 0 && ch === "a" && body.startsWith("await", i)) {
|
|
1393
|
-
const before = i === 0 ? "" : body[i - 1];
|
|
1394
|
-
const after = body[i + 5] ?? "";
|
|
1395
|
-
if (!/[A-Za-z0-9_$]/.test(before) && !/[A-Za-z0-9_$]/.test(after)) return i + 5;
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
return -1;
|
|
1399
|
-
}
|
|
1400
|
-
/** First top-level registration idiom after `fromIdx` (nested function bodies excluded), or undefined. */
|
|
1401
|
-
function registrationAfter(body, fromIdx) {
|
|
1402
|
-
let depth = 0;
|
|
1403
|
-
let quote = null;
|
|
1404
|
-
let lineComment = false;
|
|
1405
|
-
let blockComment = false;
|
|
1406
|
-
for (let i = fromIdx; i < body.length; i++) {
|
|
1407
|
-
const ch = body[i];
|
|
1408
|
-
const next = body[i + 1];
|
|
1409
|
-
if (lineComment) {
|
|
1410
|
-
if (ch === "\n") lineComment = false;
|
|
1411
|
-
continue;
|
|
1412
|
-
}
|
|
1413
|
-
if (blockComment) {
|
|
1414
|
-
if (ch === "*" && next === "/") {
|
|
1415
|
-
blockComment = false;
|
|
1416
|
-
i++;
|
|
1417
|
-
}
|
|
1418
|
-
continue;
|
|
1419
|
-
}
|
|
1420
|
-
if (quote) {
|
|
1421
|
-
if (ch === "\\") {
|
|
1422
|
-
i++;
|
|
1423
|
-
continue;
|
|
1424
|
-
}
|
|
1425
|
-
if (ch === quote) quote = null;
|
|
1426
|
-
continue;
|
|
1427
|
-
}
|
|
1428
|
-
if (ch === "/" && next === "/") {
|
|
1429
|
-
lineComment = true;
|
|
1430
|
-
i++;
|
|
1431
|
-
continue;
|
|
1432
|
-
}
|
|
1433
|
-
if (ch === "/" && next === "*") {
|
|
1434
|
-
blockComment = true;
|
|
1435
|
-
i++;
|
|
1436
|
-
continue;
|
|
1437
|
-
}
|
|
1438
|
-
if (ch === "\"" || ch === "'" || ch === "`") {
|
|
1439
|
-
quote = ch;
|
|
1440
|
-
continue;
|
|
1441
|
-
}
|
|
1442
|
-
if (ch === "{") depth++;
|
|
1443
|
-
else if (ch === "}") {
|
|
1444
|
-
if (depth === 0) break;
|
|
1445
|
-
depth--;
|
|
1446
|
-
continue;
|
|
1447
|
-
}
|
|
1448
|
-
if (depth !== 0) continue;
|
|
1449
|
-
for (const [kind, re] of ASYNC_APPLY_REGISTRATION) {
|
|
1450
|
-
const m = re.exec(body.slice(i));
|
|
1451
|
-
if (m) return [kind, body.slice(i, i + Math.min(m[0].length, 40))];
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
function checkRedlineAsyncApplyRegistration(root) {
|
|
1456
|
-
const ref = skillRefFor("redline-async-apply-registration");
|
|
1457
|
-
const files = listSourceFiles(root);
|
|
1458
|
-
const flagged = [];
|
|
1459
|
-
for (const file of files) {
|
|
1460
|
-
const text = readText(file) ?? "";
|
|
1461
|
-
const re = /export\s+async\s+function\s+apply\s*\(/g;
|
|
1462
|
-
let match;
|
|
1463
|
-
while ((match = re.exec(text)) !== null) {
|
|
1464
|
-
const bodyStart = text.indexOf("{", match.index);
|
|
1465
|
-
if (bodyStart < 0) continue;
|
|
1466
|
-
const body = blockBody(text, bodyStart);
|
|
1467
|
-
if (body === void 0) continue;
|
|
1468
|
-
const awaitIdx = firstTopLevelAwait(body);
|
|
1469
|
-
if (awaitIdx < 0) continue;
|
|
1470
|
-
const hit = registrationAfter(body, awaitIdx);
|
|
1471
|
-
if (hit) flagged.push(`${relativePath(root, file)}: async apply calls ${hit[0]} (${hit[1]}) after its first await — registration belongs in ctx.effect()/ctx.on() or before any await`);
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
if (flagged.length > 0) return {
|
|
1475
|
-
id: "redline-async-apply-registration",
|
|
1476
|
-
severity: "error",
|
|
1477
|
-
kind: "heuristic",
|
|
1478
|
-
status: "fail",
|
|
1479
|
-
message: "async apply registers after its first await (unload-window race)",
|
|
1480
|
-
skillRef: ref,
|
|
1481
|
-
detail: flagged
|
|
1482
|
-
};
|
|
1483
|
-
if (!files.some((f) => /export\s+async\s+function\s+apply\s*\(/.test(readText(f) ?? ""))) return {
|
|
1484
|
-
id: "redline-async-apply-registration",
|
|
1485
|
-
severity: "error",
|
|
1486
|
-
kind: "heuristic",
|
|
1487
|
-
status: "skip",
|
|
1488
|
-
message: "no async apply function found to inspect",
|
|
1489
|
-
skillRef: ref
|
|
1490
|
-
};
|
|
1491
|
-
return {
|
|
1492
|
-
id: "redline-async-apply-registration",
|
|
1493
|
-
severity: "error",
|
|
1494
|
-
kind: "heuristic",
|
|
1495
|
-
status: "pass",
|
|
1496
|
-
message: "no registration after the first await of any async apply",
|
|
1497
|
-
skillRef: ref
|
|
1498
|
-
};
|
|
1499
|
-
}
|
|
1500
|
-
function relativePath(root, file) {
|
|
1501
|
-
return file.replace(root.replace(/[\\/]$/, ""), "").replace(/^[\\/]/, "");
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
//#endregion
|
|
1505
|
-
//#region src/cli/lib/subprocess.ts
|
|
1506
|
-
/**
|
|
1507
|
-
* Run a command and capture its output. Uses piped stdio so callers can read
|
|
1508
|
-
* logs; the process is terminated on timeout or external abort.
|
|
1509
|
-
* @param command - executable name or path.
|
|
1510
|
-
* @param args - argument vector.
|
|
1511
|
-
* @param options - cwd, env, timeout, and abort signal.
|
|
1512
|
-
* @returns the exit code, captured streams, and timeout flag.
|
|
1513
|
-
*/
|
|
1514
|
-
function run(command, args, options = {}) {
|
|
1515
|
-
return new Promise((resolve) => {
|
|
1516
|
-
const controller = new AbortController();
|
|
1517
|
-
let timedOut = false;
|
|
1518
|
-
let settled = false;
|
|
1519
|
-
const finish = (result) => {
|
|
1520
|
-
if (settled) return;
|
|
1521
|
-
settled = true;
|
|
1522
|
-
clearTimeout(timer);
|
|
1523
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
1524
|
-
resolve(result);
|
|
1525
|
-
};
|
|
1526
|
-
const timer = options.timeoutMs ? setTimeout(() => {
|
|
1527
|
-
timedOut = true;
|
|
1528
|
-
controller.abort(/* @__PURE__ */ new Error(`command timed out after ${options.timeoutMs}ms`));
|
|
1529
|
-
}, options.timeoutMs) : void 0;
|
|
1530
|
-
const onAbort = () => controller.abort();
|
|
1531
|
-
options.signal?.addEventListener("abort", onAbort);
|
|
1532
|
-
const env = { ...process.env };
|
|
1533
|
-
for (const [key, value] of Object.entries(options.env ?? {})) if (value === void 0) delete env[key];
|
|
1534
|
-
else env[key] = value;
|
|
1535
|
-
const child = spawnCommand(command, args, {
|
|
1536
|
-
cwd: options.cwd,
|
|
1537
|
-
env,
|
|
1538
|
-
signal: controller.signal
|
|
1539
|
-
});
|
|
1540
|
-
let stdout = "";
|
|
1541
|
-
let stderr = "";
|
|
1542
|
-
child.stdout?.setEncoding("utf8");
|
|
1543
|
-
child.stderr?.setEncoding("utf8");
|
|
1544
|
-
child.stdout?.on("data", (chunk) => {
|
|
1545
|
-
stdout += chunk;
|
|
1546
|
-
});
|
|
1547
|
-
child.stderr?.on("data", (chunk) => {
|
|
1548
|
-
stderr += chunk;
|
|
1549
|
-
});
|
|
1550
|
-
child.on("error", (err) => {
|
|
1551
|
-
finish({
|
|
1552
|
-
code: null,
|
|
1553
|
-
stdout,
|
|
1554
|
-
stderr: `${stderr}\n${err.message}`,
|
|
1555
|
-
timedOut,
|
|
1556
|
-
signal: null
|
|
1557
|
-
});
|
|
1558
|
-
});
|
|
1559
|
-
child.on("close", (code, signal) => {
|
|
1560
|
-
finish({
|
|
1561
|
-
code,
|
|
1562
|
-
stdout,
|
|
1563
|
-
stderr,
|
|
1564
|
-
timedOut,
|
|
1565
|
-
signal
|
|
1566
|
-
});
|
|
1567
|
-
});
|
|
1568
|
-
});
|
|
1569
|
-
}
|
|
1570
|
-
function spawnCommand(command, args, options) {
|
|
1571
|
-
if (process.platform === "win32") return spawn(winCommandLine(command, args), {
|
|
1572
|
-
cwd: options.cwd,
|
|
1573
|
-
env: options.env,
|
|
1574
|
-
stdio: [
|
|
1575
|
-
"ignore",
|
|
1576
|
-
"pipe",
|
|
1577
|
-
"pipe"
|
|
1578
|
-
],
|
|
1579
|
-
signal: options.signal,
|
|
1580
|
-
shell: true,
|
|
1581
|
-
windowsHide: true
|
|
1582
|
-
});
|
|
1583
|
-
return spawn(command, args, {
|
|
1584
|
-
cwd: options.cwd,
|
|
1585
|
-
env: options.env,
|
|
1586
|
-
stdio: [
|
|
1587
|
-
"ignore",
|
|
1588
|
-
"pipe",
|
|
1589
|
-
"pipe"
|
|
1590
|
-
],
|
|
1591
|
-
signal: options.signal
|
|
1592
|
-
});
|
|
1593
|
-
}
|
|
1594
|
-
function winCommandLine(command, args) {
|
|
1595
|
-
return [command, ...args].map(quoteWin).join(" ");
|
|
1596
|
-
}
|
|
1597
|
-
function quoteWin(arg) {
|
|
1598
|
-
if (!/[\s"&|<>^()]/.test(arg)) return arg;
|
|
1599
|
-
return `"${arg.replace(/(["\\])/g, "\\$1")}"`;
|
|
1600
|
-
}
|
|
1601
|
-
/** Format a run result's streams into a short tail for failure reports. */
|
|
1602
|
-
function tailOf(result, lines = 40) {
|
|
1603
|
-
return `${result.stdout}\n${result.stderr}`.trim().split(/\r?\n/).slice(-lines).join("\n");
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
|
-
//#endregion
|
|
1607
|
-
//#region src/cli/commands/new.ts
|
|
1608
|
-
const NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
1609
|
-
/** Normalize and validate a user-supplied plugin name. */
|
|
1610
|
-
function normalizeName(raw) {
|
|
1611
|
-
let name = raw.trim();
|
|
1612
|
-
if (name.startsWith("@")) {
|
|
1613
|
-
const slash = name.indexOf("/");
|
|
1614
|
-
if (slash >= 0) name = name.slice(slash + 1);
|
|
1615
|
-
}
|
|
1616
|
-
if (name.startsWith("dsh-")) name = name.slice(4);
|
|
1617
|
-
if (!NAME_RE.test(name)) throw new Error(`invalid plugin name "${raw}": use lowercase letters, digits, and hyphens (e.g. hello-plugin)`);
|
|
1618
|
-
return {
|
|
1619
|
-
name,
|
|
1620
|
-
pkgName: `dsh-${name}`
|
|
1621
|
-
};
|
|
1622
|
-
}
|
|
1623
|
-
/** True when the directory exists and contains any entry. */
|
|
1624
|
-
function dirNonEmpty(dir) {
|
|
1625
|
-
if (!isDir(dir)) return false;
|
|
1626
|
-
return readdirSync(dir).length > 0;
|
|
1627
|
-
}
|
|
1628
|
-
/**
|
|
1629
|
-
* Run the scaffolder. Returns the target directory path.
|
|
1630
|
-
* @param cwd - current working directory.
|
|
1631
|
-
* @param options - name, language, target dir, force, and git flags.
|
|
1632
|
-
*/
|
|
1633
|
-
async function runNew(cwd, options) {
|
|
1634
|
-
const { name, pkgName } = normalizeName(options.name);
|
|
1635
|
-
const targetDir = resolve(options.dir ?? join(cwd, name));
|
|
1636
|
-
if (dirNonEmpty(targetDir) && !options.force) throw new Error(`target directory already exists and is not empty: ${targetDir} (use --force to overwrite template files)`);
|
|
1637
|
-
const year = String((/* @__PURE__ */ new Date()).getFullYear());
|
|
1638
|
-
const files = renderScaffold(options.lang, {
|
|
1639
|
-
name,
|
|
1640
|
-
pkgName,
|
|
1641
|
-
version: "0.1.0",
|
|
1642
|
-
year
|
|
1643
|
-
});
|
|
1644
|
-
writeScaffold(targetDir, files);
|
|
1645
|
-
if (options.git) await initGit(targetDir);
|
|
1646
|
-
return {
|
|
1647
|
-
targetDir,
|
|
1648
|
-
files: files.length
|
|
1649
|
-
};
|
|
1650
|
-
}
|
|
1651
|
-
async function initGit(targetDir) {
|
|
1652
|
-
await run("git", ["init"], {
|
|
1653
|
-
cwd: targetDir,
|
|
1654
|
-
timeoutMs: 3e4
|
|
1655
|
-
});
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
|
-
//#endregion
|
|
1659
|
-
//#region src/cli/lib/seams.ts
|
|
1660
|
-
/** Resolve the index path, tolerating the source tree and the bundled dist. */
|
|
1661
|
-
function resolveSeamIndexPath() {
|
|
1662
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
1663
|
-
const candidates = [
|
|
1664
|
-
join(here, "..", "..", "..", "data", "seams", "index.json"),
|
|
1665
|
-
join(here, "..", "..", "data", "seams", "index.json"),
|
|
1666
|
-
join(here, "..", "data", "seams", "index.json"),
|
|
1667
|
-
join(here, "data", "seams", "index.json")
|
|
1668
|
-
];
|
|
1669
|
-
for (const c of candidates) try {
|
|
1670
|
-
readFileSync(c);
|
|
1671
|
-
return c;
|
|
1672
|
-
} catch {}
|
|
1673
|
-
throw new Error("seam index not found; expected data/seams/index.json next to the package root");
|
|
1674
|
-
}
|
|
1675
|
-
/** Load and parse the seam index. */
|
|
1676
|
-
function loadSeamIndex(path = resolveSeamIndexPath()) {
|
|
1677
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
1678
|
-
}
|
|
1679
|
-
/**
|
|
1680
|
-
* Look up a seam or capability by id, area, or a free-text substring.
|
|
1681
|
-
*
|
|
1682
|
-
* @param index - parsed seam index.
|
|
1683
|
-
* @param query - id (`L3`, `A20`), area substring, or any word in a title.
|
|
1684
|
-
* @returns matches, or `state: 'unknown'` with a reason when nothing matches.
|
|
1685
|
-
*/
|
|
1686
|
-
function lookupSeam(index, query) {
|
|
1687
|
-
const q = query.trim().toLowerCase();
|
|
1688
|
-
const exactSeam = index.seams.filter((s) => s.id.toLowerCase() === q);
|
|
1689
|
-
const exactCap = index.capabilities.filter((c) => c.id.toLowerCase() === q);
|
|
1690
|
-
if (exactSeam.length || exactCap.length) return {
|
|
1691
|
-
query,
|
|
1692
|
-
state: "found",
|
|
1693
|
-
seams: exactSeam,
|
|
1694
|
-
capabilities: exactCap
|
|
1695
|
-
};
|
|
1696
|
-
const seams = index.seams.filter((s) => s.title.toLowerCase().includes(q) || s.kind.toLowerCase().includes(q) || s.target.toLowerCase().includes(q) || s.removed.some((r) => r.toLowerCase().includes(q)) || (s.ids ?? []).some((i) => i.toLowerCase().includes(q)));
|
|
1697
|
-
const capabilities = index.capabilities.filter((c) => c.area.toLowerCase().includes(q) || c.introducedIn.toLowerCase().includes(q));
|
|
1698
|
-
if (!seams.length && !capabilities.length) return {
|
|
1699
|
-
query,
|
|
1700
|
-
state: "unknown",
|
|
1701
|
-
seams: [],
|
|
1702
|
-
capabilities: [],
|
|
1703
|
-
reason: `no seam or capability matches "${query}". This is an absence of evidence in the knowledge base, not evidence that the API is absent from your target host — check references/official-docs/ before concluding either way.`
|
|
1704
|
-
};
|
|
1705
|
-
return {
|
|
1706
|
-
query,
|
|
1707
|
-
state: "found",
|
|
1708
|
-
seams,
|
|
1709
|
-
capabilities
|
|
1710
|
-
};
|
|
1711
|
-
}
|
|
1712
|
-
/** Total order over DSH version strings. */
|
|
1713
|
-
function rank(v) {
|
|
1714
|
-
const m = /^(?:dsh-v)?(\d+)\.(\d+)\.(\d+)(?:-([a-z]+)(?:\.(\d+))?)?$/i.exec(v.trim());
|
|
1715
|
-
if (!m) return [
|
|
1716
|
-
NaN,
|
|
1717
|
-
0,
|
|
1718
|
-
0,
|
|
1719
|
-
0,
|
|
1720
|
-
0
|
|
1721
|
-
];
|
|
1722
|
-
const channel = m[4] === "alpha" ? 1 : m[4] === "rc" ? 2 : m[4] === void 0 ? 3 : 0;
|
|
1723
|
-
return [
|
|
1724
|
-
Number(m[1]),
|
|
1725
|
-
Number(m[2]),
|
|
1726
|
-
Number(m[3]),
|
|
1727
|
-
channel,
|
|
1728
|
-
Number(m[5] ?? 0)
|
|
1729
|
-
];
|
|
1730
|
-
}
|
|
1731
|
-
/** Compare two ranks; a NaN on either side compares as "unknown", never "after". */
|
|
1732
|
-
function cmp(a, b) {
|
|
1733
|
-
if (Number.isNaN(a[0]) || Number.isNaN(b[0])) return NaN;
|
|
1734
|
-
for (let i = 0; i < 5; i++) if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;
|
|
1735
|
-
return 0;
|
|
1736
|
-
}
|
|
1737
|
-
/**
|
|
1738
|
-
* Every recorded change that lands AFTER the given target version.
|
|
1739
|
-
*
|
|
1740
|
-
* A target this build cannot parse yields an empty list rather than everything:
|
|
1741
|
-
* reporting the whole index for an unparseable query would read as "all of this
|
|
1742
|
-
* changed for you", which is worse than reporting nothing.
|
|
1743
|
-
*
|
|
1744
|
-
* @param index - parsed seam index.
|
|
1745
|
-
* @param target - the version the plugin targets.
|
|
1746
|
-
* @returns matching seam records.
|
|
1747
|
-
*/
|
|
1748
|
-
function seamsAfter(index, target) {
|
|
1749
|
-
const want = rank(target);
|
|
1750
|
-
if (Number.isNaN(want[0])) return [];
|
|
1751
|
-
return index.seams.filter((s) => {
|
|
1752
|
-
const got = cmp(rank(s.target.replace(/^(?:removed|retired) in /, "")), want);
|
|
1753
|
-
return !Number.isNaN(got) && got > 0;
|
|
1754
|
-
});
|
|
1755
|
-
}
|
|
1756
|
-
|
|
1757
|
-
//#endregion
|
|
1758
|
-
//#region src/cli/commands/seams.ts
|
|
1759
|
-
/** Render one seam record as human-readable text. */
|
|
1760
|
-
function renderSeam(s, out) {
|
|
1761
|
-
out.push(`${s.id} ${s.title}`);
|
|
1762
|
-
out.push(` kind ${s.kind}`);
|
|
1763
|
-
out.push(` lands in ${s.target}`);
|
|
1764
|
-
out.push(` confidence ${s.confidence}${s.inferredFrom ? ` (${s.inferredFrom})` : ""}`);
|
|
1765
|
-
out.push(` official ${s.doc}`);
|
|
1766
|
-
if (s.removed.length) out.push(` removed ${s.removed.join("; ")}`);
|
|
1767
|
-
out.push(` instead ${s.replacement}`);
|
|
1768
|
-
out.push(s.detectable ? ` detectable yes — inspect: ${s.targets.join(", ")}` : ` detectable NO — ${s.undetectableReason ?? "no reason recorded"}`);
|
|
1769
|
-
out.push("");
|
|
1770
|
-
}
|
|
1771
|
-
/** Render one capability record. */
|
|
1772
|
-
function renderCapability(c, out) {
|
|
1773
|
-
out.push(`${c.id} ${c.area}`);
|
|
1774
|
-
out.push(` introduced ${c.introducedIn}`);
|
|
1775
|
-
out.push(` anchor ${c.anchor}`);
|
|
1776
|
-
out.push(` confidence ${c.confidence}${c.inferredFrom ? ` (${c.inferredFrom})` : ""}`);
|
|
1777
|
-
out.push("");
|
|
1778
|
-
}
|
|
1779
|
-
/**
|
|
1780
|
-
* Run the seams command.
|
|
1781
|
-
*
|
|
1782
|
-
* @param index - parsed seam index.
|
|
1783
|
-
* @param options - query, since, json.
|
|
1784
|
-
* @returns exit code: 0 when answered, 2 for a usage problem, 3 for unknown.
|
|
1785
|
-
*/
|
|
1786
|
-
function runSeams(index, options) {
|
|
1787
|
-
if (options.since !== void 0) {
|
|
1788
|
-
const hits = seamsAfter(index, options.since);
|
|
1789
|
-
if (options.json) {
|
|
1790
|
-
process.stdout.write(`${JSON.stringify({
|
|
1791
|
-
since: options.since,
|
|
1792
|
-
count: hits.length,
|
|
1793
|
-
seams: hits
|
|
1794
|
-
}, null, 2)}\n`);
|
|
1795
|
-
return 0;
|
|
1796
|
-
}
|
|
1797
|
-
if (hits.length === 0) {
|
|
1798
|
-
process.stdout.write(`No recorded change lands after ${options.since}.\nThat is bounded by this index's coverage (${index.seams.length} records, measured ${index.measuredAt}, baseline ${index.hostBaseline}) — not a guarantee about releases newer than the baseline.\n`);
|
|
1799
|
-
return 0;
|
|
1800
|
-
}
|
|
1801
|
-
const out = [`${hits.length} change(s) land after ${options.since}:`, ""];
|
|
1802
|
-
for (const s of hits) renderSeam(s, out);
|
|
1803
|
-
const undetectable = hits.filter((s) => !s.detectable).length;
|
|
1804
|
-
out.push(`Note: ${undetectable} of ${hits.length} cannot be detected by static inspection; they are advisory and must not be reported as passing.`);
|
|
1805
|
-
process.stdout.write(`${out.join("\n")}\n`);
|
|
1806
|
-
return 0;
|
|
1807
|
-
}
|
|
1808
|
-
const query = options.query;
|
|
1809
|
-
if (!query) {
|
|
1810
|
-
process.stderr.write("seams: give a query (a seam id, a capability area, or a word) or --since <version>\n");
|
|
1811
|
-
return 2;
|
|
1812
|
-
}
|
|
1813
|
-
const result = lookupSeam(index, query);
|
|
1814
|
-
if (options.json) {
|
|
1815
|
-
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
1816
|
-
return result.state === "unknown" ? 3 : 0;
|
|
1817
|
-
}
|
|
1818
|
-
if (result.state === "unknown") {
|
|
1819
|
-
process.stdout.write(`${result.reason}\n`);
|
|
1820
|
-
return 3;
|
|
1821
|
-
}
|
|
1822
|
-
const out = [];
|
|
1823
|
-
if (result.seams.length) {
|
|
1824
|
-
out.push(`${result.seams.length} seam(s):`, "");
|
|
1825
|
-
for (const s of result.seams) renderSeam(s, out);
|
|
1826
|
-
}
|
|
1827
|
-
if (result.capabilities.length) {
|
|
1828
|
-
out.push(`${result.capabilities.length} capability record(s):`, "");
|
|
1829
|
-
for (const c of result.capabilities) renderCapability(c, out);
|
|
1830
|
-
}
|
|
1831
|
-
process.stdout.write(`${out.join("\n")}\n`);
|
|
1832
|
-
return 0;
|
|
1833
|
-
}
|
|
1834
|
-
|
|
1835
|
-
//#endregion
|
|
1836
|
-
//#region src/cli/commands/verify.ts
|
|
1837
|
-
/**
|
|
1838
|
-
* The verified harness line `verify` installs into its throwaway profile.
|
|
1839
|
-
*
|
|
1840
|
-
* Keep these in lockstep with `.github/workflows/compat.yml`, which installs the
|
|
1841
|
-
* same versions. `dsh` rejects an incompatible plugin/base pair at install time,
|
|
1842
|
-
* so a stale pin turns `verify` into a failure that names the *base bundle*
|
|
1843
|
-
* rather than the plugin under test:
|
|
1844
|
-
*
|
|
1845
|
-
* dsh: installation rejected: Plugin @deepseek-ai/dsh-headless@<old> is
|
|
1846
|
-
* incompatible with dsh <new>
|
|
1847
|
-
*
|
|
1848
|
-
* `tests/verify.test.ts` asserts these match compat.yml, so the two cannot drift
|
|
1849
|
-
* apart silently again. Override per run with `--base` / `--headless`.
|
|
1850
|
-
*/
|
|
1851
|
-
const VERIFY_BASE_SPEC = "@deepseek-ai/dsh-base@0.2.1-rc.2";
|
|
1852
|
-
const VERIFY_HEADLESS_SPEC = "@deepseek-ai/dsh-headless@0.2.1-rc.2";
|
|
1853
|
-
const PROFILE_WORKSPACE = `# scratch profile allowlist (mirrors the repo's compat workflow)
|
|
1854
|
-
packages:
|
|
1855
|
-
- .
|
|
1856
|
-
nodeLinker: hoisted
|
|
1857
|
-
autoInstallPeers: false
|
|
1858
|
-
allowBuilds:
|
|
1859
|
-
'@deepseek-ai/dsh-subprocess-local': true
|
|
1860
|
-
koffi: true
|
|
1861
|
-
node-pty: true
|
|
1862
|
-
protobufjs: true
|
|
1863
|
-
'@google/genai': true
|
|
1864
|
-
`;
|
|
1865
|
-
/**
|
|
1866
|
-
* Run the full verify smoke. Never throws for a verification failure; instead it
|
|
1867
|
-
* returns a non-zero exit code with the failing step tail and suggestions. Temp
|
|
1868
|
-
* directories are always cleaned up in `finally`.
|
|
1869
|
-
*/
|
|
1870
|
-
async function runVerify(options) {
|
|
1871
|
-
const root = resolve(options.root);
|
|
1872
|
-
const pkgName = readJsonIfExists(join(root, "package.json"))?.name ?? "plugin";
|
|
1873
|
-
const workDir = createTempDir("verify");
|
|
1874
|
-
const homeDir = createTempDir("home");
|
|
1875
|
-
const steps = [];
|
|
1876
|
-
let failure;
|
|
1877
|
-
const push = (step, result) => {
|
|
1878
|
-
const ok = result.code === 0 && !result.timedOut;
|
|
1879
|
-
steps.push({
|
|
1880
|
-
step,
|
|
1881
|
-
ok,
|
|
1882
|
-
detail: ok ? "ok" : tailOf(result)
|
|
1883
|
-
});
|
|
1884
|
-
};
|
|
1885
|
-
try {
|
|
1886
|
-
const pack = await run(options.pnpmBin, [
|
|
1887
|
-
"pack",
|
|
1888
|
-
"--pack-destination",
|
|
1889
|
-
workDir
|
|
1890
|
-
], {
|
|
1891
|
-
cwd: root,
|
|
1892
|
-
timeoutMs: options.timeoutMs
|
|
1893
|
-
});
|
|
1894
|
-
push("pack", pack);
|
|
1895
|
-
if (pack.code !== 0) {
|
|
1896
|
-
failure = {
|
|
1897
|
-
error: "pnpm pack failed",
|
|
1898
|
-
suggestions: suggestionsFor("pack", pack)
|
|
1899
|
-
};
|
|
1900
|
-
return {
|
|
1901
|
-
steps,
|
|
1902
|
-
exitCode: 1,
|
|
1903
|
-
...failure
|
|
1904
|
-
};
|
|
1905
|
-
}
|
|
1906
|
-
const tarball = findTarball(workDir);
|
|
1907
|
-
if (!tarball) {
|
|
1908
|
-
failure = {
|
|
1909
|
-
error: `no tarball produced in ${workDir}`,
|
|
1910
|
-
suggestions: ["run `pnpm pack --pack-destination <dir>` manually and inspect the output"]
|
|
1911
|
-
};
|
|
1912
|
-
return {
|
|
1913
|
-
steps,
|
|
1914
|
-
exitCode: 1,
|
|
1915
|
-
...failure
|
|
1916
|
-
};
|
|
1917
|
-
}
|
|
1918
|
-
const profileDir = join(homeDir, "profiles", options.profile);
|
|
1919
|
-
writeFileDeep(join(profileDir, "pnpm-workspace.yaml"), PROFILE_WORKSPACE);
|
|
1920
|
-
const add = await run(options.dshBin, [
|
|
1921
|
-
"plugin",
|
|
1922
|
-
"--profile",
|
|
1923
|
-
options.profile,
|
|
1924
|
-
"add",
|
|
1925
|
-
options.base,
|
|
1926
|
-
options.headless,
|
|
1927
|
-
tarball
|
|
1928
|
-
], {
|
|
1929
|
-
cwd: homeDir,
|
|
1930
|
-
env: { DSH_HOME: homeDir },
|
|
1931
|
-
timeoutMs: options.timeoutMs
|
|
1932
|
-
});
|
|
1933
|
-
push("install", add);
|
|
1934
|
-
if (add.code !== 0) {
|
|
1935
|
-
failure = {
|
|
1936
|
-
error: "profile install failed",
|
|
1937
|
-
suggestions: suggestionsFor("install", add)
|
|
1938
|
-
};
|
|
1939
|
-
return {
|
|
1940
|
-
steps,
|
|
1941
|
-
exitCode: 1,
|
|
1942
|
-
...failure
|
|
1943
|
-
};
|
|
1944
|
-
}
|
|
1945
|
-
const dump = await run(options.dshBin, [
|
|
1946
|
-
"--profile",
|
|
1947
|
-
options.profile,
|
|
1948
|
-
"--dump-config"
|
|
1949
|
-
], {
|
|
1950
|
-
cwd: homeDir,
|
|
1951
|
-
env: { DSH_HOME: homeDir },
|
|
1952
|
-
timeoutMs: options.timeoutMs
|
|
1953
|
-
});
|
|
1954
|
-
push("dump-config", dump);
|
|
1955
|
-
if (dump.code !== 0) {
|
|
1956
|
-
failure = {
|
|
1957
|
-
error: "dump-config failed",
|
|
1958
|
-
suggestions: suggestionsFor("dump-config", dump)
|
|
1959
|
-
};
|
|
1960
|
-
return {
|
|
1961
|
-
steps,
|
|
1962
|
-
exitCode: 1,
|
|
1963
|
-
...failure
|
|
1964
|
-
};
|
|
1965
|
-
}
|
|
1966
|
-
if (!dump.stdout.includes(pkgName)) {
|
|
1967
|
-
failure = {
|
|
1968
|
-
error: `bundle row "${pkgName}" did not mount`,
|
|
1969
|
-
suggestions: [`dump-config output did not contain "${pkgName}"`]
|
|
1970
|
-
};
|
|
1971
|
-
return {
|
|
1972
|
-
steps,
|
|
1973
|
-
exitCode: 1,
|
|
1974
|
-
...failure
|
|
1975
|
-
};
|
|
1976
|
-
}
|
|
1977
|
-
const smoke = await run(options.dshBin, [
|
|
1978
|
-
"--profile",
|
|
1979
|
-
options.profile,
|
|
1980
|
-
"Reply with exactly: ok"
|
|
1981
|
-
], {
|
|
1982
|
-
cwd: homeDir,
|
|
1983
|
-
env: { DSH_HOME: homeDir },
|
|
1984
|
-
timeoutMs: options.smokeTimeoutMs
|
|
1985
|
-
});
|
|
1986
|
-
const smokeOk = isSmokeOk(smoke.stdout, smoke.stderr);
|
|
1987
|
-
steps.push({
|
|
1988
|
-
step: "headless-smoke",
|
|
1989
|
-
ok: smokeOk,
|
|
1990
|
-
detail: smokeOk ? `${smoke.stdout}\n${smoke.stderr}`.includes("MISSING_CREDENTIAL") ? "ok (keyless)" : "ok (with key)" : tailOf(smoke)
|
|
1991
|
-
});
|
|
1992
|
-
if (!smokeOk) {
|
|
1993
|
-
failure = {
|
|
1994
|
-
error: "headless smoke did not prove tree load",
|
|
1995
|
-
suggestions: suggestionsFor("headless", smoke)
|
|
1996
|
-
};
|
|
1997
|
-
return {
|
|
1998
|
-
steps,
|
|
1999
|
-
exitCode: 1,
|
|
2000
|
-
...failure
|
|
2001
|
-
};
|
|
2002
|
-
}
|
|
2003
|
-
const remove = await run(options.dshBin, [
|
|
2004
|
-
"plugin",
|
|
2005
|
-
"--profile",
|
|
2006
|
-
options.profile,
|
|
2007
|
-
"remove",
|
|
2008
|
-
pkgName
|
|
2009
|
-
], {
|
|
2010
|
-
cwd: homeDir,
|
|
2011
|
-
env: { DSH_HOME: homeDir },
|
|
2012
|
-
timeoutMs: options.timeoutMs
|
|
2013
|
-
});
|
|
2014
|
-
push("uninstall", remove);
|
|
2015
|
-
if (remove.code !== 0) {
|
|
2016
|
-
failure = {
|
|
2017
|
-
error: "uninstall failed",
|
|
2018
|
-
suggestions: suggestionsFor("uninstall", remove)
|
|
2019
|
-
};
|
|
2020
|
-
return {
|
|
2021
|
-
steps,
|
|
2022
|
-
exitCode: 1,
|
|
2023
|
-
...failure
|
|
2024
|
-
};
|
|
2025
|
-
}
|
|
2026
|
-
return {
|
|
2027
|
-
steps,
|
|
2028
|
-
exitCode: 0,
|
|
2029
|
-
suggestions: []
|
|
2030
|
-
};
|
|
2031
|
-
} finally {
|
|
2032
|
-
cleanupAllTempDirs();
|
|
2033
|
-
}
|
|
2034
|
-
}
|
|
2035
|
-
function findTarball(dir) {
|
|
2036
|
-
for (const entry of readdirSync(dir)) if (entry.endsWith(".tgz")) return join(dir, entry);
|
|
2037
|
-
}
|
|
2038
|
-
function suggestionsFor(step, result) {
|
|
2039
|
-
const base = [`tail of "${step}":\n${tailOf(result)}`];
|
|
2040
|
-
if (result.timedOut) base.push(`command timed out; raise --timeout or --smoke-timeout`);
|
|
2041
|
-
if (step === "install") {
|
|
2042
|
-
base.push("ensure the dsh CLI is @deepseek-ai/dsh@0.2.1-rc.2 (older builds such as the rc.6 line do not satisfy the compat pin)");
|
|
2043
|
-
base.push("confirm the profile allowlist matches the repo compat workflow (native builds allowlisted)");
|
|
2044
|
-
}
|
|
2045
|
-
if (step === "headless") base.push("a hang usually means an injected service stayed pending; the smoke timeout surfaces exactly that");
|
|
2046
|
-
return base;
|
|
2047
|
-
}
|
|
2048
|
-
/** Error signatures a headless smoke prints only *after* the tree loaded. */
|
|
2049
|
-
const SMOKE_LOADED_SIGNATURES = [
|
|
2050
|
-
"MISSING_CREDENTIAL",
|
|
2051
|
-
"TRANSPORT:",
|
|
2052
|
-
"transport failed",
|
|
2053
|
-
"UNAUTHORIZED",
|
|
2054
|
-
"invalid api key",
|
|
2055
|
-
"API key is invalid"
|
|
2056
|
-
];
|
|
2057
|
-
/**
|
|
2058
|
-
* True when a headless smoke run proves the plugin tree loaded. Three accepted
|
|
2059
|
-
* outcomes, all of which require that the tree mounted and the turn dispatched:
|
|
2060
|
-
* a keyless run printing `MISSING_CREDENTIAL`, a keyed run printing `ok`, or a
|
|
2061
|
-
* keyed run whose provider call failed at the transport/auth layer.
|
|
2062
|
-
*
|
|
2063
|
-
* The third case is not a fallback for a broken plugin: a plugin that never
|
|
2064
|
-
* mounted produces no provider traffic at all, so it prints none of these
|
|
2065
|
-
* signatures and still fails this check.
|
|
2066
|
-
*
|
|
2067
|
-
* @param stdout - captured stdout.
|
|
2068
|
-
* @param stderr - captured stderr.
|
|
2069
|
-
*/
|
|
2070
|
-
function isSmokeOk(stdout, stderr) {
|
|
2071
|
-
const text = `${stdout}\n${stderr}`;
|
|
2072
|
-
if (SMOKE_LOADED_SIGNATURES.some((signature) => text.includes(signature))) return true;
|
|
2073
|
-
return /(^|[^a-z])ok([^a-z]|$)/i.test(text);
|
|
2074
|
-
}
|
|
2075
|
-
/** Resolve the dsh binary: explicit flag/env first, then PATH `dsh`. */
|
|
2076
|
-
function resolveDsh(flag) {
|
|
2077
|
-
return flag ?? process.env.DSH_PLUGIN_DEV_DSH ?? "dsh";
|
|
2078
|
-
}
|
|
2079
|
-
/** Resolve the pnpm binary: explicit flag/env first, then PATH `pnpm`. */
|
|
2080
|
-
function resolvePnpm(flag) {
|
|
2081
|
-
return flag ?? process.env.DSH_PLUGIN_DEV_PNPM ?? "pnpm";
|
|
2082
|
-
}
|
|
2083
|
-
/** Format the verify steps for the console. */
|
|
2084
|
-
function renderVerifySteps(root, steps) {
|
|
2085
|
-
const lines = [`verify: ${root}`, ""];
|
|
2086
|
-
for (const step of steps) lines.push(`${step.ok ? "✓" : "✗"} ${step.step}${step.ok ? "" : `\n${step.detail}`}`);
|
|
2087
|
-
return lines.join("\n");
|
|
2088
|
-
}
|
|
2089
|
-
|
|
2090
|
-
//#endregion
|
|
2091
|
-
//#region src/cli/main.ts
|
|
2092
|
-
const HELP = `dsh-plugin-dev — the DeepSeek Harness plugin-development CLI
|
|
2093
|
-
|
|
2094
|
-
Usage:
|
|
2095
|
-
dsh-plugin-dev <command> [options]
|
|
2096
|
-
|
|
2097
|
-
Commands:
|
|
2098
|
-
new <name> Scaffold a TypeScript or JavaScript plugin repo skeleton
|
|
2099
|
-
(src/index.ts contract template, Schemastery Config, tests,
|
|
2100
|
-
tsdown/vitest, cordis.patch.yml, five-language READMEs).
|
|
2101
|
-
Flags: --lang <ts|js> --dir <path> --force --git
|
|
2102
|
-
check Run static plugin checks and emit a CI-consumable report.
|
|
2103
|
-
Flags: --cwd <dir> --json --strict
|
|
2104
|
-
verify pnpm pack, then install/start/uninstall the bundle in a clean
|
|
2105
|
-
mkdtemp DSH_HOME profile (aligned with verify:self-contained).
|
|
2106
|
-
Flags: --cwd <dir> --dsh <bin> --pnpm <bin> --profile <name>
|
|
2107
|
-
--base <spec> --headless <spec> --timeout <ms>
|
|
2108
|
-
--smoke-timeout <ms>
|
|
2109
|
-
seams <query> Ask whether an API or capability exists in a target host:
|
|
2110
|
-
a seam id (L3), a capability id (A20), a version, or a word.
|
|
2111
|
-
Exits 3 when the knowledge base does not establish an answer —
|
|
2112
|
-
which is NOT a "no". Flags: --json
|
|
2113
|
-
seams --since <version>
|
|
2114
|
-
List every recorded breaking change that lands AFTER a version
|
|
2115
|
-
you target, flagging which ones static inspection cannot see.
|
|
2116
|
-
|
|
2117
|
-
Global:
|
|
2118
|
-
-h, --help Show this help
|
|
2119
|
-
-V, --version Print the CLI version
|
|
2120
|
-
|
|
2121
|
-
Environment tunables:
|
|
2122
|
-
DSH_PLUGIN_DEV_TEMPLATES override the scaffold templates directory
|
|
2123
|
-
DSH_PLUGIN_DEV_DSH override the dsh CLI used by verify
|
|
2124
|
-
DSH_PLUGIN_DEV_PNPM override the pnpm binary used by verify
|
|
2125
|
-
DSH_PLUGIN_DEV_TIMEOUT install/pack timeout in ms (default 300000)
|
|
2126
|
-
DSH_PLUGIN_DEV_SMOKE_TIMEOUT headless smoke timeout in ms (default 120000)
|
|
2127
|
-
`;
|
|
2128
|
-
const DEFAULT_TIMEOUT_MS = 3e5;
|
|
2129
|
-
const DEFAULT_SMOKE_TIMEOUT_MS = 12e4;
|
|
2130
|
-
/** Parse a millisecond integer flag with an env-tunable fallback. */
|
|
2131
|
-
function timeoutMs(flags, key, envKey, fallback) {
|
|
2132
|
-
const raw = flagString(flags, key, process.env[envKey]);
|
|
2133
|
-
if (raw === void 0) return fallback;
|
|
2134
|
-
const parsed = Number.parseInt(raw, 10);
|
|
2135
|
-
if (!Number.isFinite(parsed) || parsed <= 0) throw new Error(`invalid ${key} value "${raw}": expected a positive millisecond count`);
|
|
2136
|
-
return parsed;
|
|
2137
|
-
}
|
|
2138
|
-
/**
|
|
2139
|
-
* Run the CLI and return a process exit code.
|
|
2140
|
-
* @param argv - process.argv.slice(2) style input.
|
|
2141
|
-
* @param cwd - working directory (injectable for tests).
|
|
2142
|
-
*/
|
|
2143
|
-
async function main(argv, cwd = process.cwd()) {
|
|
2144
|
-
const KNOWN_FLAGS = [
|
|
2145
|
-
"help",
|
|
2146
|
-
"h",
|
|
2147
|
-
"version",
|
|
2148
|
-
"V",
|
|
2149
|
-
"lang",
|
|
2150
|
-
"dir",
|
|
2151
|
-
"force",
|
|
2152
|
-
"git",
|
|
2153
|
-
"cwd",
|
|
2154
|
-
"json",
|
|
2155
|
-
"strict",
|
|
2156
|
-
"dsh",
|
|
2157
|
-
"pnpm",
|
|
2158
|
-
"profile",
|
|
2159
|
-
"base",
|
|
2160
|
-
"headless",
|
|
2161
|
-
"timeout",
|
|
2162
|
-
"smoke-timeout",
|
|
2163
|
-
"since",
|
|
2164
|
-
"query"
|
|
2165
|
-
];
|
|
2166
|
-
let parsed;
|
|
2167
|
-
try {
|
|
2168
|
-
parsed = parseArgs(argv, KNOWN_FLAGS);
|
|
2169
|
-
} catch (err) {
|
|
2170
|
-
if (err instanceof UsageError) {
|
|
2171
|
-
process.stderr.write(`dsh-plugin-dev: ${err.message}\n`);
|
|
2172
|
-
return 2;
|
|
2173
|
-
}
|
|
2174
|
-
throw err;
|
|
2175
|
-
}
|
|
2176
|
-
const { positionals, flags } = parsed;
|
|
2177
|
-
if (flagBool(flags, "version") || flags.V === true) {
|
|
2178
|
-
process.stdout.write(`${readCliVersion()}\n`);
|
|
2179
|
-
return 0;
|
|
2180
|
-
}
|
|
2181
|
-
if (flagBool(flags, "help") || flags.h === true || positionals.length === 0) {
|
|
2182
|
-
process.stdout.write(HELP);
|
|
2183
|
-
return 0;
|
|
2184
|
-
}
|
|
2185
|
-
const command = positionals[0];
|
|
2186
|
-
try {
|
|
2187
|
-
switch (command) {
|
|
2188
|
-
case "new": {
|
|
2189
|
-
const name = positionals[1];
|
|
2190
|
-
if (!name) throw new Error("missing plugin name: dsh-plugin-dev new <name>");
|
|
2191
|
-
const lang = flagString(flags, "lang", "ts");
|
|
2192
|
-
if (lang !== "ts" && lang !== "js") throw new Error(`--lang must be "ts" or "js", got "${lang}"`);
|
|
2193
|
-
const result = await runNew(cwd, {
|
|
2194
|
-
name,
|
|
2195
|
-
lang,
|
|
2196
|
-
dir: flagString(flags, "dir"),
|
|
2197
|
-
force: flagBool(flags, "force"),
|
|
2198
|
-
git: flagBool(flags, "git")
|
|
2199
|
-
});
|
|
2200
|
-
process.stdout.write(`scaffolded ${result.files} files into ${result.targetDir}\n`);
|
|
2201
|
-
return 0;
|
|
2202
|
-
}
|
|
2203
|
-
case "check": {
|
|
2204
|
-
const root = flagString(flags, "cwd", cwd) ?? cwd;
|
|
2205
|
-
const { report, exitCode } = runCheck({
|
|
2206
|
-
root,
|
|
2207
|
-
strict: flagBool(flags, "strict")
|
|
2208
|
-
});
|
|
2209
|
-
printCheckReport(report, flagBool(flags, "json") ? "json" : "text");
|
|
2210
|
-
return exitCode;
|
|
2211
|
-
}
|
|
2212
|
-
case "verify": {
|
|
2213
|
-
const root = flagString(flags, "cwd", cwd) ?? cwd;
|
|
2214
|
-
const result = await runVerify({
|
|
2215
|
-
root,
|
|
2216
|
-
dshBin: resolveDsh(flagString(flags, "dsh")),
|
|
2217
|
-
pnpmBin: resolvePnpm(flagString(flags, "pnpm")),
|
|
2218
|
-
profile: flagString(flags, "profile", "compat") ?? "compat",
|
|
2219
|
-
base: flagString(flags, "base", "@deepseek-ai/dsh-base@0.2.1-rc.2") ?? "@deepseek-ai/dsh-base@0.2.1-rc.2",
|
|
2220
|
-
headless: flagString(flags, "headless", "@deepseek-ai/dsh-headless@0.2.1-rc.2") ?? "@deepseek-ai/dsh-headless@0.2.1-rc.2",
|
|
2221
|
-
timeoutMs: timeoutMs(flags, "timeout", "DSH_PLUGIN_DEV_TIMEOUT", DEFAULT_TIMEOUT_MS),
|
|
2222
|
-
smokeTimeoutMs: timeoutMs(flags, "smoke-timeout", "DSH_PLUGIN_DEV_SMOKE_TIMEOUT", DEFAULT_SMOKE_TIMEOUT_MS)
|
|
2223
|
-
});
|
|
2224
|
-
process.stdout.write(renderVerifySteps(root, result.steps));
|
|
2225
|
-
process.stdout.write("\n");
|
|
2226
|
-
if (result.error) {
|
|
2227
|
-
process.stdout.write(`FAIL: ${result.error}\n`);
|
|
2228
|
-
for (const suggestion of result.suggestions) process.stdout.write(` - ${suggestion}\n`);
|
|
2229
|
-
} else process.stdout.write("verify: OK\n");
|
|
2230
|
-
return result.exitCode;
|
|
2231
|
-
}
|
|
2232
|
-
case "seams": {
|
|
2233
|
-
const since = flagString(flags, "since");
|
|
2234
|
-
const query = positionals[1] ?? flagString(flags, "query");
|
|
2235
|
-
return runSeams(loadSeamIndex(), {
|
|
2236
|
-
query,
|
|
2237
|
-
since,
|
|
2238
|
-
json: flagBool(flags, "json")
|
|
2239
|
-
});
|
|
2240
|
-
}
|
|
2241
|
-
default:
|
|
2242
|
-
process.stderr.write(`unknown command "${command}"\n\n${HELP}`);
|
|
2243
|
-
return 2;
|
|
2244
|
-
}
|
|
2245
|
-
} catch (err) {
|
|
2246
|
-
process.stderr.write(`dsh-plugin-dev: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
2247
|
-
return 1;
|
|
2248
|
-
}
|
|
2249
|
-
}
|
|
2250
|
-
|
|
2251
|
-
//#endregion
|
|
2252
|
-
//#region src/cli/entry.ts
|
|
2253
|
-
main(process.argv.slice(2)).then((code) => {
|
|
2254
|
-
process.exitCode = code;
|
|
2255
|
-
}, (err) => {
|
|
2256
|
-
process.stderr.write(`dsh-plugin-dev: ${err instanceof Error ? err.stack ?? err.message : String(err)}\n`);
|
|
2257
|
-
process.exitCode = 1;
|
|
2258
|
-
});
|
|
2259
|
-
|
|
2260
|
-
//#endregion
|
|
2261
|
-
export { };
|