@inharness-ai/claude4spec 1.0.14 → 1.0.16
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/CHANGELOG.md +31 -0
- package/dist/bin/c4s/args.d.ts +2 -0
- package/dist/bin/c4s/args.js +3 -0
- package/dist/bin/c4s/args.js.map +1 -1
- package/dist/bin/c4s/commands/ask.js +2 -0
- package/dist/bin/c4s/commands/ask.js.map +1 -1
- package/dist/bin/c4s/commands/catalog.js +1 -1
- package/dist/bin/c4s/commands/catalog.js.map +1 -1
- package/dist/bin/c4s/commands/describe.d.ts +2 -0
- package/dist/bin/c4s/commands/describe.js +22 -0
- package/dist/bin/c4s/commands/describe.js.map +1 -0
- package/dist/bin/c4s/commands/find-references.d.ts +13 -0
- package/dist/bin/c4s/commands/find-references.js +81 -0
- package/dist/bin/c4s/commands/find-references.js.map +1 -0
- package/dist/bin/c4s/context.d.ts +4 -3
- package/dist/bin/c4s/context.js +17 -6
- 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/type-validation.d.ts +3 -0
- package/dist/bin/c4s/type-validation.js +14 -0
- package/dist/bin/c4s/type-validation.js.map +1 -1
- package/dist/bin/c4s-mcp.d.ts +1 -1
- package/dist/bin/c4s-mcp.js +23 -12
- package/dist/bin/c4s-mcp.js.map +1 -1
- package/dist/bin/c4s.js +20 -3
- package/dist/bin/c4s.js.map +1 -1
- package/dist/bin/claude4spec.js +122 -74
- package/dist/bin/claude4spec.js.map +1 -1
- package/dist/client/assets/{arc-E0e7X_zn.js → arc-DrA6qHTw.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-BzlqOVZv.js → architectureDiagram-3BPJPVTR-TEnwTtVX.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-BIQcApN7.js → blockDiagram-GPEHLZMM-txRnQm5w.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-CDU0V1yk.js → c4Diagram-AAUBKEIU-ad8X3Q8n.js} +1 -1
- package/dist/client/assets/channel-zmRfuI3H.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-PtDSwC5f.js → chunk-2J33WTMH-Cp08Xa7f.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-DTUPWrSO.js → chunk-4BX2VUAB-Dc_0On6j.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-Cpd59xZT.js → chunk-55IACEB6-8d1qQ5z6.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-C4DOvpJT.js → chunk-727SXJPM-TZenviWx.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-CtjeHPBB.js → chunk-AQP2D5EJ-DKRRWy-J.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-CZA3OvVr.js → chunk-FMBD7UC4-DLEErJWK.js} +1 -1
- package/dist/client/assets/{chunk-ND2GUHAM-Cbx6nQHm.js → chunk-ND2GUHAM-pKGgwz_0.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-3DunELI_.js → chunk-QZHKN3VN-DVcNz8ng.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-B9RFgPu-.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-B9RFgPu-.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-CKYJnuL7.js → cose-bilkent-S5V4N54A-DZejbxEG.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-BrvRwrr_.js → dagre-BM42HDAG-DrPrkFcW.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-BaVLuzcD.js → diagram-2AECGRRQ-Dpn8TJa2.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-9Cu7Wa7J.js → diagram-5GNKFQAL-BxkzEc_t.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-XKiCVdjO.js → diagram-KO2AKTUF-KG0o4LQ7.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-DerecU5v.js → diagram-LMA3HP47-CJ-AjQPt.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-BWcREvZ9.js → diagram-OG6HWLK6-D_FG9cDJ.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-DU3BBQJY.js → erDiagram-TEJ5UH35-DllhUlzY.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-DXO_IJeR.js → flowDiagram-I6XJVG4X-Bg3OotXu.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-CXiFZEPx.js → ganttDiagram-6RSMTGT7-BUpUL2Cj.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DHewdln-.js → gitGraphDiagram-PVQCEYII-DMRhyWth.js} +1 -1
- package/dist/client/assets/{index-DT5g2AtL.js → index-BB2RmhGR.js} +1 -1
- package/dist/client/assets/index-BXzOTCgN.css +1 -0
- package/dist/client/assets/index-DRFbyGvK.js +788 -0
- package/dist/client/assets/{index-DD0GkjkG.js → index-Daewu-VD.js} +1 -1
- package/dist/client/assets/{infoDiagram-5YYISTIA-CN40PAGW.js → infoDiagram-5YYISTIA-Bq9D64Ar.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-B8KsyuPk.js → ishikawaDiagram-YF4QCWOH-DIaKHHF-.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-BlEb3E_P.js → journeyDiagram-JHISSGLW-gQWGLTeZ.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-B080CGS9.js → kanban-definition-UN3LZRKU-vRgZ5RjE.js} +1 -1
- package/dist/client/assets/{linear-D6Tg-IET.js → linear-B4a11szP.js} +1 -1
- package/dist/client/assets/{mermaid.core-DP18nW3T.js → mermaid.core-JhUbsJFB.js} +4 -4
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-bfo7Qm5I.js → mindmap-definition-RKZ34NQL-ZH-Oz_D-.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-ZsPztPu6.js → pieDiagram-4H26LBE5-6rpNrJR6.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-DKrTleIL.js → quadrantDiagram-W4KKPZXB-DpTKtxEM.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-D4YX8ZgG.js → requirementDiagram-4Y6WPE33-DpDvZkrK.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-Bo-xm6Mc.js → sankeyDiagram-5OEKKPKP-KKjWCTYP.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-CozgdKp6.js → sequenceDiagram-3UESZ5HK-BCmXos1U.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-CiK61MwV.js → stateDiagram-AJRCARHV-Xq7jqpMj.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-C3mDHsxD.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-CgHoguI7.js → timeline-definition-PNZ67QCA-CMmq8p5q.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-TY32dxQb.js → vennDiagram-CIIHVFJN-DgK-w2Jv.js} +1 -1
- package/dist/client/assets/{wardley-L42UT6IY-C6Q7VFwH.js → wardley-L42UT6IY-C5CwlFHh.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-nZLnVsQL.js → wardleyDiagram-YWT4CUSO-D47CtDSc.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-DHdYRHEr.js → xychartDiagram-2RQKCTM6-C1M_xTVv.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/core/ask/run-ask.d.ts +3 -1
- package/dist/core/ask/run-ask.js +75 -54
- package/dist/core/ask/run-ask.js.map +1 -1
- package/dist/core/references/find-references.d.ts +13 -0
- package/dist/core/references/find-references.js +41 -0
- package/dist/core/references/find-references.js.map +1 -0
- package/dist/core/references/index.d.ts +2 -0
- package/dist/core/references/index.js +2 -0
- package/dist/core/references/index.js.map +1 -0
- package/dist/core/references/types.d.ts +45 -0
- package/dist/core/references/types.js +9 -0
- package/dist/core/references/types.js.map +1 -0
- package/dist/core/workspace/resolve.d.ts +29 -0
- package/dist/core/workspace/resolve.js +80 -0
- package/dist/core/workspace/resolve.js.map +1 -0
- package/dist/server/config.d.ts +58 -6
- package/dist/server/config.js +94 -19
- package/dist/server/config.js.map +1 -1
- package/dist/server/core/plugin-host/cli-engine.d.ts +8 -0
- package/dist/server/core/plugin-host/cli-engine.js +16 -0
- package/dist/server/core/plugin-host/cli-engine.js.map +1 -0
- package/dist/server/core/plugin-host/cross-cutting.js +1 -1
- package/dist/server/core/plugin-host/cross-cutting.js.map +1 -1
- package/dist/server/core/plugin-host/entities-router.d.ts +3 -1
- package/dist/server/core/plugin-host/entities-router.js +24 -19
- package/dist/server/core/plugin-host/entities-router.js.map +1 -1
- package/dist/server/core/plugin-host/host.js +4 -9
- package/dist/server/core/plugin-host/host.js.map +1 -1
- package/dist/server/core/plugin-host/project-host.d.ts +38 -0
- package/dist/server/core/plugin-host/project-host.js +118 -0
- package/dist/server/core/plugin-host/project-host.js.map +1 -0
- package/dist/server/core/plugin-host/registry.d.ts +14 -0
- package/dist/server/core/plugin-host/registry.js +26 -0
- package/dist/server/core/plugin-host/registry.js.map +1 -0
- package/dist/server/core/plugin-host/serialization-engine.d.ts +38 -8
- package/dist/server/core/plugin-host/serialization-engine.js +63 -39
- package/dist/server/core/plugin-host/serialization-engine.js.map +1 -1
- package/dist/server/core/plugin-host/types.d.ts +49 -27
- package/dist/server/db/index.d.ts +8 -1
- package/dist/server/db/index.js +12 -3
- package/dist/server/db/index.js.map +1 -1
- package/dist/server/db/migrations/035_m29_slug_identity.sql +248 -0
- package/dist/server/db/readonly.d.ts +8 -3
- package/dist/server/db/readonly.js +7 -4
- package/dist/server/db/readonly.js.map +1 -1
- package/dist/server/domain/raw-entity-reader.d.ts +5 -5
- package/dist/server/domain/raw-entity-reader.js +34 -39
- package/dist/server/domain/raw-entity-reader.js.map +1 -1
- package/dist/server/entities/ac/ac-analysis.service.d.ts +54 -0
- package/dist/server/entities/ac/ac-analysis.service.js +162 -0
- package/dist/server/entities/ac/ac-analysis.service.js.map +1 -0
- package/dist/server/entities/ac/mcp-server.d.ts +10 -2
- package/dist/server/entities/ac/mcp-server.js +34 -3
- package/dist/server/entities/ac/mcp-server.js.map +1 -1
- package/dist/server/entities/ac/plugin.d.ts +3 -1
- package/dist/server/entities/ac/plugin.js +9 -5
- package/dist/server/entities/ac/plugin.js.map +1 -1
- package/dist/server/entities/ac/serializer.js +1 -1
- package/dist/server/entities/ac/serializer.js.map +1 -1
- package/dist/server/entities/ac/services.d.ts +19 -7
- package/dist/server/entities/ac/services.js +65 -42
- package/dist/server/entities/ac/services.js.map +1 -1
- package/dist/server/entities/ac/system-prompt.js +1 -8
- package/dist/server/entities/ac/system-prompt.js.map +1 -1
- package/dist/server/entities/database-table/mcp-server.d.ts +2 -2
- package/dist/server/entities/database-table/mcp-server.js +5 -2
- package/dist/server/entities/database-table/mcp-server.js.map +1 -1
- package/dist/server/entities/database-table/plugin.d.ts +3 -1
- package/dist/server/entities/database-table/plugin.js +6 -5
- package/dist/server/entities/database-table/plugin.js.map +1 -1
- package/dist/server/entities/database-table/routes.d.ts +2 -2
- package/dist/server/entities/database-table/serializer.js +1 -1
- package/dist/server/entities/database-table/serializer.js.map +1 -1
- package/dist/server/entities/database-table/services.d.ts +19 -7
- package/dist/server/entities/database-table/services.js +77 -49
- package/dist/server/entities/database-table/services.js.map +1 -1
- package/dist/server/entities/database-table/system-prompt.js +1 -1
- package/dist/server/entities/database-table/system-prompt.js.map +1 -1
- package/dist/server/entities/dto/mcp-server.d.ts +2 -2
- package/dist/server/entities/dto/mcp-server.js +5 -2
- package/dist/server/entities/dto/mcp-server.js.map +1 -1
- package/dist/server/entities/dto/plugin.d.ts +3 -1
- package/dist/server/entities/dto/plugin.js +6 -5
- package/dist/server/entities/dto/plugin.js.map +1 -1
- package/dist/server/entities/dto/serializer.js +2 -2
- package/dist/server/entities/dto/serializer.js.map +1 -1
- package/dist/server/entities/dto/services.d.ts +19 -7
- package/dist/server/entities/dto/services.js +73 -49
- package/dist/server/entities/dto/services.js.map +1 -1
- package/dist/server/entities/dto/system-prompt.js +1 -1
- package/dist/server/entities/dto/system-prompt.js.map +1 -1
- package/dist/server/entities/endpoint/mcp-server.d.ts +2 -2
- package/dist/server/entities/endpoint/mcp-server.js +5 -2
- package/dist/server/entities/endpoint/mcp-server.js.map +1 -1
- package/dist/server/entities/endpoint/plugin.d.ts +3 -1
- package/dist/server/entities/endpoint/plugin.js +6 -5
- package/dist/server/entities/endpoint/plugin.js.map +1 -1
- package/dist/server/entities/endpoint/serializer.js +4 -4
- package/dist/server/entities/endpoint/serializer.js.map +1 -1
- package/dist/server/entities/endpoint/services.d.ts +21 -9
- package/dist/server/entities/endpoint/services.js +94 -65
- package/dist/server/entities/endpoint/services.js.map +1 -1
- package/dist/server/entities/endpoint/system-prompt.js +1 -1
- package/dist/server/entities/endpoint/system-prompt.js.map +1 -1
- package/dist/server/entities/mutate-opts.d.ts +15 -0
- package/dist/server/entities/mutate-opts.js +2 -0
- package/dist/server/entities/mutate-opts.js.map +1 -0
- package/dist/server/entities/ui-view/mcp-server.d.ts +2 -2
- package/dist/server/entities/ui-view/mcp-server.js +5 -2
- package/dist/server/entities/ui-view/mcp-server.js.map +1 -1
- package/dist/server/entities/ui-view/plugin.d.ts +3 -1
- package/dist/server/entities/ui-view/plugin.js +6 -5
- package/dist/server/entities/ui-view/plugin.js.map +1 -1
- package/dist/server/entities/ui-view/routes.d.ts +2 -2
- package/dist/server/entities/ui-view/serializer.js +1 -1
- package/dist/server/entities/ui-view/serializer.js.map +1 -1
- package/dist/server/entities/ui-view/services.d.ts +19 -7
- package/dist/server/entities/ui-view/services.js +68 -44
- package/dist/server/entities/ui-view/services.js.map +1 -1
- package/dist/server/entities/ui-view/system-prompt.d.ts +0 -5
- package/dist/server/entities/ui-view/system-prompt.js +3 -7
- package/dist/server/entities/ui-view/system-prompt.js.map +1 -1
- package/dist/server/external-skills/brief-implementer-template.d.ts +1 -1
- package/dist/server/external-skills/brief-implementer-template.js +1 -1
- package/dist/server/external-skills/spec-reader-template.d.ts +1 -1
- package/dist/server/external-skills/spec-reader-template.js +3 -2
- package/dist/server/external-skills/spec-reader-template.js.map +1 -1
- package/dist/server/fs/entities-watcher.d.ts +31 -0
- package/dist/server/fs/entities-watcher.js +68 -0
- package/dist/server/fs/entities-watcher.js.map +1 -0
- package/dist/server/fs/watcher.d.ts +2 -2
- package/dist/server/fs/watcher.js +7 -1
- package/dist/server/fs/watcher.js.map +1 -1
- package/dist/server/index.d.ts +11 -1
- package/dist/server/index.js +134 -639
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/c4s-reader.d.ts +2 -2
- package/dist/server/mcp/c4s-reader.js +41 -4
- package/dist/server/mcp/c4s-reader.js.map +1 -1
- package/dist/server/mcp/c4s-tools.js +2 -0
- package/dist/server/mcp/c4s-tools.js.map +1 -1
- package/dist/server/mcp/ensure-mcp-json.d.ts +9 -2
- package/dist/server/mcp/ensure-mcp-json.js +18 -4
- package/dist/server/mcp/ensure-mcp-json.js.map +1 -1
- package/dist/server/mcp/reference-tools.d.ts +8 -2
- package/dist/server/mcp/reference-tools.js +52 -179
- package/dist/server/mcp/reference-tools.js.map +1 -1
- package/dist/server/mcp/release-tools/index.d.ts +2 -2
- package/dist/server/routes/agent-turn.d.ts +41 -7
- package/dist/server/routes/agent-turn.js +84 -20
- package/dist/server/routes/agent-turn.js.map +1 -1
- package/dist/server/routes/chat.js +47 -15
- package/dist/server/routes/chat.js.map +1 -1
- package/dist/server/routes/config.d.ts +24 -0
- package/dist/server/routes/config.js +231 -0
- package/dist/server/routes/config.js.map +1 -0
- package/dist/server/routes/references.d.ts +2 -1
- package/dist/server/routes/references.js +4 -5
- package/dist/server/routes/references.js.map +1 -1
- package/dist/server/routes/releases.d.ts +2 -2
- package/dist/server/routes/static.d.ts +11 -0
- package/dist/server/routes/static.js +44 -0
- package/dist/server/routes/static.js.map +1 -0
- package/dist/server/routes/threads.js +14 -2
- package/dist/server/routes/threads.js.map +1 -1
- package/dist/server/serialization/auto-schema.d.ts +2 -1
- package/dist/server/serialization/auto-schema.js +5 -6
- package/dist/server/serialization/auto-schema.js.map +1 -1
- package/dist/server/serialization/registerAll.d.ts +7 -6
- package/dist/server/serialization/registerAll.js +17 -6
- package/dist/server/serialization/registerAll.js.map +1 -1
- package/dist/server/serialization/resolve-page.d.ts +2 -2
- package/dist/server/serialization/serializers/section.d.ts +6 -1
- package/dist/server/serialization/serializers/section.js +6 -3
- package/dist/server/serialization/serializers/section.js.map +1 -1
- package/dist/server/services/brief.d.ts +2 -2
- package/dist/server/services/chat-context.d.ts +24 -0
- package/dist/server/services/chat-context.js +70 -13
- package/dist/server/services/chat-context.js.map +1 -1
- package/dist/server/services/entity-indexer.d.ts +42 -0
- package/dist/server/services/entity-indexer.js +179 -0
- package/dist/server/services/entity-indexer.js.map +1 -0
- package/dist/server/services/entity-store.d.ts +68 -0
- package/dist/server/services/entity-store.js +162 -0
- package/dist/server/services/entity-store.js.map +1 -0
- package/dist/server/services/entity-writer.d.ts +12 -1
- package/dist/server/services/entity-writer.js +22 -11
- package/dist/server/services/entity-writer.js.map +1 -1
- package/dist/server/services/git.js +6 -1
- package/dist/server/services/git.js.map +1 -1
- package/dist/server/services/pages-frontmatter-indexer.d.ts +2 -2
- package/dist/server/services/pages-link-indexer.d.ts +2 -2
- package/dist/server/services/pages.d.ts +2 -0
- package/dist/server/services/pages.js +24 -9
- package/dist/server/services/pages.js.map +1 -1
- package/dist/server/services/plan.d.ts +2 -2
- package/dist/server/services/references.d.ts +25 -0
- package/dist/server/services/references.js +102 -21
- package/dist/server/services/references.js.map +1 -1
- package/dist/server/services/release-bundle.d.ts +0 -1
- package/dist/server/services/release-bundle.js +0 -1
- package/dist/server/services/release-bundle.js.map +1 -1
- package/dist/server/services/release-import.d.ts +2 -0
- package/dist/server/services/release-import.js +6 -4
- package/dist/server/services/release-import.js.map +1 -1
- package/dist/server/services/release.d.ts +10 -10
- package/dist/server/services/release.js +32 -63
- package/dist/server/services/release.js.map +1 -1
- package/dist/server/services/section-indexer.d.ts +4 -3
- package/dist/server/services/section-indexer.js +8 -9
- package/dist/server/services/section-indexer.js.map +1 -1
- package/dist/server/services/skill-registry.d.ts +28 -1
- package/dist/server/services/skill-registry.js +51 -10
- package/dist/server/services/skill-registry.js.map +1 -1
- package/dist/server/services/slug.js +6 -0
- package/dist/server/services/slug.js.map +1 -1
- package/dist/server/services/static-html.d.ts +24 -0
- package/dist/server/services/static-html.js +49 -0
- package/dist/server/services/static-html.js.map +1 -0
- package/dist/server/services/tags.d.ts +13 -3
- package/dist/server/services/tags.js +65 -26
- package/dist/server/services/tags.js.map +1 -1
- package/dist/server/services/todos-indexer.d.ts +2 -2
- package/dist/server/services/versions.d.ts +7 -7
- package/dist/server/services/versions.js +34 -37
- package/dist/server/services/versions.js.map +1 -1
- package/dist/server/workspace/bootstrap.d.ts +42 -0
- package/dist/server/workspace/bootstrap.js +73 -0
- package/dist/server/workspace/bootstrap.js.map +1 -0
- package/dist/server/workspace/context-cache.d.ts +48 -0
- package/dist/server/workspace/context-cache.js +147 -0
- package/dist/server/workspace/context-cache.js.map +1 -0
- package/dist/server/workspace/db-migration.d.ts +11 -0
- package/dist/server/workspace/db-migration.js +44 -0
- package/dist/server/workspace/db-migration.js.map +1 -0
- package/dist/server/workspace/middleware.d.ts +15 -0
- package/dist/server/workspace/middleware.js +36 -0
- package/dist/server/workspace/middleware.js.map +1 -0
- package/dist/server/workspace/project-context.d.ts +65 -0
- package/dist/server/workspace/project-context.js +655 -0
- package/dist/server/workspace/project-context.js.map +1 -0
- package/dist/server/workspace/project-id.d.ts +7 -0
- package/dist/server/workspace/project-id.js +11 -0
- package/dist/server/workspace/project-id.js.map +1 -0
- package/dist/server/workspace/registry.d.ts +58 -0
- package/dist/server/workspace/registry.js +264 -0
- package/dist/server/workspace/registry.js.map +1 -0
- package/dist/server/workspace/routes.d.ts +21 -0
- package/dist/server/workspace/routes.js +181 -0
- package/dist/server/workspace/routes.js.map +1 -0
- package/dist/server/workspace/types.d.ts +30 -0
- package/dist/server/workspace/types.js +6 -0
- package/dist/server/workspace/types.js.map +1 -0
- package/dist/server/ws/gateway.d.ts +12 -2
- package/dist/server/ws/gateway.js +51 -9
- package/dist/server/ws/gateway.js.map +1 -1
- package/dist/server/ws/project-emitter.d.ts +17 -0
- package/dist/server/ws/project-emitter.js +12 -0
- package/dist/server/ws/project-emitter.js.map +1 -0
- package/dist/shared/entities.d.ts +2 -2
- package/dist/shared/languages.d.ts +17 -0
- package/dist/shared/languages.js +31 -0
- package/dist/shared/languages.js.map +1 -0
- package/dist/shared/types.d.ts +11 -0
- package/dist/shared/xml-tags.d.ts +8 -0
- package/dist/shared/xml-tags.js +24 -0
- package/dist/shared/xml-tags.js.map +1 -1
- package/package.json +10 -3
- package/dist/client/assets/channel-BqjILLUr.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-LjT84-kK.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-LjT84-kK.js +0 -1
- package/dist/client/assets/index-BTXWIk4x.css +0 -1
- package/dist/client/assets/index-DcIG_8JB.js +0 -760
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-C6-8M5Sb.js +0 -1
|
@@ -0,0 +1,655 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import { readConfig } from '../config.js';
|
|
5
|
+
import { openDb } from '../db/index.js';
|
|
6
|
+
import { PagesService } from '../services/pages.js';
|
|
7
|
+
import { pagesRouter } from '../routes/pages.js';
|
|
8
|
+
import { StaticHtmlService } from '../services/static-html.js';
|
|
9
|
+
import { staticRouter } from '../routes/static.js';
|
|
10
|
+
import { tagsRouter } from '../routes/tags.js';
|
|
11
|
+
import { entitiesRouter } from '../core/plugin-host/entities-router.js';
|
|
12
|
+
import { referencesRouter } from '../routes/references.js';
|
|
13
|
+
import { TagsService, DomainError } from '../services/tags.js';
|
|
14
|
+
import { VersionService } from '../services/versions.js';
|
|
15
|
+
import { ReferencesService } from '../services/references.js';
|
|
16
|
+
import { ChatService } from '../services/chat.js';
|
|
17
|
+
import { SectionsService } from '../services/sections.js';
|
|
18
|
+
import { registerExtensionReferenceType } from '../../shared/reference-extensions.js';
|
|
19
|
+
import { SUPPORTED_LANGUAGES, isSupportedLanguage } from '../../shared/languages.js';
|
|
20
|
+
import { PlanService } from '../services/plan.js';
|
|
21
|
+
import { plansRouter } from '../routes/plans.js';
|
|
22
|
+
import { BriefService } from '../services/brief.js';
|
|
23
|
+
import { briefsRouter } from '../routes/briefs.js';
|
|
24
|
+
import { PatchService } from '../services/patch.js';
|
|
25
|
+
import { patchesRouter } from '../routes/patches.js';
|
|
26
|
+
import { RemoteAuthService } from '../services/remote-auth.js';
|
|
27
|
+
import { RemoteHttpClient, assertRemoteApiReachable } from '../services/remote-http-client.js';
|
|
28
|
+
import { remoteAccountRouter } from '../routes/remote-account.js';
|
|
29
|
+
import { remoteProjectRouter } from '../routes/remote-project.js';
|
|
30
|
+
import { PagesFrontmatterIndexer } from '../services/pages-frontmatter-indexer.js';
|
|
31
|
+
import { SectionIndexerService } from '../services/section-indexer.js';
|
|
32
|
+
import { TodosIndexerService } from '../services/todos-indexer.js';
|
|
33
|
+
import { PagesLinkIndexerService } from '../services/pages-link-indexer.js';
|
|
34
|
+
import { PageSerializer } from '../services/page-serializer.js';
|
|
35
|
+
import { PageVersionService } from '../services/page-version.js';
|
|
36
|
+
import { RawEntityReader } from '../domain/raw-entity-reader.js';
|
|
37
|
+
import { ReleaseService } from '../services/release.js';
|
|
38
|
+
import { releasesRouter } from '../routes/releases.js';
|
|
39
|
+
import { ReleasePushService } from '../services/release-push.js';
|
|
40
|
+
import { releasePushesRouter } from '../routes/release-pushes.js';
|
|
41
|
+
import { ReleaseImportService, rollbackClone } from '../services/release-import.js';
|
|
42
|
+
import { createReleaseToolsServer } from '../mcp/release-tools/index.js';
|
|
43
|
+
import { GitService } from '../services/git.js';
|
|
44
|
+
import { gitRouter } from '../routes/git.js';
|
|
45
|
+
import { PagesWatcher } from '../fs/watcher.js';
|
|
46
|
+
import { EntitiesWatcher } from '../fs/entities-watcher.js';
|
|
47
|
+
import { EntityStore } from '../services/entity-store.js';
|
|
48
|
+
import { EntityIndexerService } from '../services/entity-indexer.js';
|
|
49
|
+
import { createReferenceToolsServer } from '../mcp/reference-tools.js';
|
|
50
|
+
import { SkillRegistry, SkillResolver, findSkillsRoots } from '../services/skill-registry.js';
|
|
51
|
+
import { chatRouter } from '../routes/chat.js';
|
|
52
|
+
import { threadsRouter } from '../routes/threads.js';
|
|
53
|
+
import { sectionsRouter } from '../routes/sections.js';
|
|
54
|
+
import { todosRouter } from '../routes/todos.js';
|
|
55
|
+
import { pageLinksRouter } from '../routes/page-links.js';
|
|
56
|
+
import { errorHandler } from '../routes/errors.js';
|
|
57
|
+
import { configRouter } from '../routes/config.js';
|
|
58
|
+
import { SerializationEngine } from '../core/plugin-host/serialization-engine.js';
|
|
59
|
+
import { sectionSerializer } from '../serialization/serializers/section.js';
|
|
60
|
+
import { pluginHostRouter } from '../core/plugin-host/cross-cutting.js';
|
|
61
|
+
import { ProjectWsEmitter } from '../ws/project-emitter.js';
|
|
62
|
+
import { projectIdForCwd } from './project-id.js';
|
|
63
|
+
import { ensureWelcomePage } from './bootstrap.js';
|
|
64
|
+
// M06 registers <section_ref/> as the 6th XML reference type via the M19
|
|
65
|
+
// extension reference types slot. Registration is PROCESS-level (tag shape is
|
|
66
|
+
// static); the per-project anchor validation lives in reference-tools, which
|
|
67
|
+
// owns a per-context SectionsService — a validate closure here would leak one
|
|
68
|
+
// project's sections into every other context (M31).
|
|
69
|
+
registerExtensionReferenceType({
|
|
70
|
+
tag: 'section_ref',
|
|
71
|
+
attrOrder: ['anchor'],
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* M29: one-time best-effort backup of the derived SQLite before a DB→text
|
|
75
|
+
* export / divergent-rebuild, so the prior index is recoverable. Idempotent —
|
|
76
|
+
* skips if the `.pre-migration.bak` already exists. M31: follows the workspace
|
|
77
|
+
* slot path (the DB no longer lives in the project dir).
|
|
78
|
+
*/
|
|
79
|
+
function backupDbBeforeMigration(slotDir) {
|
|
80
|
+
const src = path.join(slotDir, 'db.sqlite');
|
|
81
|
+
const bak = path.join(slotDir, 'db.sqlite.pre-migration.bak');
|
|
82
|
+
try {
|
|
83
|
+
if (fs.existsSync(src) && !fs.existsSync(bak))
|
|
84
|
+
fs.copyFileSync(src, bak);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
console.warn('[m29] db backup failed:', err.message);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* M31: builds one fully-wired project — DB, services, watchers, indexers and
|
|
92
|
+
* the per-context router. Mechanical carve of the former startServer body;
|
|
93
|
+
* handlers are byte-identical, only the mount prefixes lost their `/api`.
|
|
94
|
+
* Await cost ≈ entityIndexer.indexAll() (<1s budget); section/todos/link
|
|
95
|
+
* indexers stay fire-and-forget.
|
|
96
|
+
*/
|
|
97
|
+
export async function buildProjectContext(deps) {
|
|
98
|
+
// Partial-build cleanup: resources acquired before a build failure (db
|
|
99
|
+
// handle, watcher fds) are released in reverse order — a failed build is
|
|
100
|
+
// cached as a 500 for THIS project only and must leak nothing.
|
|
101
|
+
const cleanup = [];
|
|
102
|
+
try {
|
|
103
|
+
return await buildInner(deps, cleanup);
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
for (const fn of cleanup.reverse()) {
|
|
107
|
+
try {
|
|
108
|
+
await fn();
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
/* best-effort */
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function buildInner(deps, cleanup) {
|
|
118
|
+
const { registry, workspace, cwd, gateway, mode } = deps;
|
|
119
|
+
const projectId = projectIdForCwd(cwd);
|
|
120
|
+
const router = Router();
|
|
121
|
+
// M31: every former WsGateway consumer now broadcasts into this project's
|
|
122
|
+
// room only — the emitter is signature-compatible (`broadcast(event)`).
|
|
123
|
+
const ws = new ProjectWsEmitter(gateway, projectId);
|
|
124
|
+
// M31: per-project agent-turn registries (was module-global in agent-turn.ts).
|
|
125
|
+
const activeAdapters = new Map();
|
|
126
|
+
const pendingInputs = new Map();
|
|
127
|
+
const skillRegistry = SkillRegistry.load(findSkillsRoots(cwd));
|
|
128
|
+
const bootConfig = readConfig(cwd);
|
|
129
|
+
// Effective pagesDir precedence: CLI flag > config.json > hardcoded 'pages'.
|
|
130
|
+
const pagesDir = deps.pagesDirOverride ?? bootConfig.pagesDir ?? 'pages';
|
|
131
|
+
// M21: briefsDir, default '.claude4spec/briefs'. Walidacja: musi byc relative,
|
|
132
|
+
// nie moze uciekac z cwd. Kolizja z pagesDir → tylko warn (user moze mocno
|
|
133
|
+
// celowo umieszczac brief'y w katalogu pages — frontmatter.type='brief'
|
|
134
|
+
// pelni hidden-tree filter).
|
|
135
|
+
const briefsDir = bootConfig.briefsDir ?? '.claude4spec/briefs';
|
|
136
|
+
if (path.isAbsolute(briefsDir)) {
|
|
137
|
+
throw new Error(`config.json: briefsDir must be relative to cwd, got: ${briefsDir}`);
|
|
138
|
+
}
|
|
139
|
+
const briefsAbs = path.resolve(cwd, briefsDir);
|
|
140
|
+
const briefsRel = path.relative(cwd, briefsAbs);
|
|
141
|
+
if (briefsRel.startsWith('..') || path.isAbsolute(briefsRel)) {
|
|
142
|
+
throw new Error(`config.json: briefsDir must not escape project root, got: ${briefsDir}`);
|
|
143
|
+
}
|
|
144
|
+
if (briefsDir === pagesDir) {
|
|
145
|
+
console.warn(`[config] briefsDir === pagesDir ("${pagesDir}") — brief files will be visible in both indexers`);
|
|
146
|
+
}
|
|
147
|
+
// M23: patchesDir, default '.claude4spec/patches'. Same validation as briefsDir.
|
|
148
|
+
const patchesDir = bootConfig.patchesDir ?? '.claude4spec/patches';
|
|
149
|
+
if (path.isAbsolute(patchesDir)) {
|
|
150
|
+
throw new Error(`config.json: patchesDir must be relative to cwd, got: ${patchesDir}`);
|
|
151
|
+
}
|
|
152
|
+
const patchesAbs = path.resolve(cwd, patchesDir);
|
|
153
|
+
const patchesRel = path.relative(cwd, patchesAbs);
|
|
154
|
+
if (patchesRel.startsWith('..') || path.isAbsolute(patchesRel)) {
|
|
155
|
+
throw new Error(`config.json: patchesDir must not escape project root, got: ${patchesDir}`);
|
|
156
|
+
}
|
|
157
|
+
if (patchesDir === pagesDir || patchesDir === briefsDir) {
|
|
158
|
+
console.warn(`[config] patchesDir collides with pagesDir/briefsDir ("${patchesDir}") — patch files will be visible in multiple indexers`);
|
|
159
|
+
}
|
|
160
|
+
// M29: entitiesDir, default '.claude4spec/entities'. Same path-safety as
|
|
161
|
+
// briefsDir/patchesDir — but this directory is COMMITTED to git (source of
|
|
162
|
+
// truth for entities; SQLite is a derived index rebuilt from it at boot).
|
|
163
|
+
const entitiesDir = bootConfig.entitiesDir ?? '.claude4spec/entities';
|
|
164
|
+
if (path.isAbsolute(entitiesDir)) {
|
|
165
|
+
throw new Error(`config.json: entitiesDir must be relative to cwd, got: ${entitiesDir}`);
|
|
166
|
+
}
|
|
167
|
+
const entitiesAbs = path.resolve(cwd, entitiesDir);
|
|
168
|
+
const entitiesRel = path.relative(cwd, entitiesAbs);
|
|
169
|
+
if (entitiesRel.startsWith('..') || path.isAbsolute(entitiesRel)) {
|
|
170
|
+
throw new Error(`config.json: entitiesDir must not escape project root, got: ${entitiesDir}`);
|
|
171
|
+
}
|
|
172
|
+
// M01 (0.1.36): resolve the remote base URL with precedence
|
|
173
|
+
// `--remote-url` flag (deps) > config.json > prod constant. The prod-constant
|
|
174
|
+
// fallback lives in RemoteHttpClient; here `null` means "use prod".
|
|
175
|
+
const remoteApiUrl = deps.remoteApiUrl ?? bootConfig.remoteApiUrl;
|
|
176
|
+
// M24: an explicit remoteApiUrl override (flag or config.json) must be a valid,
|
|
177
|
+
// reachable host — hard error at build, no fallback to the production constant.
|
|
178
|
+
// M31: failure is a per-project build failure (500), not a boot failure.
|
|
179
|
+
if (remoteApiUrl != null && remoteApiUrl.trim() !== '') {
|
|
180
|
+
await assertRemoteApiReachable(remoteApiUrl);
|
|
181
|
+
}
|
|
182
|
+
const pluginHost = deps.pluginRegistry.consolidate(bootConfig.entities);
|
|
183
|
+
const hostState = pluginHost.partition();
|
|
184
|
+
console.log(`[plugin-host] active: [${hostState.active.join(', ') || '∅'}]` +
|
|
185
|
+
(hostState.inactive.length ? `, inactive: [${hostState.inactive.join(', ')}]` : '') +
|
|
186
|
+
(hostState.unknown.length ? `, unknown: [${hostState.unknown.join(', ')}]` : ''));
|
|
187
|
+
const initialWritingStyle = bootConfig.writingStyle;
|
|
188
|
+
if (initialWritingStyle !== null && !skillRegistry.isSelectable(initialWritingStyle)) {
|
|
189
|
+
const available = skillRegistry.listSelectable().map((s) => s.slug).join(', ') || '(none)';
|
|
190
|
+
throw new Error(`config.json: writingStyle "${initialWritingStyle}" not a selectable writing-style skill. Available: ${available}`);
|
|
191
|
+
}
|
|
192
|
+
// 0.1.51: fail fast on a hand-edited language value outside SUPPORTED_LANGUAGES so
|
|
193
|
+
// a bogus display name never reaches the system prompt. PATCH /config enforces
|
|
194
|
+
// the same membership at runtime.
|
|
195
|
+
if (bootConfig.language !== null && !isSupportedLanguage(bootConfig.language)) {
|
|
196
|
+
throw new Error(`config.json: language "${bootConfig.language}" not supported. Available: ${SUPPORTED_LANGUAGES.join(', ')}`);
|
|
197
|
+
}
|
|
198
|
+
const initialConvLang = bootConfig.agent?.conversationalLanguage ?? null;
|
|
199
|
+
if (initialConvLang !== null && !isSupportedLanguage(initialConvLang)) {
|
|
200
|
+
throw new Error(`config.json: agent.conversationalLanguage "${initialConvLang}" not supported. Available: ${SUPPORTED_LANGUAGES.join(', ')}`);
|
|
201
|
+
}
|
|
202
|
+
const skillResolver = new SkillResolver(skillRegistry, cwd);
|
|
203
|
+
const db = openDb(workspace, cwd);
|
|
204
|
+
cleanup.push(() => db.close());
|
|
205
|
+
const dbSlotDir = registry.slotDir(workspace, projectId);
|
|
206
|
+
const pages = new PagesService(cwd, pagesDir);
|
|
207
|
+
await pages.ensureRoot();
|
|
208
|
+
// M30: static file server rooted at the same pagesDir, backing the HTML preview iframe.
|
|
209
|
+
const staticHtml = new StaticHtmlService(cwd, pagesDir);
|
|
210
|
+
// M21 m02multidir: drugi PagesService dla briefsDir. Wspoldziel z pierwszym
|
|
211
|
+
// zarowno PageVersionService jak i WsGateway, ale ma osobny watcher (debounce
|
|
212
|
+
// independent per katalog) i osobny PageSerializer (constructor-bound do
|
|
213
|
+
// odpowiedniego rootDir).
|
|
214
|
+
const briefsPages = new PagesService(cwd, briefsDir);
|
|
215
|
+
await briefsPages.ensureRoot();
|
|
216
|
+
// M23 m02multidir: trzeci PagesService dla patchesDir (analogicznie do briefsDir).
|
|
217
|
+
const patchesPages = new PagesService(cwd, patchesDir);
|
|
218
|
+
await patchesPages.ensureRoot();
|
|
219
|
+
const tagsService = new TagsService(db.handle);
|
|
220
|
+
const versionService = new VersionService(db.handle);
|
|
221
|
+
const rawReader = new RawEntityReader(db.handle);
|
|
222
|
+
// M17: wire snapshot capture deps. After this, every entity service
|
|
223
|
+
// mutation captures a deterministic snapshot via host.snapshot(...).
|
|
224
|
+
versionService.configureSnapshot(rawReader, pluginHost);
|
|
225
|
+
// M24: remote-account identity (device flow + local session). Single HTTP
|
|
226
|
+
// client per project context; base URL from config.remoteApiUrl (or the prod constant).
|
|
227
|
+
const remoteHttpClient = new RemoteHttpClient(remoteApiUrl);
|
|
228
|
+
const remoteAuthService = new RemoteAuthService(db.handle, remoteHttpClient);
|
|
229
|
+
const chatService = new ChatService(db.handle);
|
|
230
|
+
// Orphan cleanup: rowsy chat_message.status='streaming' pozostale po crashu poprzedniego
|
|
231
|
+
// procesu (SIGKILL/OOM) — brak aktywnego adaptera po starcie, flipujemy wszystkie na 'complete'.
|
|
232
|
+
chatService.finalizeAllStreamingRows();
|
|
233
|
+
const watcher = new PagesWatcher(pages.root, ws);
|
|
234
|
+
cleanup.push(() => watcher.close());
|
|
235
|
+
// M21 m02multidir: drugi PagesWatcher na briefsDir. Wspoldzieli ten sam
|
|
236
|
+
// gateway (broadcast `page:changed` z drugiego katalogu — UI może slot-detect
|
|
237
|
+
// przez prefix sciezki, jezeli kiedys bedzie potrzebne).
|
|
238
|
+
const briefsWatcher = new PagesWatcher(briefsPages.root, ws);
|
|
239
|
+
cleanup.push(() => briefsWatcher.close());
|
|
240
|
+
// M23 m02multidir: trzeci PagesWatcher na patchesDir.
|
|
241
|
+
const patchesWatcher = new PagesWatcher(patchesPages.root, ws);
|
|
242
|
+
cleanup.push(() => patchesWatcher.close());
|
|
243
|
+
// M29: dedicated watcher + file store + indexer for the committed entity store.
|
|
244
|
+
// The page-family watchers above are rooted outside `.claude4spec/`, so this
|
|
245
|
+
// watcher owns `<entitiesDir>` exclusively.
|
|
246
|
+
const entitiesWatcher = new EntitiesWatcher(entitiesAbs);
|
|
247
|
+
cleanup.push(() => entitiesWatcher.close());
|
|
248
|
+
const entityStore = new EntityStore(cwd, entitiesDir, entitiesWatcher, rawReader, pluginHost);
|
|
249
|
+
entityStore.ensureRoot();
|
|
250
|
+
const entityIndexer = new EntityIndexerService(db.handle, entityStore, entitiesWatcher, ws, pluginHost, tagsService, rawReader);
|
|
251
|
+
const referencesService = new ReferencesService(pages, watcher);
|
|
252
|
+
const sectionsService = new SectionsService(db.handle);
|
|
253
|
+
sectionsService.setWriteDeps({ pages, watcher });
|
|
254
|
+
const planService = new PlanService(db.handle, ws, chatService);
|
|
255
|
+
const sectionIndexer = new SectionIndexerService(db.handle, pages, watcher, ws, pluginHost);
|
|
256
|
+
const todosIndexer = new TodosIndexerService(pages, ws);
|
|
257
|
+
const pagesLinkIndexer = new PagesLinkIndexerService(pages, ws);
|
|
258
|
+
// M17: page versioning (out of L9 plugin host — decyzja 1)
|
|
259
|
+
const pageSerializer = new PageSerializer(pages);
|
|
260
|
+
// M21 m02multidir: osobny serializer dla briefsDir (PageSerializer trzyma
|
|
261
|
+
// referencje do PagesService w konstruktorze — czyta z dysku przez nia).
|
|
262
|
+
// PageVersionService akceptuje override serializera w recordVersion(),
|
|
263
|
+
// wiec dwa serializery dziela jedna instancje wersjonowania.
|
|
264
|
+
const briefsSerializer = new PageSerializer(briefsPages);
|
|
265
|
+
// M23: serializer dla patchesDir (analogicznie do briefsSerializer).
|
|
266
|
+
const patchesSerializer = new PageSerializer(patchesPages);
|
|
267
|
+
const pageVersions = new PageVersionService(db.handle, pageSerializer);
|
|
268
|
+
// M21 m02fmidx / M23: in-memory frontmatter indexer feeded przez trzy watchery.
|
|
269
|
+
const pagesFrontmatterIndexer = new PagesFrontmatterIndexer(pages, briefsPages, patchesPages, ws);
|
|
270
|
+
// Mount all active backend modules — each plugin constructs its own service,
|
|
271
|
+
// mounts its router, registers its MCP server, and registers its entity
|
|
272
|
+
// service via the supplied MountContext. Inactive plugins are skipped
|
|
273
|
+
// (config.entities).
|
|
274
|
+
pluginHost.mountBackend({
|
|
275
|
+
app: router,
|
|
276
|
+
db: db.handle,
|
|
277
|
+
host: pluginHost,
|
|
278
|
+
cwd,
|
|
279
|
+
ws,
|
|
280
|
+
tagsService,
|
|
281
|
+
versionService,
|
|
282
|
+
referencesService,
|
|
283
|
+
entityStore,
|
|
284
|
+
registerMcpServer: (name, server) => pluginHost.registerMcpServer(name, server),
|
|
285
|
+
registerEntityService: (type, service) => pluginHost.registerEntityService(type, service),
|
|
286
|
+
});
|
|
287
|
+
// Cross-cutting MCP server — owned by the host, not a plugin (M13).
|
|
288
|
+
// Registered as a factory: a fresh instance is built per agent turn so
|
|
289
|
+
// concurrent turns never share one MCP transport.
|
|
290
|
+
pluginHost.registerMcpServer('reference-tools', () => createReferenceToolsServer({
|
|
291
|
+
pluginHost,
|
|
292
|
+
tagsService,
|
|
293
|
+
referencesService,
|
|
294
|
+
pagesService: pages,
|
|
295
|
+
sectionsService,
|
|
296
|
+
ws,
|
|
297
|
+
db: db.handle,
|
|
298
|
+
cwd,
|
|
299
|
+
entityStore,
|
|
300
|
+
}));
|
|
301
|
+
// M17: ReleaseService + cross-cutting `release-tools` MCP. Like
|
|
302
|
+
// reference-tools, owned by the host (not a plugin) — release semantics
|
|
303
|
+
// are dual-track (entities + pages), neither side is a plugin owner.
|
|
304
|
+
const releaseService = new ReleaseService(db.handle, pluginHost, versionService, pageVersions, pageSerializer, rawReader, tagsService, pages, watcher, cwd);
|
|
305
|
+
// M29: release restore must persist restored entities' files.
|
|
306
|
+
releaseService.setEntityStore(entityStore);
|
|
307
|
+
// M28 Git Sync — best-effort mirroring of release create/push into the user's
|
|
308
|
+
// git repo. Probes `pages.root` for the worktree; reads config per-action.
|
|
309
|
+
const gitService = new GitService(cwd, pages.root);
|
|
310
|
+
// M25 Release Push — coordinates M17 bundle build + M24 transport; owns release_push.
|
|
311
|
+
const releasePushService = new ReleasePushService(db.handle, releaseService, remoteAuthService, gitService, cwd);
|
|
312
|
+
pluginHost.registerMcpServer('release-tools', () => createReleaseToolsServer({ releaseService, gitService, ws }));
|
|
313
|
+
// M27 Project Clone — bootstrap-time only. Runs after services exist (DB
|
|
314
|
+
// migrated, plugin host mounted, pages root ensured) but BEFORE watchers start
|
|
315
|
+
// and before listen, so restore writes land without watcher double-capture.
|
|
316
|
+
if (deps.clone) {
|
|
317
|
+
const importService = new ReleaseImportService(db.handle, releaseService, remoteHttpClient, cwd);
|
|
318
|
+
try {
|
|
319
|
+
const result = await importService.clone(deps.clone.slug, { nameOverride: deps.clone.nameOverride });
|
|
320
|
+
console.log(` cloned remote project '${deps.clone.slug}' → local release #${result.localReleaseId ?? '?'}`);
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
const code = err instanceof DomainError ? err.code : 'CLONE_FAILED';
|
|
324
|
+
console.error(`\x1b[31mclone failed\x1b[0m: ${code} — ${err instanceof Error ? err.message : String(err)}`);
|
|
325
|
+
// Full all-or-nothing rollback: cwd returns to its pre-`--clone` state. Close
|
|
326
|
+
// the DB handle first so db.sqlite can be unlinked (required on Windows).
|
|
327
|
+
db.close();
|
|
328
|
+
rollbackClone(cwd, {
|
|
329
|
+
pagesDir,
|
|
330
|
+
configCreated: deps.clone.configCreated,
|
|
331
|
+
claudeDirCreated: deps.clone.claudeDirCreated,
|
|
332
|
+
gitignoreCreated: deps.clone.gitignoreCreated,
|
|
333
|
+
dbSlotDir,
|
|
334
|
+
});
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// M21: BriefService — top-level (nie plugin), wzorzec analogiczny do
|
|
339
|
+
// PlanService. Mountowany router /briefs poniżej.
|
|
340
|
+
const briefService = new BriefService({
|
|
341
|
+
briefsPages,
|
|
342
|
+
briefsWatcher,
|
|
343
|
+
briefsSerializer,
|
|
344
|
+
pageVersions,
|
|
345
|
+
chatService,
|
|
346
|
+
releaseService,
|
|
347
|
+
frontmatterIndexer: pagesFrontmatterIndexer,
|
|
348
|
+
ws,
|
|
349
|
+
});
|
|
350
|
+
// M23: PatchService — top-level (nie plugin), wzorzec analogiczny do
|
|
351
|
+
// BriefService. Mountowany router /patches poniżej.
|
|
352
|
+
const patchService = new PatchService({
|
|
353
|
+
patchesPages,
|
|
354
|
+
patchesWatcher,
|
|
355
|
+
patchesSerializer,
|
|
356
|
+
pageVersions,
|
|
357
|
+
chatService,
|
|
358
|
+
frontmatterIndexer: pagesFrontmatterIndexer,
|
|
359
|
+
});
|
|
360
|
+
// Per-context config/meta/writing-styles (carved out of startServer inline
|
|
361
|
+
// handlers — single response builder in routes/config.ts).
|
|
362
|
+
router.use(configRouter({
|
|
363
|
+
cwd,
|
|
364
|
+
skillRegistry,
|
|
365
|
+
onContextConfigChanged: deps.onContextConfigChanged,
|
|
366
|
+
onOnboardingCompleted: (effectivePagesDir) => ensureWelcomePage(cwd, effectivePagesDir),
|
|
367
|
+
}));
|
|
368
|
+
router.use(pluginHostRouter(pluginHost));
|
|
369
|
+
router.use('/pages', pagesRouter(pages, watcher, pageVersions));
|
|
370
|
+
router.use('/static', staticRouter(staticHtml));
|
|
371
|
+
router.use('/tags', tagsRouter(tagsService, referencesService));
|
|
372
|
+
router.use('/references', referencesRouter(pluginHost, referencesService));
|
|
373
|
+
router.use('/entities', entitiesRouter(pluginHost, tagsService, versionService, entityStore));
|
|
374
|
+
// 0.1.58: peer-discovery for the `<workspace_projects>` prompt block. For each
|
|
375
|
+
// workspace project except this one, build a PeerProject whose `path` is the
|
|
376
|
+
// registry `cwd` (passed 1:1 as the `project` param to `c4s-tools.ask`); name/
|
|
377
|
+
// description are lazily read from the peer's config.json (source of truth,
|
|
378
|
+
// no denormalization). Unreadable config → entry with `path` only. Re-read per
|
|
379
|
+
// turn so peer-config edits surface on the next thread's first turn.
|
|
380
|
+
const listWorkspacePeers = () => {
|
|
381
|
+
const ws = registry.getWorkspace(workspace.name);
|
|
382
|
+
if (!ws)
|
|
383
|
+
return [];
|
|
384
|
+
return ws.projects
|
|
385
|
+
.filter((p) => p.cwd !== cwd)
|
|
386
|
+
.map((p) => {
|
|
387
|
+
const peer = { path: p.cwd };
|
|
388
|
+
try {
|
|
389
|
+
const peerCfg = readConfig(p.cwd);
|
|
390
|
+
if (peerCfg.name)
|
|
391
|
+
peer.name = peerCfg.name;
|
|
392
|
+
if (peerCfg.description)
|
|
393
|
+
peer.description = peerCfg.description;
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
/* unreadable/missing config → path-only entry, not an error */
|
|
397
|
+
}
|
|
398
|
+
return peer;
|
|
399
|
+
});
|
|
400
|
+
};
|
|
401
|
+
// Wspolne deps tury agenta — `threadsRouter` (POST /:id/ask) i `chatRouter`
|
|
402
|
+
// (POST /chat, SSE) dziela ten sam runtime i rejestr `activeAdapters`.
|
|
403
|
+
const agentDeps = {
|
|
404
|
+
pluginHost,
|
|
405
|
+
activeAdapters,
|
|
406
|
+
pendingInputs,
|
|
407
|
+
onTurnFinished: deps.onTurnFinished,
|
|
408
|
+
chatService,
|
|
409
|
+
pagesService: pages,
|
|
410
|
+
tagsService,
|
|
411
|
+
sectionsService,
|
|
412
|
+
planService,
|
|
413
|
+
briefService,
|
|
414
|
+
patchService,
|
|
415
|
+
pageVersions,
|
|
416
|
+
skillResolver,
|
|
417
|
+
skillRegistry,
|
|
418
|
+
ws,
|
|
419
|
+
cwd,
|
|
420
|
+
pagesDir,
|
|
421
|
+
mode,
|
|
422
|
+
db,
|
|
423
|
+
workspaceName: workspace.name,
|
|
424
|
+
listWorkspacePeers,
|
|
425
|
+
};
|
|
426
|
+
router.use('/threads', threadsRouter(agentDeps));
|
|
427
|
+
router.use('/sections', sectionsRouter(sectionsService));
|
|
428
|
+
router.use('/todos', todosRouter(todosIndexer));
|
|
429
|
+
router.use('/page-links', pageLinksRouter(pagesLinkIndexer));
|
|
430
|
+
router.use('/plans', plansRouter(planService));
|
|
431
|
+
router.use('/releases', releasesRouter(releaseService, ws, gitService));
|
|
432
|
+
router.use('/release-pushes', releasePushesRouter(releasePushService));
|
|
433
|
+
router.use('/git', gitRouter(gitService));
|
|
434
|
+
router.use('/briefs', briefsRouter(briefService, pageVersions));
|
|
435
|
+
router.use('/patches', patchesRouter(patchService));
|
|
436
|
+
router.use('/remote-account', remoteAccountRouter(remoteAuthService));
|
|
437
|
+
router.use('/remote-project', remoteProjectRouter(remoteAuthService, cwd));
|
|
438
|
+
router.use('/chat', chatRouter(agentDeps));
|
|
439
|
+
router.use(errorHandler);
|
|
440
|
+
watcher.onChange((relPath, kind) => {
|
|
441
|
+
if (kind === 'unlink') {
|
|
442
|
+
sectionIndexer.handleUnlink(relPath).catch((err) => {
|
|
443
|
+
console.error('[section-indexer] unlink error:', err);
|
|
444
|
+
});
|
|
445
|
+
todosIndexer.handleUnlink(relPath);
|
|
446
|
+
pagesLinkIndexer.handleUnlink(relPath);
|
|
447
|
+
pagesFrontmatterIndexer.handleUnlink('pages', relPath);
|
|
448
|
+
// M17: capture filesystem-origin delete (chokidar saw external rm)
|
|
449
|
+
pageVersions.recordVersion(relPath, 'delete', 'filesystem').catch((err) => {
|
|
450
|
+
console.warn(`[page-version] watcher delete capture for ${relPath}:`, err.message);
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
sectionIndexer.schedulePage(relPath);
|
|
455
|
+
todosIndexer.schedulePage(relPath);
|
|
456
|
+
pagesLinkIndexer.schedulePage(relPath);
|
|
457
|
+
pagesFrontmatterIndexer.schedulePage('pages', relPath);
|
|
458
|
+
// M17: capture filesystem-origin add/change. `kind === 'add'` may be a
|
|
459
|
+
// real new file (op=create) or a re-detection — pageVersions.hasAny
|
|
460
|
+
// distinguishes.
|
|
461
|
+
const op = kind === 'add' && !pageVersions.hasAny(relPath) ? 'create' : 'update';
|
|
462
|
+
pageVersions.recordVersion(relPath, op, 'filesystem').catch((err) => {
|
|
463
|
+
console.warn(`[page-version] watcher capture for ${relPath}:`, err.message);
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
// M21 m02multidir: drugi watcher dla briefsDir. Tylko frontmatter indexer
|
|
468
|
+
// + page_version (z dedykowanym briefsSerializer). Section/todos/pages-link
|
|
469
|
+
// indexery NIE pracuja na briefsDir (briefs to nie pages w sensie M02 →
|
|
470
|
+
// nie czesc nawigowalnego drzewa, nie agreguja section_ref/todo'ow do tabel).
|
|
471
|
+
briefsWatcher.onChange((relPath, kind) => {
|
|
472
|
+
if (kind === 'unlink') {
|
|
473
|
+
pagesFrontmatterIndexer.handleUnlink('briefs', relPath);
|
|
474
|
+
pageVersions.recordVersion(relPath, 'delete', 'filesystem', undefined, briefsSerializer, 'brief').catch((err) => {
|
|
475
|
+
console.warn(`[page-version] brief delete capture for ${relPath}:`, err.message);
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
pagesFrontmatterIndexer.schedulePage('briefs', relPath);
|
|
480
|
+
const op = kind === 'add' && !pageVersions.hasAny(relPath) ? 'create' : 'update';
|
|
481
|
+
pageVersions.recordVersion(relPath, op, 'filesystem', undefined, briefsSerializer, 'brief').catch((err) => {
|
|
482
|
+
console.warn(`[page-version] brief capture for ${relPath}:`, err.message);
|
|
483
|
+
});
|
|
484
|
+
// Direct disk edit (not suppressed): refresh open BriefEditors. The indexer
|
|
485
|
+
// only fires `briefs:changed` on frontmatter changes, so body-only edits
|
|
486
|
+
// need this explicit broadcast. `external` → reload-or-confirm like Pages.
|
|
487
|
+
ws.broadcast({ kind: 'briefs:changed', path: relPath, origin: 'external' });
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
// M23: trzeci watcher dla patchesDir — analogicznie do briefsWatcher.
|
|
491
|
+
patchesWatcher.onChange((relPath, kind) => {
|
|
492
|
+
if (kind === 'unlink') {
|
|
493
|
+
pagesFrontmatterIndexer.handleUnlink('patches', relPath);
|
|
494
|
+
pageVersions.recordVersion(relPath, 'delete', 'filesystem', undefined, patchesSerializer, 'patch').catch((err) => {
|
|
495
|
+
console.warn(`[page-version] patch delete capture for ${relPath}:`, err.message);
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
pagesFrontmatterIndexer.schedulePage('patches', relPath);
|
|
500
|
+
const op = kind === 'add' && !pageVersions.hasAny(relPath) ? 'create' : 'update';
|
|
501
|
+
pageVersions.recordVersion(relPath, op, 'filesystem', undefined, patchesSerializer, 'patch').catch((err) => {
|
|
502
|
+
console.warn(`[page-version] patch capture for ${relPath}:`, err.message);
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
// M29: external edits / git pull of entity files → incremental reindex.
|
|
507
|
+
entitiesWatcher.onChange((relPath, kind) => {
|
|
508
|
+
if (kind === 'unlink') {
|
|
509
|
+
entityIndexer.handleUnlink(relPath).catch((err) => {
|
|
510
|
+
console.error(`[entity-indexer] unlink ${relPath}:`, err);
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
entityIndexer.schedulePage(relPath);
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
watcher.start();
|
|
518
|
+
briefsWatcher.start();
|
|
519
|
+
patchesWatcher.start();
|
|
520
|
+
sectionIndexer.indexAll().catch((err) => {
|
|
521
|
+
console.error('[section-indexer] initial indexAll failed:', err);
|
|
522
|
+
});
|
|
523
|
+
todosIndexer.indexAll().catch((err) => {
|
|
524
|
+
console.error('[todos-indexer] initial indexAll failed:', err);
|
|
525
|
+
});
|
|
526
|
+
pagesLinkIndexer.indexAll().catch((err) => {
|
|
527
|
+
console.error('[pages-link-indexer] initial indexAll failed:', err);
|
|
528
|
+
});
|
|
529
|
+
// M17: initial sync of page_version. For each markdown file with no captured
|
|
530
|
+
// version — or whose latest captured version is a `delete` tombstone while the
|
|
531
|
+
// file is back on disk — write an `op = 'create'` baseline. The latter case
|
|
532
|
+
// covers delete+recreate that happened while the server wasn't watching
|
|
533
|
+
// (server down, `git checkout` between restarts): without this, the phantom
|
|
534
|
+
// `delete` stays the latest row and release diffs show the page as removed.
|
|
535
|
+
(async () => {
|
|
536
|
+
try {
|
|
537
|
+
const files = await pages.listMarkdownFiles();
|
|
538
|
+
for (const relPath of files) {
|
|
539
|
+
const latest = pageVersions.getLatestForPath(relPath);
|
|
540
|
+
if (latest && latest.op !== 'delete')
|
|
541
|
+
continue;
|
|
542
|
+
await pageVersions.recordVersion(relPath, 'create', 'filesystem');
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
catch (err) {
|
|
546
|
+
console.warn('[page-version] initial sync failed:', err.message);
|
|
547
|
+
}
|
|
548
|
+
})();
|
|
549
|
+
// M21: initial sync — page_version baseline dla briefów + frontmatter indexer.
|
|
550
|
+
(async () => {
|
|
551
|
+
try {
|
|
552
|
+
const files = await briefsPages.listMarkdownFiles();
|
|
553
|
+
for (const relPath of files) {
|
|
554
|
+
if (pageVersions.hasAny(relPath))
|
|
555
|
+
continue;
|
|
556
|
+
await pageVersions.recordVersion(relPath, 'create', 'filesystem', undefined, briefsSerializer, 'brief');
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
catch (err) {
|
|
560
|
+
console.warn('[page-version] briefs initial sync failed:', err.message);
|
|
561
|
+
}
|
|
562
|
+
// M23: initial sync — page_version baseline dla patchy.
|
|
563
|
+
try {
|
|
564
|
+
const files = await patchesPages.listMarkdownFiles();
|
|
565
|
+
for (const relPath of files) {
|
|
566
|
+
if (pageVersions.hasAny(relPath))
|
|
567
|
+
continue;
|
|
568
|
+
await pageVersions.recordVersion(relPath, 'create', 'filesystem', undefined, patchesSerializer, 'patch');
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
catch (err) {
|
|
572
|
+
console.warn('[page-version] patches initial sync failed:', err.message);
|
|
573
|
+
}
|
|
574
|
+
try {
|
|
575
|
+
await pagesFrontmatterIndexer.indexAll();
|
|
576
|
+
}
|
|
577
|
+
catch (err) {
|
|
578
|
+
console.warn('[pages-frontmatter-indexer] initial sync failed:', err.message);
|
|
579
|
+
}
|
|
580
|
+
})();
|
|
581
|
+
// M29: entity store boot. (1) one-time DB→text export for pre-M29 projects
|
|
582
|
+
// whose entities live only in SQLite; (2) rebuild the derived index from the
|
|
583
|
+
// committed files. Awaited BEFORE the context serves — the app is
|
|
584
|
+
// entity-centric, so serving REST/MCP before the index is ready would 404 /
|
|
585
|
+
// return empty.
|
|
586
|
+
try {
|
|
587
|
+
const fileEntityCount = entityStore.listAll().length;
|
|
588
|
+
const hasTagsFile = entityStore.readTags().length > 0;
|
|
589
|
+
const dbEntityCount = rawReader
|
|
590
|
+
.listTypes()
|
|
591
|
+
.filter((t) => pluginHost.getEntity(t))
|
|
592
|
+
.reduce((n, t) => n + rawReader.listSlugs(t).length, 0);
|
|
593
|
+
const filesPresent = fileEntityCount > 0 || hasTagsFile;
|
|
594
|
+
if (!filesPresent && dbEntityCount > 0) {
|
|
595
|
+
// Pre-M29 project: entities live only in SQLite → export to text once.
|
|
596
|
+
console.log(`[m29] exporting ${dbEntityCount} entities DB→text into ${entitiesDir} ...`);
|
|
597
|
+
backupDbBeforeMigration(dbSlotDir);
|
|
598
|
+
for (const type of rawReader.listTypes()) {
|
|
599
|
+
if (!pluginHost.getEntity(type))
|
|
600
|
+
continue;
|
|
601
|
+
for (const slug of rawReader.listSlugs(type))
|
|
602
|
+
entityStore.persist(type, slug);
|
|
603
|
+
}
|
|
604
|
+
entityStore.persistTags();
|
|
605
|
+
}
|
|
606
|
+
else if (filesPresent && dbEntityCount > 0 && fileEntityCount !== dbEntityCount) {
|
|
607
|
+
// Edge (brief migrt001 §3): committed files differ from a non-empty DB
|
|
608
|
+
// (e.g. a git pull dropped/added entities). Files win on rebuild — back up
|
|
609
|
+
// the derived DB first so the prior index is recoverable.
|
|
610
|
+
console.warn(`[m29] entity file count (${fileEntityCount}) != DB count (${dbEntityCount}); rebuilding from files (db backed up)`);
|
|
611
|
+
backupDbBeforeMigration(dbSlotDir);
|
|
612
|
+
}
|
|
613
|
+
await entityIndexer.indexAll();
|
|
614
|
+
}
|
|
615
|
+
catch (err) {
|
|
616
|
+
console.error('[entity-indexer] boot indexAll failed:', err);
|
|
617
|
+
}
|
|
618
|
+
// M29: enable tags.json persistence only AFTER the boot rebuild, so any
|
|
619
|
+
// auto-created tag during indexAll does not write files mid-rebuild.
|
|
620
|
+
tagsService.setEntityStore(entityStore);
|
|
621
|
+
// M29: enable slug-rename propagation into entity files (dto→endpoint
|
|
622
|
+
// linked_dtos, *→ac verifies). After indexAll so the index is consistent.
|
|
623
|
+
referencesService.setEntityDeps(db.handle, entityStore);
|
|
624
|
+
// Start the entities watcher only after the boot export/rebuild, so bulk
|
|
625
|
+
// self-writes during export never race a live reindex.
|
|
626
|
+
entitiesWatcher.start();
|
|
627
|
+
const writingStyle = initialWritingStyle
|
|
628
|
+
? { slug: initialWritingStyle, title: skillRegistry.resolve(initialWritingStyle).metadata.title }
|
|
629
|
+
: null;
|
|
630
|
+
return {
|
|
631
|
+
projectId,
|
|
632
|
+
cwd,
|
|
633
|
+
workspace,
|
|
634
|
+
router,
|
|
635
|
+
db,
|
|
636
|
+
pluginHost,
|
|
637
|
+
serialization: new SerializationEngine(pluginHost, sectionSerializer),
|
|
638
|
+
ws,
|
|
639
|
+
activeAdapters,
|
|
640
|
+
pendingInputs,
|
|
641
|
+
writingStyle,
|
|
642
|
+
hasInFlightTurn: () => activeAdapters.size > 0,
|
|
643
|
+
// M31 dispose sequence: watchers → MCP factories → room → db handle.
|
|
644
|
+
dispose: async () => {
|
|
645
|
+
await watcher.close();
|
|
646
|
+
await briefsWatcher.close();
|
|
647
|
+
await patchesWatcher.close();
|
|
648
|
+
await entitiesWatcher.close();
|
|
649
|
+
pluginHost.clearMcpFactories();
|
|
650
|
+
gateway.closeRoom(projectId);
|
|
651
|
+
db.close();
|
|
652
|
+
},
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
//# sourceMappingURL=project-context.js.map
|