@lsctech/polaris 0.1.0

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.
Files changed (316) hide show
  1. package/README.md +87 -0
  2. package/dist/__mocks__/tool-server-linear.js +34 -0
  3. package/dist/cli/adopt-approve.js +60 -0
  4. package/dist/cli/adopt-cognition.js +199 -0
  5. package/dist/cli/adopt-instructions.js +143 -0
  6. package/dist/cli/adopt-rules.js +169 -0
  7. package/dist/cli/adopt-scan.js +25 -0
  8. package/dist/cli/adopt-smartdocs.js +192 -0
  9. package/dist/cli/adoption-inventory.js +350 -0
  10. package/dist/cli/adoption-plan.js +222 -0
  11. package/dist/cli/args.js +28 -0
  12. package/dist/cli/args.test.js +30 -0
  13. package/dist/cli/branding.js +41 -0
  14. package/dist/cli/graph.js +358 -0
  15. package/dist/cli/index.js +127 -0
  16. package/dist/cli/index.test.js +162 -0
  17. package/dist/cli/init-detect.js +61 -0
  18. package/dist/cli/init.js +492 -0
  19. package/dist/cli/init.test.js +259 -0
  20. package/dist/cli/librarian.js +32 -0
  21. package/dist/cli/medic.js +96 -0
  22. package/dist/cli/startup.test.js +23 -0
  23. package/dist/cli/tracker.js +130 -0
  24. package/dist/cli/tracker.test.js +126 -0
  25. package/dist/cli/version.js +10 -0
  26. package/dist/cli/version.test.js +11 -0
  27. package/dist/cli/worker.js +287 -0
  28. package/dist/cluster-state/fixtures/test-clusters.json +19 -0
  29. package/dist/cluster-state/store.js +302 -0
  30. package/dist/cluster-state/store.test.js +145 -0
  31. package/dist/cluster-state/types.js +2 -0
  32. package/dist/cognition/archive.js +158 -0
  33. package/dist/cognition/closeout-librarian-types.js +161 -0
  34. package/dist/cognition/cognition.test.js +623 -0
  35. package/dist/cognition/index.js +41 -0
  36. package/dist/cognition/librarian-dispatch.js +391 -0
  37. package/dist/cognition/librarian-dispatch.test.js +247 -0
  38. package/dist/cognition/librarian-packet.js +313 -0
  39. package/dist/cognition/librarian-types.js +57 -0
  40. package/dist/cognition/route-cognition-delta.js +350 -0
  41. package/dist/cognition/summary-delta.js +279 -0
  42. package/dist/cognition/validate.js +162 -0
  43. package/dist/config/defaults.js +98 -0
  44. package/dist/config/doctor.js +273 -0
  45. package/dist/config/index.js +14 -0
  46. package/dist/config/loader.js +58 -0
  47. package/dist/config/provider-detect.js +60 -0
  48. package/dist/config/provider-detect.test.js +119 -0
  49. package/dist/config/schema.js +2 -0
  50. package/dist/config/show.js +44 -0
  51. package/dist/config/show.test.js +42 -0
  52. package/dist/config/validator.js +675 -0
  53. package/dist/config/validator.test.js +77 -0
  54. package/dist/docs/canon-check.js +334 -0
  55. package/dist/docs/canon-check.test.js +207 -0
  56. package/dist/docs/doctrine.js +133 -0
  57. package/dist/docs/doctrine.test.js +139 -0
  58. package/dist/docs/index.js +168 -0
  59. package/dist/docs/index.test.js +83 -0
  60. package/dist/docs/ingest.js +295 -0
  61. package/dist/docs/ingest.test.js +71 -0
  62. package/dist/docs/migrate.js +165 -0
  63. package/dist/docs/migrate.test.js +136 -0
  64. package/dist/docs/seed-instructions.js +147 -0
  65. package/dist/docs/seed-instructions.test.js +137 -0
  66. package/dist/docs/validate-instructions.js +267 -0
  67. package/dist/docs/validate-instructions.test.js +238 -0
  68. package/dist/finalize/artifact-policy.js +214 -0
  69. package/dist/finalize/artifact-policy.test.js +84 -0
  70. package/dist/finalize/delivery-integrity.js +141 -0
  71. package/dist/finalize/finalize.test.js +210 -0
  72. package/dist/finalize/github.js +41 -0
  73. package/dist/finalize/index.js +474 -0
  74. package/dist/finalize/linear.js +213 -0
  75. package/dist/finalize/run-report.js +47 -0
  76. package/dist/finalize/steps/01-map-update.js +11 -0
  77. package/dist/finalize/steps/02-map-validate.js +11 -0
  78. package/dist/finalize/steps/03-schema-validate.js +11 -0
  79. package/dist/finalize/steps/04-run-checks.js +118 -0
  80. package/dist/finalize/steps/05-generate-report.js +14 -0
  81. package/dist/finalize/steps/06-commit.js +39 -0
  82. package/dist/finalize/steps/07-push.js +10 -0
  83. package/dist/finalize/steps/08-create-pr.js +9 -0
  84. package/dist/finalize/steps/09-update-state.js +9 -0
  85. package/dist/finalize/steps/10-append-jsonl.js +23 -0
  86. package/dist/finalize/steps/11-update-linear.js +22 -0
  87. package/dist/finalize/steps/12-archive.js +21 -0
  88. package/dist/graph/adapter/c/adapter.js +45 -0
  89. package/dist/graph/adapter/c/extract.js +135 -0
  90. package/dist/graph/adapter/c/index.js +10 -0
  91. package/dist/graph/adapter/c/runtime.js +67 -0
  92. package/dist/graph/adapter/cpp/adapter.js +45 -0
  93. package/dist/graph/adapter/cpp/extract.js +159 -0
  94. package/dist/graph/adapter/cpp/index.js +10 -0
  95. package/dist/graph/adapter/cpp/runtime.js +61 -0
  96. package/dist/graph/adapter/csharp/adapter.js +45 -0
  97. package/dist/graph/adapter/csharp/extract.js +127 -0
  98. package/dist/graph/adapter/csharp/index.js +10 -0
  99. package/dist/graph/adapter/csharp/runtime.js +61 -0
  100. package/dist/graph/adapter/dart/adapter.js +56 -0
  101. package/dist/graph/adapter/dart/extract.js +130 -0
  102. package/dist/graph/adapter/dart/index.js +10 -0
  103. package/dist/graph/adapter/dart/runtime.js +61 -0
  104. package/dist/graph/adapter/go/adapter.js +45 -0
  105. package/dist/graph/adapter/go/extract.js +112 -0
  106. package/dist/graph/adapter/go/index.js +10 -0
  107. package/dist/graph/adapter/go/runtime.js +58 -0
  108. package/dist/graph/adapter/kotlin-java/extract-common.js +83 -0
  109. package/dist/graph/adapter/kotlin-java/index.js +15 -0
  110. package/dist/graph/adapter/kotlin-java/java-adapter.js +45 -0
  111. package/dist/graph/adapter/kotlin-java/java-extract.js +42 -0
  112. package/dist/graph/adapter/kotlin-java/kotlin-adapter.js +48 -0
  113. package/dist/graph/adapter/kotlin-java/kotlin-extract.js +58 -0
  114. package/dist/graph/adapter/kotlin-java/runtime.js +75 -0
  115. package/dist/graph/adapter/python/adapter.js +45 -0
  116. package/dist/graph/adapter/python/extract.js +121 -0
  117. package/dist/graph/adapter/python/index.js +10 -0
  118. package/dist/graph/adapter/python/runtime.js +70 -0
  119. package/dist/graph/adapter/registry.js +82 -0
  120. package/dist/graph/adapter/rust/adapter.js +45 -0
  121. package/dist/graph/adapter/rust/extract.js +110 -0
  122. package/dist/graph/adapter/rust/index.js +10 -0
  123. package/dist/graph/adapter/rust/runtime.js +74 -0
  124. package/dist/graph/adapter/shell/adapter.js +34 -0
  125. package/dist/graph/adapter/shell/extract.js +98 -0
  126. package/dist/graph/adapter/shell/index.js +8 -0
  127. package/dist/graph/adapter/svelte/adapter.js +91 -0
  128. package/dist/graph/adapter/svelte/extract.js +41 -0
  129. package/dist/graph/adapter/svelte/index.js +8 -0
  130. package/dist/graph/adapter/swift/adapter.js +45 -0
  131. package/dist/graph/adapter/swift/extract.js +120 -0
  132. package/dist/graph/adapter/swift/index.js +10 -0
  133. package/dist/graph/adapter/swift/runtime.js +70 -0
  134. package/dist/graph/adapter/types.js +2 -0
  135. package/dist/graph/adapter/typescript-javascript/adapter.js +72 -0
  136. package/dist/graph/adapter/typescript-javascript/extract.js +115 -0
  137. package/dist/graph/adapter/typescript-javascript/index.js +10 -0
  138. package/dist/graph/adapter/typescript-javascript/runtime.js +97 -0
  139. package/dist/graph/capability/index.js +105 -0
  140. package/dist/graph/governance.js +104 -0
  141. package/dist/graph/parser/extract.js +5 -0
  142. package/dist/graph/parser/loader.js +2 -0
  143. package/dist/graph/parser/pipeline.js +194 -0
  144. package/dist/graph/query/index.js +277 -0
  145. package/dist/graph/query/types.js +5 -0
  146. package/dist/graph/resolver/build-edges.js +211 -0
  147. package/dist/graph/resolver/index.js +23 -0
  148. package/dist/graph/resolver/resolve-imports.js +168 -0
  149. package/dist/graph/store/adapter.js +132 -0
  150. package/dist/graph/store/queries.js +124 -0
  151. package/dist/graph/store/types.js +4 -0
  152. package/dist/ignore/defaults.js +41 -0
  153. package/dist/ignore/parser.js +39 -0
  154. package/dist/lint/map-reference-validator.js +72 -0
  155. package/dist/loop/abort.js +188 -0
  156. package/dist/loop/abort.test.js +151 -0
  157. package/dist/loop/adapters/__tests__/terminal-cli.test.js +92 -0
  158. package/dist/loop/adapters/agent-subtask.js +137 -0
  159. package/dist/loop/adapters/agent-subtask.test.js +151 -0
  160. package/dist/loop/adapters/cli-subtask-bridge.js +108 -0
  161. package/dist/loop/adapters/index.js +9 -0
  162. package/dist/loop/adapters/registry.js +17 -0
  163. package/dist/loop/adapters/terminal-cli.js +403 -0
  164. package/dist/loop/adapters/types.js +2 -0
  165. package/dist/loop/adapters/worker-instructions.js +85 -0
  166. package/dist/loop/body-parser.js +226 -0
  167. package/dist/loop/bootstrap-packet.js +97 -0
  168. package/dist/loop/bootstrap-packet.test.js +171 -0
  169. package/dist/loop/branch-governance.js +54 -0
  170. package/dist/loop/budget.js +63 -0
  171. package/dist/loop/budget.test.js +163 -0
  172. package/dist/loop/checkpoint.js +325 -0
  173. package/dist/loop/compact-return.js +59 -0
  174. package/dist/loop/continue.js +645 -0
  175. package/dist/loop/continue.test.js +337 -0
  176. package/dist/loop/dispatch-boundary.js +335 -0
  177. package/dist/loop/dispatch-state.js +223 -0
  178. package/dist/loop/dispatch-state.test.js +186 -0
  179. package/dist/loop/dispatch.js +1236 -0
  180. package/dist/loop/dispatch.test.js +499 -0
  181. package/dist/loop/ephemeral-smoke.test.js +160 -0
  182. package/dist/loop/evidence-backfill.js +216 -0
  183. package/dist/loop/execution-adapter.js +141 -0
  184. package/dist/loop/execution-adapter.test.js +66 -0
  185. package/dist/loop/finalize-evidence.js +169 -0
  186. package/dist/loop/git-custody.js +250 -0
  187. package/dist/loop/impl-packet-input.js +38 -0
  188. package/dist/loop/index.js +270 -0
  189. package/dist/loop/ledger.js +49 -0
  190. package/dist/loop/ledger.test.js +127 -0
  191. package/dist/loop/lifecycle-dispatch.js +348 -0
  192. package/dist/loop/lifecycle-dispatch.test.js +318 -0
  193. package/dist/loop/lifecycle.js +93 -0
  194. package/dist/loop/lifecycle.test.js +150 -0
  195. package/dist/loop/orphan-recovery.js +276 -0
  196. package/dist/loop/orphan-recovery.test.js +236 -0
  197. package/dist/loop/parent.js +1566 -0
  198. package/dist/loop/parent.test.js +738 -0
  199. package/dist/loop/provider-sealed-packet.test.js +164 -0
  200. package/dist/loop/resume.js +295 -0
  201. package/dist/loop/resume.test.js +172 -0
  202. package/dist/loop/run-bootstrap.js +234 -0
  203. package/dist/loop/run-preflight.js +203 -0
  204. package/dist/loop/status.js +665 -0
  205. package/dist/loop/status.test.js +235 -0
  206. package/dist/loop/wait.js +86 -0
  207. package/dist/loop/worker-packet.js +406 -0
  208. package/dist/loop/worker-packet.test.js +243 -0
  209. package/dist/loop/worker-prompt.js +260 -0
  210. package/dist/loop/worker-prompt.test.js +247 -0
  211. package/dist/loop/worker.js +498 -0
  212. package/dist/loop/worker.test.js +372 -0
  213. package/dist/map/atlas.js +77 -0
  214. package/dist/map/backfill.js +171 -0
  215. package/dist/map/backfill.test.js +120 -0
  216. package/dist/map/index.js +255 -0
  217. package/dist/map/inference.js +73 -0
  218. package/dist/map/inference.test.js +35 -0
  219. package/dist/map/query.js +157 -0
  220. package/dist/map/query.test.js +174 -0
  221. package/dist/map/update.js +355 -0
  222. package/dist/map/update.test.js +67 -0
  223. package/dist/map/validate.js +153 -0
  224. package/dist/map/validate.test.js +90 -0
  225. package/dist/map/welfare.js +86 -0
  226. package/dist/mcp/lib/invoke.js +35 -0
  227. package/dist/mcp/lib/redact.js +24 -0
  228. package/dist/mcp/lib/redact.test.js +112 -0
  229. package/dist/mcp/lib/root.js +41 -0
  230. package/dist/mcp/lib/root.test.js +114 -0
  231. package/dist/mcp/server.js +15 -0
  232. package/dist/mcp/tools/claim-child.js +119 -0
  233. package/dist/mcp/tools/claim-child.test.js +69 -0
  234. package/dist/mcp/tools/current-state.js +73 -0
  235. package/dist/mcp/tools/current-state.test.js +114 -0
  236. package/dist/mcp/tools/dispatch-result.js +186 -0
  237. package/dist/mcp/tools/dispatch-result.test.js +109 -0
  238. package/dist/mcp/tools/index.js +222 -0
  239. package/dist/mcp/tools/index.test.js +172 -0
  240. package/dist/mcp/tools/linear.js +74 -0
  241. package/dist/mcp/tools/loop-continue.js +159 -0
  242. package/dist/mcp/tools/loop-continue.test.js +186 -0
  243. package/dist/mcp/tools/loop-dry-run.js +15 -0
  244. package/dist/mcp/tools/status.js +65 -0
  245. package/dist/medic/chart-id.js +75 -0
  246. package/dist/medic/chart-schema.js +139 -0
  247. package/dist/runs/index.js +119 -0
  248. package/dist/runs/index.test.js +184 -0
  249. package/dist/runs/ledger-tail.js +15 -0
  250. package/dist/runs/list.js +29 -0
  251. package/dist/runs/reconcile.js +74 -0
  252. package/dist/runs/show.js +10 -0
  253. package/dist/runtime/audit/logger.js +15 -0
  254. package/dist/runtime/audit/reader.js +42 -0
  255. package/dist/runtime/checkpoint.js +89 -0
  256. package/dist/runtime/continuation/confirmed.js +225 -0
  257. package/dist/runtime/continuation/confirmed.test.js +421 -0
  258. package/dist/runtime/continuation/dry-run.js +74 -0
  259. package/dist/runtime/execution-window.js +106 -0
  260. package/dist/runtime/scheduling/child-selector.js +16 -0
  261. package/dist/runtime/state.js +43 -0
  262. package/dist/runtime/status.js +46 -0
  263. package/dist/runtime/verification/envelope.js +80 -0
  264. package/dist/runtime/verification/fingerprint.js +26 -0
  265. package/dist/skill-packet/cli.test.js +105 -0
  266. package/dist/skill-packet/generator.js +225 -0
  267. package/dist/skill-packet/generator.test.js +159 -0
  268. package/dist/skill-packet/index.js +49 -0
  269. package/dist/skill-packet/types.js +2 -0
  270. package/dist/smartdocs-engine/audit.js +194 -0
  271. package/dist/smartdocs-engine/audit.test.js +122 -0
  272. package/dist/smartdocs-engine/canon-check.js +340 -0
  273. package/dist/smartdocs-engine/canon-check.test.js +234 -0
  274. package/dist/smartdocs-engine/doctrine.js +633 -0
  275. package/dist/smartdocs-engine/doctrine.test.js +374 -0
  276. package/dist/smartdocs-engine/index.js +456 -0
  277. package/dist/smartdocs-engine/index.test.js +82 -0
  278. package/dist/smartdocs-engine/ingest.js +495 -0
  279. package/dist/smartdocs-engine/ingest.test.js +163 -0
  280. package/dist/smartdocs-engine/migrate.js +217 -0
  281. package/dist/smartdocs-engine/migrate.test.js +200 -0
  282. package/dist/smartdocs-engine/seed-instructions.js +335 -0
  283. package/dist/smartdocs-engine/seed-instructions.test.js +275 -0
  284. package/dist/smartdocs-engine/smartdoc-ignore.js +258 -0
  285. package/dist/smartdocs-engine/smartdoc-ignore.test.js +146 -0
  286. package/dist/smartdocs-engine/validate-instructions.js +366 -0
  287. package/dist/smartdocs-engine/validate-instructions.test.js +283 -0
  288. package/dist/tracker/adapters/github/index.js +305 -0
  289. package/dist/tracker/adapters/jira/index.js +293 -0
  290. package/dist/tracker/adapters/linear/http-errors.test.js +51 -0
  291. package/dist/tracker/adapters/linear/index.js +621 -0
  292. package/dist/tracker/adapters/linear/index.test.js +238 -0
  293. package/dist/tracker/adapters/linear.js +50 -0
  294. package/dist/tracker/adapters/local/index.js +10 -0
  295. package/dist/tracker/adapters/local-file/index.js +159 -0
  296. package/dist/tracker/adapters/mcp-bridge.js +158 -0
  297. package/dist/tracker/adapters/mcp-bridge.test.js +12 -0
  298. package/dist/tracker/adapters/spec/index.js +146 -0
  299. package/dist/tracker/capabilities.js +2 -0
  300. package/dist/tracker/index.js +49 -0
  301. package/dist/tracker/lifecycle-policy.js +139 -0
  302. package/dist/tracker/lifecycle-transition.js +164 -0
  303. package/dist/tracker/local-graph.js +98 -0
  304. package/dist/tracker/migration.js +56 -0
  305. package/dist/tracker/schema.js +86 -0
  306. package/dist/tracker/sync/index.js +404 -0
  307. package/dist/tracker/sync/queue-store.js +95 -0
  308. package/dist/tracker/sync/queue-store.test.js +104 -0
  309. package/dist/tracker/types.js +11 -0
  310. package/dist/types/linear.js +3 -0
  311. package/dist/types/result-packet.js +12 -0
  312. package/dist/types/runtime-state.js +2 -0
  313. package/dist/types/work-contract.js +2 -0
  314. package/dist/utils/monotonic-timestamp.js +13 -0
  315. package/dist/utils/monotonic-timestamp.test.js +19 -0
  316. package/package.json +64 -0
