@rubytech/create-realagent-code 0.1.254 → 0.1.256
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/dist/__tests__/plugin-install.test.js +58 -40
- package/dist/index.js +77 -26
- package/dist/lib/plugin-install.js +31 -29
- package/package.json +1 -1
- package/payload/platform/.docs/search-surface-contract.md +58 -0
- package/payload/platform/config/brand-registry.json +8 -0
- package/payload/platform/config/brand.json +2 -2
- package/payload/platform/lib/embed-client/dist/index.d.ts +4 -0
- package/payload/platform/lib/embed-client/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/embed-client/dist/index.js +53 -0
- package/payload/platform/lib/embed-client/dist/index.js.map +1 -0
- package/payload/platform/lib/embed-client/src/index.ts +53 -0
- package/payload/platform/lib/embed-client/tsconfig.json +8 -0
- package/payload/platform/lib/graph-search/dist/index.d.ts +27 -6
- package/payload/platform/lib/graph-search/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-search/dist/index.js +19 -1
- package/payload/platform/lib/graph-search/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +12 -0
- package/payload/platform/lib/graph-search/src/index.ts +28 -6
- package/payload/platform/lib/graph-write/dist/index.d.ts +25 -0
- package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.js +80 -2
- package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-write/src/index.ts +98 -1
- package/payload/platform/neo4j/schema.cypher +126 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +3 -6
- package/payload/platform/plugins/admin/mcp/dist/index.js +14 -60
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/insight/SKILL.md +24 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +84 -31
- package/payload/platform/plugins/docs/PLUGIN.md +1 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/deployment.md +18 -5
- package/payload/platform/plugins/docs/references/graph.md +2 -0
- package/payload/platform/plugins/docs/references/internals.md +12 -1
- package/payload/platform/plugins/docs/references/memory-guide.md +4 -0
- package/payload/platform/plugins/docs/references/neo4j.md +2 -2
- package/payload/platform/plugins/docs/references/platform.md +1 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/docs/references/session-retrospective.md +5 -18
- package/payload/platform/plugins/docs/references/slides.md +31 -0
- package/payload/platform/plugins/docs/references/voice-mirror-guide.md +1 -1
- package/payload/platform/plugins/email/PLUGIN.md +2 -2
- package/payload/platform/plugins/email/mcp/dist/index.js +8 -0
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts +19 -0
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js +64 -0
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts +4 -0
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.js +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +6 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +7 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -1
- package/payload/platform/plugins/email/references/email-reference.md +4 -0
- package/payload/platform/plugins/memory/PLUGIN.md +1 -2
- package/payload/platform/plugins/memory/mcp/dist/index.js +6 -44
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.js +41 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.js +90 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.js +27 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.d.ts +10 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.js +47 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts +1 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js +5 -28
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.js +20 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.js +67 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js +34 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.js +61 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js +23 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.js +87 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js +3 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.js +34 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +19 -4
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +33 -6
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +280 -10
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js +76 -37
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +11 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts +4 -4
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js +3 -3
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +20 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +6 -3
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/vitest.config.ts +5 -0
- package/payload/platform/plugins/memory/references/schema-base.md +1 -1
- package/payload/platform/plugins/memory/references/schema-construction.md +72 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js +15 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js.map +1 -1
- package/payload/platform/plugins/slides/.claude-plugin/plugin.json +8 -0
- package/payload/platform/plugins/slides/LICENSE +21 -0
- package/payload/platform/plugins/slides/PLUGIN.md +18 -0
- package/payload/platform/plugins/slides/PROVENANCE.md +40 -0
- package/payload/platform/plugins/slides/commands/add-slide.md +29 -0
- package/payload/platform/plugins/slides/commands/slides-claus.md +39 -0
- package/payload/platform/plugins/slides/commands/slides-new-component.md +39 -0
- package/payload/platform/plugins/slides/commands/slides-outline.md +43 -0
- package/payload/platform/plugins/slides/commands/slides-review.md +52 -0
- package/payload/platform/plugins/slides/commands/slides-theme.md +64 -0
- package/payload/platform/plugins/slides/commands/slides.md +59 -0
- package/payload/platform/plugins/slides/skills/deck-system/REFERENCE.md +581 -0
- package/payload/platform/plugins/slides/skills/deck-system/SKILL.md +607 -0
- package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-board.md +426 -0
- package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-claus.md +185 -0
- package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-mbb.md +450 -0
- package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-product-launch.md +579 -0
- package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-sales.md +464 -0
- package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-sequoia.md +489 -0
- package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING.md +273 -0
- package/payload/platform/plugins/slides/skills/deck-system/deck-craft.html +1371 -0
- package/payload/platform/plugins/slides/skills/deck-system/deck-solid.html +1667 -0
- package/payload/platform/plugins/slides/skills/deck-system/deck.html +1359 -0
- package/payload/platform/plugins/url-get/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/url-get/PLUGIN.md +26 -21
- package/payload/platform/plugins/url-get/mcp/dist/index.js +3 -3
- package/payload/platform/plugins/url-get/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts +1 -2
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts.map +1 -1
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js +20 -40
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +4 -0
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -1
- package/payload/platform/scripts/identity-forbidden-token-check.mjs +0 -1
- package/payload/platform/scripts/setup-account.sh +0 -15
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts +23 -0
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js +29 -0
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +0 -2
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +32 -2
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +8 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts +13 -1
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js +26 -2
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +2 -2
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +12 -3
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js +3 -2
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +2 -2
- package/payload/platform/templates/specialists/agents/database-operator.md +3 -7
- package/payload/platform/templates/specialists/agents/typed-edge-classifier.md +1 -1
- package/payload/server/{chunk-M6A6EZD4.js → chunk-76HRO7NX.js} +16 -2
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/AdminShell-T-YknnBn.js +1 -0
- package/payload/server/public/assets/Checkbox-DmDxpqVv.js +1 -0
- package/payload/server/public/assets/admin-COUV-jgt.js +1 -0
- package/payload/server/public/assets/{arc-aUiRP9AS.js → arc-B2CweJq3.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-Dnn6Hc65.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-c09loTER.js → architectureDiagram-Q4EWVU46-DP2o-MFV.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-Cjdeyoq1.js → blockDiagram-DXYQGD6D-DO4mcYDJ.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-NY6Wlzo2.js → c4Diagram-AHTNJAMY-Sy1giHbj.js} +1 -1
- package/payload/server/public/assets/channel-CEpR_0rE.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-BK3470lx.js → chunk-2KRD3SAO-CKsCYCsN.js} +1 -1
- package/payload/server/public/assets/chunk-336JU56O-C0-P-aUF.js +2 -0
- package/payload/server/public/assets/chunk-426QAEUC-DFjEt3Zb.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-BOvVdJLf.js → chunk-4BX2VUAB-B8bqAmBa.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BXpto3yW.js → chunk-4TB4RGXK-D1k0VSlW.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-BwZyF7vR.js → chunk-55IACEB6-B-p_QNqz.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-C403gCUk.js → chunk-5FUZZQ4R-D6U6tV_j.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-CjVzXQEp.js → chunk-5PVQY5BW-CYK76xfs.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-D5bhMrtY.js → chunk-67CJDMHE-BC9js-lf.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-Si7Lgrwc.js → chunk-7N4EOEYR-4j2OqKkv.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-DMuHtDqO.js → chunk-AA7GKIK3-Coen-fXN.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-L79XKVcb.js → chunk-BSJP7CBP-CAiOBvec.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-C0O7Upmg.js → chunk-CIAEETIT-AJzzpZVb.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-DJcJAsAg.js → chunk-EDXVE4YY-BL4BKozX.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-CFDNvYu1.js → chunk-ENJZ2VHE-mhAFG8UD.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-C_E43NFJ.js → chunk-FMBD7UC4-H231gZA_.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-D9lWWHAu.js → chunk-FOC6F5B3-Cl3ZZjYG.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-ecLOxGhL.js → chunk-ICPOFSXX-DOEzvzJa.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-DuhsNH4c.js → chunk-K5T4RW27-C_ipbUDD.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-B4-A1Abi.js → chunk-KGLVRYIC-CTsDNSCU.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-BxqgHRgT.js → chunk-LIHQZDEY-DvSXhkGf.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-DEYQ5WaJ.js → chunk-ORNJ4GCN-p574NOI7.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-B7MW66KB.js → chunk-OYMX7WX6-BlEgFM6U.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-DpF06ZZQ.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-BMawmsyk.js → chunk-U2HBQHQK-B2bDK0jv.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-CT6g7pno.js → chunk-X2U36JSP-D69BxKFw.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-CBfZXZDB.js → chunk-XPW4576I-Dm-PcyUi.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-xeAluiAH.js → chunk-YZCP3GAM-Be8RnXgx.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-BRN9qUC5.js → chunk-ZZ45TVLE-Ck8PCTa4.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CYbXvKLI.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DEyHzRhq.js +1 -0
- package/payload/server/public/assets/clone-y8gexbBy.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-Br2gjtEO.js → cose-bilkent-S5V4N54A-CmkW2Eaj.js} +1 -1
- package/payload/server/public/assets/{dagre-DTjePoco.js → dagre-Dqp-ns8F.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-DHBkRke4.js → dagre-KV5264BT-ZgWWXPLc.js} +1 -1
- package/payload/server/public/assets/data-gy6QH9c1.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-BIq1-idL.js → diagram-5BDNPKRD-CTX5-ScM.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-BsIUDzV6.js → diagram-G4DWMVQ6-BovIsO6H.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-CgHSri2i.js → diagram-MMDJMWI5-DcETsQy-.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-Ce2Wh9ZX.js → diagram-TYMM5635-yyq6peoZ.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-BU0Kh6OQ.js → erDiagram-SMLLAGMA-CiNToftB.js} +1 -1
- package/payload/server/public/assets/{flatten-Bo6YRmWl.js → flatten-BtFI066E.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-B0N06MF7.js → flowDiagram-DWJPFMVM-Xnl3SpIM.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BVbx4ARZ.js → ganttDiagram-T4ZO3ILL-C1iyWe0f.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-CNs-LD5i.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-C-xRJ94t.js → gitGraphDiagram-UUTBAWPF-D97pbMQb.js} +1 -1
- package/payload/server/public/assets/graph-labels-cZu4pK16.js +1 -0
- package/payload/server/public/assets/{graph-g48ZcA5M.js → graph-qz5tFKqU.js} +3 -3
- package/payload/server/public/assets/{graphlib-YmNcoMjY.js → graphlib-Lq8ijgON.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-DsTNigSS.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-C_OarRTA.js +2 -0
- package/payload/server/public/assets/{isEmpty-D6Kr-M1M.js → isEmpty-D6QovjYR.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DTrq54yC.js → ishikawaDiagram-UXIWVN3A-B8XBdjJn.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-OZZZMrFX.js → journeyDiagram-VCZTEJTY-CZYbiOaQ.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY--w-IP9pN.js → kanban-definition-6JOO6SKY-B1PybFoh.js} +1 -1
- package/payload/server/public/assets/{line-Ckeulv5T.js → line-D-tw3hHp.js} +1 -1
- package/payload/server/public/assets/{linear-DOh_6k2k.js → linear-BHhXD3cd.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CVRAxYRD.js → mermaid-parser.core-C9RAnysF.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-B-mE18I1.js → mermaid.core-B532LT1r.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-Bm8mDicL.js → mindmap-definition-QFDTVHPH-DGlgeeTV.js} +1 -1
- package/payload/server/public/assets/{ordinal-BDi6f4xk.js → ordinal-Bl-aM5b9.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-DGES22b-.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-ChKeDbzt.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-BCmRLgGO.js → pieDiagram-DEJITSTG-DV9FIWko.js} +1 -1
- package/payload/server/public/assets/{public-DknO-g9S.js → public-Bu2_Xi0a.js} +5 -5
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CniTIUTm.js → quadrantDiagram-34T5L4WZ-Betwya4l.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-FGG5Fs7N.js +1 -0
- package/payload/server/public/assets/{reduce-CGi9ik8i.js → reduce-BD4xUd2c.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-CoxBSj9M.js → requirementDiagram-MS252O5E-Cq3vODdg.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-BjS-4jzq.js → sankeyDiagram-XADWPNL6-x8krXWcS.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-B9jVOnPR.js → sequenceDiagram-FGHM5R23-i-_uH-Yl.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-BvOQPzP8.js → stateDiagram-FHFEXIEX-il4KqSgI.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-B6zNJ6Tv.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-CdfgWLo1.js → timeline-definition-GMOUNBTQ-DATdZkA5.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-VAQQdbtf.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-DKchO3zI.js +1 -0
- package/payload/server/public/assets/useSelectionMode-A5KItZ2T.js +13 -0
- package/payload/server/public/assets/{brand-D0gNihp7.css → useSelectionMode-C-Ojh7W9.css} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-JCgpIbj-.js → vennDiagram-DHZGUBPP-BJh9tJTt.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-CBGtx0bS.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-Dei3VqHo.js → wardleyDiagram-NUSXRM2D-EMN1Hdfg.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-DUtIyoIb.js → xychartDiagram-5P7HB3ND-DbUWXa7T.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +5 -6
- package/payload/server/public/public.html +4 -5
- package/payload/server/server.js +525 -39
- package/payload/platform/plugins/admin/hooks/__tests__/session-end-retrospective.test.sh +0 -396
- package/payload/platform/plugins/admin/hooks/lib/admin-graph-pass-common.sh +0 -239
- package/payload/platform/plugins/admin/hooks/session-end-retrospective.sh +0 -214
- package/payload/server/public/assets/AdminShell-892Jy_rs.js +0 -1
- package/payload/server/public/assets/Checkbox-Bc2QzX9b.js +0 -1
- package/payload/server/public/assets/admin-D3K13ndi.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL--v-pJPNp.js +0 -1
- package/payload/server/public/assets/brand-CcN3dELF.js +0 -9
- package/payload/server/public/assets/channel-B1IT7to2.js +0 -1
- package/payload/server/public/assets/chunk-336JU56O-CdKRCIeE.js +0 -2
- package/payload/server/public/assets/chunk-426QAEUC-BybuQ3Ve.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-Bd-GrQM6.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-rjCize6i.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BORWOUt0.js +0 -1
- package/payload/server/public/assets/clone-Csqv5U6T.js +0 -1
- package/payload/server/public/assets/data-Br-pdljK.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-CI0s_tqn.js +0 -1
- package/payload/server/public/assets/graph-labels-BYH-IPCb.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-g3gYW7Qm.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-Di6oPQ_-.js +0 -2
- package/payload/server/public/assets/packet-4T2RLAQJ-CT0TB9HI.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-CXLe7TFF.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-DnPLBl-D.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-v4ND10uR.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-C3cb7Xwe.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-Dc7G3Bgm.js +0 -1
- package/payload/server/public/assets/useSelectionMode-DwsyptOw.js +0 -5
- package/payload/server/public/assets/wardley-RL74JXVD-DtgibWAt.js +0 -1
- /package/payload/server/public/assets/{_baseFor-Cam2PbSt.js → _baseFor-Cs8Y-rGh.js} +0 -0
- /package/payload/server/public/assets/{array-DYRGGQae.js → array-iHZP4KWJ.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-nWsJMTNI.js → cytoscape.esm-BR2GOQ8_.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-Du1XY3Dp.js → defaultLocale-B9aLeOTg.js} +0 -0
- /package/payload/server/public/assets/{dist-BzAsli7o.js → dist-DB-VPj_8.js} +0 -0
- /package/payload/server/public/assets/{init-B5BXBRcm.js → init-BNFRgqHM.js} +0 -0
- /package/payload/server/public/assets/{katex-HOUACuRw.js → katex-B-EfS3nw.js} +0 -0
- /package/payload/server/public/assets/{path-CNO468J-.js → path-DmWWdwp7.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-DRO6hWPh.js → rough.esm-Ci7Kjt46.js} +0 -0
- /package/payload/server/public/assets/{src-CWiyyVfn.js → src-C1jfwBq0.js} +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// permanent verification artifact.
|
|
5
5
|
import test from "node:test";
|
|
6
6
|
import assert from "node:assert/strict";
|
|
7
|
-
import { parsePluginList, computeInstallActions,
|
|
7
|
+
import { parsePluginList, computeInstallActions, parseExternalPlugins, } from "../lib/plugin-install.js";
|
|
8
8
|
test("parsePluginList extracts name@marketplace tuples", () => {
|
|
9
9
|
const stdout = `
|
|
10
10
|
❯ work@maxy-platform
|
|
@@ -24,63 +24,81 @@ test("parsePluginList returns empty array for empty stdout", () => {
|
|
|
24
24
|
assert.deepEqual(parsePluginList(""), []);
|
|
25
25
|
assert.deepEqual(parsePluginList("No plugins installed.\n"), []);
|
|
26
26
|
});
|
|
27
|
+
// `dirSrc` is the directory-source-marketplace discriminator passed as the
|
|
28
|
+
// third argument. maxy-platform is directory-source; claude-plugins-official
|
|
29
|
+
// is a remote (GitHub) marketplace that keeps version-pinned idempotence.
|
|
30
|
+
const dirSrc = new Set(["maxy-platform"]);
|
|
27
31
|
test("computeInstallActions: every desired plugin needs installing when none present", () => {
|
|
28
32
|
const desired = [
|
|
29
33
|
{ name: "admin", marketplace: "maxy-platform" },
|
|
30
34
|
{ name: "telegram", marketplace: "claude-plugins-official" },
|
|
31
35
|
];
|
|
32
|
-
const { toInstall, alreadyInstalled } = computeInstallActions(desired, []);
|
|
36
|
+
const { toInstall, toResync, alreadyInstalled } = computeInstallActions(desired, [], dirSrc);
|
|
33
37
|
assert.equal(toInstall.length, 2);
|
|
38
|
+
assert.equal(toResync.length, 0);
|
|
34
39
|
assert.equal(alreadyInstalled.length, 0);
|
|
35
40
|
});
|
|
36
|
-
test("computeInstallActions:
|
|
41
|
+
test("computeInstallActions: directory-source plugin already installed goes to resync, not skip", () => {
|
|
37
42
|
const desired = [
|
|
38
43
|
{ name: "admin", marketplace: "maxy-platform" },
|
|
39
44
|
{ name: "telegram", marketplace: "claude-plugins-official" },
|
|
40
45
|
];
|
|
41
46
|
const installed = [
|
|
42
47
|
{ name: "admin", marketplace: "maxy-platform" },
|
|
48
|
+
{ name: "telegram", marketplace: "claude-plugins-official" },
|
|
43
49
|
];
|
|
44
|
-
const { toInstall, alreadyInstalled } = computeInstallActions(desired, installed);
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
const { toInstall, toResync, alreadyInstalled } = computeInstallActions(desired, installed, dirSrc);
|
|
51
|
+
// admin's directory source changes in place with no version bump, so it must
|
|
52
|
+
// be re-synced even though it is already in `plugin list`. The remote
|
|
53
|
+
// telegram stays idempotent-skipped.
|
|
54
|
+
assert.deepEqual(toInstall.map(p => p.name), []);
|
|
55
|
+
assert.deepEqual(toResync.map(p => p.name), ["admin"]);
|
|
56
|
+
assert.deepEqual(alreadyInstalled.map(p => p.name), ["telegram"]);
|
|
47
57
|
});
|
|
48
|
-
test("computeInstallActions:
|
|
49
|
-
const desired = [
|
|
50
|
-
|
|
51
|
-
|
|
58
|
+
test("computeInstallActions: full directory-marketplace set resyncs when every plugin already installed", () => {
|
|
59
|
+
const desired = [
|
|
60
|
+
{ name: "admin", marketplace: "maxy-platform" },
|
|
61
|
+
{ name: "work", marketplace: "maxy-platform" },
|
|
62
|
+
];
|
|
63
|
+
const installed = [
|
|
64
|
+
{ name: "admin", marketplace: "maxy-platform" },
|
|
65
|
+
{ name: "work", marketplace: "maxy-platform" },
|
|
66
|
+
];
|
|
67
|
+
const { toInstall, toResync, alreadyInstalled } = computeInstallActions(desired, installed, dirSrc);
|
|
68
|
+
assert.deepEqual(toResync.map(p => p.name), ["admin", "work"]);
|
|
52
69
|
assert.equal(toInstall.length, 0);
|
|
53
|
-
assert.equal(alreadyInstalled.length,
|
|
70
|
+
assert.equal(alreadyInstalled.length, 0);
|
|
54
71
|
});
|
|
55
|
-
test("
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
assert.equal(
|
|
72
|
+
test("computeInstallActions: remote plugin already installed stays idempotent-skipped", () => {
|
|
73
|
+
const desired = [{ name: "telegram", marketplace: "claude-plugins-official" }];
|
|
74
|
+
const installed = [{ name: "telegram", marketplace: "claude-plugins-official" }];
|
|
75
|
+
const { toInstall, toResync, alreadyInstalled } = computeInstallActions(desired, installed, dirSrc);
|
|
76
|
+
assert.equal(toInstall.length, 0);
|
|
77
|
+
assert.equal(toResync.length, 0);
|
|
78
|
+
assert.deepEqual(alreadyInstalled.map(p => p.name), ["telegram"]);
|
|
60
79
|
});
|
|
61
|
-
test("
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const actions = computeConfigureActions(installed, {});
|
|
68
|
-
assert.equal(actions.length, 1);
|
|
69
|
-
assert.equal(actions[0].kind, "skip-no-secret-value");
|
|
80
|
+
test("computeInstallActions: directory-source plugin not yet installed goes to install (fresh build is clean)", () => {
|
|
81
|
+
const desired = [{ name: "admin", marketplace: "maxy-platform" }];
|
|
82
|
+
const { toInstall, toResync, alreadyInstalled } = computeInstallActions(desired, [], dirSrc);
|
|
83
|
+
assert.deepEqual(toInstall.map(p => p.name), ["admin"]);
|
|
84
|
+
assert.equal(toResync.length, 0);
|
|
85
|
+
assert.equal(alreadyInstalled.length, 0);
|
|
70
86
|
});
|
|
71
|
-
test("
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
test("computeInstallActions: name-only match on a remote marketplace skips install (legacy install state)", () => {
|
|
88
|
+
const desired = [{ name: "telegram", marketplace: "claude-plugins-official" }];
|
|
89
|
+
const installed = [{ name: "telegram", marketplace: "" }];
|
|
90
|
+
const { toInstall, toResync, alreadyInstalled } = computeInstallActions(desired, installed, dirSrc);
|
|
91
|
+
assert.equal(toInstall.length, 0);
|
|
92
|
+
assert.equal(toResync.length, 0);
|
|
93
|
+
assert.equal(alreadyInstalled.length, 1);
|
|
94
|
+
});
|
|
95
|
+
test("computeInstallActions: name-only legacy match on a directory marketplace still resyncs", () => {
|
|
96
|
+
const desired = [{ name: "admin", marketplace: "maxy-platform" }];
|
|
97
|
+
const installed = [{ name: "admin", marketplace: "" }];
|
|
98
|
+
const { toInstall, toResync, alreadyInstalled } = computeInstallActions(desired, installed, dirSrc);
|
|
99
|
+
assert.equal(toInstall.length, 0);
|
|
100
|
+
assert.deepEqual(toResync.map(p => p.name), ["admin"]);
|
|
101
|
+
assert.equal(alreadyInstalled.length, 0);
|
|
84
102
|
});
|
|
85
103
|
test("parseExternalPlugins: undefined returns []", () => {
|
|
86
104
|
assert.deepEqual(parseExternalPlugins(undefined), []);
|
|
@@ -88,12 +106,12 @@ test("parseExternalPlugins: undefined returns []", () => {
|
|
|
88
106
|
});
|
|
89
107
|
test("parseExternalPlugins: well-formed array round-trips", () => {
|
|
90
108
|
const raw = [
|
|
91
|
-
{ name: "telegram", marketplace: "claude-plugins-official",
|
|
109
|
+
{ name: "telegram", marketplace: "claude-plugins-official", channelPlugin: true },
|
|
92
110
|
{ name: "discord", marketplace: "claude-plugins-official" },
|
|
93
111
|
];
|
|
94
112
|
const out = parseExternalPlugins(raw);
|
|
95
113
|
assert.deepEqual(out, [
|
|
96
|
-
{ name: "telegram", marketplace: "claude-plugins-official",
|
|
114
|
+
{ name: "telegram", marketplace: "claude-plugins-official", channelPlugin: true },
|
|
97
115
|
{ name: "discord", marketplace: "claude-plugins-official" },
|
|
98
116
|
]);
|
|
99
117
|
});
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { installAllBrewPackages } from "./brew-install.js";
|
|
|
16
16
|
import { parseSwVers, isSupportedMacosVersion } from "./macos-version.js";
|
|
17
17
|
import { decideChromiumAction, isSnapConfinedPath } from "./snap-chromium.js";
|
|
18
18
|
import { classifyPortHolder } from "./preflight-port-classifier.js";
|
|
19
|
-
import { parsePluginList, computeInstallActions,
|
|
19
|
+
import { parsePluginList, computeInstallActions, parseExternalPlugins, } from "./lib/plugin-install.js";
|
|
20
20
|
import { findPremiumMcpDirs } from "./lib/premium-mcp-discover.js";
|
|
21
21
|
import { pickLanInterface, mergeSmbConf, formatSambaMarker, } from "./samba-provision.js";
|
|
22
22
|
import { networkInterfaces, userInfo } from "node:os";
|
|
@@ -1997,15 +1997,45 @@ function registerLocalAndExternalPlugins() {
|
|
|
1997
1997
|
logFile(`[plugin-install] ERROR brand.externalPlugins parse error=${JSON.stringify(msg.slice(0, 200))}`);
|
|
1998
1998
|
}
|
|
1999
1999
|
desired.push(...externals);
|
|
2000
|
+
// The directory-source marketplaces are exactly the local trees discovered
|
|
2001
|
+
// from on-disk marketplace.json above. Remote marketplaces (the Anthropic
|
|
2002
|
+
// ones, GitHub externals) are never in this set, so they keep version-pinned
|
|
2003
|
+
// idempotence. (Task 643.)
|
|
2004
|
+
const directorySourceMarketplaces = new Set(localTrees.map(t => t.name));
|
|
2000
2005
|
// Snapshot what's installed to compute the install set.
|
|
2001
2006
|
const pluginList = spawnSync("claude", ["plugin", "list"], { stdio: "pipe", encoding: "utf-8", env: claudePluginEnv() });
|
|
2002
2007
|
const installed = parsePluginList(pluginList.stdout ?? "");
|
|
2003
|
-
const { toInstall, alreadyInstalled } = computeInstallActions(desired, installed);
|
|
2008
|
+
const { toInstall, toResync, alreadyInstalled } = computeInstallActions(desired, installed, directorySourceMarketplaces);
|
|
2004
2009
|
for (const ref of alreadyInstalled) {
|
|
2005
2010
|
logFile(`[plugin-install] ${ref.name}@${ref.marketplace} idempotent=true`);
|
|
2006
2011
|
}
|
|
2012
|
+
// Single source of truth for the install invocation, shared by the resync
|
|
2013
|
+
// and fresh-install loops so a future flag/timeout/scope change cannot drift
|
|
2014
|
+
// between them.
|
|
2015
|
+
const pluginInstall = (ref) => spawnSync("claude", ["plugin", "install", `${ref.name}@${ref.marketplace}`, "--scope", "user"], { stdio: "pipe", encoding: "utf-8", timeout: 120_000, env: claudePluginEnv() });
|
|
2016
|
+
// Resync directory-source plugins (Task 643). A directory marketplace
|
|
2017
|
+
// overwrites its tree in place on upgrade with no version bump, so the
|
|
2018
|
+
// runtime cache snapshot the session loads from (installed_plugins.json
|
|
2019
|
+
// `installPath`) freezes at first-install time — `plugin install` and
|
|
2020
|
+
// `plugin update` both short-circuit on the pinned version and never
|
|
2021
|
+
// re-copy. Uninstall then install is the only sequence that rebuilds the
|
|
2022
|
+
// snapshot from the live tree; `install` reads the directory source live.
|
|
2023
|
+
// The uninstall+install pair is not atomic: a failed reinstall leaves the
|
|
2024
|
+
// plugin deregistered, surfaced by the ERROR line below — hardening tracked
|
|
2025
|
+
// in Task 645.
|
|
2026
|
+
for (const ref of toResync) {
|
|
2027
|
+
spawnSync("claude", ["plugin", "uninstall", `${ref.name}@${ref.marketplace}`, "--scope", "user"], { stdio: "pipe", encoding: "utf-8", timeout: 120_000, env: claudePluginEnv() });
|
|
2028
|
+
const install = pluginInstall(ref);
|
|
2029
|
+
if (install.status === 0) {
|
|
2030
|
+
logFile(`[plugin-install] recache ${ref.name}@${ref.marketplace}`);
|
|
2031
|
+
}
|
|
2032
|
+
else {
|
|
2033
|
+
const stderrShort = (install.stderr ?? "").split("\n")[0]?.slice(0, 200) ?? "";
|
|
2034
|
+
logFile(`[plugin-install] ERROR recache ${ref.name}@${ref.marketplace} exit=${install.status} stderr=${JSON.stringify(stderrShort)}`);
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2007
2037
|
for (const ref of toInstall) {
|
|
2008
|
-
const install =
|
|
2038
|
+
const install = pluginInstall(ref);
|
|
2009
2039
|
if (install.status === 0) {
|
|
2010
2040
|
logFile(`[plugin-install] ${ref.name}@${ref.marketplace} idempotent=false`);
|
|
2011
2041
|
}
|
|
@@ -2014,30 +2044,51 @@ function registerLocalAndExternalPlugins() {
|
|
|
2014
2044
|
logFile(`[plugin-install] ERROR ${ref.name}@${ref.marketplace} exit=${install.status} stderr=${JSON.stringify(stderrShort)}`);
|
|
2015
2045
|
}
|
|
2016
2046
|
}
|
|
2017
|
-
//
|
|
2018
|
-
//
|
|
2019
|
-
//
|
|
2020
|
-
//
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2047
|
+
// Cache-vs-live audit (Task 643). Prove the per-plugin cache snapshot the
|
|
2048
|
+
// runtime loads from now matches the live tree, so drift is a logged
|
|
2049
|
+
// post-condition rather than a "no such skill" surprise in a later session.
|
|
2050
|
+
// Read the authoritative load path from installed_plugins.json
|
|
2051
|
+
// (`installPath`) rather than reconstructing the cache path from a pinned
|
|
2052
|
+
// version string. Warn-only: a count mismatch is surfaced, not fatal — a
|
|
2053
|
+
// benign skill directory without a SKILL.md must not abort the install.
|
|
2054
|
+
const countSkills = (skillsDir) => {
|
|
2055
|
+
if (!existsSync(skillsDir))
|
|
2056
|
+
return 0;
|
|
2057
|
+
let n = 0;
|
|
2058
|
+
for (const entry of readdirSync(skillsDir)) {
|
|
2059
|
+
if (existsSync(join(skillsDir, entry, "SKILL.md")))
|
|
2060
|
+
n++;
|
|
2061
|
+
}
|
|
2062
|
+
return n;
|
|
2063
|
+
};
|
|
2064
|
+
let installedPluginsMap = {};
|
|
2065
|
+
try {
|
|
2066
|
+
const ipPath = join(CLAUDE_CONFIG_DIR, "plugins", "installed_plugins.json");
|
|
2067
|
+
const parsed = JSON.parse(readFileSync(ipPath, "utf-8"));
|
|
2068
|
+
installedPluginsMap = parsed.plugins ?? {};
|
|
2069
|
+
}
|
|
2070
|
+
catch {
|
|
2071
|
+
// No readable installed_plugins.json — audit reports cache-skills=0; any
|
|
2072
|
+
// failed install above already logged a recache/install ERROR line.
|
|
2073
|
+
}
|
|
2074
|
+
// `treeDirByMarketplace` is keyed on the directory-source marketplace names
|
|
2075
|
+
// (= `directorySourceMarketplaces`), so a present tree dir is itself the
|
|
2076
|
+
// directory-source test — no separate Set lookup needed.
|
|
2077
|
+
const treeDirByMarketplace = new Map(localTrees.map(t => [t.name, t.dir]));
|
|
2078
|
+
for (const ref of desired) {
|
|
2079
|
+
const treeDir = treeDirByMarketplace.get(ref.marketplace);
|
|
2080
|
+
if (!treeDir)
|
|
2029
2081
|
continue;
|
|
2030
|
-
|
|
2031
|
-
// The
|
|
2032
|
-
//
|
|
2033
|
-
|
|
2034
|
-
const
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
}
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
logFile(`[plugin-configure] ERROR ${action.plugin.name} exit=${configure.status} stderr=${JSON.stringify(stderrShort)}`);
|
|
2082
|
+
const liveSkills = countSkills(join(treeDir, ref.name, "skills"));
|
|
2083
|
+
// The resync installs at `--scope user`, so audit that scope's snapshot —
|
|
2084
|
+
// not whichever entry happens to be first, since a host may also carry a
|
|
2085
|
+
// stale project-scope entry for the same plugin.
|
|
2086
|
+
const entries = installedPluginsMap[`${ref.name}@${ref.marketplace}`] ?? [];
|
|
2087
|
+
const installPath = (entries.find(e => e.scope === "user") ?? entries[0])?.installPath;
|
|
2088
|
+
const cacheSkills = installPath ? countSkills(join(installPath, "skills")) : 0;
|
|
2089
|
+
logFile(`[plugin-install] audit ${ref.name}@${ref.marketplace} live-skills=${liveSkills} cache-skills=${cacheSkills}`);
|
|
2090
|
+
if (liveSkills !== cacheSkills) {
|
|
2091
|
+
logFile(`[plugin-install] WARN cache-drift ${ref.name}@${ref.marketplace} live-skills=${liveSkills} cache-skills=${cacheSkills}`);
|
|
2041
2092
|
}
|
|
2042
2093
|
}
|
|
2043
2094
|
// post-install assertion. The per-brand CLAUDE_CONFIG_DIR is the
|
|
@@ -28,15 +28,30 @@ export function parsePluginList(stdout) {
|
|
|
28
28
|
return out;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
* Given the desired plugins
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
31
|
+
* Given the desired plugins, what's already installed, and which marketplaces
|
|
32
|
+
* are directory sources, classify each desired plugin into one of three
|
|
33
|
+
* buckets:
|
|
34
|
+
*
|
|
35
|
+
* - `toResync` — already installed AND from a directory-source
|
|
36
|
+
* marketplace. Directory marketplaces change content
|
|
37
|
+
* in place with no version bump, so `claude plugin
|
|
38
|
+
* install`/`update` short-circuit on the pinned
|
|
39
|
+
* version and never refresh the runtime cache snapshot
|
|
40
|
+
* (Task 643). These must be uninstalled then installed
|
|
41
|
+
* to rebuild the snapshot from the live tree.
|
|
42
|
+
* - `alreadyInstalled` — already installed AND from a remote (version-pinned)
|
|
43
|
+
* marketplace. Keeps the original idempotent skip.
|
|
44
|
+
* - `toInstall` — not installed yet. A fresh install builds a correct
|
|
45
|
+
* cache snapshot, so directory-source and remote
|
|
46
|
+
* plugins are handled identically here.
|
|
47
|
+
*
|
|
48
|
+
* "Already installed" matches either the exact `<name>@<marketplace>` tuple OR
|
|
49
|
+
* a row with the same name and any marketplace (legacy install state). The
|
|
50
|
+
* directory-source decision is keyed on the marketplace name regardless of
|
|
51
|
+
* which form matched, so a legacy name-only row for a directory plugin still
|
|
52
|
+
* resyncs.
|
|
38
53
|
*/
|
|
39
|
-
export function computeInstallActions(desired, installed) {
|
|
54
|
+
export function computeInstallActions(desired, installed, directorySourceMarketplaces) {
|
|
40
55
|
const byName = new Map();
|
|
41
56
|
for (const i of installed) {
|
|
42
57
|
if (!byName.has(i.name))
|
|
@@ -44,33 +59,23 @@ export function computeInstallActions(desired, installed) {
|
|
|
44
59
|
byName.get(i.name).add(i.marketplace);
|
|
45
60
|
}
|
|
46
61
|
const toInstall = [];
|
|
62
|
+
const toResync = [];
|
|
47
63
|
const alreadyInstalled = [];
|
|
48
64
|
for (const d of desired) {
|
|
49
65
|
const marketplaces = byName.get(d.name);
|
|
50
|
-
|
|
66
|
+
const isInstalled = !!marketplaces && (marketplaces.has(d.marketplace) || marketplaces.has(""));
|
|
67
|
+
const isDirectorySource = directorySourceMarketplaces.has(d.marketplace);
|
|
68
|
+
if (isInstalled && isDirectorySource) {
|
|
69
|
+
toResync.push(d);
|
|
70
|
+
}
|
|
71
|
+
else if (isInstalled) {
|
|
51
72
|
alreadyInstalled.push(d);
|
|
52
73
|
}
|
|
53
74
|
else {
|
|
54
75
|
toInstall.push(d);
|
|
55
76
|
}
|
|
56
77
|
}
|
|
57
|
-
return { toInstall, alreadyInstalled };
|
|
58
|
-
}
|
|
59
|
-
export function computeConfigureActions(installed, env) {
|
|
60
|
-
const out = [];
|
|
61
|
-
for (const p of installed) {
|
|
62
|
-
if (!p.configureSecret) {
|
|
63
|
-
out.push({ kind: "skip-no-secret-name", plugin: p });
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
const value = env[p.configureSecret];
|
|
67
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
68
|
-
out.push({ kind: "skip-no-secret-value", plugin: p });
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
out.push({ kind: "configure", plugin: p, secretValue: value });
|
|
72
|
-
}
|
|
73
|
-
return out;
|
|
78
|
+
return { toInstall, toResync, alreadyInstalled };
|
|
74
79
|
}
|
|
75
80
|
/** Brand-config validator. brand.json#externalPlugins is optional; when
|
|
76
81
|
* present, each entry must declare name + marketplace as non-empty
|
|
@@ -96,9 +101,6 @@ export function parseExternalPlugins(raw) {
|
|
|
96
101
|
throw new Error(`brand.json#externalPlugins[${e.name}] missing 'marketplace'`);
|
|
97
102
|
}
|
|
98
103
|
const ref = { name: e.name, marketplace: e.marketplace };
|
|
99
|
-
if (typeof e.configureSecret === "string" && e.configureSecret.length > 0) {
|
|
100
|
-
ref.configureSecret = e.configureSecret;
|
|
101
|
-
}
|
|
102
104
|
if (e.channelPlugin === true) {
|
|
103
105
|
ref.channelPlugin = true;
|
|
104
106
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Search-surface parity contract
|
|
2
|
+
|
|
3
|
+
Three operator/agent surfaces run the same `hybrid()` search engine
|
|
4
|
+
(`platform/lib/graph-search`). The contract: **the same query yields the same
|
|
5
|
+
node set on every surface** unless a surface declares an explicit, documented
|
|
6
|
+
divergence.
|
|
7
|
+
|
|
8
|
+
| Surface | Entry point | Labels default | Vector floor |
|
|
9
|
+
|---|---|---|---|
|
|
10
|
+
| Chat (agent recall) | `memory-search` MCP tool → `memorySearch()` | none set ⇒ all labels | `DEFAULT_VECTOR_THRESHOLD` (0.82) |
|
|
11
|
+
| `/graph` admin page | `GET /api/admin/graph-search` | no chips ⇒ all labels; chips narrow | `DEFAULT_VECTOR_THRESHOLD` (0.82), `?threshold` overrides |
|
|
12
|
+
| `/data` admin page | `GET /api/admin/graph-search?labels=FileArtifact` | `FileArtifact` only (files) | `DEFAULT_VECTOR_THRESHOLD` (0.82), `?threshold` overrides; show-all sends `?threshold=0` |
|
|
13
|
+
|
|
14
|
+
## The two parity rules (Task 635)
|
|
15
|
+
|
|
16
|
+
1. **All labels by default.** A caller that passes no labels (chat) or an empty
|
|
17
|
+
chip set (`/graph`) searches every label — the route forwards `undefined` to
|
|
18
|
+
`hybrid()`, the lib's no-label gate, which queries every vector index. The
|
|
19
|
+
`*` wildcard is a separate explicit opt-in to the same all-labels path (no
|
|
20
|
+
current caller sends it; `/data` sends a real `FileArtifact` label instead).
|
|
21
|
+
`/graph` no longer rejects an empty chip set with a 400; chips, when present,
|
|
22
|
+
narrow post-filter.
|
|
23
|
+
|
|
24
|
+
2. **One vector floor, defined once.** `DEFAULT_VECTOR_THRESHOLD = 0.82` lives
|
|
25
|
+
in `platform/lib/graph-search/src/index.ts` and is the single source of
|
|
26
|
+
truth. Each *surface* opts into it as its default; `hybrid()` itself keeps
|
|
27
|
+
the `vectorThreshold === undefined ⇒ no floor` contract. Two literals of
|
|
28
|
+
0.82 in two files would be a drift vector — there is one constant, imported
|
|
29
|
+
by both the route (`src`) and `memory-search` (`dist`, so the lib must be
|
|
30
|
+
rebuilt for the memory plugin to see a change).
|
|
31
|
+
|
|
32
|
+
## Declared divergences (allowed, by explicit caller or post-filter)
|
|
33
|
+
|
|
34
|
+
- **`/data` is files-only.** It sends `labels=FileArtifact` — a deliberate
|
|
35
|
+
server-side caller filter to file nodes, not a parity break. (It also
|
|
36
|
+
triggers the route's `FileArtifact` index-reconcile branch before searching.)
|
|
37
|
+
- **`graph-subgraph` pivot mask.** `GET /api/admin/graph-subgraph?q=…` runs
|
|
38
|
+
`hybrid()` with `expandHops: 0` and **no** vector floor. Its output is not a
|
|
39
|
+
result list — it is intersected with a clicked node's neighbourhood to
|
|
40
|
+
narrow a pivot. "Same query, same results" does not apply to an intersection
|
|
41
|
+
mask, so it intentionally stays unthresholded.
|
|
42
|
+
- **Post-search projections** — the chat public-twin property rewrite and the
|
|
43
|
+
`/graph` Message→Conversation parent merge run after the engine returns and
|
|
44
|
+
do not change which nodes the engine selected.
|
|
45
|
+
|
|
46
|
+
## Diagnostics
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
logs-read.sh --tail server 100 | grep -E '\[graph-search\]'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- `op=labels-default applied=all` — a no-chip `/graph` request took the
|
|
53
|
+
all-labels path. Its absence on a no-labels request is the regression signal.
|
|
54
|
+
- `labels=all` (query line) — no chips (all labels); `labels=*` — explicit
|
|
55
|
+
wildcard opt-in; `labels=FileArtifact` — `/data` files search;
|
|
56
|
+
`labels=Person,…` — narrowed chip search.
|
|
57
|
+
- `threshold=0.82` on a default request; `threshold=off` only when an explicit
|
|
58
|
+
`?threshold=0` was passed.
|
|
@@ -15,6 +15,14 @@
|
|
|
15
15
|
"rfbPort": 5901,
|
|
16
16
|
"websockifyPort": 6081,
|
|
17
17
|
"cdpPort": 9223
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"hostname": "siteoffice-code",
|
|
21
|
+
"configDir": ".siteoffice-code",
|
|
22
|
+
"vncDisplay": 101,
|
|
23
|
+
"rfbPort": 5902,
|
|
24
|
+
"websockifyPort": 6082,
|
|
25
|
+
"cdpPort": 9224
|
|
18
26
|
}
|
|
19
27
|
]
|
|
20
28
|
}
|
|
@@ -68,12 +68,12 @@
|
|
|
68
68
|
"plugins": {
|
|
69
69
|
"core": ["admin", "memory", "docs", "cloudflare", "anthropic", "workflows", "work", "business-assistant", "contacts", "scheduling", "email", "prompt-optimiser", "browser"],
|
|
70
70
|
"defaultEnabled": ["sales"],
|
|
71
|
-
"available": ["deep-research", "projects", "whatsapp", "replicate", "linkedin-import", "notion-import", "obsidian-import", "x-import"],
|
|
71
|
+
"available": ["deep-research", "projects", "whatsapp", "replicate", "linkedin-import", "notion-import", "obsidian-import", "x-import", "slides"],
|
|
72
72
|
"excluded": ["telegram"]
|
|
73
73
|
},
|
|
74
74
|
|
|
75
75
|
"externalPlugins": [
|
|
76
|
-
{ "name": "discord", "marketplace": "claude-plugins-official", "
|
|
76
|
+
{ "name": "discord", "marketplace": "claude-plugins-official", "channelPlugin": true },
|
|
77
77
|
{ "name": "imessage", "marketplace": "claude-plugins-official", "channelPlugin": true },
|
|
78
78
|
{ "name": "superpowers", "marketplace": "claude-plugins-official" },
|
|
79
79
|
{ "name": "code-review", "marketplace": "claude-plugins-official" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAU1C,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAa3D;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAarE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Shared Ollama embed client. Single capped implementation used by every
|
|
3
|
+
// process that writes a vector-indexed node outside the memory plugin (admin
|
|
4
|
+
// MCP PIN setup, scheduling ICS ingest, UI lazy Person create). The memory
|
|
5
|
+
// plugin's `lib/embeddings.ts` re-exports these so there is one cap constant
|
|
6
|
+
// and one POST shape across the platform (Task 636). fetch-only — no node:fs —
|
|
7
|
+
// so it is safe to bundle into the ESM payload.
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.EMBED_INPUT_MAX_CHARS = void 0;
|
|
10
|
+
exports.embed = embed;
|
|
11
|
+
exports.embedBatch = embedBatch;
|
|
12
|
+
const OLLAMA_URL = process.env.OLLAMA_URL ?? "http://localhost:11434";
|
|
13
|
+
const EMBED_MODEL = process.env.EMBED_MODEL ?? "nomic-embed-text";
|
|
14
|
+
// nomic-embed-text has a 2048-token context (~8k chars at ~4 chars/token).
|
|
15
|
+
// An over-limit input makes the Ollama embed endpoint error; cap defensively so
|
|
16
|
+
// an oversized body embeds (truncated) instead of throwing and aborting the
|
|
17
|
+
// caller.
|
|
18
|
+
exports.EMBED_INPUT_MAX_CHARS = 8000;
|
|
19
|
+
function capInput(text) {
|
|
20
|
+
if (text.length <= exports.EMBED_INPUT_MAX_CHARS)
|
|
21
|
+
return text;
|
|
22
|
+
process.stderr.write(`[embed] op=truncate origBytes=${text.length} cappedBytes=${exports.EMBED_INPUT_MAX_CHARS}\n`);
|
|
23
|
+
return text.slice(0, exports.EMBED_INPUT_MAX_CHARS);
|
|
24
|
+
}
|
|
25
|
+
async function embed(text) {
|
|
26
|
+
const input = capInput(text);
|
|
27
|
+
const res = await fetch(`${OLLAMA_URL}/api/embed`, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: { "Content-Type": "application/json" },
|
|
30
|
+
body: JSON.stringify({ model: EMBED_MODEL, input }),
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
const body = await res.text();
|
|
34
|
+
throw new Error(`Ollama embedding failed (${res.status}): ${body}`);
|
|
35
|
+
}
|
|
36
|
+
const data = (await res.json());
|
|
37
|
+
return data.embeddings[0];
|
|
38
|
+
}
|
|
39
|
+
async function embedBatch(texts) {
|
|
40
|
+
const input = texts.map(capInput);
|
|
41
|
+
const res = await fetch(`${OLLAMA_URL}/api/embed`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: { "Content-Type": "application/json" },
|
|
44
|
+
body: JSON.stringify({ model: EMBED_MODEL, input }),
|
|
45
|
+
});
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
const body = await res.text();
|
|
48
|
+
throw new Error(`Ollama batch embedding failed (${res.status}): ${body}`);
|
|
49
|
+
}
|
|
50
|
+
const data = (await res.json());
|
|
51
|
+
return data.embeddings;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,yEAAyE;AACzE,6EAA6E;AAC7E,2EAA2E;AAC3E,6EAA6E;AAC7E,+EAA+E;AAC/E,gDAAgD;;;AAmBhD,sBAaC;AAED,gCAaC;AA7CD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,wBAAwB,CAAC;AACtE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,kBAAkB,CAAC;AAElE,2EAA2E;AAC3E,gFAAgF;AAChF,4EAA4E;AAC5E,UAAU;AACG,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,IAAI,CAAC,MAAM,IAAI,6BAAqB;QAAE,OAAO,IAAI,CAAC;IACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iCAAiC,IAAI,CAAC,MAAM,gBAAgB,6BAAqB,IAAI,CACtF,CAAC;IACF,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,6BAAqB,CAAC,CAAC;AAC9C,CAAC;AAEM,KAAK,UAAU,KAAK,CAAC,IAAY;IACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,YAAY,EAAE;QACjD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;KACpD,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA+B,CAAC;IAC9D,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC5B,CAAC;AAEM,KAAK,UAAU,UAAU,CAAC,KAAe;IAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,YAAY,EAAE;QACjD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;KACpD,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,kCAAkC,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA+B,CAAC;IAC9D,OAAO,IAAI,CAAC,UAAU,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Shared Ollama embed client. Single capped implementation used by every
|
|
2
|
+
// process that writes a vector-indexed node outside the memory plugin (admin
|
|
3
|
+
// MCP PIN setup, scheduling ICS ingest, UI lazy Person create). The memory
|
|
4
|
+
// plugin's `lib/embeddings.ts` re-exports these so there is one cap constant
|
|
5
|
+
// and one POST shape across the platform (Task 636). fetch-only — no node:fs —
|
|
6
|
+
// so it is safe to bundle into the ESM payload.
|
|
7
|
+
|
|
8
|
+
const OLLAMA_URL = process.env.OLLAMA_URL ?? "http://localhost:11434";
|
|
9
|
+
const EMBED_MODEL = process.env.EMBED_MODEL ?? "nomic-embed-text";
|
|
10
|
+
|
|
11
|
+
// nomic-embed-text has a 2048-token context (~8k chars at ~4 chars/token).
|
|
12
|
+
// An over-limit input makes the Ollama embed endpoint error; cap defensively so
|
|
13
|
+
// an oversized body embeds (truncated) instead of throwing and aborting the
|
|
14
|
+
// caller.
|
|
15
|
+
export const EMBED_INPUT_MAX_CHARS = 8000;
|
|
16
|
+
|
|
17
|
+
function capInput(text: string): string {
|
|
18
|
+
if (text.length <= EMBED_INPUT_MAX_CHARS) return text;
|
|
19
|
+
process.stderr.write(
|
|
20
|
+
`[embed] op=truncate origBytes=${text.length} cappedBytes=${EMBED_INPUT_MAX_CHARS}\n`,
|
|
21
|
+
);
|
|
22
|
+
return text.slice(0, EMBED_INPUT_MAX_CHARS);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function embed(text: string): Promise<number[]> {
|
|
26
|
+
const input = capInput(text);
|
|
27
|
+
const res = await fetch(`${OLLAMA_URL}/api/embed`, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: { "Content-Type": "application/json" },
|
|
30
|
+
body: JSON.stringify({ model: EMBED_MODEL, input }),
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
const body = await res.text();
|
|
34
|
+
throw new Error(`Ollama embedding failed (${res.status}): ${body}`);
|
|
35
|
+
}
|
|
36
|
+
const data = (await res.json()) as { embeddings: number[][] };
|
|
37
|
+
return data.embeddings[0];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function embedBatch(texts: string[]): Promise<number[][]> {
|
|
41
|
+
const input = texts.map(capInput);
|
|
42
|
+
const res = await fetch(`${OLLAMA_URL}/api/embed`, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: { "Content-Type": "application/json" },
|
|
45
|
+
body: JSON.stringify({ model: EMBED_MODEL, input }),
|
|
46
|
+
});
|
|
47
|
+
if (!res.ok) {
|
|
48
|
+
const body = await res.text();
|
|
49
|
+
throw new Error(`Ollama batch embedding failed (${res.status}): ${body}`);
|
|
50
|
+
}
|
|
51
|
+
const data = (await res.json()) as { embeddings: number[][] };
|
|
52
|
+
return data.embeddings;
|
|
53
|
+
}
|