@unbrained/pm-cli 2026.7.17 → 2026.7.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +13 -0
- package/dist/cli/commands/close.d.ts +1 -1
- package/dist/cli/commands/close.js +3 -3
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/completion.js +47 -5
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/context.d.ts +2 -2
- package/dist/cli/commands/context.js +42 -28
- package/dist/cli/commands/context.js.map +1 -1
- package/dist/cli/commands/contracts.js +5 -3
- package/dist/cli/commands/contracts.js.map +1 -1
- package/dist/cli/commands/graph.d.ts +7 -0
- package/dist/cli/commands/graph.js +11 -0
- package/dist/cli/commands/graph.js.map +1 -0
- package/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.js +3 -2
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/next.d.ts +1 -1
- package/dist/cli/commands/next.js +3 -3
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/cli/main.js +3 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/register-list-query.js +49 -7
- package/dist/cli/register-list-query.js.map +1 -1
- package/dist/cli/register-mutation.js +7 -3
- package/dist/cli/register-mutation.js.map +1 -1
- package/dist/cli-bundle/bundle-manifest.json +157 -149
- package/dist/cli-bundle/chunks/{chunk-N7I2DGLP.js → chunk-35FHWD4C.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-37V5MXAU.js.map → chunk-35FHWD4C.js.map} +1 -7
- package/dist/cli-bundle/chunks/{chunk-MSGETE6I.js → chunk-3CUQZNQ6.js} +67 -509
- package/dist/cli-bundle/chunks/chunk-3CUQZNQ6.js.map +7 -0
- package/dist/cli-bundle/chunks/chunk-3QDR6ZLU.js +800 -0
- package/dist/cli-bundle/chunks/chunk-3QDR6ZLU.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-QNUAZYGW.js → chunk-43UMFKCK.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-HF63SBLC.js → chunk-6VHUGVNP.js} +39 -16
- package/dist/cli-bundle/chunks/chunk-6VHUGVNP.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-B6SH2YNN.js → chunk-7R6UIHYY.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-NCAFUBJX.js → chunk-7UCY6DR5.js} +183 -12
- package/dist/cli-bundle/chunks/chunk-7UCY6DR5.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-23TCGBRK.js → chunk-ADXDCAKP.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-7LTCLTRG.js → chunk-AXRT7K5V.js} +16 -3
- package/dist/cli-bundle/chunks/chunk-AXRT7K5V.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-P56LKFQX.js → chunk-BDA35QG5.js} +34 -4
- package/dist/cli-bundle/chunks/chunk-BDA35QG5.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-2MPMKJF2.js → chunk-DHNG452T.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-AFSV5HBB.js → chunk-E4FXM2XB.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-QKVVV6QO.js → chunk-EWIT5WIC.js} +3 -3
- package/dist/cli-bundle/chunks/chunk-EX7OQT3Y.js +783 -0
- package/dist/cli-bundle/chunks/chunk-EX7OQT3Y.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-LLODAQMP.js → chunk-F3VC3GOV.js} +41 -18
- package/dist/cli-bundle/chunks/chunk-F3VC3GOV.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-S46R2M3W.js → chunk-GKPCTQYG.js} +1709 -5
- package/dist/cli-bundle/chunks/chunk-GKPCTQYG.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-HXVHBERL.js → chunk-HPAYDSR2.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-XNPMDSQQ.js → chunk-HYTOJW2Q.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-V3VBXQQV.js → chunk-I3INI567.js} +516 -429
- package/dist/cli-bundle/chunks/chunk-I3INI567.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-V7MP6YTN.js → chunk-IL5SPRMH.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-YQCWK2MB.js → chunk-L5BTTDU5.js} +68 -503
- package/dist/cli-bundle/chunks/chunk-L5BTTDU5.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-SIJV365F.js → chunk-NCVT6XEL.js} +17 -4
- package/dist/cli-bundle/chunks/chunk-NCVT6XEL.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-DCC2AQBD.js → chunk-OGVTB5VO.js} +32 -31
- package/dist/cli-bundle/chunks/chunk-OGVTB5VO.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-6XAZB6SE.js → chunk-QPGQNLPI.js} +1660 -7
- package/dist/cli-bundle/chunks/chunk-QPGQNLPI.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-KOEZCHRF.js → chunk-QRZNCRNA.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-G6KM4YKY.js → chunk-RXPQ5Q23.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-7CTQ7WW5.js → chunk-SIPOACV5.js} +514 -427
- package/dist/cli-bundle/chunks/chunk-SIPOACV5.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-XYJK6GIQ.js → chunk-TGBTLGPX.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-37V5MXAU.js → chunk-TLWJP5BF.js} +3 -3
- package/dist/cli-bundle/chunks/chunk-TLWJP5BF.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-3D4YVTNG.js → chunk-TZAE66GQ.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-S6FF7VW6.js → chunk-WQXRZMFN.js} +187 -16
- package/dist/cli-bundle/chunks/chunk-WQXRZMFN.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-SPFZV2GR.js → chunk-XPUTSGJU.js} +32 -31
- package/dist/cli-bundle/chunks/chunk-XPUTSGJU.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-CFSUNEL7.js → chunk-XWBD6DSR.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-MNV226E4.js → chunk-XWYQ2LT4.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-I7GY4X6Y.js → chunk-YFE7JHX3.js} +26 -5
- package/dist/cli-bundle/chunks/chunk-YFE7JHX3.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-FZGM3PNA.js → chunk-YIIIAKCE.js} +2 -2
- package/dist/cli-bundle/chunks/{close-BEP7MHF3.js → close-GPD7DTJV.js} +3 -3
- package/dist/cli-bundle/chunks/{close-Y6QFUJQN.js → close-X3CF6FQP.js} +3 -3
- package/dist/cli-bundle/chunks/{close-many-JJFW7KTT.js → close-many-J7A5EHOQ.js} +5 -5
- package/dist/cli-bundle/chunks/{close-many-QJ6FKJUE.js → close-many-NQLYGPYW.js} +5 -5
- package/dist/cli-bundle/chunks/{deps-EVTOQMKW.js → deps-MQ4ZIGZB.js} +13 -4
- package/dist/cli-bundle/chunks/{deps-5NC4IZH7.js → deps-NIIKXLPB.js} +13 -4
- package/dist/cli-bundle/chunks/{profile-U2B6Y7GE.js → profile-AVCIIZID.js} +3 -3
- package/dist/cli-bundle/chunks/{profile-AGUKS52S.js → profile-LFYO3HHX.js} +3 -3
- package/dist/cli-bundle/chunks/{register-list-query-A5KRJ5J2.js → register-list-query-MZUF2EEC.js} +41 -13
- package/dist/cli-bundle/chunks/register-list-query-MZUF2EEC.js.map +1 -0
- package/dist/cli-bundle/chunks/{register-list-query-NEYP3TXO.js → register-list-query-UKMF55FT.js} +40 -12
- package/dist/cli-bundle/chunks/register-list-query-UKMF55FT.js.map +7 -0
- package/dist/cli-bundle/chunks/{register-mutation-6LOPBAHC.js → register-mutation-2PBW2GEX.js} +15 -13
- package/dist/cli-bundle/chunks/register-mutation-2PBW2GEX.js.map +1 -0
- package/dist/cli-bundle/chunks/{register-mutation-GCZOALNJ.js → register-mutation-T6RVNJC4.js} +14 -12
- package/dist/cli-bundle/chunks/{register-mutation-GCZOALNJ.js.map → register-mutation-T6RVNJC4.js.map} +2 -2
- package/dist/cli-bundle/chunks/{register-operations-6ZZIF27A.js → register-operations-KHZYR6MG.js} +11 -11
- package/dist/cli-bundle/chunks/{register-operations-REDIAEGI.js → register-operations-WPQ2LWZJ.js} +11 -11
- package/dist/cli-bundle/chunks/{register-setup-J3JS2ZVT.js → register-setup-PGDNOXDQ.js} +5 -5
- package/dist/cli-bundle/chunks/{register-setup-BHPMN5SK.js → register-setup-TDN7WAO6.js} +5 -5
- package/dist/cli-bundle/chunks/{update-SA6AG23P.js → update-SQYZA3ZW.js} +4 -4
- package/dist/cli-bundle/chunks/{update-PQQHLYCC.js → update-XZJYS5X7.js} +4 -4
- package/dist/cli-bundle/chunks/{update-many-RQVTFJPD.js → update-many-R24B3GBK.js} +6 -6
- package/dist/cli-bundle/chunks/{update-many-TV3L3KBX.js → update-many-WQ3R3J6N.js} +6 -6
- package/dist/cli-bundle/main.js +25 -9
- package/dist/cli-bundle/main.js.map +2 -2
- package/dist/cli-bundle/sdk-runtime.js +19 -16
- package/dist/cli-bundle/sdk.js +95 -305
- package/dist/cli-bundle/sdk.js.map +4 -4
- package/dist/core/item/actionability.d.ts +12 -0
- package/dist/core/item/actionability.js +39 -4
- package/dist/core/item/actionability.js.map +1 -1
- package/dist/core/sentry/instrument.d.ts +11 -0
- package/dist/core/sentry/instrument.js +21 -2
- package/dist/core/sentry/instrument.js.map +1 -1
- package/dist/mcp/server.d.ts +16 -18
- package/dist/mcp/server.js +84 -31
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool-definitions.js +17 -4
- package/dist/mcp/tool-definitions.js.map +1 -1
- package/dist/sdk/actionability.d.ts +10 -0
- package/dist/sdk/actionability.js +14 -0
- package/dist/sdk/actionability.js.map +1 -0
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +6 -2
- package/dist/sdk/cli-contracts/enum-contracts.js +19 -2
- package/dist/sdk/cli-contracts/enum-contracts.js.map +1 -1
- package/dist/sdk/cli-contracts/flag-contracts.d.ts +2 -0
- package/dist/sdk/cli-contracts/flag-contracts.js +21 -2
- package/dist/sdk/cli-contracts/flag-contracts.js.map +1 -1
- package/dist/sdk/cli-contracts/tool-option-contracts.d.ts +2 -0
- package/dist/sdk/cli-contracts/tool-option-contracts.js +16 -2
- package/dist/sdk/cli-contracts/tool-option-contracts.js.map +1 -1
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +80 -3
- package/dist/sdk/cli-contracts/tool-parameter-tables.js.map +1 -1
- package/dist/sdk/cli-contracts/tool-schema.d.ts +20 -0
- package/dist/sdk/cli-contracts/tool-schema.js +97 -9
- package/dist/sdk/cli-contracts/tool-schema.js.map +1 -1
- package/dist/sdk/cli-contracts.d.ts +2 -2
- package/dist/sdk/cli-contracts.js +4 -4
- package/dist/sdk/cli-contracts.js.map +1 -1
- package/dist/sdk/dependencies.d.ts +42 -53
- package/dist/sdk/dependencies.js +177 -125
- package/dist/sdk/dependencies.js.map +1 -1
- package/dist/sdk/governance/validate.js +3 -3
- package/dist/sdk/governance/validate.js.map +1 -1
- package/dist/sdk/graph/analytics.d.ts +124 -0
- package/dist/sdk/graph/analytics.js +464 -0
- package/dist/sdk/graph/analytics.js.map +1 -0
- package/dist/sdk/graph/assembly.d.ts +97 -0
- package/dist/sdk/graph/assembly.js +146 -0
- package/dist/sdk/graph/assembly.js.map +1 -0
- package/dist/sdk/graph/cache.d.ts +66 -0
- package/dist/sdk/graph/cache.js +148 -0
- package/dist/sdk/graph/cache.js.map +1 -0
- package/dist/sdk/graph/governance.d.ts +108 -0
- package/dist/sdk/graph/governance.js +360 -0
- package/dist/sdk/graph/governance.js.map +1 -0
- package/dist/sdk/graph/index.d.ts +16 -0
- package/dist/sdk/graph/index.js +20 -0
- package/dist/sdk/graph/index.js.map +1 -0
- package/dist/sdk/graph/remediation.d.ts +52 -0
- package/dist/sdk/graph/remediation.js +148 -0
- package/dist/sdk/graph/remediation.js.map +1 -0
- package/dist/sdk/graph/run.d.ts +295 -0
- package/dist/sdk/graph/run.js +468 -0
- package/dist/sdk/graph/run.js.map +1 -0
- package/dist/sdk/graph/traversal.d.ts +77 -0
- package/dist/sdk/graph/traversal.js +262 -0
- package/dist/sdk/graph/traversal.js.map +1 -0
- package/dist/sdk/index.d.ts +4 -2
- package/dist/sdk/index.js +6 -4
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/query/list.d.ts +8 -0
- package/dist/sdk/query/list.js +19 -3
- package/dist/sdk/query/list.js.map +1 -1
- package/dist/sdk/relationship-context.d.ts +42 -0
- package/dist/sdk/relationship-context.js +99 -20
- package/dist/sdk/relationship-context.js.map +1 -1
- package/dist/sdk/relationships.d.ts +13 -0
- package/dist/sdk/relationships.js +30 -2
- package/dist/sdk/relationships.js.map +1 -1
- package/dist/sdk/runtime-input.d.ts +41 -0
- package/dist/sdk/runtime-input.js +422 -2
- package/dist/sdk/runtime-input.js.map +1 -1
- package/dist/sdk/runtime.d.ts +12 -23
- package/dist/sdk/runtime.js +19 -371
- package/dist/sdk/runtime.js.map +1 -1
- package/dist/sdk/test/linked-command-detection.js +12 -3
- package/dist/sdk/test/linked-command-detection.js.map +1 -1
- package/docs/AGENT_GUIDE.md +1 -0
- package/docs/COMMANDS.md +19 -1
- package/docs/RELATIONSHIP_GRAPH.md +99 -3
- package/docs/SDK.md +17 -3
- package/marketplace.json +2 -2
- package/package.json +1 -1
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/dist/cli-bundle/chunks/chunk-6XAZB6SE.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-7CTQ7WW5.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-7LTCLTRG.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-DCC2AQBD.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-HF63SBLC.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-I7GY4X6Y.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-LLODAQMP.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-MSGETE6I.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-N7I2DGLP.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-NCAFUBJX.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-P56LKFQX.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-S46R2M3W.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-S6FF7VW6.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-SIJV365F.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-SPFZV2GR.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-V3VBXQQV.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-YQCWK2MB.js.map +0 -1
- package/dist/cli-bundle/chunks/register-list-query-A5KRJ5J2.js.map +0 -1
- package/dist/cli-bundle/chunks/register-list-query-NEYP3TXO.js.map +0 -7
- package/dist/cli-bundle/chunks/register-mutation-6LOPBAHC.js.map +0 -1
- /package/dist/cli-bundle/chunks/{chunk-QNUAZYGW.js.map → chunk-43UMFKCK.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-B6SH2YNN.js.map → chunk-7R6UIHYY.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-23TCGBRK.js.map → chunk-ADXDCAKP.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-2MPMKJF2.js.map → chunk-DHNG452T.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-AFSV5HBB.js.map → chunk-E4FXM2XB.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-QKVVV6QO.js.map → chunk-EWIT5WIC.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-HXVHBERL.js.map → chunk-HPAYDSR2.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-XNPMDSQQ.js.map → chunk-HYTOJW2Q.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-V7MP6YTN.js.map → chunk-IL5SPRMH.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-KOEZCHRF.js.map → chunk-QRZNCRNA.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-G6KM4YKY.js.map → chunk-RXPQ5Q23.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-XYJK6GIQ.js.map → chunk-TGBTLGPX.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-3D4YVTNG.js.map → chunk-TZAE66GQ.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-CFSUNEL7.js.map → chunk-XWBD6DSR.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-MNV226E4.js.map → chunk-XWYQ2LT4.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-FZGM3PNA.js.map → chunk-YIIIAKCE.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{close-BEP7MHF3.js.map → close-GPD7DTJV.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{close-Y6QFUJQN.js.map → close-X3CF6FQP.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{close-many-JJFW7KTT.js.map → close-many-J7A5EHOQ.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{close-many-QJ6FKJUE.js.map → close-many-NQLYGPYW.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{deps-EVTOQMKW.js.map → deps-MQ4ZIGZB.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{deps-5NC4IZH7.js.map → deps-NIIKXLPB.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{profile-U2B6Y7GE.js.map → profile-AVCIIZID.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{profile-AGUKS52S.js.map → profile-LFYO3HHX.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{register-operations-6ZZIF27A.js.map → register-operations-KHZYR6MG.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{register-operations-REDIAEGI.js.map → register-operations-WPQ2LWZJ.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{register-setup-J3JS2ZVT.js.map → register-setup-PGDNOXDQ.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{register-setup-BHPMN5SK.js.map → register-setup-TDN7WAO6.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{update-SA6AG23P.js.map → update-SQYZA3ZW.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{update-PQQHLYCC.js.map → update-XZJYS5X7.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{update-many-RQVTFJPD.js.map → update-many-R24B3GBK.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{update-many-TV3L3KBX.js.map → update-many-WQ3R3J6N.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.js","sources":["sdk/graph/analytics.ts"],"sourceRoot":"/","sourcesContent":["/**\n * @module sdk/graph/analytics\n *\n * Structural graph analytics beyond exact components: deterministic\n * label-propagation community detection over the undirected relationship\n * structure, transitively redundant edge discovery over ordering and\n * hierarchy families, and dominator (bottleneck) analysis over one node's\n * reachable subgraph. Every analysis is deterministic, cancellable, bounded,\n * and reports exact cost metadata so agents can budget follow-up reads\n * without re-scanning the workspace.\n */\nimport {\n RelationshipGraph,\n type RelationshipEdge,\n type RelationshipKindDefinition,\n type RelationshipNeighborEdge,\n type RelationshipQueryResult,\n type RelationshipTraversalDirection,\n} from \"../relationships.js\";\nimport {\n hierarchyParentEndpoint,\n orderingPredecessorEndpoint,\n} from \"./traversal.js\";\n\n/** Default label-propagation sweeps before reporting non-convergence. */\nconst DEFAULT_MAX_ITERATIONS = 16;\n/** Default minimum member count for a reported community. */\nconst DEFAULT_MIN_COMMUNITY_SIZE = 2;\n/** Default witness-path depth searched per candidate redundant edge. */\nconst DEFAULT_REDUNDANCY_MAX_DEPTH = 8;\n\n/** One detected relationship community. */\nexport interface RelationshipCommunity {\n /** Lexicographically smallest member id, naming the community. */\n representative: string;\n /** Total member count. */\n size: number;\n /** Sorted member node ids. */\n members: string[];\n}\n\n/** Bounded community-detection controls. */\nexport interface GraphCommunityOptions {\n /** Registered relationship kinds whose edges define adjacency. */\n kinds?: readonly string[];\n /** Maximum label-propagation sweeps before reporting non-convergence; defaults to 16. */\n maxIterations?: number;\n /** Minimum member count for a reported community; defaults to 2. */\n minSize?: number;\n /** Abort signal checked once per sweep. */\n signal?: AbortSignal;\n}\n\n/** Deterministic label-propagation community analysis. */\nexport interface RelationshipCommunityAnalysis {\n /** Detected communities, largest first and by representative within equal size. */\n communities: RelationshipCommunity[];\n /** Label-propagation sweeps executed. */\n iterations: number;\n /** Whether labels stabilized before the iteration bound stopped the sweep. */\n converged: boolean;\n}\n\n/** One stored edge implied by a longer same-family witness path. */\nexport interface RedundantRelationshipEdge {\n /** The stored redundant edge in its original spelling. */\n edge: RelationshipEdge;\n /** Semantic-orientation witness node path proving the implication, endpoints inclusive. */\n witness: string[];\n}\n\n/** Bounded redundancy-scan controls. */\nexport interface GraphRedundancyOptions {\n /** Directed ordering or hierarchy kinds to scan; defaults to every eligible registered kind. */\n kinds?: readonly string[];\n /** Maximum witness-path depth searched per edge; defaults to 8. */\n maxDepth?: number;\n /** Maximum reported redundant edges. */\n limit?: number;\n /** Abort signal checked once per scanned edge. */\n signal?: AbortSignal;\n}\n\n/** One reachable node with its immediate dominator and gating weight. */\nexport interface RelationshipDominatorRow {\n /** Reachable node id. */\n id: string;\n /** Immediate dominator appearing on every root-to-node path. */\n idom: string;\n /** Nodes strictly dominated by this node — its dominator-subtree size minus itself. */\n dominatedCount: number;\n}\n\n/** Bounded dominator-analysis controls. */\nexport interface GraphDominatorOptions {\n /** Registered relationship kinds whose edges define reachability. */\n kinds?: readonly string[];\n /** Traversal direction relative to each visited node; defaults to \"outgoing\". */\n direction?: RelationshipTraversalDirection;\n /** Maximum reachability depth from the root as a non-negative integer. */\n maxDepth?: number;\n /** Abort signal checked once per processed node. */\n signal?: AbortSignal;\n}\n\n/** Dominator-tree analysis of one node's reachable subgraph. */\nexport interface RelationshipDominatorAnalysis {\n /** Analyzed root id. */\n root: string;\n /** Reachable node count including the root. */\n reachableCount: number;\n /** Non-root reachable rows sorted by gating weight, then id. */\n rows: RelationshipDominatorRow[];\n}\n\n/** Require a positive integer for one analytics bound. */\nfunction assertPositiveBound(name: string, value: number): void {\n if (!Number.isInteger(value) || value < 1)\n throw new TypeError(`Invalid ${name} bound: ${String(value)}`);\n}\n\n/** Build the deterministic undirected adjacency restricted to canonicalized kinds. */\nfunction buildUndirectedAdjacency(\n graph: RelationshipGraph,\n kinds: readonly string[] | undefined,\n): Map<string, string[]> {\n const registry = graph.registry();\n const wanted =\n kinds === undefined\n ? undefined\n : new Set(kinds.map((kind) => registry.require(kind).kind));\n const adjacency = new Map<string, string[]>();\n for (const edge of graph.edges()) {\n if (edge.source === edge.target) continue;\n if (wanted !== undefined) {\n const definition = registry.require(edge.kind);\n const matches =\n wanted.has(definition.kind) ||\n (definition.inverse !== undefined && wanted.has(definition.inverse));\n if (!matches) continue;\n }\n appendAdjacency(adjacency, edge.source, edge.target);\n appendAdjacency(adjacency, edge.target, edge.source);\n }\n for (const neighbors of adjacency.values()) neighbors.sort();\n return adjacency;\n}\n\n/** Append one neighbor to a node's adjacency list, creating the list on demand. */\nfunction appendAdjacency(\n adjacency: Map<string, string[]>,\n from: string,\n to: string,\n): void {\n const neighbors = adjacency.get(from);\n if (neighbors === undefined) adjacency.set(from, [to]);\n else neighbors.push(to);\n}\n\n/** Adopt the most frequent neighbor label with lexicographic tie-breaking. */\nfunction dominantNeighborLabel(\n neighbors: readonly string[],\n labels: Map<string, string>,\n): string {\n const counts = new Map<string, number>();\n for (const neighbor of neighbors) {\n const label = labels.get(neighbor)!;\n counts.set(label, (counts.get(label) ?? 0) + 1);\n }\n let best: string | undefined;\n let bestCount = 0;\n for (const [label, count] of counts) {\n if (count > bestCount || (count === bestCount && label < best!)) {\n best = label;\n bestCount = count;\n }\n }\n return best!;\n}\n\n/** Group stabilized labels into sorted communities meeting the size floor. */\nfunction collectCommunities(\n labels: Map<string, string>,\n minSize: number,\n): RelationshipCommunity[] {\n const groups = new Map<string, string[]>();\n for (const [id, label] of labels) {\n const members = groups.get(label);\n if (members === undefined) groups.set(label, [id]);\n else members.push(id);\n }\n const communities: RelationshipCommunity[] = [];\n for (const members of groups.values()) {\n if (members.length < minSize) continue;\n members.sort();\n communities.push({\n representative: members[0]!,\n size: members.length,\n members,\n });\n }\n return communities.sort(\n (left, right) =>\n right.size - left.size ||\n left.representative.localeCompare(right.representative),\n );\n}\n\n/**\n * Detect communities with deterministic asynchronous label propagation: nodes\n * are swept in sorted order, each adopting the most frequent label among its\n * neighbors with lexicographic tie-breaking, until labels stabilize or the\n * iteration bound stops the sweep. Adjacency is undirected — every\n * participating edge connects both endpoints symmetrically and parallel edges\n * weight their neighbor. `meta.truncated` reports non-convergence.\n */\nexport function detectRelationshipCommunities(\n graph: RelationshipGraph,\n options: GraphCommunityOptions = {},\n): RelationshipQueryResult<RelationshipCommunityAnalysis> {\n const maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;\n const minSize = options.minSize ?? DEFAULT_MIN_COMMUNITY_SIZE;\n assertPositiveBound(\"maxIterations\", maxIterations);\n assertPositiveBound(\"minSize\", minSize);\n const adjacency = buildUndirectedAdjacency(graph, options.kinds);\n const nodes = graph.nodes();\n const labels = new Map(nodes.map((id) => [id, id]));\n let iterations = 0;\n let converged = false;\n let visitedNodes = 0;\n let inspectedEdges = 0;\n while (iterations < maxIterations && !converged) {\n options.signal?.throwIfAborted();\n iterations += 1;\n converged = true;\n for (const id of nodes) {\n visitedNodes += 1;\n const neighbors = adjacency.get(id);\n if (neighbors === undefined) continue;\n inspectedEdges += neighbors.length;\n const dominant = dominantNeighborLabel(neighbors, labels);\n if (dominant !== labels.get(id)) {\n labels.set(id, dominant);\n converged = false;\n }\n }\n }\n return {\n value: {\n communities: collectCommunities(labels, minSize),\n iterations,\n converged,\n },\n meta: { visitedNodes, inspectedEdges, truncated: !converged },\n };\n}\n\n/** Decide whether a kind carries transitive semantics eligible for redundancy and duplicate analysis. */\nexport function isTransitiveKind(definition: RelationshipKindDefinition): boolean {\n return (\n definition.direction === \"directed\" &&\n (definition.ordering || definition.hierarchy)\n );\n}\n\n/** Family grouping key joining a directed kind with its inverse spelling. */\nexport function transitiveFamilyKey(definition: RelationshipKindDefinition): string {\n return definition.inverse !== undefined &&\n definition.inverse < definition.kind\n ? definition.inverse\n : definition.kind;\n}\n\n/** Orient one transitive edge into its semantic forward direction. */\nexport function orientTransitiveEdge(\n edge: RelationshipEdge,\n definition: RelationshipKindDefinition,\n): { from: string; to: string } {\n // Hierarchy families flow child -> parent; ordering families flow\n // predecessor -> successor, so inverse spellings land in one relation.\n const head = definition.hierarchy\n ? hierarchyParentEndpoint(edge, definition)\n : edge.source === orderingPredecessorEndpoint(edge, definition)\n ? edge.target\n : edge.source;\n return head === edge.target\n ? { from: edge.source, to: edge.target }\n : { from: edge.target, to: edge.source };\n}\n\n/** One semantically oriented transitive edge retaining its stored spelling. */\ninterface OrientedTransitiveEdge {\n /** Semantic tail node. */\n from: string;\n /** Semantic head node. */\n to: string;\n /** Original stored edge. */\n edge: RelationshipEdge;\n}\n\n/** Per-family oriented edges and their deterministic forward adjacency. */\ninterface TransitiveFamily {\n /** Deduplicated forward adjacency in semantic orientation, sorted after collection. */\n adjacency: Map<string, Set<string>>;\n /** Oriented edges in deterministic stored order. */\n records: OrientedTransitiveEdge[];\n}\n\n/** Resolve explicit redundancy kind filters into their family keys. */\nfunction resolveRedundancyFamilies(\n graph: RelationshipGraph,\n kinds: readonly string[] | undefined,\n): Set<string> | undefined {\n if (kinds === undefined) return undefined;\n const registry = graph.registry();\n const families = new Set<string>();\n for (const kind of kinds) {\n const definition = registry.require(kind);\n if (!isTransitiveKind(definition))\n throw new TypeError(\n `Relationship kind ${definition.kind} is not a directed ordering or hierarchy kind`,\n );\n families.add(transitiveFamilyKey(definition));\n }\n return families;\n}\n\n/** Group eligible stored edges into oriented per-family scan structures. */\nfunction collectTransitiveFamilies(\n graph: RelationshipGraph,\n wanted: Set<string> | undefined,\n): Map<string, TransitiveFamily> {\n const registry = graph.registry();\n const families = new Map<string, TransitiveFamily>();\n for (const edge of graph.edges()) {\n const definition = registry.require(edge.kind);\n if (!isTransitiveKind(definition)) continue;\n const key = transitiveFamilyKey(definition);\n if (wanted !== undefined && !wanted.has(key)) continue;\n const oriented = orientTransitiveEdge(edge, definition);\n if (oriented.from === oriented.to) continue;\n let family = families.get(key);\n if (family === undefined) {\n family = { adjacency: new Map(), records: [] };\n families.set(key, family);\n }\n const targets = family.adjacency.get(oriented.from);\n if (targets === undefined)\n family.adjacency.set(oriented.from, new Set([oriented.to]));\n else targets.add(oriented.to);\n family.records.push({ ...oriented, edge });\n }\n return families;\n}\n\n/** Freeze one family's adjacency sets into deterministic sorted lists. */\nfunction sortedFamilyAdjacency(\n family: TransitiveFamily,\n): Map<string, readonly string[]> {\n const sorted = new Map<string, readonly string[]>();\n for (const [from, targets] of family.adjacency)\n sorted.set(from, [...targets].sort());\n return sorted;\n}\n\n/** Rebuild the witness node path from breadth-first parent pointers. */\nfunction reconstructWitness(\n parents: Map<string, string>,\n from: string,\n tail: string,\n head: string,\n): string[] {\n const witness = [head];\n for (let node = tail; node !== from; node = parents.get(node)!)\n witness.push(node);\n witness.push(from);\n return witness.reverse();\n}\n\n/** Expand one witness frontier node; return the completed witness when the head is reached. */\nfunction expandWitnessFrontier(\n adjacency: Map<string, readonly string[]>,\n record: OrientedTransitiveEdge,\n current: { id: string; depth: number },\n parents: Map<string, string>,\n queue: { id: string; depth: number }[],\n cost: { visitedNodes: number; inspectedEdges: number },\n): string[] | undefined {\n for (const next of adjacency.get(current.id) ?? []) {\n cost.inspectedEdges += 1;\n // Skip the direct edge under test; deeper hops may still reach the head.\n if (current.depth === 0 && next === record.to) continue;\n if (parents.has(next)) continue;\n parents.set(next, current.id);\n if (next === record.to)\n return reconstructWitness(parents, record.from, current.id, next);\n queue.push({ id: next, depth: current.depth + 1 });\n }\n return undefined;\n}\n\n/** Search one bounded same-family witness path that implies a direct edge. */\nfunction findWitnessPath(\n adjacency: Map<string, readonly string[]>,\n record: OrientedTransitiveEdge,\n maxDepth: number,\n cost: { visitedNodes: number; inspectedEdges: number },\n): string[] | undefined {\n const parents = new Map<string, string>([[record.from, record.from]]);\n const queue = [{ id: record.from, depth: 0 }];\n for (let index = 0; index < queue.length; index += 1) {\n const current = queue[index]!;\n cost.visitedNodes += 1;\n if (current.depth >= maxDepth) continue;\n const witness = expandWitnessFrontier(\n adjacency,\n record,\n current,\n parents,\n queue,\n cost,\n );\n if (witness !== undefined) return witness;\n }\n return undefined;\n}\n\n/**\n * Find stored edges implied by a longer path of the same semantic family —\n * the transitive-reduction view of ordering and hierarchy relations. Each\n * family joins a directed kind with its inverse spelling in semantic\n * orientation, so `blocked_by` and `blocks` witness each other. The witness\n * search is breadth-first, shortest and lexicographic first, bounded by\n * `maxDepth` per edge; `meta.truncated` reports only the `limit` bound.\n */\nexport function findRedundantRelationshipEdges(\n graph: RelationshipGraph,\n options: GraphRedundancyOptions = {},\n): RelationshipQueryResult<RedundantRelationshipEdge[]> {\n const maxDepth = options.maxDepth ?? DEFAULT_REDUNDANCY_MAX_DEPTH;\n assertPositiveBound(\"maxDepth\", maxDepth);\n if (options.limit !== undefined) assertPositiveBound(\"limit\", options.limit);\n const limit = options.limit ?? Number.POSITIVE_INFINITY;\n const wanted = resolveRedundancyFamilies(graph, options.kinds);\n const families = collectTransitiveFamilies(graph, wanted);\n const value: RedundantRelationshipEdge[] = [];\n const cost = { visitedNodes: 0, inspectedEdges: 0 };\n let truncated = false;\n scan: for (const key of [...families.keys()].sort()) {\n const family = families.get(key)!;\n const adjacency = sortedFamilyAdjacency(family);\n for (const record of family.records) {\n options.signal?.throwIfAborted();\n const witness = findWitnessPath(adjacency, record, maxDepth, cost);\n if (witness === undefined) continue;\n if (value.length >= limit) {\n truncated = true;\n break scan;\n }\n value.push({ edge: record.edge, witness });\n }\n }\n return {\n value,\n meta: {\n visitedNodes: cost.visitedNodes,\n inspectedEdges: cost.inspectedEdges,\n truncated,\n },\n };\n}\n\n/** Reachability index of one root's directed subgraph. */\ninterface ReachableSubgraph {\n /** Reachable node ids in breadth-first discovery order. */\n order: string[];\n /** Deterministic successor lists per reachable node. */\n successors: Map<string, string[]>;\n /** Reachable predecessor sets per reachable node. */\n predecessors: Map<string, Set<string>>;\n /** Candidate edges inspected while indexing. */\n inspectedEdges: number;\n /** Whether the depth bound excluded reachable nodes. */\n truncated: boolean;\n}\n\n/** Mutable frontier state threaded through bounded reachability expansion. */\ninterface ReachabilityState {\n /** Nodes already discovered. */\n seen: Set<string>;\n /** Pending breadth-first nodes and their depths. */\n queue: { id: string; depth: number }[];\n /** Reachable predecessor sets per discovered node. */\n predecessors: Map<string, Set<string>>;\n /** Whether the depth bound excluded reachable nodes. */\n truncated: boolean;\n}\n\n/** Expand one node's neighbor rows into successors, predecessors, and frontier work. */\nfunction expandReachableNode(\n id: string,\n depth: number,\n rows: readonly RelationshipNeighborEdge[],\n maxDepth: number,\n state: ReachabilityState,\n): string[] {\n const nextSet = new Set<string>();\n const nexts: string[] = [];\n for (const row of rows) {\n if (row.id === id || nextSet.has(row.id)) continue;\n if (!state.seen.has(row.id)) {\n // A depth-boundary node keeps its edges to already-indexed nodes but\n // may not discover new ones; excluded discoveries mark truncation.\n if (depth >= maxDepth) {\n state.truncated = true;\n continue;\n }\n state.seen.add(row.id);\n state.queue.push({ id: row.id, depth: depth + 1 });\n }\n nextSet.add(row.id);\n nexts.push(row.id);\n let incoming = state.predecessors.get(row.id);\n if (incoming === undefined) {\n incoming = new Set();\n state.predecessors.set(row.id, incoming);\n }\n incoming.add(id);\n }\n return nexts;\n}\n\n/** Index the bounded reachable subgraph used by dominator analysis. */\nfunction indexReachableSubgraph(\n graph: RelationshipGraph,\n root: string,\n options: GraphDominatorOptions,\n): ReachableSubgraph {\n const direction = options.direction ?? \"outgoing\";\n const maxDepth = options.maxDepth ?? Number.POSITIVE_INFINITY;\n const order: string[] = [];\n const successors = new Map<string, string[]>();\n const state: ReachabilityState = {\n seen: new Set([root]),\n queue: [{ id: root, depth: 0 }],\n predecessors: new Map(),\n truncated: false,\n };\n let inspectedEdges = 0;\n for (let index = 0; index < state.queue.length; index += 1) {\n options.signal?.throwIfAborted();\n const { id, depth } = state.queue[index]!;\n order.push(id);\n const rows = graph.neighborEdges(id, {\n direction,\n ...(options.kinds === undefined ? {} : { kinds: options.kinds }),\n });\n inspectedEdges += rows.meta.inspectedEdges;\n successors.set(id, expandReachableNode(id, depth, rows.value, maxDepth, state));\n }\n return {\n order,\n successors,\n predecessors: state.predecessors,\n inspectedEdges,\n truncated: state.truncated,\n };\n}\n\n/** Compute the deterministic reverse postorder of one reachable subgraph. */\nfunction reversePostorder(subgraph: ReachableSubgraph, root: string): string[] {\n const postorder: string[] = [];\n const visited = new Set([root]);\n const stack = [{ id: root, index: 0 }];\n while (stack.length > 0) {\n const frame = stack.at(-1)!;\n const nexts = subgraph.successors.get(frame.id)!;\n if (frame.index < nexts.length) {\n const next = nexts[frame.index]!;\n frame.index += 1;\n if (!visited.has(next)) {\n visited.add(next);\n stack.push({ id: next, index: 0 });\n }\n } else {\n postorder.push(frame.id);\n stack.pop();\n }\n }\n return postorder.reverse();\n}\n\n/** Walk two dominator-tree fingers to their common ancestor by reverse-postorder number. */\nfunction intersectDominators(\n left: string,\n right: string,\n idom: Map<string, string>,\n ordinal: Map<string, number>,\n): string {\n let first = left;\n let second = right;\n while (first !== second) {\n while (ordinal.get(first)! > ordinal.get(second)!) first = idom.get(first)!;\n while (ordinal.get(second)! > ordinal.get(first)!) second = idom.get(second)!;\n }\n return first;\n}\n\n/** Fold one node's processed predecessors into its dominator candidate. */\nfunction dominatorCandidate(\n predecessors: ReadonlySet<string>,\n idom: Map<string, string>,\n ordinal: Map<string, number>,\n): string | undefined {\n let candidate: string | undefined;\n for (const pred of [...predecessors].sort()) {\n if (!idom.has(pred)) continue;\n candidate =\n candidate === undefined\n ? pred\n : intersectDominators(candidate, pred, idom, ordinal);\n }\n return candidate;\n}\n\n/** Run the Cooper–Harvey–Kennedy fixed-point over one reverse postorder. */\nfunction solveImmediateDominators(\n subgraph: ReachableSubgraph,\n root: string,\n order: readonly string[],\n ordinal: Map<string, number>,\n signal: AbortSignal | undefined,\n): Map<string, string> {\n const idom = new Map<string, string>([[root, root]]);\n let changed = true;\n while (changed) {\n changed = false;\n for (const id of order) {\n signal?.throwIfAborted();\n if (id === root) continue;\n // Every non-root node in the order was discovered through at least one\n // predecessor, so the set is always present.\n const candidate = dominatorCandidate(\n subgraph.predecessors.get(id)!,\n idom,\n ordinal,\n );\n if (candidate !== undefined && idom.get(id) !== candidate) {\n idom.set(id, candidate);\n changed = true;\n }\n }\n }\n return idom;\n}\n\n/**\n * Compute immediate dominators and gating weights over one node's reachable\n * subgraph using the Cooper–Harvey–Kennedy fixed-point. A node dominates the\n * work that every path from the root must pass through it to reach, so rows\n * with a positive `dominatedCount` are the structural bottlenecks of the\n * root's blast radius. Rows sort by gating weight, then id; `meta.truncated`\n * reports when the `maxDepth` bound excluded reachable nodes.\n */\nexport function computeRelationshipDominators(\n graph: RelationshipGraph,\n root: string,\n options: GraphDominatorOptions = {},\n): RelationshipQueryResult<RelationshipDominatorAnalysis> {\n if (!graph.hasNode(root))\n throw new TypeError(`Relationship node not found: ${root}`);\n if (\n options.maxDepth !== undefined &&\n (!Number.isInteger(options.maxDepth) || options.maxDepth < 0)\n )\n throw new TypeError(`Invalid maxDepth bound: ${String(options.maxDepth)}`);\n const subgraph = indexReachableSubgraph(graph, root, options);\n const order = reversePostorder(subgraph, root);\n const ordinal = new Map(order.map((id, index) => [id, index]));\n const idom = solveImmediateDominators(\n subgraph,\n root,\n order,\n ordinal,\n options.signal,\n );\n const subtreeSizes = new Map(order.map((id) => [id, 1]));\n for (let index = order.length - 1; index >= 0; index -= 1) {\n const id = order[index]!;\n if (id === root) continue;\n const parent = idom.get(id)!;\n subtreeSizes.set(parent, subtreeSizes.get(parent)! + subtreeSizes.get(id)!);\n }\n const rows = order\n .filter((id) => id !== root)\n .map((id) => ({\n id,\n idom: idom.get(id)!,\n dominatedCount: subtreeSizes.get(id)! - 1,\n }))\n .sort(\n (left, right) =>\n right.dominatedCount - left.dominatedCount ||\n left.id.localeCompare(right.id),\n );\n return {\n value: { root, reachableCount: subgraph.order.length, rows },\n meta: {\n visitedNodes: subgraph.order.length,\n inspectedEdges: subgraph.inspectedEdges,\n truncated: subgraph.truncated,\n },\n };\n}\n"],"names":[],"mappings":"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","debugId":"19fa7ddd-c396-5fd4-a720-522218a7b11a"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/graph/assembly
|
|
3
|
+
*
|
|
4
|
+
* Builds the shared workspace relationship graph consumed by dependency
|
|
5
|
+
* queries, bounded context packets, impact analysis, and governance audits.
|
|
6
|
+
* Assembly normalizes hierarchy, legacy scalar blockers, and structured
|
|
7
|
+
* dependency edges into one deterministic {@link RelationshipGraph}, classifies
|
|
8
|
+
* dangling references without mutating their holders, and materializes missing
|
|
9
|
+
* endpoints as placeholder nodes so bounded traversals can explain absent work
|
|
10
|
+
* instead of silently dropping it.
|
|
11
|
+
*/
|
|
12
|
+
import type { Dependency, ItemStatus } from "../../types/index.js";
|
|
13
|
+
import { RelationshipGraph, type RelationshipKindRegistry } from "../relationships.js";
|
|
14
|
+
/** Minimal item shape inspected by dependency-reference governance. */
|
|
15
|
+
export interface DependencyReferenceHolder {
|
|
16
|
+
/** Stable item identifier. */
|
|
17
|
+
id: string;
|
|
18
|
+
/** Lifecycle status used to separate actionable work from historical debt. */
|
|
19
|
+
status: ItemStatus;
|
|
20
|
+
/** Optional hierarchy parent reference. */
|
|
21
|
+
parent?: string;
|
|
22
|
+
/** Optional legacy scalar blocker reference. */
|
|
23
|
+
blocked_by?: string;
|
|
24
|
+
/** Structured dependency edges. */
|
|
25
|
+
dependencies?: Dependency[];
|
|
26
|
+
}
|
|
27
|
+
/** Storage surface that contributed a normalized dependency reference. */
|
|
28
|
+
export type DependencyReferenceSource = "parent" | "blocked_by" | "dependency";
|
|
29
|
+
/** One normalized dependency reference whose target is absent from the tracker. */
|
|
30
|
+
export interface DanglingDependencyReference {
|
|
31
|
+
/** Item that owns the reference. */
|
|
32
|
+
holder_id: string;
|
|
33
|
+
/** Missing referenced item id or legacy sentinel. */
|
|
34
|
+
target_id: string;
|
|
35
|
+
/** Relationship field or dependency kind. */
|
|
36
|
+
kind: string;
|
|
37
|
+
/** Storage surface that owns the reference and determines its remediation. */
|
|
38
|
+
source: DependencyReferenceSource;
|
|
39
|
+
/** Current lifecycle status of the holder. */
|
|
40
|
+
holder_status: ItemStatus;
|
|
41
|
+
/** Whether the holder is terminal and therefore historical, non-actionable debt. */
|
|
42
|
+
legacy_terminal: boolean;
|
|
43
|
+
/** Whether the target is the pre-structured-dependency `no-active-blocker` sentinel. */
|
|
44
|
+
no_active_blocker_sentinel: boolean;
|
|
45
|
+
}
|
|
46
|
+
/** Actionable and historical partitions returned by dependency-reference governance. */
|
|
47
|
+
export interface DanglingDependencyReferenceSummary {
|
|
48
|
+
/** Missing references held by active items; these may affect scheduling and should gate validation. */
|
|
49
|
+
active: DanglingDependencyReference[];
|
|
50
|
+
/** Missing references held only by terminal items; retained as informational history debt. */
|
|
51
|
+
legacy_terminal: DanglingDependencyReference[];
|
|
52
|
+
/** Legacy sentinel rows across active and terminal holders, called out separately from typo-like ids. */
|
|
53
|
+
no_active_blocker_sentinels: DanglingDependencyReference[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Classify missing hierarchy and dependency targets without mutating their holders.
|
|
57
|
+
*
|
|
58
|
+
* Consumers provide the workspace's terminal-status predicate so custom lifecycle
|
|
59
|
+
* schemas receive the same active-versus-historical behavior as the built-in
|
|
60
|
+
* closed/canceled statuses.
|
|
61
|
+
*/
|
|
62
|
+
export declare function collectDanglingDependencyReferences(items: readonly DependencyReferenceHolder[], isTerminal?: (status: ItemStatus) => boolean): DanglingDependencyReferenceSummary;
|
|
63
|
+
/** Return unique real missing targets while excluding the legacy no-blocker sentinel. */
|
|
64
|
+
export declare function collectMissingDependencyTargetIds(dangling: DanglingDependencyReferenceSummary): string[];
|
|
65
|
+
/** Item shape accepted by workspace relationship-graph assembly. */
|
|
66
|
+
export interface WorkspaceRelationshipItem extends DependencyReferenceHolder {
|
|
67
|
+
/** Human-readable title projected into per-node details. */
|
|
68
|
+
title: string;
|
|
69
|
+
}
|
|
70
|
+
/** Compact node projection paired with the assembled graph. */
|
|
71
|
+
export interface WorkspaceRelationshipNodeDetails {
|
|
72
|
+
/** Stable node identifier. */
|
|
73
|
+
id: string;
|
|
74
|
+
/** Human-readable node title, or a `[missing]` marker for absent endpoints. */
|
|
75
|
+
title: string;
|
|
76
|
+
/** Lifecycle status, or the `missing` marker status for absent endpoints. */
|
|
77
|
+
status: string;
|
|
78
|
+
}
|
|
79
|
+
/** Assembled workspace relationship graph with governance side-products. */
|
|
80
|
+
export interface WorkspaceRelationshipAssembly {
|
|
81
|
+
/** Deterministic relationship graph including missing placeholder nodes. */
|
|
82
|
+
graph: RelationshipGraph;
|
|
83
|
+
/** Per-node compact details covering real and missing nodes. */
|
|
84
|
+
details: WorkspaceRelationshipNodeDetails[];
|
|
85
|
+
/** Lowercased identifiers of materialized missing endpoints. */
|
|
86
|
+
missingIdSet: Set<string>;
|
|
87
|
+
/** Dangling-reference classification computed during assembly. */
|
|
88
|
+
dangling: DanglingDependencyReferenceSummary;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Build the shared workspace relationship graph including missing placeholder
|
|
92
|
+
* nodes. One assembly serves every bounded query in an invocation — dependency
|
|
93
|
+
* trees, context packets, impact analysis, path enumeration, and governance
|
|
94
|
+
* audits — so the full-workspace normalization cost is paid once instead of
|
|
95
|
+
* once per query surface.
|
|
96
|
+
*/
|
|
97
|
+
export declare function assembleWorkspaceRelationshipGraph(items: readonly WorkspaceRelationshipItem[], isTerminal?: (status: ItemStatus) => boolean, registry?: RelationshipKindRegistry): WorkspaceRelationshipAssembly;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6d8ff34a-789b-5b49-8304-9a7d53f8365d")}catch(e){}}();
|
|
3
|
+
import { RelationshipGraph, } from "../relationships.js";
|
|
4
|
+
/** Normalize a decoded reference target and reject empty legacy placeholders. */
|
|
5
|
+
function normalizeDependencyReferenceTarget(target) {
|
|
6
|
+
if (typeof target !== "string")
|
|
7
|
+
return undefined;
|
|
8
|
+
const normalized = target.trim();
|
|
9
|
+
if (!normalized ||
|
|
10
|
+
["none", "null", "n/a", "na"].includes(normalized.toLowerCase()))
|
|
11
|
+
return undefined;
|
|
12
|
+
return normalized;
|
|
13
|
+
}
|
|
14
|
+
/** Normalize a graph target while removing the historical no-blocker marker. */
|
|
15
|
+
function normalizeDependencyGraphTarget(target) {
|
|
16
|
+
const normalized = normalizeDependencyReferenceTarget(target);
|
|
17
|
+
return normalized?.toLowerCase() === "no-active-blocker"
|
|
18
|
+
? undefined
|
|
19
|
+
: normalized;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Classify missing hierarchy and dependency targets without mutating their holders.
|
|
23
|
+
*
|
|
24
|
+
* Consumers provide the workspace's terminal-status predicate so custom lifecycle
|
|
25
|
+
* schemas receive the same active-versus-historical behavior as the built-in
|
|
26
|
+
* closed/canceled statuses.
|
|
27
|
+
*/
|
|
28
|
+
export function collectDanglingDependencyReferences(items, isTerminal = (status) => status === "closed" || status === "canceled") {
|
|
29
|
+
const safeItems = items.filter((item) => typeof item?.id === "string" && item.id.trim().length > 0);
|
|
30
|
+
const knownIds = new Set(safeItems.map((item) => item.id.trim().toLowerCase()));
|
|
31
|
+
const rows = new Map();
|
|
32
|
+
const addReference = (item, target, kind, source) => {
|
|
33
|
+
const normalized = normalizeDependencyReferenceTarget(target);
|
|
34
|
+
if (!normalized || knownIds.has(normalized.toLowerCase())) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const row = {
|
|
38
|
+
holder_id: item.id.trim(),
|
|
39
|
+
target_id: normalized,
|
|
40
|
+
kind,
|
|
41
|
+
source,
|
|
42
|
+
holder_status: item.status,
|
|
43
|
+
legacy_terminal: isTerminal(item.status),
|
|
44
|
+
no_active_blocker_sentinel: normalized.toLowerCase() === "no-active-blocker",
|
|
45
|
+
};
|
|
46
|
+
rows.set(`${row.holder_id}::${row.target_id}::${row.kind}::${row.source}`, row);
|
|
47
|
+
};
|
|
48
|
+
for (const item of safeItems) {
|
|
49
|
+
addReference(item, item.parent, "parent", "parent");
|
|
50
|
+
addReference(item, item.blocked_by, "blocked_by", "blocked_by");
|
|
51
|
+
for (const dependency of item.dependencies ?? []) {
|
|
52
|
+
// Public SDK callers may supply legacy or JSON-decoded payloads that do
|
|
53
|
+
// not yet satisfy the current structured dependency contract.
|
|
54
|
+
if (typeof dependency !== "object" || dependency === null) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const legacyDependency = dependency;
|
|
58
|
+
addReference(item, legacyDependency.id, typeof legacyDependency.kind === "string"
|
|
59
|
+
? legacyDependency.kind
|
|
60
|
+
: "related", "dependency");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const sorted = [...rows.values()].sort((left, right) => left.holder_id.localeCompare(right.holder_id) ||
|
|
64
|
+
left.target_id.localeCompare(right.target_id) ||
|
|
65
|
+
left.kind.localeCompare(right.kind) ||
|
|
66
|
+
left.source.localeCompare(right.source));
|
|
67
|
+
const legacyTerminal = sorted.filter((row) => row.legacy_terminal);
|
|
68
|
+
return {
|
|
69
|
+
active: sorted.filter((row) => !row.legacy_terminal),
|
|
70
|
+
legacy_terminal: legacyTerminal,
|
|
71
|
+
no_active_blocker_sentinels: sorted.filter((row) => row.no_active_blocker_sentinel),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** Return unique real missing targets while excluding the legacy no-blocker sentinel. */
|
|
75
|
+
export function collectMissingDependencyTargetIds(dangling) {
|
|
76
|
+
const targets = new Map();
|
|
77
|
+
for (const reference of [...dangling.active, ...dangling.legacy_terminal]) {
|
|
78
|
+
if (reference.no_active_blocker_sentinel)
|
|
79
|
+
continue;
|
|
80
|
+
const target = reference.target_id.trim();
|
|
81
|
+
const key = target.toLowerCase();
|
|
82
|
+
if (!targets.has(key))
|
|
83
|
+
targets.set(key, target);
|
|
84
|
+
}
|
|
85
|
+
return [...targets.values()].sort((left, right) => left.localeCompare(right));
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Build the shared workspace relationship graph including missing placeholder
|
|
89
|
+
* nodes. One assembly serves every bounded query in an invocation — dependency
|
|
90
|
+
* trees, context packets, impact analysis, path enumeration, and governance
|
|
91
|
+
* audits — so the full-workspace normalization cost is paid once instead of
|
|
92
|
+
* once per query surface.
|
|
93
|
+
*/
|
|
94
|
+
export function assembleWorkspaceRelationshipGraph(items, isTerminal, registry) {
|
|
95
|
+
const safeItems = items.filter((item) => typeof item?.id === "string" && item.id.trim().length > 0);
|
|
96
|
+
const canonicalIds = new Map(safeItems.map((item) => [item.id.trim().toLowerCase(), item.id.trim()]));
|
|
97
|
+
const dangling = collectDanglingDependencyReferences(safeItems, isTerminal);
|
|
98
|
+
const missingIds = collectMissingDependencyTargetIds(dangling);
|
|
99
|
+
for (const id of missingIds)
|
|
100
|
+
canonicalIds.set(id.toLowerCase(), id);
|
|
101
|
+
const graphItems = safeItems.map((item) => {
|
|
102
|
+
const parent = normalizeDependencyGraphTarget(item.parent);
|
|
103
|
+
const blocker = normalizeDependencyGraphTarget(item.blocked_by);
|
|
104
|
+
const dependencies = (item.dependencies ?? []).flatMap((rawDependency) => {
|
|
105
|
+
if (typeof rawDependency !== "object" || rawDependency === null)
|
|
106
|
+
return [];
|
|
107
|
+
const dependency = rawDependency;
|
|
108
|
+
const target = normalizeDependencyGraphTarget(dependency.id);
|
|
109
|
+
if (!target)
|
|
110
|
+
return [];
|
|
111
|
+
return [
|
|
112
|
+
{
|
|
113
|
+
id: canonicalIds.get(target.toLowerCase()),
|
|
114
|
+
kind: typeof dependency.kind === "string" ? dependency.kind : "related",
|
|
115
|
+
},
|
|
116
|
+
];
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
id: item.id.trim(),
|
|
120
|
+
...(parent ? { parent: canonicalIds.get(parent.toLowerCase()) } : {}),
|
|
121
|
+
...(blocker
|
|
122
|
+
? { blocked_by: canonicalIds.get(blocker.toLowerCase()) }
|
|
123
|
+
: {}),
|
|
124
|
+
dependencies,
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
return {
|
|
128
|
+
graph: RelationshipGraph.fromItems([...graphItems, ...missingIds.map((id) => ({ id }))], registry),
|
|
129
|
+
details: [
|
|
130
|
+
...safeItems.map((item) => ({
|
|
131
|
+
id: item.id.trim(),
|
|
132
|
+
title: item.title,
|
|
133
|
+
status: item.status,
|
|
134
|
+
})),
|
|
135
|
+
...missingIds.map((id) => ({
|
|
136
|
+
id,
|
|
137
|
+
title: `[missing] ${id}`,
|
|
138
|
+
status: "missing",
|
|
139
|
+
})),
|
|
140
|
+
],
|
|
141
|
+
missingIdSet: new Set(missingIds.map((id) => id.toLowerCase())),
|
|
142
|
+
dangling,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=assembly.js.map
|
|
146
|
+
//# debugId=6d8ff34a-789b-5b49-8304-9a7d53f8365d
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assembly.js","sources":["sdk/graph/assembly.ts"],"sourceRoot":"/","sourcesContent":["/**\n * @module sdk/graph/assembly\n *\n * Builds the shared workspace relationship graph consumed by dependency\n * queries, bounded context packets, impact analysis, and governance audits.\n * Assembly normalizes hierarchy, legacy scalar blockers, and structured\n * dependency edges into one deterministic {@link RelationshipGraph}, classifies\n * dangling references without mutating their holders, and materializes missing\n * endpoints as placeholder nodes so bounded traversals can explain absent work\n * instead of silently dropping it.\n */\nimport type { Dependency, ItemStatus } from \"../../types/index.js\";\nimport {\n RelationshipGraph,\n type RelationshipKindRegistry,\n} from \"../relationships.js\";\n\n/** Minimal item shape inspected by dependency-reference governance. */\nexport interface DependencyReferenceHolder {\n /** Stable item identifier. */\n id: string;\n /** Lifecycle status used to separate actionable work from historical debt. */\n status: ItemStatus;\n /** Optional hierarchy parent reference. */\n parent?: string;\n /** Optional legacy scalar blocker reference. */\n blocked_by?: string;\n /** Structured dependency edges. */\n dependencies?: Dependency[];\n}\n\n/** Storage surface that contributed a normalized dependency reference. */\nexport type DependencyReferenceSource = \"parent\" | \"blocked_by\" | \"dependency\";\n\n/** One normalized dependency reference whose target is absent from the tracker. */\nexport interface DanglingDependencyReference {\n /** Item that owns the reference. */\n holder_id: string;\n /** Missing referenced item id or legacy sentinel. */\n target_id: string;\n /** Relationship field or dependency kind. */\n kind: string;\n /** Storage surface that owns the reference and determines its remediation. */\n source: DependencyReferenceSource;\n /** Current lifecycle status of the holder. */\n holder_status: ItemStatus;\n /** Whether the holder is terminal and therefore historical, non-actionable debt. */\n legacy_terminal: boolean;\n /** Whether the target is the pre-structured-dependency `no-active-blocker` sentinel. */\n no_active_blocker_sentinel: boolean;\n}\n\n/** Actionable and historical partitions returned by dependency-reference governance. */\nexport interface DanglingDependencyReferenceSummary {\n /** Missing references held by active items; these may affect scheduling and should gate validation. */\n active: DanglingDependencyReference[];\n /** Missing references held only by terminal items; retained as informational history debt. */\n legacy_terminal: DanglingDependencyReference[];\n /** Legacy sentinel rows across active and terminal holders, called out separately from typo-like ids. */\n no_active_blocker_sentinels: DanglingDependencyReference[];\n}\n\n/** Normalize a decoded reference target and reject empty legacy placeholders. */\nfunction normalizeDependencyReferenceTarget(\n target: unknown,\n): string | undefined {\n if (typeof target !== \"string\") return undefined;\n const normalized = target.trim();\n if (\n !normalized ||\n [\"none\", \"null\", \"n/a\", \"na\"].includes(normalized.toLowerCase())\n )\n return undefined;\n return normalized;\n}\n\n/** Normalize a graph target while removing the historical no-blocker marker. */\nfunction normalizeDependencyGraphTarget(target: unknown): string | undefined {\n const normalized = normalizeDependencyReferenceTarget(target);\n return normalized?.toLowerCase() === \"no-active-blocker\"\n ? undefined\n : normalized;\n}\n\n/**\n * Classify missing hierarchy and dependency targets without mutating their holders.\n *\n * Consumers provide the workspace's terminal-status predicate so custom lifecycle\n * schemas receive the same active-versus-historical behavior as the built-in\n * closed/canceled statuses.\n */\nexport function collectDanglingDependencyReferences(\n items: readonly DependencyReferenceHolder[],\n isTerminal: (status: ItemStatus) => boolean = (status) =>\n status === \"closed\" || status === \"canceled\",\n): DanglingDependencyReferenceSummary {\n const safeItems = items.filter(\n (item) => typeof item?.id === \"string\" && item.id.trim().length > 0,\n );\n const knownIds = new Set(\n safeItems.map((item) => item.id.trim().toLowerCase()),\n );\n const rows = new Map<string, DanglingDependencyReference>();\n const addReference = (\n item: DependencyReferenceHolder,\n target: unknown,\n kind: string,\n source: DependencyReferenceSource,\n ): void => {\n const normalized = normalizeDependencyReferenceTarget(target);\n if (!normalized || knownIds.has(normalized.toLowerCase())) {\n return;\n }\n const row: DanglingDependencyReference = {\n holder_id: item.id.trim(),\n target_id: normalized,\n kind,\n source,\n holder_status: item.status,\n legacy_terminal: isTerminal(item.status),\n no_active_blocker_sentinel:\n normalized.toLowerCase() === \"no-active-blocker\",\n };\n rows.set(\n `${row.holder_id}::${row.target_id}::${row.kind}::${row.source}`,\n row,\n );\n };\n for (const item of safeItems) {\n addReference(item, item.parent, \"parent\", \"parent\");\n addReference(item, item.blocked_by, \"blocked_by\", \"blocked_by\");\n for (const dependency of item.dependencies ?? []) {\n // Public SDK callers may supply legacy or JSON-decoded payloads that do\n // not yet satisfy the current structured dependency contract.\n if (typeof dependency !== \"object\" || dependency === null) {\n continue;\n }\n const legacyDependency = dependency as Partial<Dependency>;\n addReference(\n item,\n legacyDependency.id,\n typeof legacyDependency.kind === \"string\"\n ? legacyDependency.kind\n : \"related\",\n \"dependency\",\n );\n }\n }\n const sorted = [...rows.values()].sort(\n (left, right) =>\n left.holder_id.localeCompare(right.holder_id) ||\n left.target_id.localeCompare(right.target_id) ||\n left.kind.localeCompare(right.kind) ||\n left.source.localeCompare(right.source),\n );\n const legacyTerminal = sorted.filter((row) => row.legacy_terminal);\n return {\n active: sorted.filter((row) => !row.legacy_terminal),\n legacy_terminal: legacyTerminal,\n no_active_blocker_sentinels: sorted.filter(\n (row) => row.no_active_blocker_sentinel,\n ),\n };\n}\n\n/** Return unique real missing targets while excluding the legacy no-blocker sentinel. */\nexport function collectMissingDependencyTargetIds(\n dangling: DanglingDependencyReferenceSummary,\n): string[] {\n const targets = new Map<string, string>();\n for (const reference of [...dangling.active, ...dangling.legacy_terminal]) {\n if (reference.no_active_blocker_sentinel) continue;\n const target = reference.target_id.trim();\n const key = target.toLowerCase();\n if (!targets.has(key)) targets.set(key, target);\n }\n return [...targets.values()].sort((left, right) => left.localeCompare(right));\n}\n\n/** Item shape accepted by workspace relationship-graph assembly. */\nexport interface WorkspaceRelationshipItem extends DependencyReferenceHolder {\n /** Human-readable title projected into per-node details. */\n title: string;\n}\n\n/** Compact node projection paired with the assembled graph. */\nexport interface WorkspaceRelationshipNodeDetails {\n /** Stable node identifier. */\n id: string;\n /** Human-readable node title, or a `[missing]` marker for absent endpoints. */\n title: string;\n /** Lifecycle status, or the `missing` marker status for absent endpoints. */\n status: string;\n}\n\n/** Assembled workspace relationship graph with governance side-products. */\nexport interface WorkspaceRelationshipAssembly {\n /** Deterministic relationship graph including missing placeholder nodes. */\n graph: RelationshipGraph;\n /** Per-node compact details covering real and missing nodes. */\n details: WorkspaceRelationshipNodeDetails[];\n /** Lowercased identifiers of materialized missing endpoints. */\n missingIdSet: Set<string>;\n /** Dangling-reference classification computed during assembly. */\n dangling: DanglingDependencyReferenceSummary;\n}\n\n/**\n * Build the shared workspace relationship graph including missing placeholder\n * nodes. One assembly serves every bounded query in an invocation — dependency\n * trees, context packets, impact analysis, path enumeration, and governance\n * audits — so the full-workspace normalization cost is paid once instead of\n * once per query surface.\n */\nexport function assembleWorkspaceRelationshipGraph(\n items: readonly WorkspaceRelationshipItem[],\n isTerminal?: (status: ItemStatus) => boolean,\n registry?: RelationshipKindRegistry,\n): WorkspaceRelationshipAssembly {\n const safeItems = items.filter(\n (item) => typeof item?.id === \"string\" && item.id.trim().length > 0,\n );\n const canonicalIds = new Map(\n safeItems.map((item) => [item.id.trim().toLowerCase(), item.id.trim()]),\n );\n const dangling = collectDanglingDependencyReferences(safeItems, isTerminal);\n const missingIds = collectMissingDependencyTargetIds(dangling);\n for (const id of missingIds) canonicalIds.set(id.toLowerCase(), id);\n const graphItems = safeItems.map((item) => {\n const parent = normalizeDependencyGraphTarget(item.parent);\n const blocker = normalizeDependencyGraphTarget(item.blocked_by);\n const dependencies = (item.dependencies ?? []).flatMap((rawDependency) => {\n if (typeof rawDependency !== \"object\" || rawDependency === null)\n return [];\n const dependency = rawDependency as Partial<Dependency>;\n const target = normalizeDependencyGraphTarget(dependency.id);\n if (!target) return [];\n return [\n {\n id: canonicalIds.get(target.toLowerCase())!,\n kind:\n typeof dependency.kind === \"string\" ? dependency.kind : \"related\",\n },\n ];\n });\n return {\n id: item.id.trim(),\n ...(parent ? { parent: canonicalIds.get(parent.toLowerCase())! } : {}),\n ...(blocker\n ? { blocked_by: canonicalIds.get(blocker.toLowerCase())! }\n : {}),\n dependencies,\n };\n });\n return {\n graph: RelationshipGraph.fromItems(\n [...graphItems, ...missingIds.map((id) => ({ id }))],\n registry,\n ),\n details: [\n ...safeItems.map((item) => ({\n id: item.id.trim(),\n title: item.title,\n status: item.status,\n })),\n ...missingIds.map((id) => ({\n id,\n title: `[missing] ${id}`,\n status: \"missing\",\n })),\n ],\n missingIdSet: new Set(missingIds.map((id) => id.toLowerCase())),\n dangling,\n };\n}\n"],"names":[],"mappings":"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","debugId":"6d8ff34a-789b-5b49-8304-9a7d53f8365d"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ItemStatus } from "../../types/index.js";
|
|
2
|
+
import type { WorkspaceRelationshipAssembly, WorkspaceRelationshipItem } from "./assembly.js";
|
|
3
|
+
/** Cache observability attached to graph result envelopes. */
|
|
4
|
+
export interface GraphCacheMetadata {
|
|
5
|
+
/** Truncated workspace graph fingerprint identifying the snapshot answered from. */
|
|
6
|
+
fingerprint: string;
|
|
7
|
+
/** Whether the workspace assembly was reused from cache. */
|
|
8
|
+
assembly: "hit" | "miss";
|
|
9
|
+
/** Whether the full query result was reused from cache. */
|
|
10
|
+
result: "hit" | "miss";
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Compute the deterministic workspace graph fingerprint for one item snapshot.
|
|
14
|
+
* Items are digested in sorted order so storage enumeration order never
|
|
15
|
+
* changes the fingerprint, and the terminal classification of each status is
|
|
16
|
+
* folded in so schema changes to lifecycle semantics invalidate cached
|
|
17
|
+
* assemblies even when raw statuses are unchanged.
|
|
18
|
+
*/
|
|
19
|
+
export declare function computeWorkspaceGraphFingerprint(items: readonly WorkspaceRelationshipItem[], isTerminal?: (status: ItemStatus) => boolean): string;
|
|
20
|
+
/** One resolved cache lookup bound to a workspace snapshot. */
|
|
21
|
+
export interface WorkspaceGraphCacheLookup {
|
|
22
|
+
/** The (possibly reused) workspace assembly. */
|
|
23
|
+
assembly: WorkspaceRelationshipAssembly;
|
|
24
|
+
/** Whether the assembly came from cache instead of being rebuilt. */
|
|
25
|
+
assemblyReused: boolean;
|
|
26
|
+
/** Full fingerprint of the snapshot this lookup is bound to. */
|
|
27
|
+
fingerprint: string;
|
|
28
|
+
/**
|
|
29
|
+
* Memoize one deterministic query result under this snapshot. On a miss the
|
|
30
|
+
* freshly computed value is returned as-is while an independent clone is
|
|
31
|
+
* stored, so mutating a miss result never corrupts the cache; every hit
|
|
32
|
+
* returns a fresh clone of the stored entry. Callers must not rely on the
|
|
33
|
+
* miss and hit paths returning the same object identity.
|
|
34
|
+
*/
|
|
35
|
+
memoize<T>(queryKey: string, compute: () => T): {
|
|
36
|
+
value: T;
|
|
37
|
+
reused: boolean;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Fingerprint-keyed cache of workspace relationship assemblies and memoized
|
|
42
|
+
* deterministic query results. One entry is retained per workspace key; a
|
|
43
|
+
* changed fingerprint atomically replaces the entry and drops its memoized
|
|
44
|
+
* results. Memoized values are structured-cloned on store and on read so
|
|
45
|
+
* neither the producer nor any consumer can mutate cached state.
|
|
46
|
+
*/
|
|
47
|
+
export declare class WorkspaceGraphCache {
|
|
48
|
+
#private;
|
|
49
|
+
/** Create a cache, optionally bounding workspaces and memoized results. */
|
|
50
|
+
constructor(options?: {
|
|
51
|
+
maxResultsPerWorkspace?: number;
|
|
52
|
+
maxWorkspaces?: number;
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* Resolve the cached assembly for one workspace key and fingerprint,
|
|
56
|
+
* building and storing it on miss. The returned lookup exposes snapshot-
|
|
57
|
+
* scoped memoization for query results derived from the same assembly.
|
|
58
|
+
*/
|
|
59
|
+
lookup(key: string, fingerprint: string, build: () => WorkspaceRelationshipAssembly): WorkspaceGraphCacheLookup;
|
|
60
|
+
/** Drop every cached workspace entry and memoized result. */
|
|
61
|
+
clear(): void;
|
|
62
|
+
}
|
|
63
|
+
/** Return the process-wide shared workspace graph cache. */
|
|
64
|
+
export declare function workspaceGraphCache(): WorkspaceGraphCache;
|
|
65
|
+
/** Reset the process-wide shared workspace graph cache (tests and long-lived hosts). */
|
|
66
|
+
export declare function resetWorkspaceGraphCache(): void;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/graph/cache
|
|
3
|
+
*
|
|
4
|
+
* Incremental workspace graph cache: fingerprint-keyed reuse of the assembled
|
|
5
|
+
* relationship graph plus memoized analytics results, so long-lived processes
|
|
6
|
+
* (the MCP server, SDK consumers, packages) stop paying the full-workspace
|
|
7
|
+
* assembly and analysis cost on every bounded query. The fingerprint is a
|
|
8
|
+
* deterministic digest of every relationship-relevant item field — id, title,
|
|
9
|
+
* lifecycle status and its terminal classification, hierarchy parent, legacy
|
|
10
|
+
* blocker, and structured dependency edges — so any mutation that could change
|
|
11
|
+
* the graph or its projections invalidates the entry, while unrelated payload
|
|
12
|
+
* churn (bodies, comments) does not enter the digest at all. Every lookup
|
|
13
|
+
* reports hit/miss observability so envelopes can explain their freshness.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6c46fa7f-4566-5a15-ac76-1666770dc806")}catch(e){}}();
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
|
+
/** Default memoized query results retained per workspace entry. */
|
|
19
|
+
const DEFAULT_MAX_RESULTS_PER_WORKSPACE = 64;
|
|
20
|
+
/** Default workspace entries retained by one cache instance. */
|
|
21
|
+
const DEFAULT_MAX_WORKSPACES = 8;
|
|
22
|
+
/** Digest one item's relationship-relevant fields into a deterministic line. */
|
|
23
|
+
function fingerprintLine(item, isTerminal) {
|
|
24
|
+
const dependencies = (item.dependencies ?? [])
|
|
25
|
+
.map((rawDependency) => {
|
|
26
|
+
// Public SDK callers may supply legacy or JSON-decoded payloads; mirror
|
|
27
|
+
// assembly's defensive normalization so the digest tracks what assembly
|
|
28
|
+
// would actually index.
|
|
29
|
+
if (typeof rawDependency !== "object" || rawDependency === null)
|
|
30
|
+
return "";
|
|
31
|
+
const dependency = rawDependency;
|
|
32
|
+
return `${typeof dependency.kind === "string" ? dependency.kind : "related"}:${typeof dependency.id === "string" ? dependency.id : ""}`;
|
|
33
|
+
})
|
|
34
|
+
.sort()
|
|
35
|
+
.join(",");
|
|
36
|
+
return [
|
|
37
|
+
item.id,
|
|
38
|
+
item.title,
|
|
39
|
+
item.status,
|
|
40
|
+
isTerminal(item.status) ? "1" : "0",
|
|
41
|
+
item.parent ?? "",
|
|
42
|
+
item.blocked_by ?? "",
|
|
43
|
+
dependencies,
|
|
44
|
+
].join("\u0000");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Compute the deterministic workspace graph fingerprint for one item snapshot.
|
|
48
|
+
* Items are digested in sorted order so storage enumeration order never
|
|
49
|
+
* changes the fingerprint, and the terminal classification of each status is
|
|
50
|
+
* folded in so schema changes to lifecycle semantics invalidate cached
|
|
51
|
+
* assemblies even when raw statuses are unchanged.
|
|
52
|
+
*/
|
|
53
|
+
export function computeWorkspaceGraphFingerprint(items, isTerminal = (status) => status === "closed" || status === "canceled") {
|
|
54
|
+
const lines = items
|
|
55
|
+
.filter((item) => typeof item?.id === "string" && item.id.trim().length > 0)
|
|
56
|
+
.map((item) => fingerprintLine(item, isTerminal))
|
|
57
|
+
.sort();
|
|
58
|
+
// Separate fields and records with control characters no stored field can
|
|
59
|
+
// contain unescaped, so adjacent free-text fields can never collide.
|
|
60
|
+
return createHash("sha256").update(lines.join("\u0001")).digest("hex");
|
|
61
|
+
}
|
|
62
|
+
/** Validate one optional positive-integer cache bound, applying its default. */
|
|
63
|
+
function requirePositiveCacheBound(name, value, fallback) {
|
|
64
|
+
const bound = value ?? fallback;
|
|
65
|
+
if (!Number.isInteger(bound) || bound < 1)
|
|
66
|
+
throw new TypeError(`Invalid ${name} bound: ${String(value)}`);
|
|
67
|
+
return bound;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Fingerprint-keyed cache of workspace relationship assemblies and memoized
|
|
71
|
+
* deterministic query results. One entry is retained per workspace key; a
|
|
72
|
+
* changed fingerprint atomically replaces the entry and drops its memoized
|
|
73
|
+
* results. Memoized values are structured-cloned on store and on read so
|
|
74
|
+
* neither the producer nor any consumer can mutate cached state.
|
|
75
|
+
*/
|
|
76
|
+
export class WorkspaceGraphCache {
|
|
77
|
+
#entries = new Map();
|
|
78
|
+
#maxResultsPerWorkspace;
|
|
79
|
+
#maxWorkspaces;
|
|
80
|
+
/** Create a cache, optionally bounding workspaces and memoized results. */
|
|
81
|
+
constructor(options = {}) {
|
|
82
|
+
this.#maxResultsPerWorkspace = requirePositiveCacheBound("maxResultsPerWorkspace", options.maxResultsPerWorkspace, DEFAULT_MAX_RESULTS_PER_WORKSPACE);
|
|
83
|
+
this.#maxWorkspaces = requirePositiveCacheBound("maxWorkspaces", options.maxWorkspaces, DEFAULT_MAX_WORKSPACES);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve the cached assembly for one workspace key and fingerprint,
|
|
87
|
+
* building and storing it on miss. The returned lookup exposes snapshot-
|
|
88
|
+
* scoped memoization for query results derived from the same assembly.
|
|
89
|
+
*/
|
|
90
|
+
lookup(key, fingerprint, build) {
|
|
91
|
+
let entry = this.#entries.get(key);
|
|
92
|
+
let assemblyReused = true;
|
|
93
|
+
if (entry === undefined || entry.fingerprint !== fingerprint) {
|
|
94
|
+
entry = { fingerprint, assembly: build(), results: new Map() };
|
|
95
|
+
assemblyReused = false;
|
|
96
|
+
if (!this.#entries.has(key) &&
|
|
97
|
+
this.#entries.size >= this.#maxWorkspaces) {
|
|
98
|
+
// Evict the least recently used workspace; every lookup refreshes
|
|
99
|
+
// recency below, so insertion order tracks use order.
|
|
100
|
+
this.#entries.delete(this.#entries.keys().next().value);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Delete-and-reinsert keeps Map insertion order equal to recency order,
|
|
104
|
+
// making workspace eviction genuinely least-recently-used.
|
|
105
|
+
this.#entries.delete(key);
|
|
106
|
+
this.#entries.set(key, entry);
|
|
107
|
+
const resolved = entry;
|
|
108
|
+
const maxResults = this.#maxResultsPerWorkspace;
|
|
109
|
+
return {
|
|
110
|
+
assembly: resolved.assembly,
|
|
111
|
+
assemblyReused,
|
|
112
|
+
fingerprint,
|
|
113
|
+
memoize(queryKey, compute) {
|
|
114
|
+
const cached = resolved.results.get(queryKey);
|
|
115
|
+
if (cached !== undefined || resolved.results.has(queryKey)) {
|
|
116
|
+
// Refresh recency so eviction below is least-recently-used rather
|
|
117
|
+
// than first-inserted.
|
|
118
|
+
resolved.results.delete(queryKey);
|
|
119
|
+
resolved.results.set(queryKey, cached);
|
|
120
|
+
return { value: structuredClone(cached), reused: true };
|
|
121
|
+
}
|
|
122
|
+
const value = compute();
|
|
123
|
+
if (resolved.results.size >= maxResults) {
|
|
124
|
+
// Evict the oldest memoized result; Map preserves insertion order.
|
|
125
|
+
resolved.results.delete(resolved.results.keys().next().value);
|
|
126
|
+
}
|
|
127
|
+
resolved.results.set(queryKey, structuredClone(value));
|
|
128
|
+
return { value, reused: false };
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/** Drop every cached workspace entry and memoized result. */
|
|
133
|
+
clear() {
|
|
134
|
+
this.#entries.clear();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Process-wide shared cache used by the CLI/MCP graph and deps adapters. */
|
|
138
|
+
const sharedCache = new WorkspaceGraphCache();
|
|
139
|
+
/** Return the process-wide shared workspace graph cache. */
|
|
140
|
+
export function workspaceGraphCache() {
|
|
141
|
+
return sharedCache;
|
|
142
|
+
}
|
|
143
|
+
/** Reset the process-wide shared workspace graph cache (tests and long-lived hosts). */
|
|
144
|
+
export function resetWorkspaceGraphCache() {
|
|
145
|
+
sharedCache.clear();
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=cache.js.map
|
|
148
|
+
//# debugId=6c46fa7f-4566-5a15-ac76-1666770dc806
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sources":["sdk/graph/cache.ts"],"sourceRoot":"/","sourcesContent":["/**\n * @module sdk/graph/cache\n *\n * Incremental workspace graph cache: fingerprint-keyed reuse of the assembled\n * relationship graph plus memoized analytics results, so long-lived processes\n * (the MCP server, SDK consumers, packages) stop paying the full-workspace\n * assembly and analysis cost on every bounded query. The fingerprint is a\n * deterministic digest of every relationship-relevant item field — id, title,\n * lifecycle status and its terminal classification, hierarchy parent, legacy\n * blocker, and structured dependency edges — so any mutation that could change\n * the graph or its projections invalidates the entry, while unrelated payload\n * churn (bodies, comments) does not enter the digest at all. Every lookup\n * reports hit/miss observability so envelopes can explain their freshness.\n */\nimport { createHash } from \"node:crypto\";\nimport type { Dependency, ItemStatus } from \"../../types/index.js\";\nimport type {\n WorkspaceRelationshipAssembly,\n WorkspaceRelationshipItem,\n} from \"./assembly.js\";\n\n/** Default memoized query results retained per workspace entry. */\nconst DEFAULT_MAX_RESULTS_PER_WORKSPACE = 64;\n/** Default workspace entries retained by one cache instance. */\nconst DEFAULT_MAX_WORKSPACES = 8;\n\n/** Cache observability attached to graph result envelopes. */\nexport interface GraphCacheMetadata {\n /** Truncated workspace graph fingerprint identifying the snapshot answered from. */\n fingerprint: string;\n /** Whether the workspace assembly was reused from cache. */\n assembly: \"hit\" | \"miss\";\n /** Whether the full query result was reused from cache. */\n result: \"hit\" | \"miss\";\n}\n\n/** Digest one item's relationship-relevant fields into a deterministic line. */\nfunction fingerprintLine(\n item: WorkspaceRelationshipItem,\n isTerminal: (status: ItemStatus) => boolean,\n): string {\n const dependencies = (item.dependencies ?? [])\n .map((rawDependency) => {\n // Public SDK callers may supply legacy or JSON-decoded payloads; mirror\n // assembly's defensive normalization so the digest tracks what assembly\n // would actually index.\n if (typeof rawDependency !== \"object\" || rawDependency === null)\n return \"\";\n const dependency = rawDependency as Partial<Dependency>;\n return `${typeof dependency.kind === \"string\" ? dependency.kind : \"related\"}:${\n typeof dependency.id === \"string\" ? dependency.id : \"\"\n }`;\n })\n .sort()\n .join(\",\");\n return [\n item.id,\n item.title,\n item.status,\n isTerminal(item.status) ? \"1\" : \"0\",\n item.parent ?? \"\",\n item.blocked_by ?? \"\",\n dependencies,\n ].join(\"\\u0000\");\n}\n\n/**\n * Compute the deterministic workspace graph fingerprint for one item snapshot.\n * Items are digested in sorted order so storage enumeration order never\n * changes the fingerprint, and the terminal classification of each status is\n * folded in so schema changes to lifecycle semantics invalidate cached\n * assemblies even when raw statuses are unchanged.\n */\nexport function computeWorkspaceGraphFingerprint(\n items: readonly WorkspaceRelationshipItem[],\n isTerminal: (status: ItemStatus) => boolean = (status) =>\n status === \"closed\" || status === \"canceled\",\n): string {\n const lines = items\n .filter((item) => typeof item?.id === \"string\" && item.id.trim().length > 0)\n .map((item) => fingerprintLine(item, isTerminal))\n .sort();\n // Separate fields and records with control characters no stored field can\n // contain unescaped, so adjacent free-text fields can never collide.\n return createHash(\"sha256\").update(lines.join(\"\\u0001\")).digest(\"hex\");\n}\n\n/** One cached workspace snapshot: its assembly plus memoized query results. */\ninterface WorkspaceGraphCacheEntry {\n /** Fingerprint of the item snapshot this entry answers for. */\n fingerprint: string;\n /** Assembled relationship graph reused across queries. */\n assembly: WorkspaceRelationshipAssembly;\n /** Bounded insertion-ordered memo of deterministic query results. */\n results: Map<string, unknown>;\n}\n\n/** One resolved cache lookup bound to a workspace snapshot. */\nexport interface WorkspaceGraphCacheLookup {\n /** The (possibly reused) workspace assembly. */\n assembly: WorkspaceRelationshipAssembly;\n /** Whether the assembly came from cache instead of being rebuilt. */\n assemblyReused: boolean;\n /** Full fingerprint of the snapshot this lookup is bound to. */\n fingerprint: string;\n /**\n * Memoize one deterministic query result under this snapshot. On a miss the\n * freshly computed value is returned as-is while an independent clone is\n * stored, so mutating a miss result never corrupts the cache; every hit\n * returns a fresh clone of the stored entry. Callers must not rely on the\n * miss and hit paths returning the same object identity.\n */\n memoize<T>(queryKey: string, compute: () => T): { value: T; reused: boolean };\n}\n\n/** Validate one optional positive-integer cache bound, applying its default. */\nfunction requirePositiveCacheBound(\n name: string,\n value: number | undefined,\n fallback: number,\n): number {\n const bound = value ?? fallback;\n if (!Number.isInteger(bound) || bound < 1)\n throw new TypeError(`Invalid ${name} bound: ${String(value)}`);\n return bound;\n}\n\n/**\n * Fingerprint-keyed cache of workspace relationship assemblies and memoized\n * deterministic query results. One entry is retained per workspace key; a\n * changed fingerprint atomically replaces the entry and drops its memoized\n * results. Memoized values are structured-cloned on store and on read so\n * neither the producer nor any consumer can mutate cached state.\n */\nexport class WorkspaceGraphCache {\n readonly #entries = new Map<string, WorkspaceGraphCacheEntry>();\n readonly #maxResultsPerWorkspace: number;\n readonly #maxWorkspaces: number;\n\n /** Create a cache, optionally bounding workspaces and memoized results. */\n public constructor(\n options: { maxResultsPerWorkspace?: number; maxWorkspaces?: number } = {},\n ) {\n this.#maxResultsPerWorkspace = requirePositiveCacheBound(\n \"maxResultsPerWorkspace\",\n options.maxResultsPerWorkspace,\n DEFAULT_MAX_RESULTS_PER_WORKSPACE,\n );\n this.#maxWorkspaces = requirePositiveCacheBound(\n \"maxWorkspaces\",\n options.maxWorkspaces,\n DEFAULT_MAX_WORKSPACES,\n );\n }\n\n /**\n * Resolve the cached assembly for one workspace key and fingerprint,\n * building and storing it on miss. The returned lookup exposes snapshot-\n * scoped memoization for query results derived from the same assembly.\n */\n public lookup(\n key: string,\n fingerprint: string,\n build: () => WorkspaceRelationshipAssembly,\n ): WorkspaceGraphCacheLookup {\n let entry = this.#entries.get(key);\n let assemblyReused = true;\n if (entry === undefined || entry.fingerprint !== fingerprint) {\n entry = { fingerprint, assembly: build(), results: new Map() };\n assemblyReused = false;\n if (\n !this.#entries.has(key) &&\n this.#entries.size >= this.#maxWorkspaces\n ) {\n // Evict the least recently used workspace; every lookup refreshes\n // recency below, so insertion order tracks use order.\n this.#entries.delete(this.#entries.keys().next().value!);\n }\n }\n // Delete-and-reinsert keeps Map insertion order equal to recency order,\n // making workspace eviction genuinely least-recently-used.\n this.#entries.delete(key);\n this.#entries.set(key, entry);\n const resolved = entry;\n const maxResults = this.#maxResultsPerWorkspace;\n return {\n assembly: resolved.assembly,\n assemblyReused,\n fingerprint,\n memoize<T>(\n queryKey: string,\n compute: () => T,\n ): { value: T; reused: boolean } {\n const cached = resolved.results.get(queryKey);\n if (cached !== undefined || resolved.results.has(queryKey)) {\n // Refresh recency so eviction below is least-recently-used rather\n // than first-inserted.\n resolved.results.delete(queryKey);\n resolved.results.set(queryKey, cached);\n return { value: structuredClone(cached) as T, reused: true };\n }\n const value = compute();\n if (resolved.results.size >= maxResults) {\n // Evict the oldest memoized result; Map preserves insertion order.\n resolved.results.delete(resolved.results.keys().next().value!);\n }\n resolved.results.set(queryKey, structuredClone(value));\n return { value, reused: false };\n },\n };\n }\n\n /** Drop every cached workspace entry and memoized result. */\n public clear(): void {\n this.#entries.clear();\n }\n}\n\n/** Process-wide shared cache used by the CLI/MCP graph and deps adapters. */\nconst sharedCache = new WorkspaceGraphCache();\n\n/** Return the process-wide shared workspace graph cache. */\nexport function workspaceGraphCache(): WorkspaceGraphCache {\n return sharedCache;\n}\n\n/** Reset the process-wide shared workspace graph cache (tests and long-lived hosts). */\nexport function resetWorkspaceGraphCache(): void {\n sharedCache.clear();\n}\n"],"names":[],"mappings":"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","debugId":"6c46fa7f-4566-5a15-ac76-1666770dc806"}
|