opentasks 0.0.1 → 0.0.2
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/README.md +344 -1
- package/dist/__tests__/cli-tools.test.d.ts +8 -0
- package/dist/__tests__/cli-tools.test.d.ts.map +1 -0
- package/dist/__tests__/cli-tools.test.js +546 -0
- package/dist/__tests__/cli-tools.test.js.map +1 -0
- package/dist/__tests__/cli.test.d.ts +5 -0
- package/dist/__tests__/cli.test.d.ts.map +1 -0
- package/dist/__tests__/cli.test.js +77 -0
- package/dist/__tests__/cli.test.js.map +1 -0
- package/dist/__tests__/p1-p3-gaps.test.d.ts +2 -0
- package/dist/__tests__/p1-p3-gaps.test.d.ts.map +1 -0
- package/dist/__tests__/p1-p3-gaps.test.js +463 -0
- package/dist/__tests__/p1-p3-gaps.test.js.map +1 -0
- package/dist/cli.d.ts +19 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +702 -23
- package/dist/cli.js.map +1 -1
- package/dist/client/__tests__/client-crud.test.d.ts +7 -0
- package/dist/client/__tests__/client-crud.test.d.ts.map +1 -0
- package/dist/client/__tests__/client-crud.test.js +404 -0
- package/dist/client/__tests__/client-crud.test.js.map +1 -0
- package/dist/client/__tests__/client.test.d.ts +5 -0
- package/dist/client/__tests__/client.test.d.ts.map +1 -0
- package/dist/client/__tests__/client.test.js +518 -0
- package/dist/client/__tests__/client.test.js.map +1 -0
- package/dist/client/client.d.ts +228 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +393 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/index.d.ts +11 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +9 -0
- package/dist/client/index.js.map +1 -0
- package/dist/config/__tests__/defaults.test.d.ts +2 -0
- package/dist/config/__tests__/defaults.test.d.ts.map +1 -0
- package/dist/config/__tests__/defaults.test.js +57 -0
- package/dist/config/__tests__/defaults.test.js.map +1 -0
- package/dist/config/__tests__/env.test.d.ts +2 -0
- package/dist/config/__tests__/env.test.d.ts.map +1 -0
- package/dist/config/__tests__/env.test.js +136 -0
- package/dist/config/__tests__/env.test.js.map +1 -0
- package/dist/config/__tests__/index.test.d.ts +2 -0
- package/dist/config/__tests__/index.test.d.ts.map +1 -0
- package/dist/config/__tests__/index.test.js +113 -0
- package/dist/config/__tests__/index.test.js.map +1 -0
- package/dist/config/__tests__/loader.test.d.ts +2 -0
- package/dist/config/__tests__/loader.test.d.ts.map +1 -0
- package/dist/config/__tests__/loader.test.js +128 -0
- package/dist/config/__tests__/loader.test.js.map +1 -0
- package/dist/config/__tests__/merge.test.d.ts +2 -0
- package/dist/config/__tests__/merge.test.d.ts.map +1 -0
- package/dist/config/__tests__/merge.test.js +79 -0
- package/dist/config/__tests__/merge.test.js.map +1 -0
- package/dist/config/__tests__/schema.test.d.ts +2 -0
- package/dist/config/__tests__/schema.test.d.ts.map +1 -0
- package/dist/config/__tests__/schema.test.js +300 -0
- package/dist/config/__tests__/schema.test.js.map +1 -0
- package/dist/config/defaults.d.ts +13 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +15 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/env.d.ts +14 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +130 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/errors.d.ts +21 -0
- package/dist/config/errors.d.ts.map +1 -0
- package/dist/config/errors.js +30 -0
- package/dist/config/errors.js.map +1 -0
- package/dist/config/index.d.ts +21 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +41 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +8 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +87 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/merge.d.ts +12 -0
- package/dist/config/merge.d.ts.map +1 -0
- package/dist/config/merge.js +54 -0
- package/dist/config/merge.js.map +1 -0
- package/dist/config/schema.d.ts +644 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +491 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/__tests__/conditional-redirects.test.d.ts +2 -0
- package/dist/core/__tests__/conditional-redirects.test.d.ts.map +1 -0
- package/dist/core/__tests__/conditional-redirects.test.js +83 -0
- package/dist/core/__tests__/conditional-redirects.test.js.map +1 -0
- package/dist/core/__tests__/connections.test.d.ts +2 -0
- package/dist/core/__tests__/connections.test.d.ts.map +1 -0
- package/dist/core/__tests__/connections.test.js +158 -0
- package/dist/core/__tests__/connections.test.js.map +1 -0
- package/dist/core/__tests__/hash.test.d.ts +2 -0
- package/dist/core/__tests__/hash.test.d.ts.map +1 -0
- package/dist/core/__tests__/hash.test.js +139 -0
- package/dist/core/__tests__/hash.test.js.map +1 -0
- package/dist/core/__tests__/id.test.d.ts +2 -0
- package/dist/core/__tests__/id.test.d.ts.map +1 -0
- package/dist/core/__tests__/id.test.js +142 -0
- package/dist/core/__tests__/id.test.js.map +1 -0
- package/dist/core/__tests__/location.test.d.ts +2 -0
- package/dist/core/__tests__/location.test.d.ts.map +1 -0
- package/dist/core/__tests__/location.test.js +77 -0
- package/dist/core/__tests__/location.test.js.map +1 -0
- package/dist/core/__tests__/merge-driver.test.d.ts +2 -0
- package/dist/core/__tests__/merge-driver.test.d.ts.map +1 -0
- package/dist/core/__tests__/merge-driver.test.js +218 -0
- package/dist/core/__tests__/merge-driver.test.js.map +1 -0
- package/dist/core/__tests__/redirects.test.d.ts +2 -0
- package/dist/core/__tests__/redirects.test.d.ts.map +1 -0
- package/dist/core/__tests__/redirects.test.js +123 -0
- package/dist/core/__tests__/redirects.test.js.map +1 -0
- package/dist/core/__tests__/resolve-location-target.test.d.ts +8 -0
- package/dist/core/__tests__/resolve-location-target.test.d.ts.map +1 -0
- package/dist/core/__tests__/resolve-location-target.test.js +303 -0
- package/dist/core/__tests__/resolve-location-target.test.js.map +1 -0
- package/dist/core/__tests__/uri.test.d.ts +2 -0
- package/dist/core/__tests__/uri.test.d.ts.map +1 -0
- package/dist/core/__tests__/uri.test.js +159 -0
- package/dist/core/__tests__/uri.test.js.map +1 -0
- package/dist/core/__tests__/worktree.test.d.ts +2 -0
- package/dist/core/__tests__/worktree.test.d.ts.map +1 -0
- package/dist/core/__tests__/worktree.test.js +120 -0
- package/dist/core/__tests__/worktree.test.js.map +1 -0
- package/dist/core/conditional-redirects.d.ts +42 -0
- package/dist/core/conditional-redirects.d.ts.map +1 -0
- package/dist/core/conditional-redirects.js +59 -0
- package/dist/core/conditional-redirects.js.map +1 -0
- package/dist/core/connections.d.ts +87 -0
- package/dist/core/connections.d.ts.map +1 -0
- package/dist/core/connections.js +160 -0
- package/dist/core/connections.js.map +1 -0
- package/dist/core/discover.d.ts +39 -0
- package/dist/core/discover.d.ts.map +1 -0
- package/dist/core/discover.js +136 -0
- package/dist/core/discover.js.map +1 -0
- package/dist/core/hash.d.ts +25 -0
- package/dist/core/hash.d.ts.map +1 -0
- package/dist/core/hash.js +62 -0
- package/dist/core/hash.js.map +1 -0
- package/dist/core/id.d.ts +79 -0
- package/dist/core/id.d.ts.map +1 -0
- package/dist/core/id.js +141 -0
- package/dist/core/id.js.map +1 -0
- package/dist/core/index.d.ts +15 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +24 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/location.d.ts +70 -0
- package/dist/core/location.d.ts.map +1 -0
- package/dist/core/location.js +121 -0
- package/dist/core/location.js.map +1 -0
- package/dist/core/merge-driver.d.ts +50 -0
- package/dist/core/merge-driver.d.ts.map +1 -0
- package/dist/core/merge-driver.js +258 -0
- package/dist/core/merge-driver.js.map +1 -0
- package/dist/core/redirects.d.ts +91 -0
- package/dist/core/redirects.d.ts.map +1 -0
- package/dist/core/redirects.js +113 -0
- package/dist/core/redirects.js.map +1 -0
- package/dist/core/uri.d.ts +105 -0
- package/dist/core/uri.d.ts.map +1 -0
- package/dist/core/uri.js +190 -0
- package/dist/core/uri.js.map +1 -0
- package/dist/core/worktree.d.ts +106 -0
- package/dist/core/worktree.d.ts.map +1 -0
- package/dist/core/worktree.js +394 -0
- package/dist/core/worktree.js.map +1 -0
- package/dist/daemon/__tests__/flush.test.d.ts +5 -0
- package/dist/daemon/__tests__/flush.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/flush.test.js +213 -0
- package/dist/daemon/__tests__/flush.test.js.map +1 -0
- package/dist/daemon/__tests__/integration.test.d.ts +7 -0
- package/dist/daemon/__tests__/integration.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/integration.test.js +276 -0
- package/dist/daemon/__tests__/integration.test.js.map +1 -0
- package/dist/daemon/__tests__/ipc.test.d.ts +5 -0
- package/dist/daemon/__tests__/ipc.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/ipc.test.js +314 -0
- package/dist/daemon/__tests__/ipc.test.js.map +1 -0
- package/dist/daemon/__tests__/lifecycle.test.d.ts +5 -0
- package/dist/daemon/__tests__/lifecycle.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/lifecycle.test.js +301 -0
- package/dist/daemon/__tests__/lifecycle.test.js.map +1 -0
- package/dist/daemon/__tests__/lock.test.d.ts +5 -0
- package/dist/daemon/__tests__/lock.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/lock.test.js +192 -0
- package/dist/daemon/__tests__/lock.test.js.map +1 -0
- package/dist/daemon/__tests__/methods/graph.test.d.ts +5 -0
- package/dist/daemon/__tests__/methods/graph.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/methods/graph.test.js +309 -0
- package/dist/daemon/__tests__/methods/graph.test.js.map +1 -0
- package/dist/daemon/__tests__/methods/provider.test.d.ts +7 -0
- package/dist/daemon/__tests__/methods/provider.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/methods/provider.test.js +181 -0
- package/dist/daemon/__tests__/methods/provider.test.js.map +1 -0
- package/dist/daemon/__tests__/methods/tools.test.d.ts +5 -0
- package/dist/daemon/__tests__/methods/tools.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/methods/tools.test.js +587 -0
- package/dist/daemon/__tests__/methods/tools.test.js.map +1 -0
- package/dist/daemon/__tests__/multi-location.test.d.ts +8 -0
- package/dist/daemon/__tests__/multi-location.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/multi-location.test.js +669 -0
- package/dist/daemon/__tests__/multi-location.test.js.map +1 -0
- package/dist/daemon/__tests__/registry.test.d.ts +5 -0
- package/dist/daemon/__tests__/registry.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/registry.test.js +208 -0
- package/dist/daemon/__tests__/registry.test.js.map +1 -0
- package/dist/daemon/__tests__/watcher.test.d.ts +5 -0
- package/dist/daemon/__tests__/watcher.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/watcher.test.js +234 -0
- package/dist/daemon/__tests__/watcher.test.js.map +1 -0
- package/dist/daemon/entire-linker.d.ts +68 -0
- package/dist/daemon/entire-linker.d.ts.map +1 -0
- package/dist/daemon/entire-linker.js +439 -0
- package/dist/daemon/entire-linker.js.map +1 -0
- package/dist/daemon/entire-watcher.d.ts +66 -0
- package/dist/daemon/entire-watcher.d.ts.map +1 -0
- package/dist/daemon/entire-watcher.js +258 -0
- package/dist/daemon/entire-watcher.js.map +1 -0
- package/dist/daemon/factory.d.ts +59 -0
- package/dist/daemon/factory.d.ts.map +1 -0
- package/dist/daemon/factory.js +72 -0
- package/dist/daemon/factory.js.map +1 -0
- package/dist/daemon/flush.d.ts +51 -0
- package/dist/daemon/flush.d.ts.map +1 -0
- package/dist/daemon/flush.js +89 -0
- package/dist/daemon/flush.js.map +1 -0
- package/dist/daemon/index.d.ts +39 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +24 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/ipc.d.ts +97 -0
- package/dist/daemon/ipc.d.ts.map +1 -0
- package/dist/daemon/ipc.js +304 -0
- package/dist/daemon/ipc.js.map +1 -0
- package/dist/daemon/lifecycle.d.ts +85 -0
- package/dist/daemon/lifecycle.d.ts.map +1 -0
- package/dist/daemon/lifecycle.js +754 -0
- package/dist/daemon/lifecycle.js.map +1 -0
- package/dist/daemon/location-state.d.ts +85 -0
- package/dist/daemon/location-state.d.ts.map +1 -0
- package/dist/daemon/location-state.js +291 -0
- package/dist/daemon/location-state.js.map +1 -0
- package/dist/daemon/lock.d.ts +29 -0
- package/dist/daemon/lock.d.ts.map +1 -0
- package/dist/daemon/lock.js +131 -0
- package/dist/daemon/lock.js.map +1 -0
- package/dist/daemon/methods/__tests__/graph.test.d.ts +5 -0
- package/dist/daemon/methods/__tests__/graph.test.d.ts.map +1 -0
- package/dist/daemon/methods/__tests__/graph.test.js +274 -0
- package/dist/daemon/methods/__tests__/graph.test.js.map +1 -0
- package/dist/daemon/methods/__tests__/provider.test.d.ts +5 -0
- package/dist/daemon/methods/__tests__/provider.test.d.ts.map +1 -0
- package/dist/daemon/methods/__tests__/provider.test.js +184 -0
- package/dist/daemon/methods/__tests__/provider.test.js.map +1 -0
- package/dist/daemon/methods/__tests__/tools.test.d.ts +5 -0
- package/dist/daemon/methods/__tests__/tools.test.d.ts.map +1 -0
- package/dist/daemon/methods/__tests__/tools.test.js +295 -0
- package/dist/daemon/methods/__tests__/tools.test.js.map +1 -0
- package/dist/daemon/methods/archive.d.ts +22 -0
- package/dist/daemon/methods/archive.d.ts.map +1 -0
- package/dist/daemon/methods/archive.js +107 -0
- package/dist/daemon/methods/archive.js.map +1 -0
- package/dist/daemon/methods/graph.d.ts +26 -0
- package/dist/daemon/methods/graph.d.ts.map +1 -0
- package/dist/daemon/methods/graph.js +157 -0
- package/dist/daemon/methods/graph.js.map +1 -0
- package/dist/daemon/methods/lifecycle.d.ts +54 -0
- package/dist/daemon/methods/lifecycle.d.ts.map +1 -0
- package/dist/daemon/methods/lifecycle.js +46 -0
- package/dist/daemon/methods/lifecycle.js.map +1 -0
- package/dist/daemon/methods/location.d.ts +24 -0
- package/dist/daemon/methods/location.d.ts.map +1 -0
- package/dist/daemon/methods/location.js +72 -0
- package/dist/daemon/methods/location.js.map +1 -0
- package/dist/daemon/methods/provider.d.ts +22 -0
- package/dist/daemon/methods/provider.d.ts.map +1 -0
- package/dist/daemon/methods/provider.js +72 -0
- package/dist/daemon/methods/provider.js.map +1 -0
- package/dist/daemon/methods/tools.d.ts +23 -0
- package/dist/daemon/methods/tools.d.ts.map +1 -0
- package/dist/daemon/methods/tools.js +111 -0
- package/dist/daemon/methods/tools.js.map +1 -0
- package/dist/daemon/registry.d.ts +35 -0
- package/dist/daemon/registry.d.ts.map +1 -0
- package/dist/daemon/registry.js +189 -0
- package/dist/daemon/registry.js.map +1 -0
- package/dist/daemon/types.d.ts +101 -0
- package/dist/daemon/types.d.ts.map +1 -0
- package/dist/daemon/types.js +19 -0
- package/dist/daemon/types.js.map +1 -0
- package/dist/daemon/watcher.d.ts +62 -0
- package/dist/daemon/watcher.d.ts.map +1 -0
- package/dist/daemon/watcher.js +142 -0
- package/dist/daemon/watcher.js.map +1 -0
- package/dist/graph/EdgeTypeRegistry.d.ts +134 -0
- package/dist/graph/EdgeTypeRegistry.d.ts.map +1 -0
- package/dist/graph/EdgeTypeRegistry.js +255 -0
- package/dist/graph/EdgeTypeRegistry.js.map +1 -0
- package/dist/graph/FederatedGraph.d.ts +296 -0
- package/dist/graph/FederatedGraph.d.ts.map +1 -0
- package/dist/graph/FederatedGraph.js +406 -0
- package/dist/graph/FederatedGraph.js.map +1 -0
- package/dist/graph/GraphologyAdapter.d.ts +151 -0
- package/dist/graph/GraphologyAdapter.d.ts.map +1 -0
- package/dist/graph/GraphologyAdapter.js +209 -0
- package/dist/graph/GraphologyAdapter.js.map +1 -0
- package/dist/graph/HydratingFederatedGraph.d.ts +151 -0
- package/dist/graph/HydratingFederatedGraph.d.ts.map +1 -0
- package/dist/graph/HydratingFederatedGraph.js +327 -0
- package/dist/graph/HydratingFederatedGraph.js.map +1 -0
- package/dist/graph/__tests__/EdgeTypeRegistry.test.d.ts +2 -0
- package/dist/graph/__tests__/EdgeTypeRegistry.test.d.ts.map +1 -0
- package/dist/graph/__tests__/EdgeTypeRegistry.test.js +212 -0
- package/dist/graph/__tests__/EdgeTypeRegistry.test.js.map +1 -0
- package/dist/graph/__tests__/FederatedGraph.test.d.ts +2 -0
- package/dist/graph/__tests__/FederatedGraph.test.d.ts.map +1 -0
- package/dist/graph/__tests__/FederatedGraph.test.js +661 -0
- package/dist/graph/__tests__/FederatedGraph.test.js.map +1 -0
- package/dist/graph/__tests__/GraphologyAdapter.test.d.ts +2 -0
- package/dist/graph/__tests__/GraphologyAdapter.test.d.ts.map +1 -0
- package/dist/graph/__tests__/GraphologyAdapter.test.js +326 -0
- package/dist/graph/__tests__/GraphologyAdapter.test.js.map +1 -0
- package/dist/graph/__tests__/HydratingFederatedGraph.test.d.ts +2 -0
- package/dist/graph/__tests__/HydratingFederatedGraph.test.d.ts.map +1 -0
- package/dist/graph/__tests__/HydratingFederatedGraph.test.js +587 -0
- package/dist/graph/__tests__/HydratingFederatedGraph.test.js.map +1 -0
- package/dist/graph/__tests__/debounce.test.d.ts +5 -0
- package/dist/graph/__tests__/debounce.test.d.ts.map +1 -0
- package/dist/graph/__tests__/debounce.test.js +195 -0
- package/dist/graph/__tests__/debounce.test.js.map +1 -0
- package/dist/graph/__tests__/edge-cases.test.d.ts +8 -0
- package/dist/graph/__tests__/edge-cases.test.d.ts.map +1 -0
- package/dist/graph/__tests__/edge-cases.test.js +472 -0
- package/dist/graph/__tests__/edge-cases.test.js.map +1 -0
- package/dist/graph/__tests__/expansion.test.d.ts +2 -0
- package/dist/graph/__tests__/expansion.test.d.ts.map +1 -0
- package/dist/graph/__tests__/expansion.test.js +105 -0
- package/dist/graph/__tests__/expansion.test.js.map +1 -0
- package/dist/graph/__tests__/provider-store.test.d.ts +5 -0
- package/dist/graph/__tests__/provider-store.test.d.ts.map +1 -0
- package/dist/graph/__tests__/provider-store.test.js +791 -0
- package/dist/graph/__tests__/provider-store.test.js.map +1 -0
- package/dist/graph/__tests__/query.test.d.ts +5 -0
- package/dist/graph/__tests__/query.test.d.ts.map +1 -0
- package/dist/graph/__tests__/query.test.js +774 -0
- package/dist/graph/__tests__/query.test.js.map +1 -0
- package/dist/graph/__tests__/store.test.d.ts +5 -0
- package/dist/graph/__tests__/store.test.d.ts.map +1 -0
- package/dist/graph/__tests__/store.test.js +489 -0
- package/dist/graph/__tests__/store.test.js.map +1 -0
- package/dist/graph/__tests__/sync.test.d.ts +5 -0
- package/dist/graph/__tests__/sync.test.d.ts.map +1 -0
- package/dist/graph/__tests__/sync.test.js +129 -0
- package/dist/graph/__tests__/sync.test.js.map +1 -0
- package/dist/graph/__tests__/validation.test.d.ts +2 -0
- package/dist/graph/__tests__/validation.test.d.ts.map +1 -0
- package/dist/graph/__tests__/validation.test.js +521 -0
- package/dist/graph/__tests__/validation.test.js.map +1 -0
- package/dist/graph/coordination.d.ts +190 -0
- package/dist/graph/coordination.d.ts.map +1 -0
- package/dist/graph/coordination.js +180 -0
- package/dist/graph/coordination.js.map +1 -0
- package/dist/graph/debounce.d.ts +47 -0
- package/dist/graph/debounce.d.ts.map +1 -0
- package/dist/graph/debounce.js +95 -0
- package/dist/graph/debounce.js.map +1 -0
- package/dist/graph/expansion.d.ts +64 -0
- package/dist/graph/expansion.d.ts.map +1 -0
- package/dist/graph/expansion.js +205 -0
- package/dist/graph/expansion.js.map +1 -0
- package/dist/graph/history.d.ts +186 -0
- package/dist/graph/history.d.ts.map +1 -0
- package/dist/graph/history.js +155 -0
- package/dist/graph/history.js.map +1 -0
- package/dist/graph/index.d.ts +35 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +22 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/provider-store.d.ts +211 -0
- package/dist/graph/provider-store.d.ts.map +1 -0
- package/dist/graph/provider-store.js +568 -0
- package/dist/graph/provider-store.js.map +1 -0
- package/dist/graph/query.d.ts +90 -0
- package/dist/graph/query.d.ts.map +1 -0
- package/dist/graph/query.js +463 -0
- package/dist/graph/query.js.map +1 -0
- package/dist/graph/store.d.ts +71 -0
- package/dist/graph/store.d.ts.map +1 -0
- package/dist/graph/store.js +530 -0
- package/dist/graph/store.js.map +1 -0
- package/dist/graph/sync.d.ts +48 -0
- package/dist/graph/sync.d.ts.map +1 -0
- package/dist/graph/sync.js +60 -0
- package/dist/graph/sync.js.map +1 -0
- package/dist/graph/types.d.ts +289 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +19 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/graph/validation.d.ts +26 -0
- package/dist/graph/validation.d.ts.map +1 -0
- package/dist/graph/validation.js +338 -0
- package/dist/graph/validation.js.map +1 -0
- package/dist/index.d.ts +25 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -25
- package/dist/index.js.map +1 -1
- package/dist/materialization/archiver.d.ts +12 -0
- package/dist/materialization/archiver.d.ts.map +1 -0
- package/dist/materialization/archiver.js +273 -0
- package/dist/materialization/archiver.js.map +1 -0
- package/dist/materialization/git-archive-store.d.ts +17 -0
- package/dist/materialization/git-archive-store.d.ts.map +1 -0
- package/dist/materialization/git-archive-store.js +509 -0
- package/dist/materialization/git-archive-store.js.map +1 -0
- package/dist/materialization/git-remote-store.d.ts +22 -0
- package/dist/materialization/git-remote-store.d.ts.map +1 -0
- package/dist/materialization/git-remote-store.js +448 -0
- package/dist/materialization/git-remote-store.js.map +1 -0
- package/dist/materialization/graph-id.d.ts +53 -0
- package/dist/materialization/graph-id.d.ts.map +1 -0
- package/dist/materialization/graph-id.js +163 -0
- package/dist/materialization/graph-id.js.map +1 -0
- package/dist/materialization/http-remote-store.d.ts +12 -0
- package/dist/materialization/http-remote-store.d.ts.map +1 -0
- package/dist/materialization/http-remote-store.js +143 -0
- package/dist/materialization/http-remote-store.js.map +1 -0
- package/dist/materialization/index.d.ts +15 -0
- package/dist/materialization/index.d.ts.map +1 -0
- package/dist/materialization/index.js +17 -0
- package/dist/materialization/index.js.map +1 -0
- package/dist/materialization/remote-store-factory.d.ts +17 -0
- package/dist/materialization/remote-store-factory.d.ts.map +1 -0
- package/dist/materialization/remote-store-factory.js +46 -0
- package/dist/materialization/remote-store-factory.js.map +1 -0
- package/dist/materialization/snapshot.d.ts +34 -0
- package/dist/materialization/snapshot.d.ts.map +1 -0
- package/dist/materialization/snapshot.js +177 -0
- package/dist/materialization/snapshot.js.map +1 -0
- package/dist/materialization/types.d.ts +300 -0
- package/dist/materialization/types.d.ts.map +1 -0
- package/dist/materialization/types.js +17 -0
- package/dist/materialization/types.js.map +1 -0
- package/dist/providers/__tests__/beads.test.d.ts +5 -0
- package/dist/providers/__tests__/beads.test.d.ts.map +1 -0
- package/dist/providers/__tests__/beads.test.js +591 -0
- package/dist/providers/__tests__/beads.test.js.map +1 -0
- package/dist/providers/__tests__/claude-tasks.test.d.ts +5 -0
- package/dist/providers/__tests__/claude-tasks.test.d.ts.map +1 -0
- package/dist/providers/__tests__/claude-tasks.test.js +392 -0
- package/dist/providers/__tests__/claude-tasks.test.js.map +1 -0
- package/dist/providers/__tests__/from-config.test.d.ts +5 -0
- package/dist/providers/__tests__/from-config.test.d.ts.map +1 -0
- package/dist/providers/__tests__/from-config.test.js +152 -0
- package/dist/providers/__tests__/from-config.test.js.map +1 -0
- package/dist/providers/__tests__/materialization.test.d.ts +5 -0
- package/dist/providers/__tests__/materialization.test.d.ts.map +1 -0
- package/dist/providers/__tests__/materialization.test.js +407 -0
- package/dist/providers/__tests__/materialization.test.js.map +1 -0
- package/dist/providers/__tests__/native.test.d.ts +5 -0
- package/dist/providers/__tests__/native.test.d.ts.map +1 -0
- package/dist/providers/__tests__/native.test.js +566 -0
- package/dist/providers/__tests__/native.test.js.map +1 -0
- package/dist/providers/__tests__/registry.test.d.ts +5 -0
- package/dist/providers/__tests__/registry.test.d.ts.map +1 -0
- package/dist/providers/__tests__/registry.test.js +183 -0
- package/dist/providers/__tests__/registry.test.js.map +1 -0
- package/dist/providers/beads.d.ts +46 -0
- package/dist/providers/beads.d.ts.map +1 -0
- package/dist/providers/beads.js +865 -0
- package/dist/providers/beads.js.map +1 -0
- package/dist/providers/claude-tasks.d.ts +56 -0
- package/dist/providers/claude-tasks.d.ts.map +1 -0
- package/dist/providers/claude-tasks.js +282 -0
- package/dist/providers/claude-tasks.js.map +1 -0
- package/dist/providers/entire.d.ts +88 -0
- package/dist/providers/entire.d.ts.map +1 -0
- package/dist/providers/entire.js +409 -0
- package/dist/providers/entire.js.map +1 -0
- package/dist/providers/from-config.d.ts +47 -0
- package/dist/providers/from-config.d.ts.map +1 -0
- package/dist/providers/from-config.js +150 -0
- package/dist/providers/from-config.js.map +1 -0
- package/dist/providers/index.d.ts +26 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +29 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/location.d.ts +44 -0
- package/dist/providers/location.d.ts.map +1 -0
- package/dist/providers/location.js +157 -0
- package/dist/providers/location.js.map +1 -0
- package/dist/providers/materialization.d.ts +46 -0
- package/dist/providers/materialization.d.ts.map +1 -0
- package/dist/providers/materialization.js +237 -0
- package/dist/providers/materialization.js.map +1 -0
- package/dist/providers/native.d.ts +32 -0
- package/dist/providers/native.d.ts.map +1 -0
- package/dist/providers/native.js +552 -0
- package/dist/providers/native.js.map +1 -0
- package/dist/providers/registry.d.ts +11 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +97 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/sudocode.d.ts +49 -0
- package/dist/providers/sudocode.d.ts.map +1 -0
- package/dist/providers/sudocode.js +945 -0
- package/dist/providers/sudocode.js.map +1 -0
- package/dist/providers/sync.d.ts +299 -0
- package/dist/providers/sync.d.ts.map +1 -0
- package/dist/providers/sync.js +93 -0
- package/dist/providers/sync.js.map +1 -0
- package/dist/providers/traits/RelationshipQueryable.d.ts +129 -0
- package/dist/providers/traits/RelationshipQueryable.d.ts.map +1 -0
- package/dist/providers/traits/RelationshipQueryable.js +68 -0
- package/dist/providers/traits/RelationshipQueryable.js.map +1 -0
- package/dist/providers/traits/TaskManageable.d.ts +157 -0
- package/dist/providers/traits/TaskManageable.d.ts.map +1 -0
- package/dist/providers/traits/TaskManageable.js +37 -0
- package/dist/providers/traits/TaskManageable.js.map +1 -0
- package/dist/providers/traits/Watchable.d.ts +216 -0
- package/dist/providers/traits/Watchable.d.ts.map +1 -0
- package/dist/providers/traits/Watchable.js +37 -0
- package/dist/providers/traits/Watchable.js.map +1 -0
- package/dist/providers/traits/__tests__/RelationshipQueryable.test.d.ts +2 -0
- package/dist/providers/traits/__tests__/RelationshipQueryable.test.d.ts.map +1 -0
- package/dist/providers/traits/__tests__/RelationshipQueryable.test.js +169 -0
- package/dist/providers/traits/__tests__/RelationshipQueryable.test.js.map +1 -0
- package/dist/providers/traits/__tests__/TaskManageable.test.d.ts +2 -0
- package/dist/providers/traits/__tests__/TaskManageable.test.d.ts.map +1 -0
- package/dist/providers/traits/__tests__/TaskManageable.test.js +172 -0
- package/dist/providers/traits/__tests__/TaskManageable.test.js.map +1 -0
- package/dist/providers/traits/index.d.ts +13 -0
- package/dist/providers/traits/index.d.ts.map +1 -0
- package/dist/providers/traits/index.js +10 -0
- package/dist/providers/traits/index.js.map +1 -0
- package/dist/providers/types.d.ts +284 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +30 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/schema/__tests__/validation.test.d.ts +2 -0
- package/dist/schema/__tests__/validation.test.d.ts.map +1 -0
- package/dist/schema/__tests__/validation.test.js +241 -0
- package/dist/schema/__tests__/validation.test.js.map +1 -0
- package/dist/schema/base.d.ts +68 -0
- package/dist/schema/base.d.ts.map +1 -0
- package/dist/schema/base.js +5 -0
- package/dist/schema/base.js.map +1 -0
- package/dist/schema/edges.d.ts +49 -0
- package/dist/schema/edges.d.ts.map +1 -0
- package/dist/schema/edges.js +9 -0
- package/dist/schema/edges.js.map +1 -0
- package/dist/schema/index.d.ts +11 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +8 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/nodes.d.ts +97 -0
- package/dist/schema/nodes.d.ts.map +1 -0
- package/dist/schema/nodes.js +5 -0
- package/dist/schema/nodes.js.map +1 -0
- package/dist/schema/storage.d.ts +107 -0
- package/dist/schema/storage.d.ts.map +1 -0
- package/dist/schema/storage.js +10 -0
- package/dist/schema/storage.js.map +1 -0
- package/dist/schema/validation.d.ts +61 -0
- package/dist/schema/validation.d.ts.map +1 -0
- package/dist/schema/validation.js +170 -0
- package/dist/schema/validation.js.map +1 -0
- package/dist/storage/__tests__/atomic-write.test.d.ts +5 -0
- package/dist/storage/__tests__/atomic-write.test.d.ts.map +1 -0
- package/dist/storage/__tests__/atomic-write.test.js +170 -0
- package/dist/storage/__tests__/atomic-write.test.js.map +1 -0
- package/dist/storage/__tests__/file-lock.test.d.ts +2 -0
- package/dist/storage/__tests__/file-lock.test.d.ts.map +1 -0
- package/dist/storage/__tests__/file-lock.test.js +89 -0
- package/dist/storage/__tests__/file-lock.test.js.map +1 -0
- package/dist/storage/__tests__/jsonl.test.d.ts +2 -0
- package/dist/storage/__tests__/jsonl.test.d.ts.map +1 -0
- package/dist/storage/__tests__/jsonl.test.js +228 -0
- package/dist/storage/__tests__/jsonl.test.js.map +1 -0
- package/dist/storage/__tests__/locked-writer.test.d.ts +2 -0
- package/dist/storage/__tests__/locked-writer.test.d.ts.map +1 -0
- package/dist/storage/__tests__/locked-writer.test.js +109 -0
- package/dist/storage/__tests__/locked-writer.test.js.map +1 -0
- package/dist/storage/__tests__/sqlite.test.d.ts +2 -0
- package/dist/storage/__tests__/sqlite.test.d.ts.map +1 -0
- package/dist/storage/__tests__/sqlite.test.js +470 -0
- package/dist/storage/__tests__/sqlite.test.js.map +1 -0
- package/dist/storage/atomic-write.d.ts +38 -0
- package/dist/storage/atomic-write.d.ts.map +1 -0
- package/dist/storage/atomic-write.js +83 -0
- package/dist/storage/atomic-write.js.map +1 -0
- package/dist/storage/file-lock.d.ts +66 -0
- package/dist/storage/file-lock.d.ts.map +1 -0
- package/dist/storage/file-lock.js +176 -0
- package/dist/storage/file-lock.js.map +1 -0
- package/dist/storage/index.d.ts +11 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +13 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/interface.d.ts +219 -0
- package/dist/storage/interface.d.ts.map +1 -0
- package/dist/storage/interface.js +22 -0
- package/dist/storage/interface.js.map +1 -0
- package/dist/storage/jsonl.d.ts +106 -0
- package/dist/storage/jsonl.d.ts.map +1 -0
- package/dist/storage/jsonl.js +218 -0
- package/dist/storage/jsonl.js.map +1 -0
- package/dist/storage/locked-writer.d.ts +67 -0
- package/dist/storage/locked-writer.d.ts.map +1 -0
- package/dist/storage/locked-writer.js +105 -0
- package/dist/storage/locked-writer.js.map +1 -0
- package/dist/storage/sqlite-schema.d.ts +48 -0
- package/dist/storage/sqlite-schema.d.ts.map +1 -0
- package/dist/storage/sqlite-schema.js +169 -0
- package/dist/storage/sqlite-schema.js.map +1 -0
- package/dist/storage/sqlite.d.ts +73 -0
- package/dist/storage/sqlite.d.ts.map +1 -0
- package/dist/storage/sqlite.js +698 -0
- package/dist/storage/sqlite.js.map +1 -0
- package/dist/tools/__tests__/annotate.test.d.ts +5 -0
- package/dist/tools/__tests__/annotate.test.d.ts.map +1 -0
- package/dist/tools/__tests__/annotate.test.js +314 -0
- package/dist/tools/__tests__/annotate.test.js.map +1 -0
- package/dist/tools/__tests__/link.test.d.ts +5 -0
- package/dist/tools/__tests__/link.test.d.ts.map +1 -0
- package/dist/tools/__tests__/link.test.js +245 -0
- package/dist/tools/__tests__/link.test.js.map +1 -0
- package/dist/tools/__tests__/query.test.d.ts +5 -0
- package/dist/tools/__tests__/query.test.d.ts.map +1 -0
- package/dist/tools/__tests__/query.test.js +288 -0
- package/dist/tools/__tests__/query.test.js.map +1 -0
- package/dist/tools/__tests__/task.test.d.ts +5 -0
- package/dist/tools/__tests__/task.test.d.ts.map +1 -0
- package/dist/tools/__tests__/task.test.js +178 -0
- package/dist/tools/__tests__/task.test.js.map +1 -0
- package/dist/tools/annotate.d.ts +17 -0
- package/dist/tools/annotate.d.ts.map +1 -0
- package/dist/tools/annotate.js +218 -0
- package/dist/tools/annotate.js.map +1 -0
- package/dist/tools/index.d.ts +14 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +14 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/link.d.ts +17 -0
- package/dist/tools/link.d.ts.map +1 -0
- package/dist/tools/link.js +127 -0
- package/dist/tools/link.js.map +1 -0
- package/dist/tools/query.d.ts +17 -0
- package/dist/tools/query.d.ts.map +1 -0
- package/dist/tools/query.js +342 -0
- package/dist/tools/query.js.map +1 -0
- package/dist/tools/task.d.ts +20 -0
- package/dist/tools/task.d.ts.map +1 -0
- package/dist/tools/task.js +161 -0
- package/dist/tools/task.js.map +1 -0
- package/dist/tools/types.d.ts +334 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +19 -0
- package/dist/tools/types.js.map +1 -0
- package/package.json +40 -5
|
@@ -0,0 +1,865 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beads Provider
|
|
3
|
+
*
|
|
4
|
+
* Provider that integrates with Beads via CLI.
|
|
5
|
+
* Handles beads:// and bd:// URI schemes.
|
|
6
|
+
*/
|
|
7
|
+
import { exec as execCallback } from 'child_process';
|
|
8
|
+
import { promisify } from 'util';
|
|
9
|
+
import chokidar from 'chokidar';
|
|
10
|
+
import { ProviderError as ProviderErrorClass } from './types.js';
|
|
11
|
+
import { filterEdgesByType, filterEdgesByDirection } from './traits/RelationshipQueryable.js';
|
|
12
|
+
const execAsync = promisify(execCallback);
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Constants
|
|
15
|
+
// ============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Pattern for beads:// or bd:// URIs
|
|
18
|
+
* Format: beads://[workspace/]id or bd://[workspace/]id
|
|
19
|
+
*/
|
|
20
|
+
const BEADS_URI_PATTERN = /^(beads|bd):\/\/(?:([^/]+)\/)?(.+)$/i;
|
|
21
|
+
/**
|
|
22
|
+
* Pattern for Beads issue IDs
|
|
23
|
+
*/
|
|
24
|
+
const BEADS_ID_PATTERN = /^bd-[a-z0-9]+$/i;
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Helper Functions
|
|
27
|
+
// ============================================================================
|
|
28
|
+
/**
|
|
29
|
+
* Map Beads priority to normalized 0-4 scale
|
|
30
|
+
*/
|
|
31
|
+
function mapPriority(priority) {
|
|
32
|
+
if (priority === undefined)
|
|
33
|
+
return undefined;
|
|
34
|
+
if (typeof priority === 'number') {
|
|
35
|
+
// Assume already 0-4 scale
|
|
36
|
+
return Math.max(0, Math.min(4, priority));
|
|
37
|
+
}
|
|
38
|
+
// Map string priorities
|
|
39
|
+
switch (priority.toLowerCase()) {
|
|
40
|
+
case 'critical':
|
|
41
|
+
case 'highest':
|
|
42
|
+
return 0;
|
|
43
|
+
case 'high':
|
|
44
|
+
return 1;
|
|
45
|
+
case 'medium':
|
|
46
|
+
case 'normal':
|
|
47
|
+
return 2;
|
|
48
|
+
case 'low':
|
|
49
|
+
return 3;
|
|
50
|
+
case 'lowest':
|
|
51
|
+
return 4;
|
|
52
|
+
default:
|
|
53
|
+
return 2;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Valid task actions for each status state
|
|
58
|
+
*/
|
|
59
|
+
function validActionsForStatus(status) {
|
|
60
|
+
switch (status) {
|
|
61
|
+
case 'open':
|
|
62
|
+
return ['start', 'block', 'close'];
|
|
63
|
+
case 'in_progress':
|
|
64
|
+
return ['complete', 'block', 'close'];
|
|
65
|
+
case 'blocked':
|
|
66
|
+
return ['reopen', 'close'];
|
|
67
|
+
case 'closed':
|
|
68
|
+
return ['reopen'];
|
|
69
|
+
default:
|
|
70
|
+
return ['start', 'complete', 'block', 'reopen', 'close'];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Convert Beads issue to ProviderNode
|
|
75
|
+
*/
|
|
76
|
+
function beadsIssueToProviderNode(issue, workspace = '.') {
|
|
77
|
+
return {
|
|
78
|
+
id: issue.id,
|
|
79
|
+
uri: `beads://${workspace}/${issue.id}`,
|
|
80
|
+
type: 'issue',
|
|
81
|
+
title: issue.title,
|
|
82
|
+
content: issue.description,
|
|
83
|
+
status: issue.status,
|
|
84
|
+
priority: mapPriority(issue.priority),
|
|
85
|
+
rawData: issue,
|
|
86
|
+
fetchedAt: new Date().toISOString(),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// Beads Provider Implementation
|
|
91
|
+
// ============================================================================
|
|
92
|
+
/**
|
|
93
|
+
* Create a Beads provider with relationship querying and optional watching support
|
|
94
|
+
*/
|
|
95
|
+
export function createBeadsProvider(config = {}) {
|
|
96
|
+
const executable = config.executable ?? 'bd';
|
|
97
|
+
const cwd = config.cwd;
|
|
98
|
+
const timeout = config.timeout ?? 30000;
|
|
99
|
+
const extraArgs = config.extraArgs ?? [];
|
|
100
|
+
const watchPath = config.watchPath;
|
|
101
|
+
const watchDebounceMs = config.watchDebounceMs ?? 200;
|
|
102
|
+
const capabilities = {
|
|
103
|
+
read: true,
|
|
104
|
+
write: true,
|
|
105
|
+
search: true,
|
|
106
|
+
watch: !!watchPath,
|
|
107
|
+
mount: true,
|
|
108
|
+
feedback: false,
|
|
109
|
+
};
|
|
110
|
+
// =========================================================================
|
|
111
|
+
// Watch State (only active when watchPath is configured)
|
|
112
|
+
// =========================================================================
|
|
113
|
+
/** Cached content hashes for change diffing: beads issue id → hash of serialized data */
|
|
114
|
+
const cachedHashes = new Map();
|
|
115
|
+
/** Cached edge signatures for edge change detection: "from:to:type" → true */
|
|
116
|
+
const cachedEdgeKeys = new Set();
|
|
117
|
+
/** chokidar watcher instance */
|
|
118
|
+
let fileWatcher = null;
|
|
119
|
+
/** Current watch callback */
|
|
120
|
+
let watchCallback = null;
|
|
121
|
+
/** Debounce timer for coalescing rapid file changes */
|
|
122
|
+
let debounceTimer = null;
|
|
123
|
+
/**
|
|
124
|
+
* Simple hash for diffing (not cryptographic — just for detecting changes).
|
|
125
|
+
* Uses the same approach as sync.ts calculateContentHash.
|
|
126
|
+
*/
|
|
127
|
+
function quickHash(input) {
|
|
128
|
+
let hash = 0;
|
|
129
|
+
for (let i = 0; i < input.length; i++) {
|
|
130
|
+
const char = input.charCodeAt(i);
|
|
131
|
+
hash = (hash << 5) - hash + char;
|
|
132
|
+
hash = hash & hash;
|
|
133
|
+
}
|
|
134
|
+
return hash.toString(16);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Build a stable hash key for a Beads issue (substantive fields only)
|
|
138
|
+
*/
|
|
139
|
+
function issueHashKey(issue) {
|
|
140
|
+
const substantive = {
|
|
141
|
+
title: issue.title,
|
|
142
|
+
description: issue.description,
|
|
143
|
+
status: issue.status,
|
|
144
|
+
priority: issue.priority,
|
|
145
|
+
tags: issue.tags ? [...issue.tags].sort() : undefined,
|
|
146
|
+
blocks: issue.blocks ? [...issue.blocks].sort() : undefined,
|
|
147
|
+
blockedBy: issue.blockedBy ? [...issue.blockedBy].sort() : undefined,
|
|
148
|
+
// Structured format (bd v0.49+)
|
|
149
|
+
dependency_count: issue.dependency_count,
|
|
150
|
+
dependent_count: issue.dependent_count,
|
|
151
|
+
parent: issue.parent,
|
|
152
|
+
children: issue.children ? [...issue.children].sort() : undefined,
|
|
153
|
+
};
|
|
154
|
+
return quickHash(JSON.stringify(substantive));
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Compute the set of edge keys from an issue's relationship fields
|
|
158
|
+
*/
|
|
159
|
+
function issueEdgeKeys(issue) {
|
|
160
|
+
const keys = new Set();
|
|
161
|
+
// Legacy format: blocks/blockedBy string arrays
|
|
162
|
+
if (issue.blocks) {
|
|
163
|
+
for (const id of issue.blocks)
|
|
164
|
+
keys.add(`${issue.id}:${id}:blocks`);
|
|
165
|
+
}
|
|
166
|
+
if (issue.blockedBy) {
|
|
167
|
+
for (const id of issue.blockedBy)
|
|
168
|
+
keys.add(`${id}:${issue.id}:blocks`);
|
|
169
|
+
}
|
|
170
|
+
// Structured format (bd v0.49+): dependencies array with {issue_id, depends_on_id, type}
|
|
171
|
+
if (issue.dependencies) {
|
|
172
|
+
for (const dep of issue.dependencies) {
|
|
173
|
+
// dep.depends_on_id blocks dep.issue_id
|
|
174
|
+
keys.add(`${dep.depends_on_id}:${dep.issue_id}:blocks`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (issue.parent) {
|
|
178
|
+
keys.add(`${issue.parent}:${issue.id}:parent-child`);
|
|
179
|
+
}
|
|
180
|
+
if (issue.children) {
|
|
181
|
+
for (const id of issue.children)
|
|
182
|
+
keys.add(`${issue.id}:${id}:parent-child`);
|
|
183
|
+
}
|
|
184
|
+
return keys;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Diff current Beads state against cached hashes and emit change events.
|
|
188
|
+
* Called when file watcher detects a change.
|
|
189
|
+
*/
|
|
190
|
+
async function diffAndEmit() {
|
|
191
|
+
if (!watchCallback)
|
|
192
|
+
return;
|
|
193
|
+
try {
|
|
194
|
+
const output = await execBd(['list', '--json']);
|
|
195
|
+
const issues = parseJson(output);
|
|
196
|
+
const currentIds = new Set();
|
|
197
|
+
const currentEdgeKeys = new Set();
|
|
198
|
+
for (const issue of issues) {
|
|
199
|
+
// Beads uses "tombstone" status for soft-deleted issues — treat as deleted
|
|
200
|
+
const isTombstone = issue.status === 'tombstone';
|
|
201
|
+
if (isTombstone) {
|
|
202
|
+
// Only emit 'deleted' if we previously knew about this issue
|
|
203
|
+
if (cachedHashes.has(issue.id)) {
|
|
204
|
+
watchCallback({
|
|
205
|
+
kind: 'node',
|
|
206
|
+
event: {
|
|
207
|
+
type: 'deleted',
|
|
208
|
+
nodeId: issue.id,
|
|
209
|
+
uri: `beads://./${issue.id}`,
|
|
210
|
+
timestamp: new Date().toISOString(),
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
cachedHashes.delete(issue.id);
|
|
214
|
+
}
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
currentIds.add(issue.id);
|
|
218
|
+
const hash = issueHashKey(issue);
|
|
219
|
+
const prevHash = cachedHashes.get(issue.id);
|
|
220
|
+
const providerNode = beadsIssueToProviderNode(issue);
|
|
221
|
+
if (!prevHash) {
|
|
222
|
+
// New issue
|
|
223
|
+
watchCallback({
|
|
224
|
+
kind: 'node',
|
|
225
|
+
event: {
|
|
226
|
+
type: 'created',
|
|
227
|
+
nodeId: issue.id,
|
|
228
|
+
uri: providerNode.uri,
|
|
229
|
+
node: providerNode,
|
|
230
|
+
timestamp: new Date().toISOString(),
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
else if (prevHash !== hash) {
|
|
235
|
+
// Changed issue — compute changed fields if possible
|
|
236
|
+
const event = {
|
|
237
|
+
type: 'updated',
|
|
238
|
+
nodeId: issue.id,
|
|
239
|
+
uri: providerNode.uri,
|
|
240
|
+
node: providerNode,
|
|
241
|
+
timestamp: new Date().toISOString(),
|
|
242
|
+
};
|
|
243
|
+
// We can report changed fields by comparing against cached data
|
|
244
|
+
// but we only store hashes, not full data. For field-level we'd
|
|
245
|
+
// need to cache full issue objects. For now, we report the node
|
|
246
|
+
// change without field detail — consumers can diff themselves.
|
|
247
|
+
watchCallback({ kind: 'node', event });
|
|
248
|
+
}
|
|
249
|
+
cachedHashes.set(issue.id, hash);
|
|
250
|
+
// Collect current edges
|
|
251
|
+
for (const key of issueEdgeKeys(issue)) {
|
|
252
|
+
currentEdgeKeys.add(key);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// Detect deleted issues
|
|
256
|
+
for (const [id] of cachedHashes) {
|
|
257
|
+
if (!currentIds.has(id)) {
|
|
258
|
+
watchCallback({
|
|
259
|
+
kind: 'node',
|
|
260
|
+
event: {
|
|
261
|
+
type: 'deleted',
|
|
262
|
+
nodeId: id,
|
|
263
|
+
uri: `beads://./${id}`,
|
|
264
|
+
timestamp: new Date().toISOString(),
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
cachedHashes.delete(id);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// Detect edge changes
|
|
271
|
+
// New edges
|
|
272
|
+
for (const key of currentEdgeKeys) {
|
|
273
|
+
if (!cachedEdgeKeys.has(key)) {
|
|
274
|
+
const [from, to, type] = key.split(':');
|
|
275
|
+
const event = {
|
|
276
|
+
type: 'created',
|
|
277
|
+
edge: { from, to, type },
|
|
278
|
+
sourceUri: `beads://./${from}`,
|
|
279
|
+
targetUri: `beads://./${to}`,
|
|
280
|
+
timestamp: new Date().toISOString(),
|
|
281
|
+
};
|
|
282
|
+
watchCallback({ kind: 'edge', event });
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// Deleted edges
|
|
286
|
+
for (const key of cachedEdgeKeys) {
|
|
287
|
+
if (!currentEdgeKeys.has(key)) {
|
|
288
|
+
const [from, to, type] = key.split(':');
|
|
289
|
+
const event = {
|
|
290
|
+
type: 'deleted',
|
|
291
|
+
edge: { from, to, type },
|
|
292
|
+
sourceUri: `beads://./${from}`,
|
|
293
|
+
targetUri: `beads://./${to}`,
|
|
294
|
+
timestamp: new Date().toISOString(),
|
|
295
|
+
};
|
|
296
|
+
watchCallback({ kind: 'edge', event });
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// Update cached edge state
|
|
300
|
+
cachedEdgeKeys.clear();
|
|
301
|
+
for (const key of currentEdgeKeys) {
|
|
302
|
+
cachedEdgeKeys.add(key);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// Resilient — log internally but don't crash the watcher
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Handle a raw file change event with debouncing
|
|
311
|
+
*/
|
|
312
|
+
function onFileChange() {
|
|
313
|
+
if (debounceTimer) {
|
|
314
|
+
clearTimeout(debounceTimer);
|
|
315
|
+
}
|
|
316
|
+
debounceTimer = setTimeout(() => {
|
|
317
|
+
debounceTimer = null;
|
|
318
|
+
void diffAndEmit();
|
|
319
|
+
}, watchDebounceMs);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Seed the cached hashes from current Beads state (so the first
|
|
323
|
+
* diff only emits genuine changes, not the entire existing dataset)
|
|
324
|
+
*/
|
|
325
|
+
async function seedCache() {
|
|
326
|
+
try {
|
|
327
|
+
const output = await execBd(['list', '--json']);
|
|
328
|
+
const issues = parseJson(output);
|
|
329
|
+
cachedHashes.clear();
|
|
330
|
+
cachedEdgeKeys.clear();
|
|
331
|
+
for (const issue of issues) {
|
|
332
|
+
// Skip tombstoned (deleted) issues when seeding cache
|
|
333
|
+
if (issue.status === 'tombstone')
|
|
334
|
+
continue;
|
|
335
|
+
cachedHashes.set(issue.id, issueHashKey(issue));
|
|
336
|
+
for (const key of issueEdgeKeys(issue)) {
|
|
337
|
+
cachedEdgeKeys.add(key);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
// If we can't seed, first diff will treat everything as 'created'
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Shell-escape a single argument
|
|
347
|
+
*/
|
|
348
|
+
function shellEscape(arg) {
|
|
349
|
+
// If arg contains spaces, quotes, or special shell chars, wrap in single quotes
|
|
350
|
+
// and escape any existing single quotes
|
|
351
|
+
if (/['\s"\\$`!]/.test(arg)) {
|
|
352
|
+
return `'${arg.replace(/'/g, "'\\''")}'`;
|
|
353
|
+
}
|
|
354
|
+
return arg;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Execute a bd CLI command
|
|
358
|
+
* @param args - Command arguments
|
|
359
|
+
* @param context - Optional operational context for per-call overrides (cwd, timeout)
|
|
360
|
+
*/
|
|
361
|
+
async function execBd(args, context) {
|
|
362
|
+
const command = [executable, ...extraArgs, ...args.map(shellEscape)].join(' ');
|
|
363
|
+
try {
|
|
364
|
+
const { stdout } = await execAsync(command, {
|
|
365
|
+
cwd: context?.cwd ?? cwd,
|
|
366
|
+
timeout: context?.timeout ?? timeout,
|
|
367
|
+
env: { ...process.env },
|
|
368
|
+
});
|
|
369
|
+
return stdout.trim();
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
const err = error;
|
|
373
|
+
if (err.code === 'ENOENT') {
|
|
374
|
+
throw new ProviderErrorClass('PROVIDER_ERROR', `Beads CLI not found: ${executable}`, 'beads');
|
|
375
|
+
}
|
|
376
|
+
if (err.killed) {
|
|
377
|
+
throw new ProviderErrorClass('TIMEOUT', `Command timed out: ${command}`, 'beads');
|
|
378
|
+
}
|
|
379
|
+
// Extract error details from stdout if available (bd returns JSON errors)
|
|
380
|
+
let errorMessage = err.message ?? 'Unknown error';
|
|
381
|
+
if (err.stdout) {
|
|
382
|
+
try {
|
|
383
|
+
const parsed = JSON.parse(err.stdout);
|
|
384
|
+
if (parsed.error) {
|
|
385
|
+
errorMessage = parsed.error;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
// Not JSON, use stdout as-is if it has content
|
|
390
|
+
if (err.stdout.trim()) {
|
|
391
|
+
errorMessage = err.stdout.trim();
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
throw new ProviderErrorClass('OPERATION_FAILED', `Beads CLI error: ${errorMessage}`, 'beads', error instanceof Error ? error : undefined);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Parse JSON output from bd CLI
|
|
400
|
+
*/
|
|
401
|
+
function parseJson(output) {
|
|
402
|
+
try {
|
|
403
|
+
return JSON.parse(output);
|
|
404
|
+
}
|
|
405
|
+
catch {
|
|
406
|
+
throw new ProviderErrorClass('PROVIDER_ERROR', 'Failed to parse Beads CLI output as JSON', 'beads');
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
name: 'beads',
|
|
411
|
+
schemes: ['beads', 'bd'],
|
|
412
|
+
capabilities,
|
|
413
|
+
// =========================================================================
|
|
414
|
+
// URI Operations
|
|
415
|
+
// =========================================================================
|
|
416
|
+
parseUri(uri) {
|
|
417
|
+
// Check for beads:// or bd:// URI
|
|
418
|
+
const match = uri.match(BEADS_URI_PATTERN);
|
|
419
|
+
if (match) {
|
|
420
|
+
const scheme = match[1].toLowerCase();
|
|
421
|
+
const workspace = match[2] || '.';
|
|
422
|
+
const id = match[3];
|
|
423
|
+
return {
|
|
424
|
+
scheme,
|
|
425
|
+
workspace,
|
|
426
|
+
id,
|
|
427
|
+
isRelative: workspace === '.',
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
// Check for bare Beads ID
|
|
431
|
+
if (BEADS_ID_PATTERN.test(uri)) {
|
|
432
|
+
return {
|
|
433
|
+
scheme: 'beads',
|
|
434
|
+
workspace: '.',
|
|
435
|
+
id: uri,
|
|
436
|
+
isRelative: true,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
return null;
|
|
440
|
+
},
|
|
441
|
+
buildUri(id, options) {
|
|
442
|
+
const workspace = options?.workspace ?? '.';
|
|
443
|
+
if (options?.relative) {
|
|
444
|
+
return id;
|
|
445
|
+
}
|
|
446
|
+
return `beads://${workspace}/${id}`;
|
|
447
|
+
},
|
|
448
|
+
isValidUri(uri) {
|
|
449
|
+
return this.parseUri(uri) !== null;
|
|
450
|
+
},
|
|
451
|
+
// =========================================================================
|
|
452
|
+
// CRUD Operations
|
|
453
|
+
// =========================================================================
|
|
454
|
+
async get(id, context) {
|
|
455
|
+
// Parse URI if full URI is passed
|
|
456
|
+
const parsed = this.parseUri(id);
|
|
457
|
+
const issueId = parsed?.id ?? id;
|
|
458
|
+
const workspace = parsed?.workspace ?? '.';
|
|
459
|
+
try {
|
|
460
|
+
const output = await execBd(['show', issueId, '--json'], context);
|
|
461
|
+
// bd show returns an array, take the first element
|
|
462
|
+
const issues = parseJson(output);
|
|
463
|
+
if (!issues || issues.length === 0) {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
// Treat tombstoned (soft-deleted) issues as not found
|
|
467
|
+
if (issues[0].status === 'tombstone') {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
return beadsIssueToProviderNode(issues[0], workspace);
|
|
471
|
+
}
|
|
472
|
+
catch (error) {
|
|
473
|
+
// Return null for not found, re-throw other errors
|
|
474
|
+
if (error instanceof ProviderErrorClass && error.code === 'OPERATION_FAILED') {
|
|
475
|
+
const message = error.message.toLowerCase();
|
|
476
|
+
if (message.includes('not found') ||
|
|
477
|
+
message.includes('does not exist') ||
|
|
478
|
+
message.includes('no issue found matching')) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
throw error;
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
async list(filter, context) {
|
|
486
|
+
const args = ['list', '--json'];
|
|
487
|
+
// Add filters if supported by bd CLI
|
|
488
|
+
if (filter?.status) {
|
|
489
|
+
args.push('--status', filter.status);
|
|
490
|
+
}
|
|
491
|
+
if (filter?.limit) {
|
|
492
|
+
args.push('--limit', String(filter.limit));
|
|
493
|
+
}
|
|
494
|
+
const output = await execBd(args, context);
|
|
495
|
+
const issues = parseJson(output);
|
|
496
|
+
return issues
|
|
497
|
+
.filter((issue) => issue.status !== 'tombstone')
|
|
498
|
+
.map((issue) => beadsIssueToProviderNode(issue));
|
|
499
|
+
},
|
|
500
|
+
async create(input, context) {
|
|
501
|
+
const args = ['create', input.title];
|
|
502
|
+
if (input.content) {
|
|
503
|
+
args.push('--description', input.content);
|
|
504
|
+
}
|
|
505
|
+
if (input.status) {
|
|
506
|
+
args.push('--status', input.status);
|
|
507
|
+
}
|
|
508
|
+
if (input.priority !== undefined) {
|
|
509
|
+
args.push('--priority', String(input.priority));
|
|
510
|
+
}
|
|
511
|
+
args.push('--json');
|
|
512
|
+
const output = await execBd(args, context);
|
|
513
|
+
const issue = parseJson(output);
|
|
514
|
+
return beadsIssueToProviderNode(issue);
|
|
515
|
+
},
|
|
516
|
+
async update(id, updates, context) {
|
|
517
|
+
// Parse URI if full URI is passed
|
|
518
|
+
const parsed = this.parseUri(id);
|
|
519
|
+
const issueId = parsed?.id ?? id;
|
|
520
|
+
const args = ['update', issueId];
|
|
521
|
+
if (updates.title) {
|
|
522
|
+
args.push('--title', updates.title);
|
|
523
|
+
}
|
|
524
|
+
if (updates.content) {
|
|
525
|
+
args.push('--description', updates.content);
|
|
526
|
+
}
|
|
527
|
+
if (updates.status) {
|
|
528
|
+
args.push('--status', updates.status);
|
|
529
|
+
}
|
|
530
|
+
if (updates.priority !== undefined) {
|
|
531
|
+
args.push('--priority', String(updates.priority));
|
|
532
|
+
}
|
|
533
|
+
args.push('--json');
|
|
534
|
+
const output = await execBd(args, context);
|
|
535
|
+
// bd update returns an array, take the first element
|
|
536
|
+
const issues = parseJson(output);
|
|
537
|
+
if (!issues || issues.length === 0) {
|
|
538
|
+
throw new ProviderErrorClass('OPERATION_FAILED', 'Update returned no results', 'beads');
|
|
539
|
+
}
|
|
540
|
+
return beadsIssueToProviderNode(issues[0]);
|
|
541
|
+
},
|
|
542
|
+
async delete(id, context) {
|
|
543
|
+
// Parse URI if full URI is passed
|
|
544
|
+
const parsed = this.parseUri(id);
|
|
545
|
+
const issueId = parsed?.id ?? id;
|
|
546
|
+
await execBd(['delete', issueId, '--force'], context);
|
|
547
|
+
},
|
|
548
|
+
// =========================================================================
|
|
549
|
+
// Search
|
|
550
|
+
// =========================================================================
|
|
551
|
+
async search(query, options) {
|
|
552
|
+
const args = ['search', query, '--json'];
|
|
553
|
+
if (options?.limit) {
|
|
554
|
+
args.push('--limit', String(options.limit));
|
|
555
|
+
}
|
|
556
|
+
const output = await execBd(args);
|
|
557
|
+
const issues = parseJson(output);
|
|
558
|
+
return issues
|
|
559
|
+
.filter((issue) => issue.status !== 'tombstone')
|
|
560
|
+
.map((issue) => beadsIssueToProviderNode(issue));
|
|
561
|
+
},
|
|
562
|
+
// =========================================================================
|
|
563
|
+
// RelationshipQueryable Implementation
|
|
564
|
+
// =========================================================================
|
|
565
|
+
async queryEdges(nodeId, options) {
|
|
566
|
+
// Parse URI if full URI is passed
|
|
567
|
+
const parsed = this.parseUri(nodeId);
|
|
568
|
+
const issueId = parsed?.id ?? nodeId;
|
|
569
|
+
try {
|
|
570
|
+
const output = await execBd(['show', issueId, '--json']);
|
|
571
|
+
const issues = parseJson(output);
|
|
572
|
+
if (!issues || issues.length === 0) {
|
|
573
|
+
return [];
|
|
574
|
+
}
|
|
575
|
+
const issue = issues[0];
|
|
576
|
+
// Tombstoned issues have no meaningful edges
|
|
577
|
+
if (issue.status === 'tombstone') {
|
|
578
|
+
return [];
|
|
579
|
+
}
|
|
580
|
+
let edges = [];
|
|
581
|
+
// --- Legacy format: blocks/blockedBy string arrays ---
|
|
582
|
+
if (issue.blocks && Array.isArray(issue.blocks)) {
|
|
583
|
+
for (const blockedId of issue.blocks) {
|
|
584
|
+
edges.push({ from: issueId, to: blockedId, type: 'blocks' });
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (issue.blockedBy && Array.isArray(issue.blockedBy)) {
|
|
588
|
+
for (const blockerId of issue.blockedBy) {
|
|
589
|
+
edges.push({ from: blockerId, to: issueId, type: 'blocks' });
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
// --- bd v0.49+ format from `bd show --json` ---
|
|
593
|
+
// `dependencies` = issues THIS issue depends on (they block this)
|
|
594
|
+
// Each element is a full issue object with an `id` field
|
|
595
|
+
if (issue.dependencies && Array.isArray(issue.dependencies)) {
|
|
596
|
+
for (const dep of issue.dependencies) {
|
|
597
|
+
if (dep.id) {
|
|
598
|
+
// Full object format from `bd show` — dep.id is the blocker
|
|
599
|
+
edges.push({ from: dep.id, to: issueId, type: 'blocks' });
|
|
600
|
+
}
|
|
601
|
+
else if (dep.depends_on_id && dep.issue_id) {
|
|
602
|
+
// Compact format from `bd list` — depends_on_id blocks issue_id
|
|
603
|
+
edges.push({ from: dep.depends_on_id, to: dep.issue_id, type: 'blocks' });
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
// `dependents` = issues that depend on THIS issue (this blocks them)
|
|
608
|
+
if (issue.dependents && Array.isArray(issue.dependents)) {
|
|
609
|
+
for (const dep of issue.dependents) {
|
|
610
|
+
if (dep.id) {
|
|
611
|
+
edges.push({ from: issueId, to: dep.id, type: 'blocks' });
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
// --- Parent/children ---
|
|
616
|
+
if (issue.parent) {
|
|
617
|
+
edges.push({ from: issue.parent, to: issueId, type: 'parent-child' });
|
|
618
|
+
}
|
|
619
|
+
if (issue.children && Array.isArray(issue.children)) {
|
|
620
|
+
for (const childId of issue.children) {
|
|
621
|
+
edges.push({ from: issueId, to: childId, type: 'parent-child' });
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
// Deduplicate edges (multiple formats may report the same relationship)
|
|
625
|
+
const seen = new Set();
|
|
626
|
+
edges = edges.filter((edge) => {
|
|
627
|
+
const key = `${edge.from}:${edge.to}:${edge.type}`;
|
|
628
|
+
if (seen.has(key))
|
|
629
|
+
return false;
|
|
630
|
+
seen.add(key);
|
|
631
|
+
return true;
|
|
632
|
+
});
|
|
633
|
+
// Apply filters if specified
|
|
634
|
+
if (options?.edgeType) {
|
|
635
|
+
edges = filterEdgesByType(edges, options.edgeType);
|
|
636
|
+
}
|
|
637
|
+
if (options?.direction) {
|
|
638
|
+
edges = filterEdgesByDirection(edges, issueId, options.direction);
|
|
639
|
+
}
|
|
640
|
+
if (options?.limit && edges.length > options.limit) {
|
|
641
|
+
edges = edges.slice(0, options.limit);
|
|
642
|
+
}
|
|
643
|
+
return edges;
|
|
644
|
+
}
|
|
645
|
+
catch (error) {
|
|
646
|
+
// Return empty for not found, re-throw other errors
|
|
647
|
+
if (error instanceof ProviderErrorClass && error.code === 'OPERATION_FAILED') {
|
|
648
|
+
const message = error.message.toLowerCase();
|
|
649
|
+
if (message.includes('not found') ||
|
|
650
|
+
message.includes('does not exist') ||
|
|
651
|
+
message.includes('no issue found matching')) {
|
|
652
|
+
return [];
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
throw error;
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
supportedEdgeTypes() {
|
|
659
|
+
return [
|
|
660
|
+
{ type: 'blocks', canQuery: true, canCreate: true, canDelete: true },
|
|
661
|
+
{ type: 'parent-child', canQuery: true, canCreate: true, canDelete: true },
|
|
662
|
+
];
|
|
663
|
+
},
|
|
664
|
+
// =========================================================================
|
|
665
|
+
// Watchable Implementation (only functional when watchPath is configured)
|
|
666
|
+
// =========================================================================
|
|
667
|
+
watchGranularity: {
|
|
668
|
+
// Beads diffs at the node level. We can detect which nodes changed
|
|
669
|
+
// but don't track individual field changes (would require caching
|
|
670
|
+
// full issue objects rather than just hashes).
|
|
671
|
+
reportsChangedFields: false,
|
|
672
|
+
reportsPreviousValues: false,
|
|
673
|
+
// Beads embeds relationships in the node (blocks/blockedBy/parent/children).
|
|
674
|
+
// We extract and diff these separately, so we can emit edge events.
|
|
675
|
+
reportsEdgeChanges: true,
|
|
676
|
+
mechanism: 'file-watch',
|
|
677
|
+
},
|
|
678
|
+
startWatching(callback) {
|
|
679
|
+
if (!watchPath) {
|
|
680
|
+
return; // Watching not configured — silently no-op
|
|
681
|
+
}
|
|
682
|
+
// Replace callback if already watching
|
|
683
|
+
watchCallback = callback;
|
|
684
|
+
if (fileWatcher) {
|
|
685
|
+
return; // Already watching, just updated callback
|
|
686
|
+
}
|
|
687
|
+
// Seed cache before starting watcher so we only emit real changes
|
|
688
|
+
void seedCache().then(() => {
|
|
689
|
+
if (!watchCallback)
|
|
690
|
+
return; // Stopped before seed completed
|
|
691
|
+
fileWatcher = chokidar.watch(watchPath, {
|
|
692
|
+
ignoreInitial: true,
|
|
693
|
+
persistent: true,
|
|
694
|
+
awaitWriteFinish: {
|
|
695
|
+
stabilityThreshold: 100,
|
|
696
|
+
pollInterval: 20,
|
|
697
|
+
},
|
|
698
|
+
});
|
|
699
|
+
fileWatcher.on('add', onFileChange);
|
|
700
|
+
fileWatcher.on('change', onFileChange);
|
|
701
|
+
fileWatcher.on('unlink', onFileChange);
|
|
702
|
+
fileWatcher.on('error', () => {
|
|
703
|
+
// Resilient — continue watching despite transient errors
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
},
|
|
707
|
+
stopWatching() {
|
|
708
|
+
watchCallback = null;
|
|
709
|
+
if (debounceTimer) {
|
|
710
|
+
clearTimeout(debounceTimer);
|
|
711
|
+
debounceTimer = null;
|
|
712
|
+
}
|
|
713
|
+
if (fileWatcher) {
|
|
714
|
+
void fileWatcher.close();
|
|
715
|
+
fileWatcher = null;
|
|
716
|
+
}
|
|
717
|
+
},
|
|
718
|
+
get isWatching() {
|
|
719
|
+
return fileWatcher !== null && watchCallback !== null;
|
|
720
|
+
},
|
|
721
|
+
// =========================================================================
|
|
722
|
+
// TaskManageable Implementation
|
|
723
|
+
// =========================================================================
|
|
724
|
+
taskCapabilities: {
|
|
725
|
+
actions: ['start', 'complete', 'block', 'reopen', 'close'],
|
|
726
|
+
supportsAssignment: true,
|
|
727
|
+
supportsReadyQuery: true,
|
|
728
|
+
statusModel: ['open', 'in_progress', 'blocked', 'closed'],
|
|
729
|
+
},
|
|
730
|
+
async transitionTask(id, action, context) {
|
|
731
|
+
const statusMap = {
|
|
732
|
+
start: 'in_progress',
|
|
733
|
+
complete: 'closed',
|
|
734
|
+
block: 'blocked',
|
|
735
|
+
reopen: 'open',
|
|
736
|
+
close: 'closed',
|
|
737
|
+
};
|
|
738
|
+
const targetStatus = statusMap[action];
|
|
739
|
+
if (!targetStatus) {
|
|
740
|
+
throw new ProviderErrorClass('NOT_SUPPORTED', `Unsupported task action: ${action}`, 'beads');
|
|
741
|
+
}
|
|
742
|
+
const parsed = this.parseUri(id);
|
|
743
|
+
const issueId = parsed?.id ?? id;
|
|
744
|
+
// Validate transition is allowed from current state
|
|
745
|
+
const current = await this.get(issueId, context);
|
|
746
|
+
if (current) {
|
|
747
|
+
const currentStatus = current.status ?? 'open';
|
|
748
|
+
const allowed = validActionsForStatus(currentStatus);
|
|
749
|
+
if (!allowed.includes(action)) {
|
|
750
|
+
throw new ProviderErrorClass('NOT_SUPPORTED', `Cannot ${action} an issue in '${currentStatus}' state. Valid actions: ${allowed.join(', ')}`, 'beads');
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
const output = await execBd(['update', issueId, '--status', targetStatus, '--json'], context);
|
|
754
|
+
const issues = parseJson(output);
|
|
755
|
+
if (!issues || issues.length === 0) {
|
|
756
|
+
throw new ProviderErrorClass('OPERATION_FAILED', 'Transition returned no results', 'beads');
|
|
757
|
+
}
|
|
758
|
+
return beadsIssueToProviderNode(issues[0]);
|
|
759
|
+
},
|
|
760
|
+
async readyTasks(options, context) {
|
|
761
|
+
const output = await execBd(['list', '--json'], context);
|
|
762
|
+
const issues = parseJson(output);
|
|
763
|
+
const readyIssues = [];
|
|
764
|
+
for (const issue of issues) {
|
|
765
|
+
// Skip tombstoned and non-open issues
|
|
766
|
+
if (issue.status === 'tombstone' || issue.status !== 'open')
|
|
767
|
+
continue;
|
|
768
|
+
// Apply tag filter
|
|
769
|
+
if (options?.tags) {
|
|
770
|
+
const issueTags = issue.tags ?? [];
|
|
771
|
+
if (!options.tags.every((t) => issueTags.includes(t)))
|
|
772
|
+
continue;
|
|
773
|
+
}
|
|
774
|
+
// Apply priority filter
|
|
775
|
+
if (options?.priority !== undefined) {
|
|
776
|
+
const normalized = mapPriority(issue.priority);
|
|
777
|
+
if (normalized === undefined || normalized > options.priority)
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
// Apply assignee filter
|
|
781
|
+
if (options?.assignee) {
|
|
782
|
+
if (issue.assignee !== options.assignee)
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
// Check for active blockers
|
|
786
|
+
let hasActiveBlocker = false;
|
|
787
|
+
// Legacy format: blockedBy
|
|
788
|
+
if (issue.blockedBy && issue.blockedBy.length > 0) {
|
|
789
|
+
// Need to check if blockers are still active
|
|
790
|
+
for (const blockerId of issue.blockedBy) {
|
|
791
|
+
try {
|
|
792
|
+
const blockerOutput = await execBd(['show', blockerId, '--json'], context);
|
|
793
|
+
const blockerIssues = parseJson(blockerOutput);
|
|
794
|
+
if (blockerIssues?.[0] &&
|
|
795
|
+
blockerIssues[0].status !== 'closed' &&
|
|
796
|
+
blockerIssues[0].status !== 'tombstone') {
|
|
797
|
+
hasActiveBlocker = true;
|
|
798
|
+
break;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
catch {
|
|
802
|
+
// If we can't resolve the blocker, assume it's active
|
|
803
|
+
hasActiveBlocker = true;
|
|
804
|
+
break;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
// Structured format (bd v0.49+): dependencies
|
|
809
|
+
if (!hasActiveBlocker && issue.dependencies && issue.dependencies.length > 0) {
|
|
810
|
+
for (const dep of issue.dependencies) {
|
|
811
|
+
const depId = dep.id ?? dep.depends_on_id;
|
|
812
|
+
if (!depId)
|
|
813
|
+
continue;
|
|
814
|
+
try {
|
|
815
|
+
const depOutput = await execBd(['show', depId, '--json'], context);
|
|
816
|
+
const depIssues = parseJson(depOutput);
|
|
817
|
+
if (depIssues?.[0] &&
|
|
818
|
+
depIssues[0].status !== 'closed' &&
|
|
819
|
+
depIssues[0].status !== 'tombstone') {
|
|
820
|
+
hasActiveBlocker = true;
|
|
821
|
+
break;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
catch {
|
|
825
|
+
hasActiveBlocker = true;
|
|
826
|
+
break;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
if (!hasActiveBlocker) {
|
|
831
|
+
readyIssues.push(beadsIssueToProviderNode(issue));
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
// Sort by priority (lower number = higher priority)
|
|
835
|
+
readyIssues.sort((a, b) => {
|
|
836
|
+
const aPriority = a.priority ?? Infinity;
|
|
837
|
+
const bPriority = b.priority ?? Infinity;
|
|
838
|
+
return aPriority - bPriority;
|
|
839
|
+
});
|
|
840
|
+
// Apply limit
|
|
841
|
+
if (options?.limit && readyIssues.length > options.limit) {
|
|
842
|
+
return readyIssues.slice(0, options.limit);
|
|
843
|
+
}
|
|
844
|
+
return readyIssues;
|
|
845
|
+
},
|
|
846
|
+
async assignTask(id, assignee, context) {
|
|
847
|
+
const parsed = this.parseUri(id);
|
|
848
|
+
const issueId = parsed?.id ?? id;
|
|
849
|
+
const output = await execBd(['update', issueId, '--assignee', assignee, '--json'], context);
|
|
850
|
+
const issues = parseJson(output);
|
|
851
|
+
if (!issues || issues.length === 0) {
|
|
852
|
+
throw new ProviderErrorClass('OPERATION_FAILED', 'Assign returned no results', 'beads');
|
|
853
|
+
}
|
|
854
|
+
return beadsIssueToProviderNode(issues[0]);
|
|
855
|
+
},
|
|
856
|
+
async validActions(id, context) {
|
|
857
|
+
const node = await this.get(id, context);
|
|
858
|
+
if (!node) {
|
|
859
|
+
throw new ProviderErrorClass('NOT_FOUND', `Issue not found: ${id}`, 'beads');
|
|
860
|
+
}
|
|
861
|
+
return validActionsForStatus(node.status ?? 'open');
|
|
862
|
+
},
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
//# sourceMappingURL=beads.js.map
|