@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,335 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DRAFT_MARKER = void 0;
4
+ exports.hasDraftMarker = hasDraftMarker;
5
+ exports.generateDraft = generateDraft;
6
+ exports.generateSummaryDraft = generateSummaryDraft;
7
+ exports.seedInstructions = seedInstructions;
8
+ exports.seedSummary = seedSummary;
9
+ exports.seedInstructionsAll = seedInstructionsAll;
10
+ exports.seedSummaryAll = seedSummaryAll;
11
+ const node_fs_1 = require("node:fs");
12
+ const node_path_1 = require("node:path");
13
+ const loader_js_1 = require("../config/loader.js");
14
+ const atlas_js_1 = require("../map/atlas.js");
15
+ const smartdoc_ignore_js_1 = require("./smartdoc-ignore.js");
16
+ exports.DRAFT_MARKER = "<!-- polaris:draft -->";
17
+ function hasDraftMarker(filePath) {
18
+ try {
19
+ const content = (0, node_fs_1.readFileSync)(filePath, "utf-8");
20
+ return content.includes(exports.DRAFT_MARKER);
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ }
26
+ function collectDirs(dir, root, eligibilityOpts = {}, result = { eligible: [], ineligible: [] }) {
27
+ try {
28
+ for (const entry of (0, node_fs_1.readdirSync)(dir, { withFileTypes: true })) {
29
+ if (!entry.isDirectory())
30
+ continue;
31
+ const full = (0, node_path_1.join)(dir, entry.name);
32
+ const rel = (0, node_path_1.relative)(root, full).replace(/\\/g, "/");
33
+ // Check if directory is eligible for Smart Docs coverage
34
+ const eligibility = (0, smartdoc_ignore_js_1.isDirectoryEligible)(full, root, eligibilityOpts);
35
+ if (!eligibility.eligible) {
36
+ result.ineligible.push({
37
+ path: rel,
38
+ reason: eligibility.reason || "unknown",
39
+ category: eligibility.category === "eligible" ? undefined : eligibility.category,
40
+ });
41
+ continue;
42
+ }
43
+ result.eligible.push(rel);
44
+ collectDirs(full, root, eligibilityOpts, result);
45
+ }
46
+ }
47
+ catch {
48
+ // ignore unreadable dirs
49
+ }
50
+ return result;
51
+ }
52
+ function generateDraft(targetDir, repoRoot, allRoutes) {
53
+ const filesInDir = Object.entries(allRoutes).filter(([filePath]) => {
54
+ const fileDir = (0, node_path_1.dirname)(filePath);
55
+ const normDir = targetDir.replace(/\\/g, "/");
56
+ return fileDir === normDir || (normDir === "." && !filePath.includes("/"));
57
+ });
58
+ const domains = [...new Set(filesInDir.map(([, e]) => e.domain))].filter(Boolean);
59
+ const routes = [...new Set(filesInDir.map(([, e]) => e.route))].filter(Boolean);
60
+ const taskchains = [...new Set(filesInDir.map(([, e]) => e.taskchain))].filter(Boolean);
61
+ // Nearby doc references: .md files in atlas whose route overlaps with this dir's routes
62
+ const nearbyDocs = Object.entries(allRoutes)
63
+ .filter(([p]) => p.endsWith(".md") || p.startsWith("docs/"))
64
+ .filter(([, e]) => routes.some((r) => e.route === r || e.domain === domains[0]))
65
+ .map(([p]) => p)
66
+ .slice(0, 5);
67
+ const dirLabel = (0, node_path_1.basename)(targetDir) || (0, node_path_1.basename)(repoRoot);
68
+ const lines = [
69
+ exports.DRAFT_MARKER,
70
+ `# ${dirLabel}`,
71
+ "",
72
+ "> Polaris draft — review and remove the `<!-- polaris:draft -->` marker to promote.",
73
+ "",
74
+ "## Purpose",
75
+ "",
76
+ "<!-- One paragraph describing what this folder does. -->",
77
+ "",
78
+ ];
79
+ if (domains.length > 0)
80
+ lines.push(`**Domain:** ${domains.join(", ")}`);
81
+ if (routes.length > 0)
82
+ lines.push(`**Route:** ${routes.join(", ")}`);
83
+ if (taskchains.length > 0)
84
+ lines.push(`**Taskchain:** ${taskchains.join(", ")}`);
85
+ if (domains.length + routes.length + taskchains.length > 0)
86
+ lines.push("");
87
+ lines.push("## What belongs here", "");
88
+ if (filesInDir.length > 0) {
89
+ for (const [filePath, entry] of filesInDir) {
90
+ lines.push(`- \`${(0, node_path_1.basename)(filePath)}\` — ${entry.route} (${entry.domain})`);
91
+ }
92
+ }
93
+ else {
94
+ lines.push("<!-- Bulleted file list of contents. -->");
95
+ }
96
+ lines.push("");
97
+ lines.push("## What does not belong here", "");
98
+ lines.push("<!-- Explicit exclusions of files or responsibilities. -->");
99
+ lines.push("");
100
+ lines.push("## Editing rules", "");
101
+ lines.push("<!-- Behavioral constraints for agents and humans. -->");
102
+ lines.push("");
103
+ lines.push("## Architecture assumptions", "");
104
+ lines.push("<!-- What the code assumes about the world. -->");
105
+ lines.push("");
106
+ lines.push("## Read before editing", "");
107
+ if (nearbyDocs.length > 0) {
108
+ for (const docPath of nearbyDocs) {
109
+ lines.push(`- [${(0, node_path_1.basename)(docPath)}](${docPath})`);
110
+ }
111
+ }
112
+ else {
113
+ lines.push("<!-- Links to canonical sources (doctrine, specs). -->");
114
+ }
115
+ lines.push("");
116
+ lines.push("## Related routes", "");
117
+ lines.push("<!-- Atlas route pointer to sibling or parent folders. -->");
118
+ lines.push("");
119
+ return lines.join("\n");
120
+ }
121
+ function generateSummaryDraft(targetDir, repoRoot, _allRoutes) {
122
+ const dirLabel = (0, node_path_1.basename)(targetDir) || (0, node_path_1.basename)(repoRoot);
123
+ const lines = [
124
+ exports.DRAFT_MARKER,
125
+ `# Summary: ${dirLabel}`,
126
+ "",
127
+ "> Polaris draft — review and remove the `<!-- polaris:draft -->` marker to promote.",
128
+ "",
129
+ "## Purpose",
130
+ "<!-- One-line statement of what this folder does. -->",
131
+ "",
132
+ "## Core Concepts",
133
+ "<!-- 3–7 key concepts a reader needs before diving into source. -->",
134
+ "",
135
+ "## Architectural Role",
136
+ "<!-- How this folder fits into the larger system. -->",
137
+ "",
138
+ "## Key Constraints",
139
+ "<!-- The most important non-obvious behavioral limits. -->",
140
+ "",
141
+ "## Important Relationships",
142
+ "<!-- Upstream/downstream dependencies on other folders. -->",
143
+ "",
144
+ "## Current State",
145
+ "<!-- What is implemented, what is not yet, known gaps. -->",
146
+ "",
147
+ "## Route Health",
148
+ "<!-- Current operational condition. Workers should understand route health in under 10 seconds. -->",
149
+ "",
150
+ "### Healthy",
151
+ "<!-- If the route is healthy, state why. Otherwise omit this subsection. -->",
152
+ "",
153
+ "### Monitoring",
154
+ "<!-- Any ongoing monitoring or observations. Omit if none. -->",
155
+ "",
156
+ "### Known Issues",
157
+ "<!-- Any known problems or risks. Omit if none. -->",
158
+ "",
159
+ "### Recent Treatments",
160
+ "<!-- Recent fixes or improvements, with chart references if applicable. Omit if none. -->",
161
+ "",
162
+ "### Improvement Opportunities",
163
+ "<!-- Potential future improvements. Omit if none. -->",
164
+ "",
165
+ "## Canonical References",
166
+ "",
167
+ "```yaml",
168
+ "canonical_docs:",
169
+ " - POLARIS.md",
170
+ "<!-- Add navigation paths to canonical docs, specs, or doctrine. These are retrieval paths, not reading assignments. -->",
171
+ "```",
172
+ "",
173
+ "## Known Drift",
174
+ "<!-- Places where the summary may be stale (honesty field). -->",
175
+ "",
176
+ ];
177
+ return lines.join("\n");
178
+ }
179
+ function seedInstructions(targetPath, repoRoot, opts = {}) {
180
+ const absTarget = (0, node_path_1.resolve)(repoRoot, targetPath);
181
+ // Path traversal check: ensure absTarget is within repoRoot
182
+ const relCheck = (0, node_path_1.relative)(repoRoot, absTarget);
183
+ if (relCheck.startsWith("..") || relCheck.startsWith("/")) {
184
+ throw new Error(`Path traversal detected: target path is outside repo root`);
185
+ }
186
+ const outFile = (0, node_path_1.join)(absTarget, "POLARIS.md");
187
+ if ((0, node_fs_1.existsSync)(outFile)) {
188
+ if (hasDraftMarker(outFile)) {
189
+ return "skipped-draft";
190
+ }
191
+ return "skipped-exists";
192
+ }
193
+ const config = (0, loader_js_1.loadConfig)(repoRoot);
194
+ const atlasPath = (0, node_path_1.resolve)(repoRoot, config.repo.sidecarOutputPath ?? ".polaris/map");
195
+ const allRoutes = {
196
+ ...(0, atlas_js_1.readFileRoutes)(atlasPath),
197
+ ...(0, atlas_js_1.readNeedsReview)(atlasPath),
198
+ };
199
+ const relTarget = (0, node_path_1.relative)(repoRoot, absTarget).replace(/\\/g, "/");
200
+ const content = generateDraft(relTarget, repoRoot, allRoutes);
201
+ if (!opts.dryRun) {
202
+ (0, node_fs_1.writeFileSync)(outFile, content, "utf-8");
203
+ }
204
+ return "written";
205
+ }
206
+ function seedSummary(targetPath, repoRoot, opts = {}) {
207
+ const absTarget = (0, node_path_1.resolve)(repoRoot, targetPath);
208
+ const relCheck = (0, node_path_1.relative)(repoRoot, absTarget);
209
+ if (relCheck.startsWith("..") || relCheck.startsWith("/")) {
210
+ throw new Error(`Path traversal detected: target path is outside repo root`);
211
+ }
212
+ const outFile = (0, node_path_1.join)(absTarget, "SUMMARY.md");
213
+ if ((0, node_fs_1.existsSync)(outFile)) {
214
+ if (hasDraftMarker(outFile)) {
215
+ return "skipped-draft";
216
+ }
217
+ return "skipped-exists";
218
+ }
219
+ const config = (0, loader_js_1.loadConfig)(repoRoot);
220
+ const atlasPath = (0, node_path_1.resolve)(repoRoot, config.repo.sidecarOutputPath ?? ".polaris/map");
221
+ const allRoutes = {
222
+ ...(0, atlas_js_1.readFileRoutes)(atlasPath),
223
+ ...(0, atlas_js_1.readNeedsReview)(atlasPath),
224
+ };
225
+ const relTarget = (0, node_path_1.relative)(repoRoot, absTarget).replace(/\\/g, "/");
226
+ const content = generateSummaryDraft(relTarget, repoRoot, allRoutes);
227
+ if (!opts.dryRun) {
228
+ (0, node_fs_1.writeFileSync)(outFile, content, "utf-8");
229
+ }
230
+ return "written";
231
+ }
232
+ function seedInstructionsAll(repoRoot, opts = {}) {
233
+ const config = (0, loader_js_1.loadConfig)(repoRoot);
234
+ const atlasPath = (0, node_path_1.resolve)(repoRoot, config.repo.sidecarOutputPath ?? ".polaris/map");
235
+ const allRoutes = {
236
+ ...(0, atlas_js_1.readFileRoutes)(atlasPath),
237
+ ...(0, atlas_js_1.readNeedsReview)(atlasPath),
238
+ };
239
+ // Root handling: skipped by default for POLARIS.md (root uses AGENTS.md/CLAUDE.md)
240
+ const rootEligibility = (0, smartdoc_ignore_js_1.isDirectoryEligible)(repoRoot, repoRoot, {
241
+ isRoot: true,
242
+ skipRoot: opts.includeRoot ? false : true,
243
+ });
244
+ let skippedRoot;
245
+ if (!rootEligibility.eligible) {
246
+ skippedRoot = { path: ".", reason: rootEligibility.reason || "root skipped" };
247
+ }
248
+ // Collect eligible subdirectories
249
+ const eligibilityOpts = {
250
+ includeAgentFolders: opts.includeAgentFolders,
251
+ includeHidden: opts.includeHidden,
252
+ skipRoot: true, // Always skip root in collectDirs, we handle it separately
253
+ };
254
+ const { eligible: dirs, ineligible: skippedIneligible } = collectDirs(repoRoot, repoRoot, eligibilityOpts);
255
+ // Build the list of dirs to process
256
+ const dirsToProcess = [];
257
+ if (rootEligibility.eligible) {
258
+ dirsToProcess.push(".");
259
+ }
260
+ dirsToProcess.push(...dirs);
261
+ const written = [];
262
+ const skippedExists = [];
263
+ const skippedDraft = [];
264
+ for (const relDir of dirsToProcess) {
265
+ const absDir = (0, node_path_1.resolve)(repoRoot, relDir);
266
+ const outFile = (0, node_path_1.join)(absDir, "POLARIS.md");
267
+ if ((0, node_fs_1.existsSync)(outFile)) {
268
+ if (hasDraftMarker(outFile)) {
269
+ skippedDraft.push(relDir);
270
+ }
271
+ else {
272
+ skippedExists.push(relDir);
273
+ }
274
+ continue;
275
+ }
276
+ const content = generateDraft(relDir, repoRoot, allRoutes);
277
+ if (!opts.dryRun) {
278
+ (0, node_fs_1.writeFileSync)(outFile, content, "utf-8");
279
+ }
280
+ written.push(relDir);
281
+ }
282
+ return { written, skippedExists, skippedDraft, skippedIneligible, skippedRoot };
283
+ }
284
+ function seedSummaryAll(repoRoot, opts = {}) {
285
+ const config = (0, loader_js_1.loadConfig)(repoRoot);
286
+ const atlasPath = (0, node_path_1.resolve)(repoRoot, config.repo.sidecarOutputPath ?? ".polaris/map");
287
+ const allRoutes = {
288
+ ...(0, atlas_js_1.readFileRoutes)(atlasPath),
289
+ ...(0, atlas_js_1.readNeedsReview)(atlasPath),
290
+ };
291
+ // Root handling: skipped by default for SUMMARY.md (match POLARIS.md behavior)
292
+ const rootEligibility = (0, smartdoc_ignore_js_1.isDirectoryEligible)(repoRoot, repoRoot, {
293
+ isRoot: true,
294
+ skipRoot: opts.includeRoot ? false : true,
295
+ });
296
+ let skippedRoot;
297
+ if (!rootEligibility.eligible) {
298
+ skippedRoot = { path: ".", reason: rootEligibility.reason || "root skipped" };
299
+ }
300
+ // Collect eligible subdirectories
301
+ const eligibilityOpts = {
302
+ includeAgentFolders: opts.includeAgentFolders,
303
+ includeHidden: opts.includeHidden,
304
+ skipRoot: true, // Always skip root in collectDirs, we handle it separately
305
+ };
306
+ const { eligible: dirs, ineligible: skippedIneligible } = collectDirs(repoRoot, repoRoot, eligibilityOpts);
307
+ // Build the list of dirs to process
308
+ const dirsToProcess = [];
309
+ if (rootEligibility.eligible) {
310
+ dirsToProcess.push(".");
311
+ }
312
+ dirsToProcess.push(...dirs);
313
+ const written = [];
314
+ const skippedExists = [];
315
+ const skippedDraft = [];
316
+ for (const relDir of dirsToProcess) {
317
+ const absDir = (0, node_path_1.resolve)(repoRoot, relDir);
318
+ const outFile = (0, node_path_1.join)(absDir, "SUMMARY.md");
319
+ if ((0, node_fs_1.existsSync)(outFile)) {
320
+ if (hasDraftMarker(outFile)) {
321
+ skippedDraft.push(relDir);
322
+ }
323
+ else {
324
+ skippedExists.push(relDir);
325
+ }
326
+ continue;
327
+ }
328
+ const content = generateSummaryDraft(relDir, repoRoot, allRoutes);
329
+ if (!opts.dryRun) {
330
+ (0, node_fs_1.writeFileSync)(outFile, content, "utf-8");
331
+ }
332
+ written.push(relDir);
333
+ }
334
+ return { written, skippedExists, skippedDraft, skippedIneligible, skippedRoot };
335
+ }
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const seed_instructions_js_1 = require("./seed-instructions.js");
7
+ const TMP = (0, node_path_1.join)(process.cwd(), ".test-docs-seed-tmp");
8
+ function makeEntry(overrides = {}) {
9
+ return {
10
+ domain: "test-domain",
11
+ route: "test-route",
12
+ taskchain: "test-chain",
13
+ confidence: 0.9,
14
+ classification: "indexed",
15
+ last_updated: "2026-01-01T00:00:00Z",
16
+ updated_by: "test",
17
+ tags: [],
18
+ ...overrides,
19
+ };
20
+ }
21
+ function setup() {
22
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "src/map"), { recursive: true });
23
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "src/cli"), { recursive: true });
24
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, ".polaris/map"), { recursive: true });
25
+ // Minimal polaris.config.json so loadConfig doesn't fail
26
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "polaris.config.json"), JSON.stringify({ repo: {}, map: {} }));
27
+ // Empty atlas files
28
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, ".polaris/map/file-routes.json"), JSON.stringify({}));
29
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, ".polaris/map/needs-review.json"), JSON.stringify({}));
30
+ }
31
+ function teardown() {
32
+ (0, node_fs_1.rmSync)(TMP, { recursive: true, force: true });
33
+ }
34
+ (0, vitest_1.describe)("hasDraftMarker", () => {
35
+ (0, vitest_1.beforeEach)(setup);
36
+ (0, vitest_1.afterEach)(teardown);
37
+ (0, vitest_1.it)("returns true when file starts with draft marker", () => {
38
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "POLARIS.md"), `${seed_instructions_js_1.DRAFT_MARKER}\n# title`);
39
+ (0, vitest_1.expect)((0, seed_instructions_js_1.hasDraftMarker)((0, node_path_1.join)(TMP, "POLARIS.md"))).toBe(true);
40
+ });
41
+ (0, vitest_1.it)("returns false when file has no draft marker", () => {
42
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "POLARIS.md"), "# Human-written doc");
43
+ (0, vitest_1.expect)((0, seed_instructions_js_1.hasDraftMarker)((0, node_path_1.join)(TMP, "POLARIS.md"))).toBe(false);
44
+ });
45
+ (0, vitest_1.it)("returns false for nonexistent file", () => {
46
+ (0, vitest_1.expect)((0, seed_instructions_js_1.hasDraftMarker)((0, node_path_1.join)(TMP, "nonexistent.md"))).toBe(false);
47
+ });
48
+ });
49
+ (0, vitest_1.describe)("generateDraft", () => {
50
+ (0, vitest_1.it)("includes draft marker at top", () => {
51
+ const content = (0, seed_instructions_js_1.generateDraft)("src/map", TMP, {});
52
+ (0, vitest_1.expect)(content.startsWith(seed_instructions_js_1.DRAFT_MARKER)).toBe(true);
53
+ });
54
+ (0, vitest_1.it)("uses directory basename as heading", () => {
55
+ const content = (0, seed_instructions_js_1.generateDraft)("src/map", TMP, {});
56
+ (0, vitest_1.expect)(content).toContain("# map");
57
+ });
58
+ (0, vitest_1.it)("includes domain and route from atlas entries in that directory", () => {
59
+ const routes = {
60
+ "src/map/atlas.ts": makeEntry({ domain: "atlas", route: "polaris-map" }),
61
+ };
62
+ const content = (0, seed_instructions_js_1.generateDraft)("src/map", TMP, routes);
63
+ (0, vitest_1.expect)(content).toContain("atlas");
64
+ (0, vitest_1.expect)(content).toContain("polaris-map");
65
+ });
66
+ (0, vitest_1.it)("lists files in the directory", () => {
67
+ const routes = {
68
+ "src/map/atlas.ts": makeEntry({ domain: "atlas", route: "polaris-map" }),
69
+ "src/map/update.ts": makeEntry({ domain: "atlas", route: "polaris-map" }),
70
+ };
71
+ const content = (0, seed_instructions_js_1.generateDraft)("src/map", TMP, routes);
72
+ (0, vitest_1.expect)(content).toContain("`atlas.ts`");
73
+ (0, vitest_1.expect)(content).toContain("`update.ts`");
74
+ });
75
+ (0, vitest_1.it)("does not include files from other directories", () => {
76
+ const routes = {
77
+ "src/cli/index.ts": makeEntry({ domain: "cli", route: "polaris-cli" }),
78
+ "src/map/atlas.ts": makeEntry({ domain: "atlas", route: "polaris-map" }),
79
+ };
80
+ const content = (0, seed_instructions_js_1.generateDraft)("src/map", TMP, routes);
81
+ (0, vitest_1.expect)(content).not.toContain("`index.ts`");
82
+ });
83
+ });
84
+ (0, vitest_1.describe)("seedInstructions", () => {
85
+ (0, vitest_1.beforeEach)(setup);
86
+ (0, vitest_1.afterEach)(teardown);
87
+ (0, vitest_1.it)("writes a POLARIS.md draft and returns written", () => {
88
+ const result = (0, seed_instructions_js_1.seedInstructions)("src/map", TMP);
89
+ (0, vitest_1.expect)(result).toBe("written");
90
+ const outPath = (0, node_path_1.join)(TMP, "src/map/POLARIS.md");
91
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)(outPath)).toBe(true);
92
+ const content = (0, node_fs_1.readFileSync)(outPath, "utf-8");
93
+ (0, vitest_1.expect)(content).toContain(seed_instructions_js_1.DRAFT_MARKER);
94
+ });
95
+ (0, vitest_1.it)("returns skipped-exists when human-edited POLARIS.md present", () => {
96
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/POLARIS.md"), "# Human-edited");
97
+ const result = (0, seed_instructions_js_1.seedInstructions)("src/map", TMP);
98
+ (0, vitest_1.expect)(result).toBe("skipped-exists");
99
+ });
100
+ (0, vitest_1.it)("returns skipped-draft when draft POLARIS.md already present", () => {
101
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/POLARIS.md"), `${seed_instructions_js_1.DRAFT_MARKER}\n# Draft`);
102
+ const result = (0, seed_instructions_js_1.seedInstructions)("src/map", TMP);
103
+ (0, vitest_1.expect)(result).toBe("skipped-draft");
104
+ });
105
+ (0, vitest_1.it)("does not write file in dry-run mode", () => {
106
+ const result = (0, seed_instructions_js_1.seedInstructions)("src/map", TMP, { dryRun: true });
107
+ (0, vitest_1.expect)(result).toBe("written");
108
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(TMP, "src/map/POLARIS.md"))).toBe(false);
109
+ });
110
+ });
111
+ (0, vitest_1.describe)("seedInstructionsAll", () => {
112
+ (0, vitest_1.beforeEach)(setup);
113
+ (0, vitest_1.afterEach)(teardown);
114
+ (0, vitest_1.it)("generates drafts for directories without POLARIS.md", () => {
115
+ const { written, skippedIneligible } = (0, seed_instructions_js_1.seedInstructionsAll)(TMP);
116
+ (0, vitest_1.expect)(written).toContain("src/map");
117
+ (0, vitest_1.expect)(written).toContain("src/cli");
118
+ (0, vitest_1.expect)(skippedIneligible).toBeDefined();
119
+ });
120
+ (0, vitest_1.it)("skips directories with human-edited POLARIS.md", () => {
121
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/POLARIS.md"), "# Human-edited");
122
+ const { written, skippedExists, skippedIneligible } = (0, seed_instructions_js_1.seedInstructionsAll)(TMP);
123
+ (0, vitest_1.expect)(skippedExists).toContain("src/map");
124
+ (0, vitest_1.expect)(written).not.toContain("src/map");
125
+ (0, vitest_1.expect)(skippedIneligible).toBeDefined();
126
+ });
127
+ (0, vitest_1.it)("skips directories with draft POLARIS.md", () => {
128
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/POLARIS.md"), `${seed_instructions_js_1.DRAFT_MARKER}\n# Draft`);
129
+ const { skippedDraft, skippedIneligible } = (0, seed_instructions_js_1.seedInstructionsAll)(TMP);
130
+ (0, vitest_1.expect)(skippedDraft).toContain("src/map");
131
+ (0, vitest_1.expect)(skippedIneligible).toBeDefined();
132
+ });
133
+ (0, vitest_1.it)("does not write files in dry-run mode", () => {
134
+ const { written, skippedIneligible } = (0, seed_instructions_js_1.seedInstructionsAll)(TMP, { dryRun: true });
135
+ (0, vitest_1.expect)(written.length).toBeGreaterThan(0);
136
+ for (const dir of written) {
137
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(TMP, dir, "POLARIS.md"))).toBe(false);
138
+ }
139
+ (0, vitest_1.expect)(skippedIneligible).toBeDefined();
140
+ });
141
+ (0, vitest_1.it)("skips ineligible directories like node_modules and dist", () => {
142
+ // Create ineligible directories
143
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "node_modules"), { recursive: true });
144
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "dist"), { recursive: true });
145
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "src/node_modules"), { recursive: true });
146
+ const { written, skippedIneligible } = (0, seed_instructions_js_1.seedInstructionsAll)(TMP);
147
+ // node_modules and dist should be in skippedIneligible
148
+ const ineligiblePaths = skippedIneligible.map((s) => s.path);
149
+ (0, vitest_1.expect)(ineligiblePaths).toContain("node_modules");
150
+ (0, vitest_1.expect)(ineligiblePaths).toContain("dist");
151
+ (0, vitest_1.expect)(ineligiblePaths).toContain("src/node_modules");
152
+ // node_modules and dist should NOT be in written
153
+ (0, vitest_1.expect)(written).not.toContain("node_modules");
154
+ (0, vitest_1.expect)(written).not.toContain("dist");
155
+ (0, vitest_1.expect)(written).not.toContain("src/node_modules");
156
+ });
157
+ (0, vitest_1.it)("skips root by default for POLARIS.md", () => {
158
+ const { written, skippedRoot } = (0, seed_instructions_js_1.seedInstructionsAll)(TMP);
159
+ // Root should not be in written
160
+ (0, vitest_1.expect)(written).not.toContain(".");
161
+ // Root should be in skippedRoot
162
+ (0, vitest_1.expect)(skippedRoot).toBeDefined();
163
+ (0, vitest_1.expect)(skippedRoot?.path).toBe(".");
164
+ });
165
+ (0, vitest_1.it)("includes root when includeRoot option is set", () => {
166
+ const { written, skippedRoot } = (0, seed_instructions_js_1.seedInstructionsAll)(TMP, { includeRoot: true });
167
+ // Root should be in written
168
+ (0, vitest_1.expect)(written).toContain(".");
169
+ // Root should not be in skippedRoot
170
+ (0, vitest_1.expect)(skippedRoot).toBeUndefined();
171
+ });
172
+ });
173
+ (0, vitest_1.describe)("generateSummaryDraft", () => {
174
+ (0, vitest_1.it)("includes draft marker at top", () => {
175
+ const content = (0, seed_instructions_js_1.generateSummaryDraft)("src/map", TMP, {});
176
+ (0, vitest_1.expect)(content.startsWith(seed_instructions_js_1.DRAFT_MARKER)).toBe(true);
177
+ });
178
+ (0, vitest_1.it)("uses directory basename in heading", () => {
179
+ const content = (0, seed_instructions_js_1.generateSummaryDraft)("src/map", TMP, {});
180
+ (0, vitest_1.expect)(content).toContain("# Summary: map");
181
+ });
182
+ (0, vitest_1.it)("includes all standard schema sections", () => {
183
+ const content = (0, seed_instructions_js_1.generateSummaryDraft)("src/map", TMP, {});
184
+ (0, vitest_1.expect)(content).toContain("## Purpose");
185
+ (0, vitest_1.expect)(content).toContain("## Core Concepts");
186
+ (0, vitest_1.expect)(content).toContain("## Architectural Role");
187
+ (0, vitest_1.expect)(content).toContain("## Key Constraints");
188
+ (0, vitest_1.expect)(content).toContain("## Important Relationships");
189
+ (0, vitest_1.expect)(content).toContain("## Current State");
190
+ (0, vitest_1.expect)(content).toContain("## Known Drift");
191
+ (0, vitest_1.expect)(content).toContain("## Linked Canonical Sources");
192
+ });
193
+ });
194
+ (0, vitest_1.describe)("seedSummary", () => {
195
+ (0, vitest_1.beforeEach)(setup);
196
+ (0, vitest_1.afterEach)(teardown);
197
+ (0, vitest_1.it)("writes a SUMMARY.md draft and returns written", () => {
198
+ const result = (0, seed_instructions_js_1.seedSummary)("src/map", TMP);
199
+ (0, vitest_1.expect)(result).toBe("written");
200
+ const outPath = (0, node_path_1.join)(TMP, "src/map/SUMMARY.md");
201
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)(outPath)).toBe(true);
202
+ const content = (0, node_fs_1.readFileSync)(outPath, "utf-8");
203
+ (0, vitest_1.expect)(content).toContain(seed_instructions_js_1.DRAFT_MARKER);
204
+ (0, vitest_1.expect)(content).toContain("# Summary: map");
205
+ });
206
+ (0, vitest_1.it)("returns skipped-exists when human-edited SUMMARY.md present", () => {
207
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/SUMMARY.md"), "# Human-edited");
208
+ const result = (0, seed_instructions_js_1.seedSummary)("src/map", TMP);
209
+ (0, vitest_1.expect)(result).toBe("skipped-exists");
210
+ });
211
+ (0, vitest_1.it)("returns skipped-draft when draft SUMMARY.md already present", () => {
212
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/SUMMARY.md"), `${seed_instructions_js_1.DRAFT_MARKER}\n# Draft`);
213
+ const result = (0, seed_instructions_js_1.seedSummary)("src/map", TMP);
214
+ (0, vitest_1.expect)(result).toBe("skipped-draft");
215
+ });
216
+ (0, vitest_1.it)("does not write file in dry-run mode", () => {
217
+ const result = (0, seed_instructions_js_1.seedSummary)("src/map", TMP, { dryRun: true });
218
+ (0, vitest_1.expect)(result).toBe("written");
219
+ (0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(TMP, "src/map/SUMMARY.md"))).toBe(false);
220
+ });
221
+ });
222
+ (0, vitest_1.describe)("seedSummaryAll", () => {
223
+ (0, vitest_1.beforeEach)(setup);
224
+ (0, vitest_1.afterEach)(teardown);
225
+ (0, vitest_1.it)("generates drafts for directories without SUMMARY.md", () => {
226
+ const { written, skippedIneligible } = (0, seed_instructions_js_1.seedSummaryAll)(TMP);
227
+ (0, vitest_1.expect)(written).toContain("src/map");
228
+ (0, vitest_1.expect)(written).toContain("src/cli");
229
+ (0, vitest_1.expect)(skippedIneligible).toBeDefined();
230
+ });
231
+ (0, vitest_1.it)("skips root by default for SUMMARY.md", () => {
232
+ const { written, skippedRoot } = (0, seed_instructions_js_1.seedSummaryAll)(TMP);
233
+ // Root should not be in written
234
+ (0, vitest_1.expect)(written).not.toContain(".");
235
+ // Root should be in skippedRoot
236
+ (0, vitest_1.expect)(skippedRoot).toBeDefined();
237
+ (0, vitest_1.expect)(skippedRoot?.path).toBe(".");
238
+ });
239
+ (0, vitest_1.it)("includes root when includeRoot option is set for SUMMARY.md", () => {
240
+ const { written, skippedRoot } = (0, seed_instructions_js_1.seedSummaryAll)(TMP, { includeRoot: true });
241
+ // Root should be in written
242
+ (0, vitest_1.expect)(written).toContain(".");
243
+ // Root should not be in skippedRoot
244
+ (0, vitest_1.expect)(skippedRoot).toBeUndefined();
245
+ });
246
+ (0, vitest_1.it)("skips directories with human-edited SUMMARY.md", () => {
247
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/SUMMARY.md"), "# Human-edited");
248
+ const { written, skippedExists, skippedIneligible } = (0, seed_instructions_js_1.seedSummaryAll)(TMP);
249
+ (0, vitest_1.expect)(skippedExists).toContain("src/map");
250
+ (0, vitest_1.expect)(written).not.toContain("src/map");
251
+ (0, vitest_1.expect)(skippedIneligible).toBeDefined();
252
+ });
253
+ (0, vitest_1.it)("skips directories with draft SUMMARY.md", () => {
254
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/SUMMARY.md"), `${seed_instructions_js_1.DRAFT_MARKER}\n# Draft`);
255
+ const { skippedDraft, skippedIneligible } = (0, seed_instructions_js_1.seedSummaryAll)(TMP);
256
+ (0, vitest_1.expect)(skippedDraft).toContain("src/map");
257
+ (0, vitest_1.expect)(skippedIneligible).toBeDefined();
258
+ });
259
+ (0, vitest_1.it)("skips ineligible directories like node_modules and dist", () => {
260
+ // Create ineligible directories
261
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "node_modules"), { recursive: true });
262
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "dist"), { recursive: true });
263
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "coverage"), { recursive: true });
264
+ const { written, skippedIneligible } = (0, seed_instructions_js_1.seedSummaryAll)(TMP);
265
+ // node_modules, dist, coverage should be in skippedIneligible
266
+ const ineligiblePaths = skippedIneligible.map((s) => s.path);
267
+ (0, vitest_1.expect)(ineligiblePaths).toContain("node_modules");
268
+ (0, vitest_1.expect)(ineligiblePaths).toContain("dist");
269
+ (0, vitest_1.expect)(ineligiblePaths).toContain("coverage");
270
+ // node_modules, dist, coverage should NOT be in written
271
+ (0, vitest_1.expect)(written).not.toContain("node_modules");
272
+ (0, vitest_1.expect)(written).not.toContain("dist");
273
+ (0, vitest_1.expect)(written).not.toContain("coverage");
274
+ });
275
+ });