@@ -0,0 +1,238 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const index_js_1 = require("./index.js");
5
+ const local_graph_js_1 = require("../../local-graph.js");
6
+ (0, vitest_1.describe)("LinearAdapter", () => {
7
+ let config;
8
+ let linearClient;
9
+ (0, vitest_1.beforeEach)(() => {
10
+ config = {
11
+ tracker: {
12
+ linear: {
13
+ enabled: true,
14
+ teamId: "mock-team-id",
15
+ projectId: "mock-project-id",
16
+ },
17
+ },
18
+ };
19
+ linearClient = {
20
+ listTeams: vitest_1.vi.fn(),
21
+ listProjects: vitest_1.vi.fn(),
22
+ listIssues: vitest_1.vi.fn(),
23
+ getIssueById: vitest_1.vi.fn(),
24
+ };
25
+ linearClient.listTeams.mockResolvedValue([
26
+ { id: "mock-team-id", name: "Mock Team" },
27
+ ]);
28
+ linearClient.listProjects.mockResolvedValue([
29
+ { id: "mock-project-id", name: "Mock Project" },
30
+ ]);
31
+ linearClient.listIssues.mockResolvedValue([
32
+ {
33
+ id: "issue-1",
34
+ title: "Test Issue 1",
35
+ state: { id: "status-id-1", name: "Todo" },
36
+ relations: {
37
+ nodes: [
38
+ {
39
+ id: "rel-1",
40
+ type: "blocks",
41
+ issue: { id: "issue-2" },
42
+ relatedIssue: { id: "issue-1" },
43
+ },
44
+ ],
45
+ },
46
+ inverseRelations: { nodes: [] },
47
+ children: { nodes: [] },
48
+ },
49
+ {
50
+ id: "issue-2",
51
+ title: "Test Issue 2",
52
+ state: { id: "status-id-2", name: "In Progress" },
53
+ relations: { nodes: [] },
54
+ inverseRelations: { nodes: [] },
55
+ children: { nodes: [] },
56
+ },
57
+ ]);
58
+ linearClient.getIssueById.mockResolvedValueOnce({
59
+ id: "root-issue-id",
60
+ identifier: "POL-198",
61
+ title: "Root issue",
62
+ state: { id: "status-id-3", name: "Todo" },
63
+ relations: {
64
+ nodes: [
65
+ {
66
+ id: "rel-2",
67
+ type: "blocked_by",
68
+ issue: { id: "root-issue-id", identifier: "POL-198", title: "Root issue" },
69
+ relatedIssue: { id: "blocker-id", identifier: "POL-42", title: "Blocking issue" },
70
+ },
71
+ {
72
+ id: "rel-3",
73
+ type: "blocks",
74
+ issue: { id: "root-issue-id", identifier: "POL-198", title: "Root issue" },
75
+ relatedIssue: { id: "blocked-id", identifier: "POL-199", title: "Blocked issue" },
76
+ },
77
+ ],
78
+ },
79
+ inverseRelations: { nodes: [] },
80
+ children: { nodes: [{ id: "child-issue-id", identifier: "POL-200", title: "Child issue" }] },
81
+ });
82
+ linearClient.getIssueById.mockResolvedValue({
83
+ id: "child-issue-id",
84
+ identifier: "POL-200",
85
+ title: "Child issue",
86
+ state: { id: "status-id-4", name: "In Progress" },
87
+ relations: { nodes: [] },
88
+ inverseRelations: { nodes: [] },
89
+ children: { nodes: [] },
90
+ });
91
+ });
92
+ (0, vitest_1.afterEach)(() => {
93
+ vitest_1.vi.clearAllMocks();
94
+ });
95
+ (0, vitest_1.it)("throws when LINEAR_API_KEY is missing for direct Linear API usage", async () => {
96
+ const originalApiKey = process.env["LINEAR_API_KEY"];
97
+ delete process.env["LINEAR_API_KEY"];
98
+ config.tracker.linear.teamId = "mock-team-id";
99
+ try {
100
+ const adapter = new index_js_1.LinearAdapter(config);
101
+ await (0, vitest_1.expect)(adapter.syncIn()).rejects.toThrow("LINEAR_API_KEY is required for the 'linear' tracker adapter.");
102
+ }
103
+ finally {
104
+ if (originalApiKey === undefined) {
105
+ delete process.env["LINEAR_API_KEY"];
106
+ }
107
+ else {
108
+ process.env["LINEAR_API_KEY"] = originalApiKey;
109
+ }
110
+ }
111
+ });
112
+ (0, vitest_1.it)("should return a LocalGraph instance", async () => {
113
+ const adapter = new index_js_1.LinearAdapter(config, linearClient);
114
+ const graph = await adapter.syncIn();
115
+ (0, vitest_1.expect)(graph).toBeInstanceOf(local_graph_js_1.LocalGraph);
116
+ });
117
+ (0, vitest_1.it)("should correctly map Linear issues to ExecutionGraphV2 nodes", async () => {
118
+ const adapter = new index_js_1.LinearAdapter(config, linearClient);
119
+ const graph = await adapter.syncIn();
120
+ const fullGraph = graph.fullGraph;
121
+ (0, vitest_1.expect)(fullGraph.nodes["issue-1"]).toEqual({
122
+ id: "issue-1",
123
+ title: "Test Issue 1",
124
+ status: "Todo",
125
+ });
126
+ (0, vitest_1.expect)(fullGraph.nodes["issue-2"]).toEqual({
127
+ id: "issue-2",
128
+ title: "Test Issue 2",
129
+ status: "In Progress",
130
+ });
131
+ });
132
+ (0, vitest_1.it)("should correctly map Linear issue dependencies", async () => {
133
+ const adapter = new index_js_1.LinearAdapter(config, linearClient);
134
+ const graph = await adapter.syncIn();
135
+ const fullGraph = graph.fullGraph;
136
+ (0, vitest_1.expect)(fullGraph.dependencies["issue-1"]).toEqual(["issue-2"]);
137
+ (0, vitest_1.expect)(fullGraph.dependencies["issue-2"]).toBeUndefined();
138
+ });
139
+ (0, vitest_1.it)("should create a cluster based on project and team IDs", async () => {
140
+ const adapter = new index_js_1.LinearAdapter(config, linearClient);
141
+ const graph = await adapter.syncIn();
142
+ const fullGraph = graph.fullGraph;
143
+ const expectedClusterId = "Mock Team-mock-project-id";
144
+ (0, vitest_1.expect)(fullGraph.activeCluster).toBe(expectedClusterId);
145
+ (0, vitest_1.expect)(fullGraph.clusters[expectedClusterId]).toEqual({
146
+ id: expectedClusterId,
147
+ title: "Linear Project: mock-project-id (Mock Team)",
148
+ children: ["issue-1", "issue-2"],
149
+ });
150
+ });
151
+ (0, vitest_1.it)("should throw an error if teamId is not found", async () => {
152
+ config.tracker.linear.teamId = "non-existent-team";
153
+ linearClient.listTeams.mockResolvedValueOnce([
154
+ { id: "another-team-id", name: "Another Team" },
155
+ ]);
156
+ const adapter = new index_js_1.LinearAdapter(config, linearClient);
157
+ await (0, vitest_1.expect)(adapter.syncIn()).rejects.toThrow("Linear team with ID or name 'non-existent-team' not found.");
158
+ });
159
+ (0, vitest_1.it)("should throw an error if projectId is not found in team", async () => {
160
+ config.tracker.linear.projectId = "non-existent-project";
161
+ linearClient.listProjects.mockResolvedValueOnce([
162
+ { id: "another-project-id", name: "Another Project" },
163
+ ]);
164
+ const adapter = new index_js_1.LinearAdapter(config, linearClient);
165
+ await (0, vitest_1.expect)(adapter.syncIn()).rejects.toThrow("Linear project with ID or name 'non-existent-project' not found in team 'Mock Team'.");
166
+ });
167
+ (0, vitest_1.it)("should warn and fetch all issues if no teamId is specified", async () => {
168
+ config.tracker.linear.teamId = undefined;
169
+ const consoleWarnSpy = vitest_1.vi.spyOn(console, 'warn').mockImplementation(() => { });
170
+ linearClient.listIssues.mockResolvedValueOnce([
171
+ {
172
+ id: "issue-3",
173
+ title: "Global Issue",
174
+ state: { id: "status-id-3", name: "Todo" },
175
+ relations: { nodes: [] },
176
+ inverseRelations: { nodes: [] },
177
+ children: { nodes: [] },
178
+ },
179
+ ]);
180
+ const adapter = new index_js_1.LinearAdapter(config, linearClient);
181
+ const graph = await adapter.syncIn();
182
+ const fullGraph = graph.fullGraph;
183
+ (0, vitest_1.expect)(consoleWarnSpy).toHaveBeenCalledWith("No Linear teamId specified in config. Fetching all accessible Linear issues. Consider specifying 'teamId' for better scope.");
184
+ (0, vitest_1.expect)(fullGraph.nodes["issue-3"]).toBeDefined();
185
+ (0, vitest_1.expect)(fullGraph.activeCluster).toBe("default");
186
+ (0, vitest_1.expect)(fullGraph.clusters["default"].title).toBe("All Linear Issues");
187
+ consoleWarnSpy.mockRestore();
188
+ });
189
+ (0, vitest_1.it)("syncs by Linear issue identifier including children and dependency relations", async () => {
190
+ const adapter = new index_js_1.LinearAdapter(config, linearClient);
191
+ const graph = await adapter.syncIn("POL-198");
192
+ const fullGraph = graph.fullGraph;
193
+ (0, vitest_1.expect)(linearClient.getIssueById).toHaveBeenCalledWith("POL-198");
194
+ (0, vitest_1.expect)(linearClient.getIssueById).toHaveBeenCalledWith("child-issue-id");
195
+ (0, vitest_1.expect)(fullGraph.activeCluster).toBe("POL-198");
196
+ (0, vitest_1.expect)(fullGraph.clusters["POL-198"].children.slice().sort()).toEqual(["POL-198", "POL-199", "POL-200", "POL-42"].sort());
197
+ (0, vitest_1.expect)(fullGraph.nodes["POL-198"]).toEqual({
198
+ id: "POL-198",
199
+ title: "Root issue",
200
+ status: "Todo",
201
+ });
202
+ (0, vitest_1.expect)(fullGraph.nodes["POL-200"]).toEqual({
203
+ id: "POL-200",
204
+ title: "Child issue",
205
+ status: "In Progress",
206
+ });
207
+ (0, vitest_1.expect)(fullGraph.dependencies["POL-198"]).toEqual(["POL-42"]);
208
+ (0, vitest_1.expect)(fullGraph.dependencies["POL-199"]).toEqual(["POL-198"]);
209
+ });
210
+ (0, vitest_1.it)("ignores unknown relation types safely", async () => {
211
+ const consoleWarnSpy = vitest_1.vi.spyOn(console, "warn").mockImplementation(() => { });
212
+ linearClient.listIssues.mockResolvedValueOnce([
213
+ {
214
+ id: "issue-unknown-rel",
215
+ title: "Issue with unknown relation",
216
+ state: { id: "status-id-1", name: "Todo" },
217
+ relations: {
218
+ nodes: [
219
+ {
220
+ id: "rel-unknown",
221
+ type: "related",
222
+ issue: { id: "issue-unknown-rel" },
223
+ relatedIssue: { id: "issue-other" },
224
+ },
225
+ ],
226
+ },
227
+ inverseRelations: { nodes: [] },
228
+ children: { nodes: [] },
229
+ },
230
+ ]);
231
+ const adapter = new index_js_1.LinearAdapter(config, linearClient);
232
+ const graph = await adapter.syncIn();
233
+ const fullGraph = graph.fullGraph;
234
+ (0, vitest_1.expect)(fullGraph.dependencies["issue-unknown-rel"]).toBeUndefined();
235
+ (0, vitest_1.expect)(consoleWarnSpy).toHaveBeenCalledWith("Linear relation type 'related' is not mapped to dependencies (supported types: blocks, blocked_by, depends_on); ignoring.");
236
+ consoleWarnSpy.mockRestore();
237
+ });
238
+ });
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LinearAdapter = void 0;
4
+ /**
5
+ * Placeholder Linear Adapter for demonstration and testing purposes.
6
+ * This adapter simulates interactions with Linear.
7
+ */
8
+ class LinearAdapter {
9
+ /**
10
+ * Simulates fetching data from Linear.
11
+ * @param input - The sync input parameters.
12
+ * @returns A promise resolving to mock data.
13
+ */
14
+ async fetchData(input) {
15
+ console.log(`LinearAdapter: Simulating fetchData for trackerId: ${input.trackerId}`);
16
+ // Return some mock data for demonstration
17
+ return [
18
+ { id: 'LIN-1', title: 'Mock Issue 1', description: 'This is a mock issue.' },
19
+ { id: 'LIN-2', title: 'Mock Issue 2', description: 'Another mock issue.' },
20
+ ];
21
+ }
22
+ /**
23
+ * Simulates applying a mutation to Linear.
24
+ * @param mutation - The mutation record to apply.
25
+ * @returns A promise resolving to the updated mutation record.
26
+ */
27
+ async applyMutation(mutation) {
28
+ console.log(`LinearAdapter: Simulating applyMutation for mutation ID: ${mutation.id}`);
29
+ // Simulate success
30
+ return { ...mutation, status: 'succeeded', remoteId: `remote-${mutation.entityId}` };
31
+ }
32
+ /**
33
+ * Simulates conflict detection. Always returns false for now.
34
+ * @returns Always returns false.
35
+ */
36
+ detectConflict(localEntity, remoteEntity) {
37
+ console.log('LinearAdapter: Simulating conflict detection (always false)');
38
+ return false; // No conflicts for now
39
+ }
40
+ /**
41
+ * Simulates remote fingerprint generation.
42
+ * @param entity - The entity to generate a fingerprint for.
43
+ * @returns A simple mock fingerprint string.
44
+ */
45
+ generateRemoteFingerprint(entity) {
46
+ console.log('LinearAdapter: Simulating remote fingerprint generation');
47
+ return `mock-fingerprint-${entity.id || 'unknown'}`;
48
+ }
49
+ }
50
+ exports.LinearAdapter = LinearAdapter;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LocalAdapter = void 0;
4
+ const local_graph_js_1 = require("../../local-graph.js");
5
+ class LocalAdapter {
6
+ async syncIn(clusterId, repoRoot = process.cwd()) {
7
+ return local_graph_js_1.LocalGraph.load(clusterId, repoRoot);
8
+ }
9
+ }
10
+ exports.LocalAdapter = LocalAdapter;
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LocalFileAdapter = void 0;
4
+ /**
5
+ * Local-file tracker adapter for file-backed task management.
6
+ *
7
+ * This adapter provides a stable file-backed task model using the LocalGraph
8
+ * execution graph as its backing store. It supports read operations and
9
+ * limited mutation capabilities appropriate for local development workflows.
10
+ */
11
+ class LocalFileAdapter {
12
+ /**
13
+ * Returns the capabilities supported by the local-file adapter.
14
+ */
15
+ getCapabilities() {
16
+ return {
17
+ supportsChildRelationships: true,
18
+ supportsStatusUpdates: true,
19
+ supportsComments: false, // Comments would require file format changes
20
+ supportsLinks: false, // Links would require file format changes
21
+ supportsDependencies: true,
22
+ supportsLifecycleMapping: true,
23
+ supportsCreateChild: true, // Via graph mutation
24
+ };
25
+ }
26
+ /**
27
+ * Maps a local-file status to a normalized lifecycle state.
28
+ *
29
+ * The local-file adapter uses the same normalized lifecycle states as
30
+ * Polaris config, so mapping is straightforward.
31
+ *
32
+ * @param nativeStatus - The native status string from the local graph.
33
+ * @returns A status mapping result with the normalized state and support status.
34
+ */
35
+ mapNativeStatus(nativeStatus) {
36
+ const normalizedStatus = nativeStatus.toLowerCase().trim();
37
+ // Local-file uses the same normalized lifecycle states
38
+ const validStates = [
39
+ "backlog",
40
+ "in_progress",
41
+ "in_review",
42
+ "done",
43
+ "blocked",
44
+ "cancelled",
45
+ "no_status_change",
46
+ ];
47
+ if (validStates.includes(normalizedStatus)) {
48
+ return {
49
+ lifecycleState: normalizedStatus,
50
+ supported: true,
51
+ };
52
+ }
53
+ return {
54
+ lifecycleState: "no_status_change",
55
+ supported: false,
56
+ reason: `Unknown local-file status '${nativeStatus}'. Valid states are: ${validStates.join(", ")}`,
57
+ };
58
+ }
59
+ /**
60
+ * Attempts to transition a local-file task to a lifecycle state.
61
+ *
62
+ * This would update the task's status in the LocalGraph. For now,
63
+ * this is a placeholder that returns skip results.
64
+ *
65
+ * @param taskId - The task ID in the local graph.
66
+ * @param lifecycleState - The target normalized lifecycle state.
67
+ * @param evidence - Optional evidence for the transition (e.g., commit hash).
68
+ * @returns A lifecycle transition result indicating success, skip, or failure.
69
+ */
70
+ async transitionLifecycleState(taskId, lifecycleState, evidence) {
71
+ if (lifecycleState === "no_status_change") {
72
+ return {
73
+ applied: false,
74
+ skipped: true,
75
+ skipReason: "Lifecycle state is 'no_status_change', skipping transition",
76
+ };
77
+ }
78
+ // Placeholder implementation - would update LocalGraph node status
79
+ console.warn(`LocalFileAdapter: transitionLifecycleState not fully implemented. Would transition ${taskId} to ${lifecycleState}.`);
80
+ return {
81
+ applied: false,
82
+ skipped: true,
83
+ skipReason: "Lifecycle state transitions are not yet implemented for local-file adapter",
84
+ };
85
+ }
86
+ /**
87
+ * Adds a comment to a local-file task.
88
+ *
89
+ * Comments are not currently supported by the local-file format.
90
+ *
91
+ * @param taskId - The task ID in the local graph.
92
+ * @param body - The comment body text.
93
+ * @returns A comment result indicating success, skip, or failure.
94
+ */
95
+ async addComment(taskId, body) {
96
+ return {
97
+ added: false,
98
+ unsupported: true,
99
+ reason: "Local-file adapter does not support comments. The file format does not include comment storage.",
100
+ };
101
+ }
102
+ /**
103
+ * Attaches a link to a local-file task.
104
+ *
105
+ * Links are not currently supported by the local-file format.
106
+ *
107
+ * @param taskId - The task ID in the local graph.
108
+ * @param url - The URL to attach.
109
+ * @param title - Optional title for the link.
110
+ * @returns A link result indicating success, skip, or failure.
111
+ */
112
+ async attachLink(taskId, url, title) {
113
+ return {
114
+ attached: false,
115
+ unsupported: true,
116
+ reason: "Local-file adapter does not support link attachments. The file format does not include link storage.",
117
+ };
118
+ }
119
+ /**
120
+ * Adds a dependency relation between local-file tasks.
121
+ *
122
+ * This would update the dependency map in the LocalGraph. For now,
123
+ * this is a placeholder that returns skip results.
124
+ *
125
+ * @param taskId - The ID of the task that depends on another.
126
+ * @param dependsOnTaskId - The ID of the task that is depended on.
127
+ * @returns A dependency result indicating success, skip, or failure.
128
+ */
129
+ async addDependency(taskId, dependsOnTaskId) {
130
+ // Placeholder implementation - would update LocalGraph dependency map
131
+ console.warn(`LocalFileAdapter: addDependency not fully implemented. Would add dependency from ${taskId} to ${dependsOnTaskId}.`);
132
+ return {
133
+ added: false,
134
+ unsupported: false,
135
+ error: "Adding dependencies is not yet implemented for local-file adapter",
136
+ };
137
+ }
138
+ /**
139
+ * Creates a child task under a parent task in the local graph.
140
+ *
141
+ * This would create a new node in the LocalGraph. For now,
142
+ * this is a placeholder that returns skip results.
143
+ *
144
+ * @param parentId - The ID of the parent task.
145
+ * @param title - The title of the child task.
146
+ * @param body - Optional body/description of the child task.
147
+ * @returns A create child result indicating success, skip, or failure.
148
+ */
149
+ async createChild(parentId, title, body) {
150
+ // Placeholder implementation - would create new node in LocalGraph
151
+ console.warn(`LocalFileAdapter: createChild not fully implemented. Would create child '${title}' under ${parentId}.`);
152
+ return {
153
+ created: false,
154
+ unsupported: false,
155
+ error: "Creating child tasks is not yet implemented for local-file adapter",
156
+ };
157
+ }
158
+ }
159
+ exports.LocalFileAdapter = LocalFileAdapter;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpBridgeAdapter = void 0;
4
+ const MCP_BRIDGE_UNAVAILABLE_MESSAGE = "MCP bridge adapter is unavailable because '@tool-server/linear' is not installed. Install MCP bridge dependencies or switch tracker.adapter to 'linear'.";
5
+ function isMissingModuleError(error) {
6
+ if (!(error instanceof Error)) {
7
+ return false;
8
+ }
9
+ return (error.message.includes("Cannot find module '@tool-server/linear'") ||
10
+ error.message.includes("Cannot find package '@tool-server/linear'") ||
11
+ error.message.includes("ERR_MODULE_NOT_FOUND"));
12
+ }
13
+ async function loadMcpLinearTools() {
14
+ try {
15
+ const tools = await import("@tool-server/linear");
16
+ return {
17
+ mcp_linear_list_issues: tools.mcp_linear_list_issues,
18
+ mcp_linear_save_issue: tools.mcp_linear_save_issue,
19
+ };
20
+ }
21
+ catch (error) {
22
+ if (isMissingModuleError(error)) {
23
+ throw new Error(MCP_BRIDGE_UNAVAILABLE_MESSAGE);
24
+ }
25
+ throw error;
26
+ }
27
+ }
28
+ /**
29
+ * MCP Bridge Adapter for interacting with Linear via the MCP.
30
+ * This adapter fetches issues from Linear and applies mutations (e.g., status updates) to Linear issues.
31
+ */
32
+ class McpBridgeAdapter {
33
+ toolsLoader;
34
+ toolsPromise;
35
+ constructor(toolsLoader = loadMcpLinearTools) {
36
+ this.toolsLoader = toolsLoader;
37
+ }
38
+ async getTools() {
39
+ this.toolsPromise ??= this.toolsLoader().catch((error) => {
40
+ this.toolsPromise = undefined;
41
+ if (isMissingModuleError(error)) {
42
+ throw new Error(MCP_BRIDGE_UNAVAILABLE_MESSAGE);
43
+ }
44
+ throw error;
45
+ });
46
+ return this.toolsPromise;
47
+ }
48
+ /**
49
+ * Fetches data (issues) from Linear using the MCP bridge.
50
+ * @param input - The sync input parameters, including the Linear team ID.
51
+ * @returns A promise resolving to an array of Linear issues.
52
+ */
53
+ async fetchData(input) {
54
+ const { mcp_linear_list_issues } = await this.getTools();
55
+ console.log(`McpBridgeAdapter: Fetching data for trackerId: ${input.trackerId}`);
56
+ // Assuming input.trackerId contains the Linear team ID or can be derived from config
57
+ // For now, let's assume we need a team ID to list issues. This will need to come from configuration.
58
+ // As a placeholder, we'll use a hardcoded team if not provided in input.
59
+ const teamId = input.trackerId; // This needs to be refined based on actual config
60
+ if (!teamId) {
61
+ console.warn('McpBridgeAdapter: No teamId provided in TrackerSyncInput. Cannot fetch issues.');
62
+ return [];
63
+ }
64
+ try {
65
+ const issues = await mcp_linear_list_issues({ team: teamId });
66
+ console.log(`McpBridgeAdapter: Fetched ${issues.length} issues from Linear.`);
67
+ return issues;
68
+ }
69
+ catch (error) {
70
+ console.error('McpBridgeAdapter: Error fetching issues from Linear:', error);
71
+ throw error;
72
+ }
73
+ }
74
+ /**
75
+ * Applies a mutation record to a Linear issue using the MCP bridge.
76
+ * @param mutation - The mutation record to apply.
77
+ * @returns A promise resolving to the updated mutation record.
78
+ */
79
+ async applyMutation(mutation) {
80
+ const { mcp_linear_save_issue } = await this.getTools();
81
+ console.log(`McpBridgeAdapter: Applying mutation for ID: ${mutation.id}, entityType: ${mutation.entityType}, entityId: ${mutation.entityId}`);
82
+ if (mutation.entityType === 'issue' && mutation.type === 'update') {
83
+ try {
84
+ // Assuming payload contains fields to update in Linear issue
85
+ const updatedIssue = await mcp_linear_save_issue({
86
+ id: mutation.entityId,
87
+ ...mutation.payload, // Spread the payload to update issue fields
88
+ });
89
+ console.log(`McpBridgeAdapter: Successfully updated Linear issue ${mutation.entityId}.`);
90
+ return { ...mutation, status: 'succeeded', remoteId: updatedIssue.id };
91
+ }
92
+ catch (error) {
93
+ console.error(`McpBridgeAdapter: Error updating Linear issue ${mutation.entityId}:`, error);
94
+ return { ...mutation, status: 'failed', error: error.message };
95
+ }
96
+ }
97
+ else if (mutation.entityType === 'issue' && mutation.type === 'create') {
98
+ try {
99
+ // Assuming payload contains fields to create a Linear issue
100
+ if (!mutation.payload.team) {
101
+ return { ...mutation, status: 'failed', error: 'Team is required for creating a Linear issue.' };
102
+ }
103
+ if (!mutation.payload.title) {
104
+ return { ...mutation, status: 'failed', error: 'Title is required for creating a Linear issue.' };
105
+ }
106
+ const newIssue = await mcp_linear_save_issue({
107
+ team: mutation.payload.team,
108
+ title: mutation.payload.title,
109
+ description: mutation.payload.description,
110
+ // Add other fields as necessary from payload
111
+ ...mutation.payload,
112
+ });
113
+ console.log(`McpBridgeAdapter: Successfully created Linear issue ${newIssue.id}.`);
114
+ return { ...mutation, status: 'succeeded', remoteId: newIssue.id };
115
+ }
116
+ catch (error) {
117
+ console.error(`McpBridgeAdapter: Error creating Linear issue:`, error);
118
+ return { ...mutation, status: 'failed', error: error.message };
119
+ }
120
+ }
121
+ // Handle other mutation types or entity types as needed
122
+ console.warn(`McpBridgeAdapter: Unsupported mutation type or entity type: ${mutation.type} ${mutation.entityType}`);
123
+ return { ...mutation, status: 'failed', error: 'Unsupported mutation type or entity type' };
124
+ }
125
+ /**
126
+ * Compares local state with remote state to detect conflicts.
127
+ * This is a placeholder and needs a proper implementation based on how local and remote entities are structured.
128
+ * A common approach is to compare a "version" field or a hash of relevant fields.
129
+ * @param localEntity - The local representation of an entity.
130
+ * @param remoteEntity - The remote representation of the same entity.
131
+ * @returns True if a conflict is detected, false otherwise.
132
+ */
133
+ detectConflict(localEntity, remoteEntity) {
134
+ // For a basic implementation, we can compare a lastUpdated timestamp or a content hash.
135
+ // This will depend on the structure of localEntity and LinearIssue.
136
+ // For now, a very basic comparison:
137
+ if (!localEntity || !remoteEntity) {
138
+ return false; // Cannot detect conflict if one is missing
139
+ }
140
+ // More sophisticated conflict detection would compare relevant fields, e.g.,
141
+ // if (localEntity.lastUpdated > remoteEntity.updatedAt) { return true; }
142
+ // Or if (JSON.stringify(localEntity.importantFields) !== JSON.stringify(remoteEntity.importantFields)) { return true; }
143
+ console.log('McpBridgeAdapter: Simulating conflict detection (always false for now)');
144
+ return false; // Placeholder
145
+ }
146
+ /**
147
+ * Generates a remote fingerprint for a given Linear entity (issue).
148
+ * This fingerprint can be used for quick comparison to detect changes.
149
+ * @param entity - The entity to generate a fingerprint for.
150
+ * @returns A string representing the remote fingerprint.
151
+ */
152
+ generateRemoteFingerprint(entity) {
153
+ // A simple fingerprint could be a hash of the issue's content and its last update timestamp.
154
+ // For Linear issues, `updatedAt` is a good candidate.
155
+ return `${entity.id}-${entity.updatedAt}-${entity.title}-${entity.description}`; // Basic fingerprint
156
+ }
157
+ }
158
+ exports.McpBridgeAdapter = McpBridgeAdapter;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const mcp_bridge_js_1 = require("./mcp-bridge.js");
5
+ (0, vitest_1.describe)("McpBridgeAdapter", () => {
6
+ (0, vitest_1.it)("fails gracefully when MCP bridge dependencies are missing", async () => {
7
+ const adapter = new mcp_bridge_js_1.McpBridgeAdapter(async () => {
8
+ throw new Error("Cannot find module '@tool-server/linear'");
9
+ });
10
+ await (0, vitest_1.expect)(adapter.fetchData({ trackerId: "POL-1" })).rejects.toThrow("MCP bridge adapter is unavailable because '@tool-server/linear' is not installed.");
11
+ });
12
+ });