@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,213 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertNotDoneState = assertNotDoneState;
4
+ exports.findReviewState = findReviewState;
5
+ exports.postLinearComment = postLinearComment;
6
+ exports.updateLinearIssueAfterFinalize = updateLinearIssueAfterFinalize;
7
+ const node_https_1 = require("node:https");
8
+ const lifecycle_policy_js_1 = require("../tracker/lifecycle-policy.js");
9
+ // ──────────────────────────────────────────────────────────────────────────────
10
+ // Review-gate policy
11
+ // ──────────────────────────────────────────────────────────────────────────────
12
+ /**
13
+ * State types that finalize is PROHIBITED from transitioning to.
14
+ * Human review is the ONLY authority for Done/Closed transitions.
15
+ */
16
+ const DONE_STATE_TYPES = new Set(["completed", "canceled", "cancelled"]);
17
+ /**
18
+ * Guard: throws if the given state type corresponds to Done or Closed.
19
+ * Called before every issueUpdate — prevents any future code from silently
20
+ * adding a Done-transition path.
21
+ */
22
+ function assertNotDoneState(stateType, stateName) {
23
+ if (DONE_STATE_TYPES.has(stateType.toLowerCase())) {
24
+ throw new Error(`[Linear review-gate] Finalize is prohibited from transitioning issues to Done or Closed states. ` +
25
+ `Attempted: "${stateName}" (type: "${stateType}"). ` +
26
+ `Only human review may mark issues as Done/Closed.`);
27
+ }
28
+ }
29
+ // ──────────────────────────────────────────────────────────────────────────────
30
+ // Internal HTTP helper
31
+ // ──────────────────────────────────────────────────────────────────────────────
32
+ async function linearGraphQL(query, variables, apiKey) {
33
+ const payload = JSON.stringify({ query, variables });
34
+ return new Promise((resolve, reject) => {
35
+ const req = (0, node_https_1.request)({
36
+ hostname: "api.linear.app",
37
+ path: "/graphql",
38
+ method: "POST",
39
+ headers: {
40
+ "Content-Type": "application/json",
41
+ Authorization: apiKey,
42
+ },
43
+ }, (res) => {
44
+ const chunks = [];
45
+ res.on("data", (chunk) => chunks.push(chunk));
46
+ res.on("end", () => {
47
+ if ((res.statusCode ?? 0) >= 400) {
48
+ reject(new Error(`Linear API returned ${res.statusCode}`));
49
+ return;
50
+ }
51
+ try {
52
+ const text = Buffer.concat(chunks).toString("utf-8");
53
+ const parsed = JSON.parse(text);
54
+ if (parsed.errors && Array.isArray(parsed.errors) && parsed.errors.length > 0) {
55
+ reject(new Error(`Linear API GraphQL errors: ${JSON.stringify(parsed.errors)}`));
56
+ }
57
+ else {
58
+ resolve(parsed.data);
59
+ }
60
+ }
61
+ catch (err) {
62
+ reject(new Error(`Failed to parse Linear API response: ${err instanceof Error ? err.message : String(err)}`));
63
+ }
64
+ });
65
+ });
66
+ req.on("error", reject);
67
+ req.write(payload);
68
+ req.end();
69
+ });
70
+ }
71
+ // ──────────────────────────────────────────────────────────────────────────────
72
+ // Review-state discovery
73
+ // ──────────────────────────────────────────────────────────────────────────────
74
+ /**
75
+ * Finds an "In Review" workflow state for the issue's team.
76
+ * Matches by state type === "review" first, then by name ("In Review" / "Review").
77
+ * Returns null if the issue has no team or no review-type state exists.
78
+ */
79
+ async function findReviewState(issueId, apiKey) {
80
+ const issueData = await linearGraphQL(`query GetIssueTeam($id: String!) { issue(id: $id) { team { id } } }`, { id: issueId }, apiKey);
81
+ const teamId = issueData.issue?.team?.id;
82
+ if (!teamId)
83
+ return null;
84
+ const statesData = await linearGraphQL(`query GetWorkflowStates($teamId: String!) {
85
+ workflowStates(filter: { team: { id: { eq: $teamId } } }) {
86
+ nodes { id name type }
87
+ }
88
+ }`, { teamId }, apiKey);
89
+ const states = statesData.workflowStates?.nodes ?? [];
90
+ return (states.find((s) => s.type.toLowerCase() === "review") ??
91
+ states.find((s) => /^in\s+review$/i.test(s.name) || /^review$/i.test(s.name)) ??
92
+ null);
93
+ }
94
+ // ──────────────────────────────────────────────────────────────────────────────
95
+ // Comment body builder
96
+ // ──────────────────────────────────────────────────────────────────────────────
97
+ function buildCommentBody(opts) {
98
+ const lines = [
99
+ `**polaris finalize complete** — run \`${opts.state.run_id}\``,
100
+ ``,
101
+ `| Field | Value |`,
102
+ `|---|---|`,
103
+ `| Branch | \`${opts.branch}\` |`,
104
+ `| PR | ${opts.prUrl} |`,
105
+ `| Children completed | ${opts.state.completed_children.length} |`,
106
+ `| Map validation | ${opts.validationPassed ? "✓ passed" : "✗ failed"} |`,
107
+ ];
108
+ if (opts.reviewStateMissing) {
109
+ lines.push(``, `> ⚠️ No "In Review" workflow state found for this issue's team — issue state was not updated automatically. Transition manually if needed.`);
110
+ }
111
+ return lines.join("\n");
112
+ }
113
+ // ──────────────────────────────────────────────────────────────────────────────
114
+ // Public API
115
+ // ──────────────────────────────────────────────────────────────────────────────
116
+ /** Posts a finalize-complete comment without attempting a state transition. */
117
+ async function postLinearComment(options) {
118
+ const { issueId, state, branch, prUrl, validationPassed, apiKey } = options;
119
+ const body = buildCommentBody({ state, branch, prUrl, validationPassed, reviewStateMissing: false });
120
+ const data = await linearGraphQL(`mutation CreateComment($issueId: String!, $body: String!) {
121
+ commentCreate(input: { issueId: $issueId, body: $body }) { success }
122
+ }`, { issueId, body }, apiKey);
123
+ if (data.commentCreate?.success !== true) {
124
+ throw new Error(`Linear commentCreate failed: ${JSON.stringify(data.commentCreate)}`);
125
+ }
126
+ }
127
+ /**
128
+ * Full post-finalize Linear update (review-gate policy):
129
+ *
130
+ * 1. Resolves the lifecycle policy for parent-all-children-complete event.
131
+ * 2. If policy says skip (e.g., no_status_change), skips state transition.
132
+ * 3. Otherwise, queries the issue's team for an "In Review" workflow state.
133
+ * 4. If found — calls issueUpdate to transition (NEVER to Done/Closed).
134
+ * 5. If not found — skips state transition; comment body notes the missing state.
135
+ * 6. Always posts a finalize-complete comment.
136
+ *
137
+ * POLICY: This function must NEVER call issueUpdate with a Done or Closed
138
+ * state ID. The assertNotDoneState guard enforces this at runtime.
139
+ */
140
+ async function updateLinearIssueAfterFinalize(options) {
141
+ const { issueId, state, branch, prUrl, validationPassed, apiKey, lifecyclePolicy } = options;
142
+ // Resolve lifecycle transition from policy
143
+ const lifecycleTransition = (0, lifecycle_policy_js_1.resolveLifecycleTransition)("parent-all-children-complete", lifecyclePolicy);
144
+ // If policy says skip, skip the state transition entirely
145
+ if (lifecycleTransition.skip) {
146
+ console.log(`[Linear] Skipping lifecycle transition for ${issueId}: ${lifecycleTransition.skipReason}`);
147
+ const body = buildCommentBody({
148
+ state,
149
+ branch,
150
+ prUrl,
151
+ validationPassed,
152
+ reviewStateMissing: false,
153
+ });
154
+ const commentData = await linearGraphQL(`mutation CreateComment($issueId: String!, $body: String!) {
155
+ commentCreate(input: { issueId: $issueId, body: $body }) { success }
156
+ }`, { issueId, body }, apiKey);
157
+ if (commentData.commentCreate?.success !== true) {
158
+ throw new Error(`Linear commentCreate failed: ${JSON.stringify(commentData.commentCreate)}`);
159
+ }
160
+ return;
161
+ }
162
+ // Only attempt state transition when the policy maps to the "in_review" normalized state.
163
+ // Other normalized states (e.g. "done", "no_status_change") are not handled by this function.
164
+ const targetState = lifecycleTransition.targetState;
165
+ if (targetState !== "in_review") {
166
+ console.log(`[Linear] Skipping lifecycle transition for ${issueId}: target state "${targetState}" is not handled by Linear finalize`);
167
+ const body = buildCommentBody({
168
+ state,
169
+ branch,
170
+ prUrl,
171
+ validationPassed,
172
+ reviewStateMissing: false,
173
+ });
174
+ const commentData = await linearGraphQL(`mutation CreateComment($issueId: String!, $body: String!) {
175
+ commentCreate(input: { issueId: $issueId, body: $body }) { success }
176
+ }`, { issueId, body }, apiKey);
177
+ if (commentData.commentCreate?.success !== true) {
178
+ throw new Error(`Linear commentCreate failed: ${JSON.stringify(commentData.commentCreate)}`);
179
+ }
180
+ return;
181
+ }
182
+ let reviewState = null;
183
+ try {
184
+ reviewState = await findReviewState(issueId, apiKey);
185
+ }
186
+ catch (err) {
187
+ // Log the error so auth/network/GraphQL failures are visible, then fall back to comment-only
188
+ console.error(`[Linear] findReviewState failed for issue ${issueId}: ${err instanceof Error ? err.message : String(err)}`);
189
+ }
190
+ if (reviewState !== null) {
191
+ // Enforce review-gate: must never transition to Done or Closed.
192
+ assertNotDoneState(reviewState.type, reviewState.name);
193
+ const updateData = await linearGraphQL(`mutation UpdateIssueState($id: String!, $stateId: String!) {
194
+ issueUpdate(id: $id, input: { stateId: $stateId }) { success }
195
+ }`, { id: issueId, stateId: reviewState.id }, apiKey);
196
+ if (updateData.issueUpdate?.success !== true) {
197
+ throw new Error(`Linear issueUpdate failed: ${JSON.stringify(updateData.issueUpdate)}`);
198
+ }
199
+ }
200
+ const body = buildCommentBody({
201
+ state,
202
+ branch,
203
+ prUrl,
204
+ validationPassed,
205
+ reviewStateMissing: reviewState === null,
206
+ });
207
+ const commentData = await linearGraphQL(`mutation CreateComment($issueId: String!, $body: String!) {
208
+ commentCreate(input: { issueId: $issueId, body: $body }) { success }
209
+ }`, { issueId, body }, apiKey);
210
+ if (commentData.commentCreate?.success !== true) {
211
+ throw new Error(`Linear commentCreate failed: ${JSON.stringify(commentData.commentCreate)}`);
212
+ }
213
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateRunReport = generateRunReport;
4
+ function generateRunReport(data) {
5
+ const { state, branch, validationPassed, prUrl, artifacts, notes } = data;
6
+ const total = state.completed_children.length + state.open_children.length;
7
+ const completedCount = state.completed_children.length;
8
+ const childRows = state.completed_children
9
+ .map((id) => `| ${id} | — | — | Done |`)
10
+ .concat(state.open_children.map((id) => `| ${id} | — | — | Open |`))
11
+ .join("\n");
12
+ const artifactList = artifacts && artifacts.length > 0
13
+ ? artifacts.map((a) => `- ${a}`).join("\n")
14
+ : "- current-state.json\n- run-report.md";
15
+ const notesList = notes && notes.length > 0
16
+ ? notes.map((n) => `- ${n}`).join("\n")
17
+ : "_None_";
18
+ const blockerNote = state.blocker
19
+ ? `\n**Blocker:** ${state.blocker.reason} (child: ${state.blocker.child_id})\n`
20
+ : "";
21
+ return `# Run Report: ${state.run_id}
22
+
23
+ **Status:** ${state.status}
24
+ **Branch:** ${branch}
25
+ **PR:** ${prUrl ?? "TBD — set at delivery step 9"}
26
+ **Children completed:** ${completedCount} of ${total}
27
+ **Validation:** ${validationPassed ? "passed" : "failed"}
28
+ ${blockerNote}
29
+ ## Children
30
+
31
+ | ID | Title | Commit | Status |
32
+ |---|---|---|---|
33
+ ${childRows || "_No children recorded_"}
34
+
35
+ ## Artifacts produced
36
+
37
+ ${artifactList}
38
+
39
+ ## Validation summary
40
+
41
+ ${validationPassed ? "Map validate passed. Schema validate passed." : "One or more validations failed — see step output above."}
42
+
43
+ ## Notes
44
+
45
+ ${notesList}
46
+ `;
47
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepMapUpdate = stepMapUpdate;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const node_path_1 = require("node:path");
6
+ function stepMapUpdate(repoRoot) {
7
+ const result = (0, node_child_process_1.spawnSync)(process.execPath, [(0, node_path_1.resolve)(repoRoot, "dist/cli/index.js"), "map", "update", "--changed"], { cwd: repoRoot, encoding: "utf-8", stdio: "inherit" });
8
+ if (result.status !== 0) {
9
+ process.stderr.write("Warning: map update --changed failed; proceeding to validate.\n");
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepMapValidate = stepMapValidate;
4
+ const validate_js_1 = require("../../map/validate.js");
5
+ function stepMapValidate(repoRoot) {
6
+ const result = (0, validate_js_1.runMapValidate)(repoRoot, 30);
7
+ if (result.hasError) {
8
+ process.stderr.write("finalize aborted: map validation failed — run polaris map validate for details\n");
9
+ process.exit(1);
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepSchemaValidate = stepSchemaValidate;
4
+ const checkpoint_js_1 = require("../../loop/checkpoint.js");
5
+ function stepSchemaValidate(state) {
6
+ const errors = (0, checkpoint_js_1.validateState)(state);
7
+ if (errors.length > 0) {
8
+ process.stderr.write(`finalize aborted: current-state.json schema invalid:\n${errors.join("\n")}\n`);
9
+ process.exit(1);
10
+ }
11
+ }
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepRunChecks = stepRunChecks;
4
+ const node_child_process_1 = require("node:child_process");
5
+ function parseShellArgs(cmdLine) {
6
+ const args = [];
7
+ let current = "";
8
+ let inSingleQuote = false;
9
+ let inDoubleQuote = false;
10
+ let escaped = false;
11
+ for (let i = 0; i < cmdLine.length; i++) {
12
+ const char = cmdLine[i];
13
+ if (escaped) {
14
+ current += char;
15
+ escaped = false;
16
+ continue;
17
+ }
18
+ if (char === "\\") {
19
+ escaped = true;
20
+ continue;
21
+ }
22
+ if (char === "'" && !inDoubleQuote) {
23
+ inSingleQuote = !inSingleQuote;
24
+ continue;
25
+ }
26
+ if (char === '"' && !inSingleQuote) {
27
+ inDoubleQuote = !inDoubleQuote;
28
+ continue;
29
+ }
30
+ if (char === " " && !inSingleQuote && !inDoubleQuote) {
31
+ if (current.length > 0) {
32
+ args.push(current);
33
+ current = "";
34
+ }
35
+ continue;
36
+ }
37
+ current += char;
38
+ }
39
+ if (current.length > 0) {
40
+ args.push(current);
41
+ }
42
+ return args;
43
+ }
44
+ function normalizeGitPath(filePath) {
45
+ return filePath.replace(/\\/g, "/").replace(/^\.\//, "");
46
+ }
47
+ function getStagedPaths(repoRoot) {
48
+ const output = (0, node_child_process_1.execFileSync)("git", ["diff", "--cached", "--name-only", "--diff-filter=ACMR"], {
49
+ cwd: repoRoot,
50
+ encoding: "utf-8",
51
+ });
52
+ return output
53
+ .split("\n")
54
+ .map((line) => normalizeGitPath(line.trim()))
55
+ .filter(Boolean);
56
+ }
57
+ function isBlockedDeliveryPath(filePath) {
58
+ return (filePath.startsWith(".taskchain_artifacts/")
59
+ || filePath.endsWith(".bak")
60
+ || filePath.startsWith(".polaris/runs/"));
61
+ }
62
+ function isForeignClusterArtifact(filePath, activeClusterId) {
63
+ if (!activeClusterId) {
64
+ return false;
65
+ }
66
+ const match = /^\.polaris\/clusters\/([^/]+)\//.exec(filePath);
67
+ return Boolean(match && match[1] !== activeClusterId);
68
+ }
69
+ function formatPathList(paths) {
70
+ return paths.map((filePath) => ` - ${filePath}`).join("\n");
71
+ }
72
+ function runStagedArtifactPreflight(repoRoot, options) {
73
+ if (options.skipDelivery) {
74
+ console.log("[4/13] Skipping staged delivery artifact check (--skip-delivery).");
75
+ return;
76
+ }
77
+ const stagedPaths = getStagedPaths(repoRoot);
78
+ if (stagedPaths.length === 0) {
79
+ return;
80
+ }
81
+ const blockedPaths = stagedPaths.filter(isBlockedDeliveryPath);
82
+ const foreignClusterPaths = stagedPaths.filter((filePath) => isForeignClusterArtifact(filePath, options.activeClusterId));
83
+ if (foreignClusterPaths.length > 0) {
84
+ console.warn([
85
+ "finalize warning: staged artifacts from other clusters detected:",
86
+ formatPathList(foreignClusterPaths),
87
+ `Corrective action: keep only active cluster ${options.activeClusterId ?? "<unknown>"} artifacts staged for delivery, or unstage these paths with 'git restore --staged <path>'.`,
88
+ ].join("\n"));
89
+ }
90
+ if (blockedPaths.length > 0) {
91
+ process.stderr.write([
92
+ "finalize aborted: staged delivery-blocked paths detected:",
93
+ formatPathList(blockedPaths),
94
+ "Corrective action: unstage these paths with 'git restore --staged <path>' (or remove them) before rerunning finalize delivery.",
95
+ ].join("\n") + "\n");
96
+ process.exit(1);
97
+ }
98
+ }
99
+ function stepRunChecks(repoRoot, checks, options = {}) {
100
+ for (const check of checks) {
101
+ const argv = parseShellArgs(check);
102
+ const cmd = argv[0];
103
+ if (!cmd)
104
+ continue;
105
+ const args = argv.slice(1);
106
+ const result = (0, node_child_process_1.spawnSync)(cmd, args, {
107
+ cwd: repoRoot,
108
+ encoding: "utf-8",
109
+ stdio: "inherit",
110
+ shell: false,
111
+ });
112
+ if (result.status !== 0) {
113
+ process.stderr.write(`finalize aborted: check failed: ${check}\n`);
114
+ process.exit(1);
115
+ }
116
+ }
117
+ runStagedArtifactPreflight(repoRoot, options);
118
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepGenerateReport = stepGenerateReport;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const run_report_js_1 = require("../run-report.js");
7
+ function stepGenerateReport(repoRoot, state, branch, validationPassed) {
8
+ const reportPath = (0, node_path_1.resolve)(repoRoot, ".polaris", "runs", "run-report.md");
9
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(reportPath), { recursive: true });
10
+ const content = (0, run_report_js_1.generateRunReport)({ state, branch, validationPassed });
11
+ (0, node_fs_1.writeFileSync)(reportPath, content, "utf-8");
12
+ console.log(`Run report written: ${reportPath}`);
13
+ return reportPath;
14
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepCommit = stepCommit;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const artifact_policy_js_1 = require("../artifact-policy.js");
8
+ function stepCommit(repoRoot, state, _stateFile, _reportPath) {
9
+ const msg = `polaris finalize: ${state.run_id}\n\nChildren: ${state.completed_children.length} completed\nBranch: ${getBranch(repoRoot)}`;
10
+ const promotedTargets = (0, artifact_policy_js_1.getArtifactPromotionStageTargets)(state.cluster_id)
11
+ .filter((target) => (0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, target)));
12
+ if (promotedTargets.length > 0) {
13
+ (0, node_child_process_1.execFileSync)("git", ["add", "--", ...promotedTargets], { cwd: repoRoot, stdio: "inherit" });
14
+ }
15
+ const stagedPaths = (0, node_child_process_1.execFileSync)("git", ["diff", "--cached", "--name-only"], {
16
+ cwd: repoRoot,
17
+ encoding: "utf-8",
18
+ }).trim().split("\n").filter(Boolean);
19
+ const blockedArtifacts = (0, artifact_policy_js_1.findArtifactPromotionViolations)(stagedPaths, state.cluster_id)
20
+ .map((violation) => violation.path);
21
+ if (blockedArtifacts.length > 0) {
22
+ (0, node_child_process_1.execFileSync)("git", ["restore", "--staged", "--", ...blockedArtifacts], { cwd: repoRoot, stdio: "inherit" });
23
+ }
24
+ (0, node_child_process_1.execFileSync)("git", ["commit", "--allow-empty", "-m", msg], { cwd: repoRoot, stdio: "inherit" });
25
+ const sha = (0, node_child_process_1.execFileSync)("git", ["rev-parse", "HEAD"], { cwd: repoRoot, encoding: "utf-8" }).trim();
26
+ console.log(`Finalize commit: ${sha}`);
27
+ return sha;
28
+ }
29
+ function getBranch(repoRoot) {
30
+ try {
31
+ return (0, node_child_process_1.execFileSync)("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
32
+ cwd: repoRoot,
33
+ encoding: "utf-8",
34
+ }).trim();
35
+ }
36
+ catch {
37
+ return "";
38
+ }
39
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepPush = stepPush;
4
+ const node_child_process_1 = require("node:child_process");
5
+ function stepPush(repoRoot, branch) {
6
+ (0, node_child_process_1.execFileSync)("git", ["push", "-u", "origin", branch], {
7
+ cwd: repoRoot,
8
+ stdio: "inherit",
9
+ });
10
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepCreatePr = stepCreatePr;
4
+ const github_js_1 = require("../github.js");
5
+ function stepCreatePr(repoRoot, branch, state, draft) {
6
+ const prUrl = (0, github_js_1.createDraftPr)({ repoRoot, branch, state, draft });
7
+ console.log(`PR created: ${prUrl}`);
8
+ return prUrl;
9
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepUpdateState = stepUpdateState;
4
+ const checkpoint_js_1 = require("../../loop/checkpoint.js");
5
+ function stepUpdateState(stateFile, state, prUrl) {
6
+ const updated = { ...state, pr_url: prUrl, status: "complete" };
7
+ (0, checkpoint_js_1.writeStateAtomic)(stateFile, updated);
8
+ return updated;
9
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepAppendJsonl = stepAppendJsonl;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ function stepAppendJsonl(telemetryFile, state, prUrl) {
7
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(telemetryFile), { recursive: true });
8
+ const ts = new Date().toISOString();
9
+ const prOpened = {
10
+ event: "pr-opened",
11
+ run_id: state.run_id,
12
+ pr_url: prUrl,
13
+ timestamp: ts,
14
+ };
15
+ const runComplete = {
16
+ event: "run-complete",
17
+ run_id: state.run_id,
18
+ children_completed: state.completed_children.length,
19
+ timestamp: ts,
20
+ };
21
+ (0, node_fs_1.appendFileSync)(telemetryFile, JSON.stringify(prOpened) + "\n", "utf-8");
22
+ (0, node_fs_1.appendFileSync)(telemetryFile, JSON.stringify(runComplete) + "\n", "utf-8");
23
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepUpdateLinear = stepUpdateLinear;
4
+ const linear_js_1 = require("../linear.js");
5
+ async function stepUpdateLinear(state, branch, prUrl, validationPassed, linearEnabled, parentIssueId, lifecyclePolicy) {
6
+ if (!linearEnabled) {
7
+ console.log("[11/12] Linear integration disabled — skipping.");
8
+ return;
9
+ }
10
+ const apiKey = process.env["LINEAR_API_KEY"];
11
+ if (!apiKey) {
12
+ process.stderr.write("Warning: LINEAR_API_KEY not set — skipping Linear update.\n");
13
+ return;
14
+ }
15
+ const issueId = parentIssueId ?? state.cluster_id;
16
+ if (!issueId) {
17
+ process.stderr.write("Warning: no Linear parent issue ID — skipping Linear update.\n");
18
+ return;
19
+ }
20
+ await (0, linear_js_1.updateLinearIssueAfterFinalize)({ issueId, state, branch, prUrl, validationPassed, apiKey, lifecyclePolicy });
21
+ console.log(`Linear parent ${issueId} updated.`);
22
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stepArchive = stepArchive;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ function stepArchive(repoRoot, state, stateFile, reportPath) {
7
+ const archiveDir = (0, node_path_1.resolve)(repoRoot, ".polaris", "runs", state.run_id);
8
+ (0, node_fs_1.mkdirSync)(archiveDir, { recursive: true });
9
+ (0, node_fs_1.copyFileSync)(stateFile, (0, node_path_1.join)(archiveDir, "current-state.json"));
10
+ if ((0, node_fs_1.existsSync)(reportPath)) {
11
+ (0, node_fs_1.copyFileSync)(reportPath, (0, node_path_1.join)(archiveDir, "run-report.md"));
12
+ }
13
+ const mapDir = (0, node_path_1.resolve)(repoRoot, ".polaris", "map");
14
+ for (const file of ["file-routes.json", "needs-review.json", "exemptions.json", "atlas-index.json"]) {
15
+ const src = (0, node_path_1.join)(mapDir, file);
16
+ if ((0, node_fs_1.existsSync)(src)) {
17
+ (0, node_fs_1.copyFileSync)(src, (0, node_path_1.join)(archiveDir, file));
18
+ }
19
+ }
20
+ console.log(`Run archived to .polaris/runs/${state.run_id}/`);
21
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CAdapter = void 0;
4
+ exports.createCAdapter = createCAdapter;
5
+ const node_path_1 = require("node:path");
6
+ const extract_js_1 = require("./extract.js");
7
+ const runtime_js_1 = require("./runtime.js");
8
+ const DEFAULT_EXTENSIONS = [".c", ".h"];
9
+ class CAdapter {
10
+ loadRuntime;
11
+ languageId = "c";
12
+ fileExtensions = DEFAULT_EXTENSIONS;
13
+ confidence = "high";
14
+ limitations = [
15
+ "Extracts declaration-level symbols only (functions, structs, includes).",
16
+ "Does not perform macro expansion or preprocessor execution.",
17
+ ];
18
+ constructor(loadRuntime) {
19
+ this.loadRuntime = loadRuntime;
20
+ }
21
+ async extractSymbols(filePath, source) {
22
+ const language = detectLanguage(filePath);
23
+ if (!language) {
24
+ throw new Error(`Unsupported C file extension: ${(0, node_path_1.extname)(filePath)}`);
25
+ }
26
+ const runtime = await this.loadRuntime();
27
+ const tree = runtime.parse(source, language);
28
+ return (0, extract_js_1.extractCSymbolsFromTree)(tree);
29
+ }
30
+ resolveImportSpecifier(specifier, _context) {
31
+ const trimmed = specifier.trim();
32
+ if (trimmed.length === 0) {
33
+ return null;
34
+ }
35
+ return trimmed;
36
+ }
37
+ }
38
+ exports.CAdapter = CAdapter;
39
+ function createCAdapter(options = {}) {
40
+ return new CAdapter(options.loadRuntime ?? runtime_js_1.loadTreeSitterRuntime);
41
+ }
42
+ function detectLanguage(filePath) {
43
+ const extension = (0, node_path_1.extname)(filePath).toLowerCase();
44
+ return extension === ".c" || extension === ".h" ? "c" : null;
45
+ }