@inharness-ai/claude4spec 1.0.20 → 1.0.22
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/.claude/skills/c4s-brief-implementer/SKILL.md +117 -57
- package/CHANGELOG.md +26 -0
- package/dist/bin/c4s/commands/agent.d.ts +18 -0
- package/dist/bin/c4s/commands/agent.js +102 -0
- package/dist/bin/c4s/commands/agent.js.map +1 -0
- package/dist/bin/c4s/commands/ask.d.ts +9 -8
- package/dist/bin/c4s/commands/ask.js +23 -31
- package/dist/bin/c4s/commands/ask.js.map +1 -1
- package/dist/bin/c4s/commands/catalog.d.ts +1 -1
- package/dist/bin/c4s/commands/catalog.js +2 -2
- package/dist/bin/c4s/commands/catalog.js.map +1 -1
- package/dist/bin/c4s/commands/describe.d.ts +1 -1
- package/dist/bin/c4s/commands/describe.js +2 -2
- package/dist/bin/c4s/commands/describe.js.map +1 -1
- package/dist/bin/c4s/commands/detail.d.ts +1 -1
- package/dist/bin/c4s/commands/detail.js +2 -2
- package/dist/bin/c4s/commands/detail.js.map +1 -1
- package/dist/bin/c4s/commands/element-list.d.ts +1 -1
- package/dist/bin/c4s/commands/element-list.js +2 -2
- package/dist/bin/c4s/commands/element-list.js.map +1 -1
- package/dist/bin/c4s/commands/find-references.js +1 -1
- package/dist/bin/c4s/commands/find-references.js.map +1 -1
- package/dist/bin/c4s/commands/inline-mention.d.ts +1 -1
- package/dist/bin/c4s/commands/inline-mention.js +2 -2
- package/dist/bin/c4s/commands/inline-mention.js.map +1 -1
- package/dist/bin/c4s/commands/list-slugs.d.ts +1 -1
- package/dist/bin/c4s/commands/list-slugs.js +2 -2
- package/dist/bin/c4s/commands/list-slugs.js.map +1 -1
- package/dist/bin/c4s/commands/list-tags.d.ts +1 -1
- package/dist/bin/c4s/commands/list-tags.js +2 -2
- package/dist/bin/c4s/commands/list-tags.js.map +1 -1
- package/dist/bin/c4s/commands/plugins.d.ts +9 -0
- package/dist/bin/c4s/commands/plugins.js +81 -0
- package/dist/bin/c4s/commands/plugins.js.map +1 -0
- package/dist/bin/c4s/commands/resolve.d.ts +1 -1
- package/dist/bin/c4s/commands/resolve.js +2 -2
- package/dist/bin/c4s/commands/resolve.js.map +1 -1
- package/dist/bin/c4s/commands/single-element.d.ts +1 -1
- package/dist/bin/c4s/commands/single-element.js +2 -2
- package/dist/bin/c4s/commands/single-element.js.map +1 -1
- package/dist/bin/c4s/commands/tagged-list-mixed.d.ts +1 -1
- package/dist/bin/c4s/commands/tagged-list-mixed.js +2 -2
- package/dist/bin/c4s/commands/tagged-list-mixed.js.map +1 -1
- package/dist/bin/c4s/commands/tagged-list.d.ts +1 -1
- package/dist/bin/c4s/commands/tagged-list.js +2 -2
- package/dist/bin/c4s/commands/tagged-list.js.map +1 -1
- package/dist/bin/c4s/context.d.ts +3 -3
- package/dist/bin/c4s/context.js +7 -4
- package/dist/bin/c4s/context.js.map +1 -1
- package/dist/bin/c4s/errors.d.ts +1 -1
- package/dist/bin/c4s/errors.js.map +1 -1
- package/dist/bin/c4s-mcp.js +6 -2
- package/dist/bin/c4s-mcp.js.map +1 -1
- package/dist/bin/c4s.js +19 -4
- package/dist/bin/c4s.js.map +1 -1
- package/dist/bin/gitignore.js +7 -11
- package/dist/bin/gitignore.js.map +1 -1
- package/dist/client/assets/{arc-qrIe4IVl.js → arc-C9oTB3b1.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-CF6sgG8n.js → architectureDiagram-3BPJPVTR-Bno5ViqK.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-Cf8Tx0VN.js → blockDiagram-GPEHLZMM-CJYBoeWQ.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-BDkuMEyf.js → c4Diagram-AAUBKEIU-DaaqWE6s.js} +1 -1
- package/dist/client/assets/channel-Cei_E79M.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-ChycTonk.js → chunk-2J33WTMH-P_I0OPMy.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-BpUgWjxx.js → chunk-4BX2VUAB-CCySMlh5.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-CeHg_yjT.js → chunk-55IACEB6-CEUyqKGF.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-BpxYq7ab.js → chunk-727SXJPM-CoTSYOVz.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-bghkOtr6.js → chunk-AQP2D5EJ-DB0nMxPr.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-4sXokGgd.js → chunk-FMBD7UC4-PG3m6-_a.js} +1 -1
- package/dist/client/assets/{chunk-ND2GUHAM-DYQOCE5T.js → chunk-ND2GUHAM-CBNk6IaV.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-NkVuDlFD.js → chunk-QZHKN3VN-CLFa0WvN.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-DUe_fAto.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DUe_fAto.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-1l4P4WRI.js → cose-bilkent-S5V4N54A-BDwDDxHN.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-CSQie-gR.js → dagre-BM42HDAG-DR-1e8N5.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-DME9ULoN.js → diagram-2AECGRRQ-C-tHgBWt.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-Dn1Rw5k5.js → diagram-5GNKFQAL-uLmoKaJL.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-Duh_PNWR.js → diagram-KO2AKTUF-8Fd-xuOy.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-B7Q5pV60.js → diagram-LMA3HP47-C1gniWsn.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-C0KL_RDd.js → diagram-OG6HWLK6-BMWjZbeC.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-D5elfwSC.js → erDiagram-TEJ5UH35-CIUO8hrR.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-BHmjX-WI.js → flowDiagram-I6XJVG4X-Ccw5YEf3.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-KvoGFbS2.js → ganttDiagram-6RSMTGT7-BAvlf8cY.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DsZL8BfK.js → gitGraphDiagram-PVQCEYII-ChCkdYar.js} +1 -1
- package/dist/client/assets/{index-zzILqHQN.js → index-BotCWOKC.js} +1 -1
- package/dist/client/assets/index-CtdzGyqj.js +805 -0
- package/dist/client/assets/{index-ClaVbrEF.js → index-DtpKHGD1.js} +1 -1
- package/dist/client/assets/{infoDiagram-5YYISTIA-DoQ6iSpJ.js → infoDiagram-5YYISTIA-CZMGwNyB.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-akftyN0J.js → ishikawaDiagram-YF4QCWOH-CubjZGk6.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-PPex4PiV.js → journeyDiagram-JHISSGLW-DzwOyVzB.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-D114i3s1.js → kanban-definition-UN3LZRKU-CXznoTY9.js} +1 -1
- package/dist/client/assets/{linear-BuwQPJom.js → linear-EDwTFRrU.js} +1 -1
- package/dist/client/assets/{mermaid.core-CMX3GAvM.js → mermaid.core-Lae2097R.js} +4 -4
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-ClBxWJju.js → mindmap-definition-RKZ34NQL-DFjIW41g.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-hj5zVPj5.js → pieDiagram-4H26LBE5-CZDLR1jd.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-CRbR0G7M.js → quadrantDiagram-W4KKPZXB-CTGDzbqp.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-Dto4B70I.js → requirementDiagram-4Y6WPE33-CeH0NbMv.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-DyYP8rwY.js → sankeyDiagram-5OEKKPKP-B6ZTjurV.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-C-mrSLrJ.js → sequenceDiagram-3UESZ5HK-DcTRztVx.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-IoDlhAe6.js → stateDiagram-AJRCARHV-nUgRVZSA.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-D9pJuQbI.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-DEXg3TEw.js → timeline-definition-PNZ67QCA-CXm5n4rV.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-CNu7LaT1.js → vennDiagram-CIIHVFJN-EmNJBYNd.js} +1 -1
- package/dist/client/assets/{wardley-L42UT6IY-0hGvREmD.js → wardley-L42UT6IY-MLrlp8H-.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-CVLz-xFz.js → wardleyDiagram-YWT4CUSO-5QoES25n.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-CFymKAcX.js → xychartDiagram-2RQKCTM6-CbDEQbY0.js} +1 -1
- package/dist/client/index.html +1 -1
- package/dist/core/agent/run-agent.d.ts +61 -0
- package/dist/core/agent/run-agent.js +212 -0
- package/dist/core/agent/run-agent.js.map +1 -0
- package/dist/core/ask/run-ask.d.ts +1 -1
- package/dist/core/ask/run-ask.js +14 -5
- package/dist/core/ask/run-ask.js.map +1 -1
- package/dist/core/workspace/resolve.d.ts +2 -0
- package/dist/core/workspace/resolve.js +2 -1
- package/dist/core/workspace/resolve.js.map +1 -1
- package/dist/plugin-types/ambient.d.ts +30 -0
- package/dist/plugin-types/plugin-runtime.d.ts +172 -0
- package/dist/plugin-types/ui.d.ts +154 -0
- package/dist/server/config.d.ts +12 -0
- package/dist/server/config.js +26 -0
- package/dist/server/config.js.map +1 -1
- package/dist/server/core/plugin-host/__fixtures__/plugins.d.ts +14 -0
- package/dist/server/core/plugin-host/__fixtures__/plugins.js +56 -0
- package/dist/server/core/plugin-host/__fixtures__/plugins.js.map +1 -0
- package/dist/server/core/plugin-host/base-packages.d.ts +14 -0
- package/dist/server/core/plugin-host/base-packages.js +26 -0
- package/dist/server/core/plugin-host/base-packages.js.map +1 -0
- package/dist/server/core/plugin-host/cache-bust.d.ts +10 -0
- package/dist/server/core/plugin-host/cache-bust.js +21 -0
- package/dist/server/core/plugin-host/cache-bust.js.map +1 -0
- package/dist/server/core/plugin-host/cli-engine.d.ts +7 -2
- package/dist/server/core/plugin-host/cli-engine.js +11 -3
- package/dist/server/core/plugin-host/cli-engine.js.map +1 -1
- package/dist/server/core/plugin-host/cli-plugins.d.ts +23 -0
- package/dist/server/core/plugin-host/cli-plugins.js +49 -0
- package/dist/server/core/plugin-host/cli-plugins.js.map +1 -0
- package/dist/server/core/plugin-host/cross-cutting.d.ts +41 -4
- package/dist/server/core/plugin-host/cross-cutting.js +52 -4
- package/dist/server/core/plugin-host/cross-cutting.js.map +1 -1
- package/dist/server/core/plugin-host/entities-router.d.ts +2 -1
- package/dist/server/core/plugin-host/entities-router.js +16 -1
- package/dist/server/core/plugin-host/entities-router.js.map +1 -1
- package/dist/server/core/plugin-host/frontend-assets.d.ts +100 -0
- package/dist/server/core/plugin-host/frontend-assets.js +262 -0
- package/dist/server/core/plugin-host/frontend-assets.js.map +1 -0
- package/dist/server/core/plugin-host/frontend-manifest.d.ts +33 -0
- package/dist/server/core/plugin-host/frontend-manifest.js +52 -0
- package/dist/server/core/plugin-host/frontend-manifest.js.map +1 -0
- package/dist/server/core/plugin-host/loader.d.ts +107 -0
- package/dist/server/core/plugin-host/loader.js +196 -0
- package/dist/server/core/plugin-host/loader.js.map +1 -0
- package/dist/server/core/plugin-host/manifest-adapter.d.ts +30 -0
- package/dist/server/core/plugin-host/manifest-adapter.js +119 -0
- package/dist/server/core/plugin-host/manifest-adapter.js.map +1 -0
- package/dist/server/core/plugin-host/overlay-loader.d.ts +60 -0
- package/dist/server/core/plugin-host/overlay-loader.js +243 -0
- package/dist/server/core/plugin-host/overlay-loader.js.map +1 -0
- package/dist/server/core/plugin-host/plugin-watcher.d.ts +41 -0
- package/dist/server/core/plugin-host/plugin-watcher.js +95 -0
- package/dist/server/core/plugin-host/plugin-watcher.js.map +1 -0
- package/dist/server/core/plugin-host/project-host.d.ts +8 -2
- package/dist/server/core/plugin-host/project-host.js +56 -6
- package/dist/server/core/plugin-host/project-host.js.map +1 -1
- package/dist/server/core/plugin-host/registry.d.ts +26 -2
- package/dist/server/core/plugin-host/registry.js +107 -2
- package/dist/server/core/plugin-host/registry.js.map +1 -1
- package/dist/server/core/plugin-host/runtime-shims.d.ts +26 -0
- package/dist/server/core/plugin-host/runtime-shims.js +96 -0
- package/dist/server/core/plugin-host/runtime-shims.js.map +1 -0
- package/dist/server/core/plugin-host/types.d.ts +105 -3
- package/dist/server/db/migrations/041_chat_thread_transagent.sql +22 -0
- package/dist/server/db/migrations/042_chat_thread_drop_context_type_check.sql +61 -0
- package/dist/server/external-skills/brief-implementer-template.d.ts +1 -1
- package/dist/server/external-skills/brief-implementer-template.js +5 -2
- package/dist/server/external-skills/brief-implementer-template.js.map +1 -1
- package/dist/server/external-skills/spec-reader-template.d.ts +1 -1
- package/dist/server/external-skills/spec-reader-template.js +14 -0
- package/dist/server/external-skills/spec-reader-template.js.map +1 -1
- package/dist/server/index.js +98 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/c4s-tools.d.ts +6 -1
- package/dist/server/mcp/c4s-tools.js +18 -13
- package/dist/server/mcp/c4s-tools.js.map +1 -1
- package/dist/server/mcp/release-tools/index.d.ts +11 -0
- package/dist/server/mcp/release-tools/index.js +68 -5
- package/dist/server/mcp/release-tools/index.js.map +1 -1
- package/dist/server/mcp/release-tools/projection.d.ts +11 -2
- package/dist/server/mcp/release-tools/projection.js +36 -7
- package/dist/server/mcp/release-tools/projection.js.map +1 -1
- package/dist/server/mcp/release-tools/types.d.ts +39 -2
- package/dist/server/mcp/transagent-tools.d.ts +26 -0
- package/dist/server/mcp/transagent-tools.js +75 -0
- package/dist/server/mcp/transagent-tools.js.map +1 -0
- package/dist/server/plugin-runtime/index.d.ts +17 -0
- package/dist/server/plugin-runtime/index.js +16 -0
- package/dist/server/plugin-runtime/index.js.map +1 -0
- package/dist/server/plugin-runtime/ui.d.ts +15 -0
- package/dist/server/plugin-runtime/ui.js +15 -0
- package/dist/server/plugin-runtime/ui.js.map +1 -0
- package/dist/server/routes/agent-turn.d.ts +17 -1
- package/dist/server/routes/agent-turn.js +121 -36
- package/dist/server/routes/agent-turn.js.map +1 -1
- package/dist/server/routes/briefs.js +12 -4
- package/dist/server/routes/briefs.js.map +1 -1
- package/dist/server/routes/chat.js +18 -0
- package/dist/server/routes/chat.js.map +1 -1
- package/dist/server/routes/config.d.ts +8 -0
- package/dist/server/routes/config.js +41 -3
- package/dist/server/routes/config.js.map +1 -1
- package/dist/server/routes/plans.js +13 -0
- package/dist/server/routes/plans.js.map +1 -1
- package/dist/server/routes/plugins.d.ts +43 -0
- package/dist/server/routes/plugins.js +93 -0
- package/dist/server/routes/plugins.js.map +1 -0
- package/dist/server/routes/threads.js +30 -5
- package/dist/server/routes/threads.js.map +1 -1
- package/dist/server/serialization/registerAll.d.ts +4 -0
- package/dist/server/serialization/registerAll.js +4 -2
- package/dist/server/serialization/registerAll.js.map +1 -1
- package/dist/server/services/brief.d.ts +30 -8
- package/dist/server/services/brief.js +58 -28
- package/dist/server/services/brief.js.map +1 -1
- package/dist/server/services/chat-context.d.ts +34 -0
- package/dist/server/services/chat-context.js +68 -21
- package/dist/server/services/chat-context.js.map +1 -1
- package/dist/server/services/chat.d.ts +18 -1
- package/dist/server/services/chat.js +74 -23
- package/dist/server/services/chat.js.map +1 -1
- package/dist/server/services/entity-indexer.js +21 -14
- package/dist/server/services/entity-indexer.js.map +1 -1
- package/dist/server/services/entity-writer.d.ts +2 -3
- package/dist/server/services/entity-writer.js.map +1 -1
- package/dist/server/services/plan.d.ts +7 -1
- package/dist/server/services/plan.js +17 -4
- package/dist/server/services/plan.js.map +1 -1
- package/dist/server/services/skill-registry.d.ts +31 -2
- package/dist/server/services/skill-registry.js +73 -1
- package/dist/server/services/skill-registry.js.map +1 -1
- package/dist/server/services/transagent-dispatcher.d.ts +60 -0
- package/dist/server/services/transagent-dispatcher.js +147 -0
- package/dist/server/services/transagent-dispatcher.js.map +1 -0
- package/dist/server/skills/brief-author/SKILL.md +26 -17
- package/dist/server/workspace/context-cache.d.ts +9 -0
- package/dist/server/workspace/context-cache.js +14 -0
- package/dist/server/workspace/context-cache.js.map +1 -1
- package/dist/server/workspace/project-context.d.ts +3 -0
- package/dist/server/workspace/project-context.js +108 -5
- package/dist/server/workspace/project-context.js.map +1 -1
- package/dist/server/workspace/registry.d.ts +28 -1
- package/dist/server/workspace/registry.js +57 -1
- package/dist/server/workspace/registry.js.map +1 -1
- package/dist/server/workspace/types.d.ts +15 -0
- package/dist/shared/entities.d.ts +50 -4
- package/dist/shared/entities.js +1 -0
- package/dist/shared/entities.js.map +1 -1
- package/dist/shared/plugin-host/frontend-manifest.d.ts +56 -0
- package/dist/shared/plugin-host/frontend-manifest.js +89 -0
- package/dist/shared/plugin-host/frontend-manifest.js.map +1 -0
- package/dist/shared/plugin-host/host-api.d.ts +60 -0
- package/dist/shared/plugin-host/host-api.js +67 -0
- package/dist/shared/plugin-host/host-api.js.map +1 -0
- package/dist/shared/plugin-host/manifest.d.ts +194 -0
- package/dist/shared/plugin-host/manifest.js +52 -0
- package/dist/shared/plugin-host/manifest.js.map +1 -0
- package/dist/shared/plugin-host/ui-kit-surface.d.ts +22 -0
- package/dist/shared/plugin-host/ui-kit-surface.js +25 -0
- package/dist/shared/plugin-host/ui-kit-surface.js.map +1 -0
- package/dist/shared/types.d.ts +5 -0
- package/package.json +18 -3
- package/dist/client/assets/channel-CTF_J4I4.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-Dt9RLC8r.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Dt9RLC8r.js +0 -1
- package/dist/client/assets/index-DnLELaLA.js +0 -798
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-BblFLijq.js +0 -1
|
@@ -3,24 +3,129 @@
|
|
|
3
3
|
* singleton — the registry is immutable after `registerAllPlugins(registry)`
|
|
4
4
|
* runs at process start, and `consolidate(config.entities)` is a pure factory
|
|
5
5
|
* producing one ProjectPluginHost per project context.
|
|
6
|
+
*
|
|
7
|
+
* M33: the base layer is no longer process-immutable — the hot-reload
|
|
8
|
+
* pipeline mutates it via `registerPlugin` / `unregisterPlugin` and then
|
|
9
|
+
* invalidates dependent `ProjectContext`s (axis B). The registry additionally
|
|
10
|
+
* retains a per-plugin {@link RegisteredPluginRecord} so the host can surface
|
|
11
|
+
* non-entity capabilities (settings/commands) and the reload pipeline can call
|
|
12
|
+
* the old version's `onUnregister` before re-registering.
|
|
6
13
|
*/
|
|
7
14
|
import { ProjectPluginHostImpl } from './project-host.js';
|
|
15
|
+
import { PluginManifestError, lowerEntityContribution, validateWritingStyle, } from './manifest-adapter.js';
|
|
8
16
|
export class PluginRegistryImpl {
|
|
9
17
|
modules = new Map();
|
|
18
|
+
// M33: base-layer plugins by name, in registration order. The source
|
|
19
|
+
// of truth for `listWritingStyles` / `listPluginRecords` so a hot-reload that
|
|
20
|
+
// calls `unregisterPlugin` cleanly drops the old version's styles too.
|
|
21
|
+
plugins = new Map();
|
|
10
22
|
registerEntityModule(module) {
|
|
11
23
|
if (!module.type) {
|
|
12
24
|
throw new Error('plugin-registry: module.type is required');
|
|
13
25
|
}
|
|
14
26
|
this.modules.set(module.type, module);
|
|
15
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Validate a manifest's shape and lower every contribution WITHOUT mutating
|
|
30
|
+
* the registry. Throws `PluginManifestError` on any structural problem (the
|
|
31
|
+
* loader/reload pipeline catches it). The hot-reload pipeline calls this
|
|
32
|
+
* BEFORE tearing the old version down, so a structurally-broken new version
|
|
33
|
+
* never leaves the pool missing a type ("old stays").
|
|
34
|
+
*/
|
|
35
|
+
validateAndLower(manifest) {
|
|
36
|
+
if (!manifest || typeof manifest !== 'object') {
|
|
37
|
+
throw new PluginManifestError('plugin manifest must be an object');
|
|
38
|
+
}
|
|
39
|
+
if (typeof manifest.name !== 'string' || typeof manifest.version !== 'string') {
|
|
40
|
+
throw new PluginManifestError('plugin manifest requires string name + version');
|
|
41
|
+
}
|
|
42
|
+
if (manifest.contributes == null || typeof manifest.contributes !== 'object') {
|
|
43
|
+
throw new PluginManifestError(`plugin "${manifest.name}" — contributes must be an object`);
|
|
44
|
+
}
|
|
45
|
+
// Two-pass for atomicity: lower (validate) every contribution first, so a
|
|
46
|
+
// throw on a later entity/style never leaves earlier ones registered.
|
|
47
|
+
const entityModules = (manifest.contributes.entities ?? []).map(lowerEntityContribution);
|
|
48
|
+
const styles = (manifest.contributes.writingStyles ?? []).map(validateWritingStyle);
|
|
49
|
+
// `onUnregister` is a required slot from the HOST_API 1.0.0 baseline. A
|
|
50
|
+
// runtime manifest missing it is not crashed over — warn (parity with L8
|
|
51
|
+
// slot validation) and substitute a no-op so the reload pipeline still works.
|
|
52
|
+
let onUnregister;
|
|
53
|
+
if (typeof manifest.onUnregister === 'function') {
|
|
54
|
+
onUnregister = () => manifest.onUnregister();
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
console.warn(`[plugin-registry] plugin "${manifest.name}" — required slot onUnregister is missing; using a no-op teardown`);
|
|
58
|
+
onUnregister = () => { };
|
|
59
|
+
}
|
|
60
|
+
const settings = manifest.contributes.settings ?? [];
|
|
61
|
+
const commands = manifest.contributes.commands ?? [];
|
|
62
|
+
return {
|
|
63
|
+
record: {
|
|
64
|
+
name: manifest.name,
|
|
65
|
+
version: manifest.version,
|
|
66
|
+
contributedTypes: entityModules.map((m) => m.type),
|
|
67
|
+
settings,
|
|
68
|
+
commands,
|
|
69
|
+
styles,
|
|
70
|
+
entityModules,
|
|
71
|
+
onUnregister,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
validatePlugin(manifest) {
|
|
76
|
+
this.validateAndLower(manifest);
|
|
77
|
+
}
|
|
78
|
+
registerPlugin(manifest) {
|
|
79
|
+
const { record } = this.validateAndLower(manifest);
|
|
80
|
+
for (const module of record.entityModules) {
|
|
81
|
+
this.registerEntityModule(module);
|
|
82
|
+
}
|
|
83
|
+
// Re-registration (hot-reload) overwrites the prior record; Map keeps the
|
|
84
|
+
// first-seen insertion order, which is what we want for stable section order.
|
|
85
|
+
this.plugins.set(record.name, record);
|
|
86
|
+
}
|
|
87
|
+
unregisterPlugin(name) {
|
|
88
|
+
const record = this.plugins.get(name);
|
|
89
|
+
if (!record)
|
|
90
|
+
return;
|
|
91
|
+
try {
|
|
92
|
+
record.onUnregister();
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
// Idempotent + non-throwing by contract — a throw is a warning, never a block.
|
|
96
|
+
console.warn(`[plugin-registry] onUnregister of "${name}" threw: ${err.message}`);
|
|
97
|
+
}
|
|
98
|
+
for (const module of record.entityModules) {
|
|
99
|
+
// Only drop the module if it is STILL the one this plugin contributed — a
|
|
100
|
+
// later same-typed registration (another base plugin contributing the same
|
|
101
|
+
// type) would have overwritten the slot, and must not be clobbered here.
|
|
102
|
+
if (this.modules.get(module.type) === module) {
|
|
103
|
+
this.modules.delete(module.type);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
this.plugins.delete(name);
|
|
107
|
+
}
|
|
108
|
+
listPluginRecords() {
|
|
109
|
+
return Array.from(this.plugins.values()).map((r) => ({
|
|
110
|
+
name: r.name,
|
|
111
|
+
version: r.version,
|
|
112
|
+
contributedTypes: [...r.contributedTypes],
|
|
113
|
+
settings: r.settings,
|
|
114
|
+
commands: r.commands,
|
|
115
|
+
onUnregister: r.onUnregister,
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
listWritingStyles() {
|
|
119
|
+
return Array.from(this.plugins.values()).flatMap((r) => r.styles);
|
|
120
|
+
}
|
|
16
121
|
listAvailable() {
|
|
17
122
|
return Array.from(this.modules.values()).sort((a, b) => a.displayOrder - b.displayOrder);
|
|
18
123
|
}
|
|
19
124
|
getAvailable(type) {
|
|
20
125
|
return this.modules.get(type) ?? null;
|
|
21
126
|
}
|
|
22
|
-
consolidate(
|
|
23
|
-
return new ProjectPluginHostImpl(this,
|
|
127
|
+
consolidate(config, overlay) {
|
|
128
|
+
return new ProjectPluginHostImpl(this, config?.entities, overlay);
|
|
24
129
|
}
|
|
25
130
|
}
|
|
26
131
|
//# sourceMappingURL=registry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../../src/server/core/plugin-host/registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../../src/server/core/plugin-host/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M33 "Option B" shared-singleton shims.
|
|
3
|
+
*
|
|
4
|
+
* The host publishes its OWN already-imported module namespaces onto
|
|
5
|
+
* `window.__c4s_shared` (see client `shared-runtime.ts`). The import map points
|
|
6
|
+
* each bare peer specifier at one of these tiny server-served ESM modules, which
|
|
7
|
+
* re-export from that global. A plugin's `import "react"` therefore resolves to
|
|
8
|
+
* the host's live React reconciler — not a second copy.
|
|
9
|
+
*
|
|
10
|
+
* The named-export list per peer is enumerated from the actually-installed
|
|
11
|
+
* package at runtime (cached), so the shim never drifts from the host's exports
|
|
12
|
+
* — avoiding a brittle hand-maintained list. `@c4s/plugin-runtime` is our own
|
|
13
|
+
* fixed surface (and a browser module the server can't import), so it is listed
|
|
14
|
+
* explicitly.
|
|
15
|
+
*/
|
|
16
|
+
import type { SharedPeerSpecifier } from '../../../shared/plugin-host/frontend-manifest.js';
|
|
17
|
+
/** Bare specifier → URL slug used in `/api/plugins/runtime/<slug>.js`. */
|
|
18
|
+
export declare const PEER_SLUG: Record<SharedPeerSpecifier, string>;
|
|
19
|
+
/** Build the import map injected into the page. Bare specifier → shim URL. */
|
|
20
|
+
export declare function buildImportMap(): Record<string, string>;
|
|
21
|
+
/**
|
|
22
|
+
* Render (and cache) the ESM shim for one runtime slug. Returns `null` for an
|
|
23
|
+
* unknown slug. Never throws — a peer whose package can't be introspected
|
|
24
|
+
* server-side falls back to a default-only shim.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getRuntimeShim(slug: string): Promise<string | null>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M33 "Option B" shared-singleton shims.
|
|
3
|
+
*
|
|
4
|
+
* The host publishes its OWN already-imported module namespaces onto
|
|
5
|
+
* `window.__c4s_shared` (see client `shared-runtime.ts`). The import map points
|
|
6
|
+
* each bare peer specifier at one of these tiny server-served ESM modules, which
|
|
7
|
+
* re-export from that global. A plugin's `import "react"` therefore resolves to
|
|
8
|
+
* the host's live React reconciler — not a second copy.
|
|
9
|
+
*
|
|
10
|
+
* The named-export list per peer is enumerated from the actually-installed
|
|
11
|
+
* package at runtime (cached), so the shim never drifts from the host's exports
|
|
12
|
+
* — avoiding a brittle hand-maintained list. `@c4s/plugin-runtime` is our own
|
|
13
|
+
* fixed surface (and a browser module the server can't import), so it is listed
|
|
14
|
+
* explicitly.
|
|
15
|
+
*/
|
|
16
|
+
import { SHARED_PEER_SPECIFIERS, PLUGIN_RUNTIME_EXPORT_NAMES, PLUGIN_RUNTIME_UI_EXPORT_NAMES, } from '../../../shared/plugin-host/frontend-manifest.js';
|
|
17
|
+
/** Bare specifier → URL slug used in `/api/plugins/runtime/<slug>.js`. */
|
|
18
|
+
export const PEER_SLUG = {
|
|
19
|
+
react: 'react',
|
|
20
|
+
'react/jsx-runtime': 'react-jsx-runtime',
|
|
21
|
+
'react/jsx-dev-runtime': 'react-jsx-dev-runtime',
|
|
22
|
+
'react-dom': 'react-dom',
|
|
23
|
+
'react-dom/client': 'react-dom-client',
|
|
24
|
+
'@tiptap/core': 'tiptap-core',
|
|
25
|
+
'@tanstack/react-query': 'react-query',
|
|
26
|
+
'@tanstack/react-router': 'react-router',
|
|
27
|
+
'@c4s/plugin-runtime': 'plugin-runtime',
|
|
28
|
+
'@c4s/plugin-runtime/ui': 'plugin-runtime-ui',
|
|
29
|
+
};
|
|
30
|
+
const SLUG_PEER = Object.fromEntries(SHARED_PEER_SPECIFIERS.map((spec) => [PEER_SLUG[spec], spec]));
|
|
31
|
+
/**
|
|
32
|
+
* The named exports of our own client surfaces — browser modules the server
|
|
33
|
+
* can't introspect. Single source of truth lives in shared; parity tests
|
|
34
|
+
* (plugin-runtime.test.ts, plugin-runtime-ui.test.ts) guard them against drift.
|
|
35
|
+
*/
|
|
36
|
+
const PLUGIN_RUNTIME_EXPORTS = PLUGIN_RUNTIME_EXPORT_NAMES;
|
|
37
|
+
const PLUGIN_RUNTIME_UI_EXPORTS = PLUGIN_RUNTIME_UI_EXPORT_NAMES;
|
|
38
|
+
/** Build the import map injected into the page. Bare specifier → shim URL. */
|
|
39
|
+
export function buildImportMap() {
|
|
40
|
+
const map = {};
|
|
41
|
+
for (const spec of SHARED_PEER_SPECIFIERS) {
|
|
42
|
+
map[spec] = `/api/plugins/runtime/${PEER_SLUG[spec]}.js`;
|
|
43
|
+
}
|
|
44
|
+
return map;
|
|
45
|
+
}
|
|
46
|
+
const ID_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
47
|
+
function renderShimSource(specifier, names) {
|
|
48
|
+
const accessor = `globalThis.__c4s_shared[${JSON.stringify(specifier)}]`;
|
|
49
|
+
const lines = [
|
|
50
|
+
`// Auto-generated host singleton shim for "${specifier}".`,
|
|
51
|
+
`const __m = ${accessor};`,
|
|
52
|
+
`if (!__m) throw new Error('c4s plugin-runtime: missing shared singleton "${specifier}" — host did not publish window.__c4s_shared');`,
|
|
53
|
+
`export default (__m && __m.default !== undefined ? __m.default : __m);`,
|
|
54
|
+
];
|
|
55
|
+
for (const name of names) {
|
|
56
|
+
if (name === 'default' || name === '__esModule' || !ID_RE.test(name))
|
|
57
|
+
continue;
|
|
58
|
+
lines.push(`export const ${name} = __m[${JSON.stringify(name)}];`);
|
|
59
|
+
}
|
|
60
|
+
return lines.join('\n') + '\n';
|
|
61
|
+
}
|
|
62
|
+
const shimCache = new Map();
|
|
63
|
+
/**
|
|
64
|
+
* Render (and cache) the ESM shim for one runtime slug. Returns `null` for an
|
|
65
|
+
* unknown slug. Never throws — a peer whose package can't be introspected
|
|
66
|
+
* server-side falls back to a default-only shim.
|
|
67
|
+
*/
|
|
68
|
+
export async function getRuntimeShim(slug) {
|
|
69
|
+
const cached = shimCache.get(slug);
|
|
70
|
+
if (cached)
|
|
71
|
+
return cached;
|
|
72
|
+
const specifier = SLUG_PEER[slug];
|
|
73
|
+
if (!specifier)
|
|
74
|
+
return null;
|
|
75
|
+
let names;
|
|
76
|
+
if (specifier === '@c4s/plugin-runtime') {
|
|
77
|
+
names = [...PLUGIN_RUNTIME_EXPORTS];
|
|
78
|
+
}
|
|
79
|
+
else if (specifier === '@c4s/plugin-runtime/ui') {
|
|
80
|
+
names = [...PLUGIN_RUNTIME_UI_EXPORTS];
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
try {
|
|
84
|
+
const ns = (await import(specifier));
|
|
85
|
+
names = Object.keys(ns);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
console.warn(`[plugin-runtime] could not introspect "${specifier}" for shim exports: ${err.message}`);
|
|
89
|
+
names = [];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const source = renderShimSource(specifier, names);
|
|
93
|
+
shimCache.set(slug, source);
|
|
94
|
+
return source;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=runtime-shims.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-shims.js","sourceRoot":"","sources":["../../../../src/server/core/plugin-host/runtime-shims.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@ import type { Database } from 'better-sqlite3';
|
|
|
10
10
|
import type { Router } from 'express';
|
|
11
11
|
import type { McpServerInstance } from '@inharness-ai/agent-adapters';
|
|
12
12
|
import type { EntityModuleManifest, PluginActivationState, SystemPromptContribution } from '../../../shared/plugin-host/types.js';
|
|
13
|
+
import type { PluginCommandContribution, PluginManifest, PluginSettingsSection, WritingStyleContribution } from '../../../shared/plugin-host/manifest.js';
|
|
13
14
|
import type { EntityDiff, EntitySerializer, RestoreContext, RestoreResult, SerializeContext, SnapshotData } from '../../serialization/types.js';
|
|
14
15
|
import type { TagsService } from '../../services/tags.js';
|
|
15
16
|
import type { VersionService } from '../../services/versions.js';
|
|
@@ -89,6 +90,49 @@ export interface BackendModule extends EntityModuleManifest {
|
|
|
89
90
|
mount?: PluginMountFn;
|
|
90
91
|
};
|
|
91
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* M33: per-`ProjectContext` overlay of project-local plugins loaded
|
|
95
|
+
* from `<cwd>/.claude4spec/plugins/` (behind the `trustProjectPlugins` gate).
|
|
96
|
+
* The overlay is relative to the project — two projects in one process carry
|
|
97
|
+
* different overlays. `listLocal()` returns already-validated, trust-gated
|
|
98
|
+
* modules; `origin(type)` maps a type back to its source path under
|
|
99
|
+
* `.claude4spec/plugins/` for diagnostics (shadow report).
|
|
100
|
+
*/
|
|
101
|
+
export interface ProjectPluginOverlay {
|
|
102
|
+
/** Project-local modules of THIS project (post validation + trust gate). */
|
|
103
|
+
listLocal(): BackendModule[];
|
|
104
|
+
/** Source path under `<cwd>/.claude4spec/plugins/` for the given type. */
|
|
105
|
+
origin(type: string): string;
|
|
106
|
+
/**
|
|
107
|
+
* M33 — Settings sections contributed by trusted project-local
|
|
108
|
+
* plugins (one per plugin with `contributes.settings`). Trust is implicit:
|
|
109
|
+
* the overlay is built only on the trusted path.
|
|
110
|
+
*/
|
|
111
|
+
listSettings(): PluginSettingsSection[];
|
|
112
|
+
/** M33 — declarative editor commands from trusted project-local plugins. */
|
|
113
|
+
listCommands(): PluginCommandContribution[];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* M33 — a registered base-layer plugin, retained by the registry so the
|
|
117
|
+
* host can surface its non-entity capabilities (settings/commands) and the
|
|
118
|
+
* hot-reload pipeline can tear it down via `onUnregister` before re-registering.
|
|
119
|
+
*/
|
|
120
|
+
export interface RegisteredPluginRecord {
|
|
121
|
+
name: string;
|
|
122
|
+
version: string;
|
|
123
|
+
/** Entity types this plugin contributed (for unregister + diagnostics). */
|
|
124
|
+
contributedTypes: string[];
|
|
125
|
+
settings: PluginSettingsSection['fields'];
|
|
126
|
+
commands: PluginCommandContribution[];
|
|
127
|
+
/** Required teardown hook (idempotent, non-throwing by contract). */
|
|
128
|
+
onUnregister: () => void;
|
|
129
|
+
}
|
|
130
|
+
/** One overlay type that shadows a same-named base type (cross-layer collision). */
|
|
131
|
+
export interface ShadowedType {
|
|
132
|
+
type: string;
|
|
133
|
+
/** Source path of the overlay module that won. */
|
|
134
|
+
overlayOrigin: string;
|
|
135
|
+
}
|
|
92
136
|
/**
|
|
93
137
|
* M31 split: process-immutable plugin catalog. Populated once at process
|
|
94
138
|
* start via `registerAllPlugins(registry)`; `consolidate` is a PURE factory —
|
|
@@ -97,15 +141,52 @@ export interface BackendModule extends EntityModuleManifest {
|
|
|
97
141
|
export interface PluginRegistry {
|
|
98
142
|
/** Register a plugin manifest. Idempotent on `module.type`. */
|
|
99
143
|
registerEntityModule(module: BackendModule): void;
|
|
144
|
+
/**
|
|
145
|
+
* M33: register a runtime plugin manifest. Validates the manifest shape and
|
|
146
|
+
* fans `contributes.entities[]` out to `registerEntityModule(...)` (each
|
|
147
|
+
* lowered from its authoring shape). Throws `PluginManifestError` on a
|
|
148
|
+
* structurally invalid manifest — the loader catches this per-package. Does
|
|
149
|
+
* NOT gate on hostApiVersion/engines (that is the loader's job).
|
|
150
|
+
*/
|
|
151
|
+
registerPlugin(manifest: PluginManifest): void;
|
|
152
|
+
/**
|
|
153
|
+
* M33 — validate a manifest's shape + lower all its contributions
|
|
154
|
+
* WITHOUT mutating the registry; throws on a structural problem. The reload
|
|
155
|
+
* pipeline calls this before `unregisterPlugin` so a structurally-broken new
|
|
156
|
+
* version never leaves the pool missing a type (atomic "old stays").
|
|
157
|
+
*/
|
|
158
|
+
validatePlugin(manifest: PluginManifest): void;
|
|
159
|
+
/**
|
|
160
|
+
* M33 — tear down a previously-registered base plugin by name: call
|
|
161
|
+
* its `onUnregister` (idempotent, non-throwing) and drop its entity modules +
|
|
162
|
+
* retained capability record. The hot-reload pipeline calls this on the OLD
|
|
163
|
+
* version before re-`registerPlugin`-ing the fresh module. No-op for an
|
|
164
|
+
* unknown name.
|
|
165
|
+
*/
|
|
166
|
+
unregisterPlugin(name: string): void;
|
|
167
|
+
/** M33 — retained base-layer plugin records (for capabilities + reload). */
|
|
168
|
+
listPluginRecords(): RegisteredPluginRecord[];
|
|
100
169
|
/** All registered modules, regardless of activation. */
|
|
101
170
|
listAvailable(): BackendModule[];
|
|
102
171
|
/** Lookup including inactive — used for broken-chip categorisation. */
|
|
103
172
|
getAvailable(type: string): BackendModule | null;
|
|
104
173
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
174
|
+
* M15: writing styles contributed by base-layer (workspace/npm)
|
|
175
|
+
* plugins, collected during `registerPlugin`. Pushed into each project's
|
|
176
|
+
* SkillRegistry as `source: "plugin"` at context build (project-local overlay
|
|
177
|
+
* styles are pushed separately, behind the trust gate).
|
|
178
|
+
*/
|
|
179
|
+
listWritingStyles(): WritingStyleContribution[];
|
|
180
|
+
/**
|
|
181
|
+
* Derive a per-project host. The effective pool is `base ∪ overlay`
|
|
182
|
+
* (base ∪ overlay); the `config.entities` whitelist is applied to that merged
|
|
183
|
+
* pool, not to the base alone. `config.entities === undefined` ⇒ all available
|
|
184
|
+
* active (v1 backward compat). `overlay === undefined` ⇒ effective pool =
|
|
185
|
+
* base (parity with the base-only case). No side effects.
|
|
107
186
|
*/
|
|
108
|
-
consolidate(
|
|
187
|
+
consolidate(config: {
|
|
188
|
+
entities?: string[];
|
|
189
|
+
} | null | undefined, overlay?: ProjectPluginOverlay): ProjectPluginHost;
|
|
109
190
|
}
|
|
110
191
|
/** Plugin self-registration hook — exported by each entities/*\/plugin.ts. */
|
|
111
192
|
export type PluginOnRegister = (registry: PluginRegistry) => void;
|
|
@@ -114,6 +195,21 @@ export interface ProjectPluginHost {
|
|
|
114
195
|
listAvailable(): BackendModule[];
|
|
115
196
|
/** Active modules only (filtered by the consolidated whitelist). */
|
|
116
197
|
listEntities(): BackendModule[];
|
|
198
|
+
/**
|
|
199
|
+
* M33 — Settings sections of ALL loaded + trusted plugins in the
|
|
200
|
+
* effective pool (base ∪ trusted overlay), one per plugin with
|
|
201
|
+
* `contributes.settings`. Deliberately does NOT filter by `config.entities`
|
|
202
|
+
* (contrast with `listEntities()`): a plugin's settings survive deactivation
|
|
203
|
+
* of its entity types — the user needs the panel to re-enable them. This is
|
|
204
|
+
* axis B (pool + trust), not axis A (entity whitelist).
|
|
205
|
+
*/
|
|
206
|
+
listSettings(): PluginSettingsSection[];
|
|
207
|
+
/**
|
|
208
|
+
* M33 — declarative editor slash-commands of ALL loaded + trusted
|
|
209
|
+
* plugins, independent of `config.entities` (same two-axis rationale as
|
|
210
|
+
* `listSettings()`). Routed into the editor via `registerEditorExtension`.
|
|
211
|
+
*/
|
|
212
|
+
listCommands(): PluginCommandContribution[];
|
|
117
213
|
/** Lookup by type — returns null for inactive or unknown. */
|
|
118
214
|
getEntity(type: string): BackendModule | null;
|
|
119
215
|
/** Lookup including inactive — used for broken-chip categorisation. */
|
|
@@ -121,6 +217,12 @@ export interface ProjectPluginHost {
|
|
|
121
217
|
isActive(type: string): boolean;
|
|
122
218
|
/** Activation snapshot — input for GET /_meta/entities. (Rename of `state()`.) */
|
|
123
219
|
partition(): PluginActivationState;
|
|
220
|
+
/**
|
|
221
|
+
* M33: overlay types that shadow a same-named base type. Empty when
|
|
222
|
+
* there is no overlay or no cross-layer collision. Feeds the per-project
|
|
223
|
+
* `/_meta/plugins` shadow report and the M19 consistency check.
|
|
224
|
+
*/
|
|
225
|
+
shadowReport(): ShadowedType[];
|
|
124
226
|
/**
|
|
125
227
|
* Mount every active backend module into the supplied Express app + the
|
|
126
228
|
* host-internal MCP registry. Iterates `listEntities()` and invokes each
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
-- 0.1.69 Transagents ("bańki") — a chat/patch thread can delegate a unit of
|
|
2
|
+
-- work to a hidden CHILD thread of the same spec. The child runs a full turn,
|
|
3
|
+
-- streams live into the parent's panel, and returns only a `summary` to the
|
|
4
|
+
-- parent LLM's context.
|
|
5
|
+
--
|
|
6
|
+
-- chat_thread gains a self-referential parent pointer (NULL = top-level thread,
|
|
7
|
+
-- NOT NULL = child banka) plus the parent tool_use id that spawned it (used for
|
|
8
|
+
-- F5 reconstruction: resolve childThreadId from the stored tool_use row via
|
|
9
|
+
-- (parent_thread_id, spawned_by_tool_use_id)).
|
|
10
|
+
--
|
|
11
|
+
-- Migration 029 rebuilt chat_thread without a context_type CHECK; here we only
|
|
12
|
+
-- ADD COLUMN, so no table rebuild is needed. The self-FK on parent_thread_id is
|
|
13
|
+
-- safe under ALTER TABLE ADD COLUMN — the migration runner disables foreign_keys
|
|
14
|
+
-- around the batch (see migrate.ts), so this neither rebuilds nor cascade-checks
|
|
15
|
+
-- existing rows.
|
|
16
|
+
-- Spec: 0.1.69 brief — Transagents.
|
|
17
|
+
|
|
18
|
+
ALTER TABLE chat_thread ADD COLUMN parent_thread_id TEXT
|
|
19
|
+
REFERENCES chat_thread(id) ON DELETE CASCADE; -- NULL = top-level; NOT NULL = child banka
|
|
20
|
+
ALTER TABLE chat_thread ADD COLUMN spawned_by_tool_use_id TEXT;
|
|
21
|
+
|
|
22
|
+
CREATE INDEX idx_chat_thread_parent_thread_id ON chat_thread(parent_thread_id);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
-- M05/0.1.79 'ask' context_type — older published versions rebuilt chat_thread
|
|
2
|
+
-- in migration 029 WITH `CHECK (context_type IN ('chat','brief','patch'))`.
|
|
3
|
+
-- SQLite cannot ALTER/DROP a CHECK and 029 is already recorded as applied, so
|
|
4
|
+
-- DBs created by those versions still reject 'ask'. Rebuild the table once more
|
|
5
|
+
-- with NO context_type CHECK (validation lives in CONTEXT_TYPE_REGISTRY,
|
|
6
|
+
-- chat-context.ts). Idempotent: a rebuild is harmless for DBs already lacking
|
|
7
|
+
-- the constraint. FK-safe — migrate.ts disables foreign_keys around the batch,
|
|
8
|
+
-- so the DROP does not cascade-delete chat_message / chat_subagent_task /
|
|
9
|
+
-- chat_queued_message rows, and the self-FK parent_thread_id re-resolves once
|
|
10
|
+
-- the new table is renamed in.
|
|
11
|
+
-- Full column set as of migrations 005/009/010/011/013/021/024/022/029/033/041.
|
|
12
|
+
|
|
13
|
+
CREATE TABLE chat_thread_new (
|
|
14
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
15
|
+
title TEXT,
|
|
16
|
+
last_session_id TEXT,
|
|
17
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
18
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
19
|
+
current_todo_items TEXT,
|
|
20
|
+
plan_mode INTEGER NOT NULL DEFAULT 0,
|
|
21
|
+
initial_system_prompt TEXT,
|
|
22
|
+
last_usage_json TEXT,
|
|
23
|
+
plan_id INTEGER REFERENCES plan(id) ON DELETE SET NULL,
|
|
24
|
+
last_seen_plan_version INTEGER,
|
|
25
|
+
last_context_size INTEGER,
|
|
26
|
+
context_type TEXT NOT NULL DEFAULT 'chat',
|
|
27
|
+
brief_path TEXT,
|
|
28
|
+
patch_path TEXT,
|
|
29
|
+
initial_architecture_config_json TEXT,
|
|
30
|
+
parent_thread_id TEXT REFERENCES chat_thread(id) ON DELETE CASCADE,
|
|
31
|
+
spawned_by_tool_use_id TEXT
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
INSERT INTO chat_thread_new (
|
|
35
|
+
id, title, last_session_id, created_at, updated_at, current_todo_items,
|
|
36
|
+
plan_mode, initial_system_prompt, last_usage_json, plan_id,
|
|
37
|
+
last_seen_plan_version, last_context_size, context_type, brief_path,
|
|
38
|
+
patch_path, initial_architecture_config_json, parent_thread_id,
|
|
39
|
+
spawned_by_tool_use_id
|
|
40
|
+
)
|
|
41
|
+
SELECT
|
|
42
|
+
id, title, last_session_id, created_at, updated_at, current_todo_items,
|
|
43
|
+
plan_mode, initial_system_prompt, last_usage_json, plan_id,
|
|
44
|
+
last_seen_plan_version, last_context_size, context_type, brief_path,
|
|
45
|
+
patch_path, initial_architecture_config_json, parent_thread_id,
|
|
46
|
+
spawned_by_tool_use_id
|
|
47
|
+
FROM chat_thread;
|
|
48
|
+
|
|
49
|
+
DROP TABLE chat_thread;
|
|
50
|
+
|
|
51
|
+
ALTER TABLE chat_thread_new RENAME TO chat_thread;
|
|
52
|
+
|
|
53
|
+
CREATE INDEX idx_chat_thread_plan ON chat_thread(plan_id);
|
|
54
|
+
|
|
55
|
+
CREATE INDEX IF NOT EXISTS idx_chat_thread_brief_path
|
|
56
|
+
ON chat_thread(brief_path) WHERE brief_path IS NOT NULL;
|
|
57
|
+
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_chat_thread_patch_path
|
|
59
|
+
ON chat_thread(patch_path) WHERE patch_path IS NOT NULL;
|
|
60
|
+
|
|
61
|
+
CREATE INDEX idx_chat_thread_parent_thread_id ON chat_thread(parent_thread_id);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const BRIEF_IMPLEMENTER_FRONTMATTER = "---\nname: c4s-brief-implementer\ndescription: Implement features described in claude4spec briefs (markdown files in .claude4spec/briefs/). Briefs are self-contained \u2014 they include all context needed for implementation (entity snapshots, section diffs, narrative). After implementation, if you discover drift between the brief and reality (missing details, incorrect assumptions, edge cases not covered), generate a patch file in .claude4spec/patches/ as feedback for the specification author. Use when implementing changes in a code repository that has a .claude4spec/briefs/ directory.\n---\n";
|
|
2
|
-
export declare const BRIEF_IMPLEMENTER_BODY = "# c4s-brief-implementer\n\nThis skill describes how to implement a release brief in **your code repository**\n(not the spec repo). A brief is a self-contained markdown file under\n`.claude4spec/briefs/` that captures everything you need to ship the change:\nentity snapshots, section diffs, narrative, acceptance criteria.\n\n**This skill does NOT assume the `c4s` CLI is installed.** Briefs are designed\nto be self-contained \u2014 you do not need to read the main specification or query\nthe entity database. If the brief references something you cannot find in its\nbody, treat that as drift and file a patch (step 4 below).\n\n## Workflow\n\n### 1. Discover\n\n```sh\nls .claude4spec/briefs/ # list available briefs\ncat .claude4spec/briefs/<slug>.md\n```\n\nIf `.claude4spec/` is not in your current directory, walk up the directory tree\nuntil you find it (similar to how git finds `.git/`).\n\n### 2. Read the brief as self-contained input\n\nEvery brief has YAML frontmatter:\n\n```yaml\n---\ntype: brief\nfrom_release: v0.1.16\nto_release: v0.1.17\ngenerator_version: brief-author@0.1\nimplemented: false\n---\n```\n\nThe body contains everything you need \u2014 entity snapshots, section diffs, the\nnarrative of what changes, and acceptance criteria. **Do not read the main\nspecification.**\n\nIf the brief is unclear \u2014 a missing detail, an ambiguous wording, a decision\nyou'd otherwise have to guess \u2014 you have two paths:\n\n**Synchronous (preferred when available).** Ask the specification agent in the\nsame terminal and continue once you have an answer:\n\n```bash\nc4s ask \"Brief nie precyzuje X \u2014 czy chodzi o A czy B?\" --ct brief --brief <brief-slug>.md\n```\n\nContinue the same thread with `c4s ask \"...\" --thread <threadId>` (the\n`threadId` is printed with the answer). This path requires `c4s` installed\n*and* a running `npx @inharness-ai/claude4spec` server. When either is unavailable, skip it.\n\nIf `c4s ask` returns `PROJECT_NOT_FOUND` despite a running server, your cwd is\nprobably reached through a **symlink** (common for `.claude/skills/<name>`\nprojects): `c4s` resolves `process.cwd()` to the real path, which is NOT the one\nregistered in `~/.claude4spec/workspaces.json`. Pass the registered (symlink) path\nexplicitly \u2014 `--project` is run through `path.resolve`, which does NOT canonicalize\nsymlinks, so it matches the registry:\n\n```bash\nc4s ask \"Brief nie precyzuje X \u2014 ...\" --ct brief --brief <brief-slug>.md --project /abs/path/to/registered/skill-dir\n```\n\n**Asynchronous (always available).** If you cannot ask synchronously, proceed\nwith your best judgement and file a patch afterwards (step 4) so the\nspec-author can fold the clarification into the next brief.\n\n### 3. Implement\n\nStandard code flow in your target repository: read existing code, plan, edit,\ntest. Stay focused on what the brief specifies.\n\n### 4. Feedback loop (patches)\n\nWhen you discover that the brief diverges from reality \u2014 a missing detail, an\nincorrect assumption, an edge case not covered, or anything else the\nspec-author should know \u2014 write a patch file:\n\n```sh\nmkdir -p .claude4spec/patches\n```\n\nCreate `.claude4spec/patches/<brief-slug>-<short-desc>.md` with this format:\n\n```markdown\n---\ntype: patch\nbrief: v0-1-16-to-v0-1-17.md # path relative to briefs/\npatch_kind: drift # drift | missing | incorrect | clarification\ncreated_at: 2026-05-11T17:32:00Z\ncreated_by: claude-code # or \"cursor\", \"aider\", ...\n---\n\n# Patch \u2014 short title\n\n## What I found\n\n\u2026description of the drift / missing detail / incorrect assumption\u2026\n\n## Suggestion\n\n\u2026what the spec-author should consider in a follow-up brief or entity edits\u2026\n```\n\nPatch-kind values:\n\n- `drift` \u2014 the brief described behavior X, but the codebase already does Y.\n- `missing` \u2014 the brief is silent on a detail you had to decide yourself.\n- `incorrect` \u2014 the brief is factually wrong about existing code.\n- `clarification` \u2014 the brief is ambiguous; you guessed but it should be made\n explicit for next time.\n\nThe `.claude4spec/patches/` directory is created **lazily** \u2014 only when you\nfile your first patch. The claude4spec server does NOT create it.\n\n### 5. Mark brief as implemented\n\nWhen the implementation is genuinely finished \u2014 code committed, tests green,\nmerged to main / accepted by the user \u2014 flip the brief's frontmatter to\n`implemented: true`:\n\n```bash\n# Option A \u2014 Edit tool: change the line `implemented: false` \u2192 `implemented: true`.\n# Option B \u2014 yq (idempotent; adds the field to legacy briefs that never had it):\nyq -i '.implemented = true' .claude4spec/briefs/<brief-slug>.md\n```\n\n`implemented: true` is a **declaration**, not a computed fact derived from git.\nA revert on main does NOT roll the flag back. Set it ONLY when implementation\nis realistically done \u2014 never proactively or \"just in case\".\n\n### 6. Hand-off\n\nThe spec-author reads patches manually (`ls .claude4spec/patches/`, `cat`)\nand folds them into the next brief or entity edits. There is no UI listing in\nthis release \u2014 patches are raw markdown.\n\n## Notes\n\nThis
|
|
2
|
+
export declare const BRIEF_IMPLEMENTER_BODY = "# c4s-brief-implementer\n\nThis skill describes how to implement a release brief in **your code repository**\n(not the spec repo). A brief is a self-contained markdown file under\n`.claude4spec/briefs/` that captures everything you need to ship the change:\nentity snapshots, section diffs, narrative, acceptance criteria.\n\n**This skill does NOT assume the `c4s` CLI is installed.** Briefs are designed\nto be self-contained \u2014 you do not need to read the main specification or query\nthe entity database. If the brief references something you cannot find in its\nbody, treat that as drift and file a patch (step 4 below).\n\n## Workflow\n\n### 1. Discover\n\n```sh\nls .claude4spec/briefs/ # list available briefs\ncat .claude4spec/briefs/<slug>.md\n```\n\nIf `.claude4spec/` is not in your current directory, walk up the directory tree\nuntil you find it (similar to how git finds `.git/`).\n\n### 2. Read the brief as self-contained input\n\nEvery brief has YAML frontmatter:\n\n```yaml\n---\ntype: brief\nfrom_release: v0.1.16\nto_release: v0.1.17\ngenerator_version: brief-author@0.1\nimplemented: false\n---\n```\n\nThe body contains everything you need \u2014 entity snapshots, section diffs, the\nnarrative of what changes, and acceptance criteria. **Do not read the main\nspecification.**\n\nIf the brief is unclear \u2014 a missing detail, an ambiguous wording, a decision\nyou'd otherwise have to guess \u2014 you have two paths:\n\n**Synchronous (preferred when available).** Ask the specification agent in the\nsame terminal and continue once you have an answer:\n\n```bash\nc4s ask \"Brief nie precyzuje X \u2014 czy chodzi o A czy B?\" --ct brief --brief <brief-slug>.md\n```\n\nContinue the same thread with `c4s ask \"...\" --thread <threadId>` (the\n`threadId` is printed with the answer). This path requires `c4s` installed\n*and* a running `npx @inharness-ai/claude4spec` server. When either is unavailable, skip it.\n\nIf `c4s ask` returns `PROJECT_NOT_FOUND` despite a running server, your cwd is\nprobably reached through a **symlink** (common for `.claude/skills/<name>`\nprojects): `c4s` resolves `process.cwd()` to the real path, which is NOT the one\nregistered in `~/.claude4spec/workspaces.json`. Pass the registered (symlink) path\nexplicitly \u2014 `--project` is run through `path.resolve`, which does NOT canonicalize\nsymlinks, so it matches the registry:\n\n```bash\nc4s ask \"Brief nie precyzuje X \u2014 ...\" --ct brief --brief <brief-slug>.md --project /abs/path/to/registered/skill-dir\n```\n\n**Asynchronous (always available).** If you cannot ask synchronously, proceed\nwith your best judgement and file a patch afterwards (step 4) so the\nspec-author can fold the clarification into the next brief.\n\n### 3. Implement\n\nStandard code flow in your target repository: read existing code, plan, edit,\ntest. Stay focused on what the brief specifies.\n\n### 4. Feedback loop (patches)\n\nWhen you discover that the brief diverges from reality \u2014 a missing detail, an\nincorrect assumption, an edge case not covered, or anything else the\nspec-author should know \u2014 write a patch file:\n\n```sh\nmkdir -p .claude4spec/patches\n```\n\nCreate `.claude4spec/patches/<brief-slug>-<short-desc>.md` with this format:\n\n```markdown\n---\ntype: patch\nbrief: v0-1-16-to-v0-1-17.md # path relative to briefs/\npatch_kind: drift # drift | missing | incorrect | clarification\ncreated_at: 2026-05-11T17:32:00Z\ncreated_by: claude-code # or \"cursor\", \"aider\", ...\n---\n\n# Patch \u2014 short title\n\n## What I found\n\n\u2026description of the drift / missing detail / incorrect assumption\u2026\n\n## Suggestion\n\n\u2026what the spec-author should consider in a follow-up brief or entity edits\u2026\n```\n\nPatch-kind values:\n\n- `drift` \u2014 the brief described behavior X, but the codebase already does Y.\n- `missing` \u2014 the brief is silent on a detail you had to decide yourself.\n- `incorrect` \u2014 the brief is factually wrong about existing code.\n- `clarification` \u2014 the brief is ambiguous; you guessed but it should be made\n explicit for next time.\n\nThe `.claude4spec/patches/` directory is created **lazily** \u2014 only when you\nfile your first patch. The claude4spec server does NOT create it.\n\n### 5. Mark brief as implemented\n\nWhen the implementation is genuinely finished \u2014 code committed, tests green,\nmerged to main / accepted by the user \u2014 flip the brief's frontmatter to\n`implemented: true`:\n\n```bash\n# Option A \u2014 Edit tool: change the line `implemented: false` \u2192 `implemented: true`.\n# Option B \u2014 yq (idempotent; adds the field to legacy briefs that never had it):\nyq -i '.implemented = true' .claude4spec/briefs/<brief-slug>.md\n```\n\n`implemented: true` is a **declaration**, not a computed fact derived from git.\nA revert on main does NOT roll the flag back. Set it ONLY when implementation\nis realistically done \u2014 never proactively or \"just in case\".\n\n### 6. Hand-off\n\nThe spec-author reads patches manually (`ls .claude4spec/patches/`, `cat`)\nand folds them into the next brief or entity edits. There is no UI listing in\nthis release \u2014 patches are raw markdown.\n\n## Notes\n\nThis is a **base skill** generated by claude4spec. It already covers what you\nneed to read briefs and ask the c4s agent questions. Feel free to **adapt it to\nyour own workflow** (e.g. add a git/PR flow) or use it as-is \u2014 this base copy\nunder `.claude4spec/skills/` is refreshed on server start, so copy it into your\nproject's `.claude/skills/` if you want edits that stick.\n";
|
|
@@ -146,7 +146,10 @@ this release — patches are raw markdown.
|
|
|
146
146
|
|
|
147
147
|
## Notes
|
|
148
148
|
|
|
149
|
-
This
|
|
150
|
-
|
|
149
|
+
This is a **base skill** generated by claude4spec. It already covers what you
|
|
150
|
+
need to read briefs and ask the c4s agent questions. Feel free to **adapt it to
|
|
151
|
+
your own workflow** (e.g. add a git/PR flow) or use it as-is — this base copy
|
|
152
|
+
under \`.claude4spec/skills/\` is refreshed on server start, so copy it into your
|
|
153
|
+
project's \`.claude/skills/\` if you want edits that stick.
|
|
151
154
|
`;
|
|
152
155
|
//# sourceMappingURL=brief-implementer-template.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brief-implementer-template.js","sourceRoot":"","sources":["../../../src/server/external-skills/brief-implementer-template.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,6BAA6B,GAAG;;;;CAI5C,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG
|
|
1
|
+
{"version":3,"file":"brief-implementer-template.js","sourceRoot":"","sources":["../../../src/server/external-skills/brief-implementer-template.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,6BAA6B,GAAG;;;;CAI5C,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoJrC,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const SPEC_READER_FRONTMATTER = "---\nname: c4s-spec-reader\ndescription: Read claude4spec specification entities (endpoints, DTOs, tables, AC, UI views) referenced from markdown pages through XML tags like <inline_mention/>, <single_element/>, <tagged_list/>. Use when working in a repository whose pages/ contain these tags or whose .claude4spec/ directory exists. Resolves entity slugs to full data via c4s CLI or c4s-reader MCP server.\n---\n";
|
|
2
|
-
export declare const SPEC_READER_BODY = "# c4s-spec-reader\n\nThis repository contains a claude4spec specification. Pages (`*.md`) reference\nentities stored in `.claude4spec/db.sqlite` through XML tags. This skill teaches\nyou how to resolve them.\n\nAll commands below walk up from the agent's cwd to the nearest `.claude4spec/` \u2014\nno absolute paths are required.\n\n## Resolving a tag\n\nInstall `claude4spec` (Node 20+) and use the `c4s` CLI. Subcommand names match\nXML tag names 1:1.\n\n| XML tag | CLI equivalent |\n|---------|----------------|\n| `<inline_mention type=\"endpoint\" slug=\"X\"/>` | `c4s inline_mention --type endpoint --slug X` |\n| `<single_element type=\"dto\" slug=\"X\"/>` | `c4s single_element --type dto --slug X` |\n| `<element_list type=\"endpoint\" slugs=\"a,b,c\"/>` | `c4s element_list --type endpoint --slugs a,b,c` |\n| `<tagged_list type=\"dto\" tags=\"auth\" filter=\"and\"/>` | `c4s tagged_list --type dto --tags auth --filter and` |\n| `<tagged_list_mixed tags=\"public\"/>` | `c4s tagged_list_mixed --tags public` |\n\n## Expanding a whole page\n\n```sh\nc4s resolve some-page.md # writes markdown with tags expanded inline\nc4s resolve some-page.md --format json # writes { content, resolved: [...] }\n```\n\n## Discovery\n\n- `c4s catalog` \u2014 active entity types with counts + version + description + roleNoun + mcpToolsLine per type (smoke test).\n- `c4s describe --type <t> [--view <v>]` \u2014 JSON Schema per view for one type (on-demand).\n- `c4s list-tags` \u2014 all tags with per-type counts.\n- `c4s list-slugs --type endpoint` \u2014 all slugs for a given type.\n\nAll output is JSON (pretty) by default. Use `--compact` for pipelines and\n`--format text` for terminal-friendly output. Errors go to stderr as JSON with\nan exit code > 0.\n\nThe database is opened **read-only** \u2014 `c4s` never mutates the project.\n\n## Asking the spec agent\n\nWhen a question goes beyond resolving entities or pages, `c4s ask` runs a\nsynchronous agent turn against the specification:\n\n```sh\nc4s ask \"<question>\" --ct chat\n```\n\nUnlike the read-only commands above, `c4s ask` requires a running\n`npx @inharness-ai/claude4spec` server (it delegates the turn to the server's agent).\n\n### `PROJECT_NOT_FOUND` when the project dir is a symlink\n\nIf `c4s ask` (or any `c4s` command) returns `PROJECT_NOT_FOUND` even though a\nserver is running, your cwd is most likely reached through a **symlink** (common\nfor `.claude/skills/<name>` that points elsewhere). `c4s` resolves `process.cwd()`\nthrough the symlink to the real path, which is NOT the path registered in\n`~/.claude4spec/workspaces.json`. Pass the registered (symlink) path explicitly \u2014\n`--project` is run through `path.resolve`, which does NOT canonicalize symlinks, so\nit matches the registry exactly:\n\n```sh\nc4s ask \"<question>\" --ct chat --project /abs/path/to/registered/project-dir\n```\n";
|
|
2
|
+
export declare const SPEC_READER_BODY = "# c4s-spec-reader\n\nThis repository contains a claude4spec specification. Pages (`*.md`) reference\nentities stored in `.claude4spec/db.sqlite` through XML tags. This skill teaches\nyou how to resolve them.\n\nAll commands below walk up from the agent's cwd to the nearest `.claude4spec/` \u2014\nno absolute paths are required.\n\n## Resolving a tag\n\nInstall `claude4spec` (Node 20+) and use the `c4s` CLI. Subcommand names match\nXML tag names 1:1.\n\n| XML tag | CLI equivalent |\n|---------|----------------|\n| `<inline_mention type=\"endpoint\" slug=\"X\"/>` | `c4s inline_mention --type endpoint --slug X` |\n| `<single_element type=\"dto\" slug=\"X\"/>` | `c4s single_element --type dto --slug X` |\n| `<element_list type=\"endpoint\" slugs=\"a,b,c\"/>` | `c4s element_list --type endpoint --slugs a,b,c` |\n| `<tagged_list type=\"dto\" tags=\"auth\" filter=\"and\"/>` | `c4s tagged_list --type dto --tags auth --filter and` |\n| `<tagged_list_mixed tags=\"public\"/>` | `c4s tagged_list_mixed --tags public` |\n\n## Expanding a whole page\n\n```sh\nc4s resolve some-page.md # writes markdown with tags expanded inline\nc4s resolve some-page.md --format json # writes { content, resolved: [...] }\n```\n\n## Discovery\n\n- `c4s catalog` \u2014 active entity types with counts + version + description + roleNoun + mcpToolsLine per type (smoke test).\n- `c4s describe --type <t> [--view <v>]` \u2014 JSON Schema per view for one type (on-demand).\n- `c4s list-tags` \u2014 all tags with per-type counts.\n- `c4s list-slugs --type endpoint` \u2014 all slugs for a given type.\n\nAll output is JSON (pretty) by default. Use `--compact` for pipelines and\n`--format text` for terminal-friendly output. Errors go to stderr as JSON with\nan exit code > 0.\n\nThe database is opened **read-only** \u2014 `c4s` never mutates the project.\n\n## Asking the spec agent\n\nWhen a question goes beyond resolving entities or pages, `c4s ask` runs a\nsynchronous agent turn against the specification:\n\n```sh\nc4s ask \"<question>\" --ct chat\n```\n\nUnlike the read-only commands above, `c4s ask` requires a running\n`npx @inharness-ai/claude4spec` server (it delegates the turn to the server's agent).\n\n### `PROJECT_NOT_FOUND` when the project dir is a symlink\n\nIf `c4s ask` (or any `c4s` command) returns `PROJECT_NOT_FOUND` even though a\nserver is running, your cwd is most likely reached through a **symlink** (common\nfor `.claude/skills/<name>` that points elsewhere). `c4s` resolves `process.cwd()`\nthrough the symlink to the real path, which is NOT the path registered in\n`~/.claude4spec/workspaces.json`. Pass the registered (symlink) path explicitly \u2014\n`--project` is run through `path.resolve`, which does NOT canonicalize symlinks, so\nit matches the registry exactly:\n\n```sh\nc4s ask \"<question>\" --ct chat --project /abs/path/to/registered/project-dir\n```\n\n### `SERVER_NOT_RECOGNIZED` / `PROJECT_BUILD_FAILED` \u2014 the project failed to build\n\nIf `c4s ask` reports the server is \"not a claude4spec server\", or\n`GET /api/projects/<id>/config` returns `PROJECT_BUILD_FAILED`, the server IS\nrunning but **that project failed to build**. A common cause is the configured\n`writingStyle` skill failing to load: a skill under `.claude/skills/` whose\nfrontmatter `version` exceeds the supported version is skipped at scan time, so\nthe style is \"not a selectable writing-style skill\".\n\n`c4s ask` surfaces the real `PROJECT_BUILD_FAILED` message, which names the cause\n(e.g. `writingStyle \"X\" was found on disk but skipped: version 2 > supported 1`).\nFix the skill's frontmatter (`version` is a format-compat gate \u2014 keep it `1`, don't\nuse it as a content counter) and restart the server.\n";
|
|
@@ -70,5 +70,19 @@ it matches the registry exactly:
|
|
|
70
70
|
\`\`\`sh
|
|
71
71
|
c4s ask "<question>" --ct chat --project /abs/path/to/registered/project-dir
|
|
72
72
|
\`\`\`
|
|
73
|
+
|
|
74
|
+
### \`SERVER_NOT_RECOGNIZED\` / \`PROJECT_BUILD_FAILED\` — the project failed to build
|
|
75
|
+
|
|
76
|
+
If \`c4s ask\` reports the server is "not a claude4spec server", or
|
|
77
|
+
\`GET /api/projects/<id>/config\` returns \`PROJECT_BUILD_FAILED\`, the server IS
|
|
78
|
+
running but **that project failed to build**. A common cause is the configured
|
|
79
|
+
\`writingStyle\` skill failing to load: a skill under \`.claude/skills/\` whose
|
|
80
|
+
frontmatter \`version\` exceeds the supported version is skipped at scan time, so
|
|
81
|
+
the style is "not a selectable writing-style skill".
|
|
82
|
+
|
|
83
|
+
\`c4s ask\` surfaces the real \`PROJECT_BUILD_FAILED\` message, which names the cause
|
|
84
|
+
(e.g. \`writingStyle "X" was found on disk but skipped: version 2 > supported 1\`).
|
|
85
|
+
Fix the skill's frontmatter (\`version\` is a format-compat gate — keep it \`1\`, don't
|
|
86
|
+
use it as a content counter) and restart the server.
|
|
73
87
|
`;
|
|
74
88
|
//# sourceMappingURL=spec-reader-template.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec-reader-template.js","sourceRoot":"","sources":["../../../src/server/external-skills/spec-reader-template.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;CAItC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG
|
|
1
|
+
{"version":3,"file":"spec-reader-template.js","sourceRoot":"","sources":["../../../src/server/external-skills/spec-reader-template.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;CAItC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiF/B,CAAC"}
|