@magic-spells/constellation 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/core/code.d.ts +46 -0
  2. package/dist/core/code.js +169 -0
  3. package/dist/core/code.js.map +1 -0
  4. package/dist/core/git.d.ts +8 -0
  5. package/dist/core/git.js +36 -4
  6. package/dist/core/git.js.map +1 -1
  7. package/dist/core/sync.d.ts +1 -0
  8. package/dist/core/sync.js +18 -8
  9. package/dist/core/sync.js.map +1 -1
  10. package/dist/core/validate.js +13 -2
  11. package/dist/core/validate.js.map +1 -1
  12. package/dist/core/writer.d.ts +25 -0
  13. package/dist/core/writer.js +65 -1
  14. package/dist/core/writer.js.map +1 -1
  15. package/dist/mcp/server.js +478 -16
  16. package/dist/mcp/server.js.map +1 -1
  17. package/docs/001-file-format.md +22 -4
  18. package/docs/002-mcp.md +29 -1
  19. package/docs/003-mcp-upgrade-plan.md +138 -0
  20. package/examples/constellation/datatype/DATATYPE-TICKET.md +5 -0
  21. package/package.json +4 -2
  22. package/schemas/card.json +46 -2
  23. package/skill/SKILL.md +34 -7
  24. package/skill/methodology.md +5 -2
  25. package/viewer/dist/assets/{arc-CMMRgIq9.js → arc-YuzGWkw8.js} +1 -1
  26. package/viewer/dist/assets/architecture-7EHR7CIX-BAboPvK1.js +1 -0
  27. package/viewer/dist/assets/{architectureDiagram-3BPJPVTR-CB5p_qlN.js → architectureDiagram-3BPJPVTR-BgksqMlF.js} +1 -1
  28. package/viewer/dist/assets/{blockDiagram-GPEHLZMM-DpnMj_e6.js → blockDiagram-GPEHLZMM-Bc6JILFK.js} +1 -1
  29. package/viewer/dist/assets/{c4Diagram-AAUBKEIU-f91ngVN8.js → c4Diagram-AAUBKEIU-CRVt42df.js} +1 -1
  30. package/viewer/dist/assets/channel-D8YnBgqu.js +1 -0
  31. package/viewer/dist/assets/{chunk-2J33WTMH-y7Pz5tMO.js → chunk-2J33WTMH-CpuwKeX6.js} +1 -1
  32. package/viewer/dist/assets/{chunk-3OPIFGDE-Ir_ghIUQ.js → chunk-3OPIFGDE-BG_ijJhE.js} +1 -1
  33. package/viewer/dist/assets/{chunk-4BX2VUAB-BTPyM1ux.js → chunk-4BX2VUAB-Bgz1tnDP.js} +1 -1
  34. package/viewer/dist/assets/{chunk-55IACEB6-CtNd8e4Y.js → chunk-55IACEB6-NdWURd2K.js} +1 -1
  35. package/viewer/dist/assets/{chunk-5ZQYHXKU-Dd3yz721.js → chunk-5ZQYHXKU-wzW5x_7z.js} +1 -1
  36. package/viewer/dist/assets/{chunk-727SXJPM-CAM8mGbv.js → chunk-727SXJPM-BxKeJXYf.js} +1 -1
  37. package/viewer/dist/assets/{chunk-AQP2D5EJ-C3nW9Uve.js → chunk-AQP2D5EJ-gPm6xhPX.js} +1 -1
  38. package/viewer/dist/assets/{chunk-BSJP7CBP-r6MRPvAH.js → chunk-BSJP7CBP-C30ZXEUD.js} +1 -1
  39. package/viewer/dist/assets/{chunk-CSCIHK7Q-Cn-ZTxsS.js → chunk-CSCIHK7Q-C9h7yfl1.js} +1 -1
  40. package/viewer/dist/assets/{chunk-FMBD7UC4-5axXeZJa.js → chunk-FMBD7UC4-BcSnkYc3.js} +1 -1
  41. package/viewer/dist/assets/{chunk-KSCS5N6A-BwmNx0l0.js → chunk-KSCS5N6A-rxSD5-MD.js} +1 -1
  42. package/viewer/dist/assets/{chunk-L5ZTLDWV-C2YNkUjB.js → chunk-L5ZTLDWV-DGwFsVWy.js} +1 -1
  43. package/viewer/dist/assets/{chunk-LZXEDZCA-CznuDgQD.js → chunk-LZXEDZCA-BY3sTuvt.js} +2 -2
  44. package/viewer/dist/assets/{chunk-ND2GUHAM-CokDnghi.js → chunk-ND2GUHAM-PqmKwdzq.js} +1 -1
  45. package/viewer/dist/assets/{chunk-NZK2D7GU-aaU0v4QE.js → chunk-NZK2D7GU-BAZbzxhl.js} +1 -1
  46. package/viewer/dist/assets/{chunk-O5CBEL6O-ByfKhkZf.js → chunk-O5CBEL6O-SvZfZ-0j.js} +1 -1
  47. package/viewer/dist/assets/chunk-QZHKN3VN-ClYnv9g5.js +1 -0
  48. package/viewer/dist/assets/chunk-WU5MYG2G-CvL2Yleq.js +1 -0
  49. package/viewer/dist/assets/{chunk-XPW4576I-Amo3awtq.js → chunk-XPW4576I-1OXPbRQX.js} +1 -1
  50. package/viewer/dist/assets/classDiagram-4FO5ZUOK-B8YUd1jx.js +1 -0
  51. package/viewer/dist/assets/classDiagram-v2-Q7XG4LA2-B8YUd1jx.js +1 -0
  52. package/viewer/dist/assets/{cose-bilkent-S5V4N54A-CO8yESCW.js → cose-bilkent-S5V4N54A-DtCvLpah.js} +1 -1
  53. package/viewer/dist/assets/{dagre-BM42HDAG-BnmNVNI2.js → dagre-BM42HDAG-B55Ilz10.js} +1 -1
  54. package/viewer/dist/assets/{diagram-2AECGRRQ-lcGXcbei.js → diagram-2AECGRRQ-ClqSMarp.js} +1 -1
  55. package/viewer/dist/assets/{diagram-5GNKFQAL-Cj3-lPUt.js → diagram-5GNKFQAL-Dx74UdxY.js} +1 -1
  56. package/viewer/dist/assets/{diagram-KO2AKTUF-CtXdRI4M.js → diagram-KO2AKTUF-Vj0buH8e.js} +1 -1
  57. package/viewer/dist/assets/{diagram-LMA3HP47-CIyLAzX7.js → diagram-LMA3HP47-DpEm8RZd.js} +1 -1
  58. package/viewer/dist/assets/{diagram-OG6HWLK6-BwF4bQCv.js → diagram-OG6HWLK6-Crl3BdwC.js} +1 -1
  59. package/viewer/dist/assets/{dist-DzXuQd4N.js → dist-C2uHOEFB.js} +1 -1
  60. package/viewer/dist/assets/{erDiagram-TEJ5UH35-DjwFw9yq.js → erDiagram-TEJ5UH35-B-Mf-EHP.js} +1 -1
  61. package/viewer/dist/assets/eventmodeling-FCH6USID-CZ5gxAxG.js +1 -0
  62. package/viewer/dist/assets/{flowDiagram-I6XJVG4X-CzXbf7vQ.js → flowDiagram-I6XJVG4X-B9stChWN.js} +1 -1
  63. package/viewer/dist/assets/{ganttDiagram-6RSMTGT7-BYcIhfmm.js → ganttDiagram-6RSMTGT7-DzWlclwM.js} +1 -1
  64. package/viewer/dist/assets/{gitGraph-WXDBUCRP-H8XeJ9QB.js → gitGraph-WXDBUCRP-CdVI3GTp.js} +1 -1
  65. package/viewer/dist/assets/{gitGraphDiagram-PVQCEYII-DtAPXKFK.js → gitGraphDiagram-PVQCEYII-Dn9yRc1N.js} +1 -1
  66. package/viewer/dist/assets/{index-DLPCG_Or.js → index-BsGRgBOD.js} +4 -4
  67. package/viewer/dist/assets/{info-J43DQDTF-BQScorZ0.js → info-J43DQDTF-CXV3Mm9T.js} +1 -1
  68. package/viewer/dist/assets/{infoDiagram-5YYISTIA-Udl1omvH.js → infoDiagram-5YYISTIA-zIUka_J2.js} +1 -1
  69. package/viewer/dist/assets/{ishikawaDiagram-YF4QCWOH-VnfzT_hk.js → ishikawaDiagram-YF4QCWOH-DsZwNuE3.js} +1 -1
  70. package/viewer/dist/assets/{journeyDiagram-JHISSGLW-Btn4EVoD.js → journeyDiagram-JHISSGLW-BhSTSB2s.js} +1 -1
  71. package/viewer/dist/assets/{kanban-definition-UN3LZRKU-flOzWhPe.js → kanban-definition-UN3LZRKU-sCAldj86.js} +1 -1
  72. package/viewer/dist/assets/{line-DJJ9BLuY.js → line-D7b3fopb.js} +1 -1
  73. package/viewer/dist/assets/{linear-C2SUy5ns.js → linear-BWlvVc_d.js} +1 -1
  74. package/viewer/dist/assets/{mermaid-parser.core-xhSeYiZo.js → mermaid-parser.core-BdEYBvaj.js} +2 -2
  75. package/viewer/dist/assets/{mermaid.core-DmeSIitY.js → mermaid.core-C9bGWeJU.js} +3 -3
  76. package/viewer/dist/assets/{mindmap-definition-RKZ34NQL-CCJcMKx1.js → mindmap-definition-RKZ34NQL-DbTvvku-.js} +1 -1
  77. package/viewer/dist/assets/{packet-YPE3B663-DS8RscAk.js → packet-YPE3B663-DRfLruyq.js} +1 -1
  78. package/viewer/dist/assets/{pie-LRSECV5Y-I2ZQhrNJ.js → pie-LRSECV5Y-47xXMkK-.js} +1 -1
  79. package/viewer/dist/assets/{pieDiagram-4H26LBE5-BS5HMs4j.js → pieDiagram-4H26LBE5-Ckno9E1M.js} +1 -1
  80. package/viewer/dist/assets/{quadrantDiagram-W4KKPZXB-W4H8cw2_.js → quadrantDiagram-W4KKPZXB-XB5kJ_2c.js} +1 -1
  81. package/viewer/dist/assets/{radar-GUYGQ44K-kf6QvSne.js → radar-GUYGQ44K-CLwIH5Zr.js} +1 -1
  82. package/viewer/dist/assets/{requirementDiagram-4Y6WPE33-DSbuDQGQ.js → requirementDiagram-4Y6WPE33-D3fApL0X.js} +1 -1
  83. package/viewer/dist/assets/{sankeyDiagram-5OEKKPKP-CH8Qr2vL.js → sankeyDiagram-5OEKKPKP-6UdaRhuZ.js} +1 -1
  84. package/viewer/dist/assets/{sequenceDiagram-3UESZ5HK-EugVcdad.js → sequenceDiagram-3UESZ5HK-ClIrrs0w.js} +1 -1
  85. package/viewer/dist/assets/{src-CM_9kdrU.js → src-BPb55SrS.js} +1 -1
  86. package/viewer/dist/assets/{stateDiagram-AJRCARHV-DiFl94Qy.js → stateDiagram-AJRCARHV-CCsrcv5R.js} +1 -1
  87. package/viewer/dist/assets/stateDiagram-v2-BHNVJYJU-C1phrPNi.js +1 -0
  88. package/viewer/dist/assets/{timeline-definition-PNZ67QCA-B0KW9GUN.js → timeline-definition-PNZ67QCA-BkiWQlVI.js} +1 -1
  89. package/viewer/dist/assets/{treeView-BLDUP644-CAEY4mxq.js → treeView-BLDUP644-m1mGpAE8.js} +1 -1
  90. package/viewer/dist/assets/{treemap-LRROVOQU-VVaEaTlU.js → treemap-LRROVOQU-Bapvwi0Q.js} +1 -1
  91. package/viewer/dist/assets/{vennDiagram-CIIHVFJN-BSLGNfJd.js → vennDiagram-CIIHVFJN-BlH71Nmx.js} +1 -1
  92. package/viewer/dist/assets/{wardley-L42UT6IY-C-5cXbAU.js → wardley-L42UT6IY-CPRSoKgV.js} +1 -1
  93. package/viewer/dist/assets/{wardleyDiagram-YWT4CUSO-COk4TVnQ.js → wardleyDiagram-YWT4CUSO-C-ptFJ9t.js} +1 -1
  94. package/viewer/dist/assets/{xychartDiagram-2RQKCTM6-CClGJLJp.js → xychartDiagram-2RQKCTM6-C4rfeH4W.js} +1 -1
  95. package/viewer/dist/index.html +1 -1
  96. package/viewer/dist/assets/architecture-7EHR7CIX-Cbb-syEI.js +0 -1
  97. package/viewer/dist/assets/channel-C2bkEQHQ.js +0 -1
  98. package/viewer/dist/assets/chunk-QZHKN3VN-DJRjGeIo.js +0 -1
  99. package/viewer/dist/assets/chunk-WU5MYG2G-C63BVvr_.js +0 -1
  100. package/viewer/dist/assets/classDiagram-4FO5ZUOK-z_bO1V-j.js +0 -1
  101. package/viewer/dist/assets/classDiagram-v2-Q7XG4LA2-z_bO1V-j.js +0 -1
  102. package/viewer/dist/assets/eventmodeling-FCH6USID-BlKFmSzA.js +0 -1
  103. package/viewer/dist/assets/stateDiagram-v2-BHNVJYJU-BlJV8F13.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { readFile, rm } from 'node:fs/promises';
1
+ import { readFile, rm, stat } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
@@ -9,12 +9,28 @@ import { loadPlan } from '../core/indexer.js';
9
9
  import { lintPlan } from '../core/lint.js';
10
10
  import { resolvePlanDir } from '../core/resolve.js';
11
11
  import { TYPE_NAMES } from '../core/types.js';
12
- import { diffPlan, planDirty, planLog, writeSyncPoint } from '../core/git.js';
12
+ import { changedFilesSince, diffPlan, headSha, planDirty, planLog, readSyncPoint, writeSyncPoint, } from '../core/git.js';
13
+ import { computeSyncStatus } from '../core/sync.js';
14
+ import { boundPathsForCard, resolveCodeForCard } from '../core/code.js';
13
15
  import { searchCards } from './search.js';
14
- import { applyCardPatch, createCardFile, deepMerge, relPathForHandle, reservedFieldKeys, updateCardFile, } from '../core/writer.js';
16
+ import { applyCardPatch, bodyHeadingTexts, createCardFile, deepMerge, relPathForHandle, replaceBodySection, reservedFieldKeys, updateCardFile, withAppendedNote, } from '../core/writer.js';
15
17
  import { connectedRepoToFm, listConnectedRepos, readConnectedRepos, removeConnectedRepoEntry, resolveConnectedRepo, upsertConnectedRepo, } from '../core/repos.js';
16
18
  const INSTRUCTIONS = `# Constellation MCP
17
19
 
20
+ Constellation is this project's durable, cross-session memory for AI agents — treat it as
21
+ memory you share with every past and future agent, not docs you skim. Before changing code
22
+ an area's cards cover, READ those cards: you're recovering prior agents' understanding, not
23
+ starting fresh. After changing that code, bring the cards back into line — that's part of
24
+ "done," like updating tests. The payoff is that understanding COMPOUNDS across sessions
25
+ instead of being re-derived from scratch each time; that only holds if you keep the cards
26
+ true. A card you can't trust is worse than no card.
27
+
28
+ Put in cards what the code can't say — intent, decisions (and the alternatives you rejected),
29
+ current built/live state, gotchas, cross-cutting rules. Do NOT duplicate what the repo already
30
+ holds — DDL, signatures, code: link to it instead; copies drift. "built"/"verified" is a
31
+ claim, not a fact — stamp it with set_verified so a later agent can re-check whether the bound
32
+ code moved (stale_report / check_sync). Durability, not distrust.
33
+
18
34
  The project's architecture plan lives as markdown files in a constellation/ folder.
19
35
  Each file is a **card** (the filename is the handle: api/API-TICKETS.md = API-TICKETS);
20
36
  cards are linked by undirected **connections** derived from the connections: frontmatter
@@ -22,11 +38,21 @@ list, handle-shaped frontmatter values, [[HANDLE]] body links, and mermaid node
22
38
 
23
39
  Retrieval is hydrated: get_card / search / traverse can return connected cards with
24
40
  their FULL frontmatter and body in one call (connected: "full"). Use that when you are
25
- about to work on an area; use "summary" for orientation.
41
+ about to work on an area; use "summary" for orientation. get_card can also hand back the
42
+ CODE a card is bound to — code: "paths" returns the resolved file paths of its connected
43
+ FILE cards (path:) plus its own code_refs; code: "direct" attaches their contents (capped,
44
+ binaries/lockfiles/generated skipped) so a background coder starts from intent + current
45
+ code in one call. assemble turns a delta (or a handle set) into a work package: the changed
46
+ cards + their neighborhood (full) + bound code + a heuristic build order + FILE-DISJOINT
47
+ units you can fan out one sub-agent per, with no two touching the same file.
26
48
 
27
49
  Writes are validated: every write tool lints and returns issues for the file it touched.
28
50
  update_card patch.fields deep-merges (arrays replace, null deletes); body replaces.
29
- Body-only updates never reformat frontmatter.
51
+ Body-only updates never reformat frontmatter. Prefer SMALL, cheap writes over rewriting a
52
+ whole card — make the honest update the easy one: append_note adds an append-only typed note
53
+ (decision / gotcha / state / deviation / verified) with no full-body rewrite; edit_section
54
+ replaces a single ## section in place. Reach for these to record a correction the moment you
55
+ learn it, so cards stay true instead of drifting.
30
56
 
31
57
  describe_type is the type reference, served by this server: call it with no args for the
32
58
  catalog of all 17 card types, or with a type (e.g. describe_type PAGE) for that type's
@@ -34,7 +60,13 @@ frontmatter schema + a golden example. Consult it before authoring a type you ha
34
60
  this session — you don't need the authoring skill loaded to get the fields right.
35
61
 
36
62
  Change tracking is git: diff_plan reports per-card changes since the sync marker (or HEAD).
37
- Never stamp dirty flags into cards.
63
+ Never stamp dirty flags or changelogs into cards — "what changed" is git's job. The one
64
+ recorded baseline that IS allowed is verification provenance: set_verified stamps verified_sha
65
+ (the git sha you checked a card against) + verified_at. That is the basis of a claim, not a
66
+ change flag — and the staleness VERDICT is always recomputed live (stale_report / check_sync),
67
+ never stored. stale_report lists built/verified cards whose bound code changed since their
68
+ verified_sha (reverse drift); check_sync rolls that per-card drift plus the plan-global state
69
+ into one definition-of-done verdict (advisory — the server reports, it can't block).
38
70
 
39
71
  "Sync the plan" / "sync the plan to the code" = bring the CODE up to match the plan (the
40
72
  plan is the source of truth — behavior changes in the plan FIRST, then in code, never the
@@ -62,9 +94,10 @@ changes as the proposal; on approval, bring the CODE up to match via the sync lo
62
94
  FINISH by reconciling — re-read the touched cards against the code, run check_integrity so
63
95
  no affected card is left an orphan and every connection is set, bump status (planned →
64
96
  building → built → verified), commit, and set_sync_point. In plan mode the write tools are
65
- unavailable by design (the read tools — get_card, list_cards, search, traverse,
66
- describe_type, check_integrity, diff_plan, plan_log are marked read-only and stay
67
- available), so spend plan mode READING: pull in as much of the relevant plan as you can
97
+ unavailable by design (the read tools — get_card, list_cards, search, traverse, assemble,
98
+ describe_type, check_integrity, diff_plan, plan_log, stale_report, check_sync,
99
+ list_connected_repos — are marked read-only and stay available), so spend plan mode READING:
100
+ pull in as much of the relevant plan as you can
68
101
  (traverse from the entry points, connected: "full") to build a strong model of the project
69
102
  fast, fold the intended card edits into the plan you present, and write them to
70
103
  Constellation first, before any code, once the user approves.
@@ -231,15 +264,137 @@ function connectedCards(index, handle, detail) {
231
264
  function issuesForFile(issues, relPath) {
232
265
  return issues.filter((i) => i.file === relPath);
233
266
  }
267
+ /**
268
+ * Code-side drift: for every card that makes a claim about code it is bound to
269
+ * (status built/verified, or carrying a verified_sha) compare its bound files
270
+ * against its baseline (its own verified_sha, else the passed base, else the
271
+ * sync marker). A card whose bound code changed — or whose bound file vanished —
272
+ * since it was verified is stale. The verdict is computed live and never stored.
273
+ * Shared by stale_report and check_sync.
274
+ */
275
+ async function computeStaleCards(root, index, base) {
276
+ let marker = null;
277
+ try {
278
+ marker = (await readSyncPoint(root))?.synced_sha ?? null;
279
+ }
280
+ catch {
281
+ marker = null;
282
+ }
283
+ const fallback = base ?? marker ?? null;
284
+ const stale = [];
285
+ const noBaseline = [];
286
+ let checked = 0;
287
+ for (const card of index.cards.values()) {
288
+ const verifiedSha = typeof card.frontmatter.verified_sha === 'string'
289
+ ? card.frontmatter.verified_sha
290
+ : undefined;
291
+ const isClaim = card.status === 'built' || card.status === 'verified' || Boolean(verifiedSha);
292
+ if (!isClaim)
293
+ continue;
294
+ if (boundPathsForCard(index, card).length === 0)
295
+ continue;
296
+ checked++;
297
+ const baseline = verifiedSha ?? fallback ?? undefined;
298
+ const resolved = await resolveCodeForCard(root, index, card, 'paths');
299
+ const paths = resolved.files.map((f) => f.path);
300
+ const missing = resolved.files.filter((f) => !f.exists).map((f) => f.path);
301
+ if (!baseline) {
302
+ noBaseline.push({ handle: card.handle, status: card.status ?? null, files: paths });
303
+ continue;
304
+ }
305
+ let changed;
306
+ try {
307
+ changed = await changedFilesSince(root, baseline, paths);
308
+ }
309
+ catch {
310
+ noBaseline.push({
311
+ handle: card.handle,
312
+ status: card.status ?? null,
313
+ files: paths,
314
+ reason: `baseline ${baseline.slice(0, 8)} unreachable in git history`,
315
+ });
316
+ continue;
317
+ }
318
+ const changedFiles = paths.filter((p) => changed.has(p));
319
+ if (changedFiles.length > 0 || missing.length > 0) {
320
+ stale.push({
321
+ handle: card.handle,
322
+ name: card.name ?? null,
323
+ status: card.status ?? null,
324
+ baseline: baseline.slice(0, 12),
325
+ baseline_source: verifiedSha ? 'verified_sha' : base ? 'argument' : 'sync-marker',
326
+ changed_files: changedFiles,
327
+ missing_files: missing,
328
+ });
329
+ }
330
+ }
331
+ return { checked, stale, no_baseline: noBaseline };
332
+ }
333
+ // Rough dependency tiers for assemble's suggested build order: data first, then
334
+ // contracts, then surfaces. Connections are undirected, so this is a heuristic
335
+ // by type, not a true topological sort.
336
+ const TYPE_TIER = {
337
+ DB: 0, DATATYPE: 1, ROLE: 2, EXTERNAL: 2, EVENT: 2,
338
+ API: 3, JOB: 3, STATE: 4, FLOW: 4, COMPONENT: 5, PAGE: 6,
339
+ FILE: 7, TEST: 8, DOC: 9, DIAGRAM: 9, AGENT: 9, PLAN: 9,
340
+ };
341
+ const tierOf = (type) => TYPE_TIER[type] ?? 5;
342
+ /**
343
+ * Partition seed handles into groups whose bound file sets are disjoint, so each
344
+ * group can be handed to its own sub-agent with no risk of two agents editing
345
+ * the same file. Seeds that share any bound file land in the same group.
346
+ */
347
+ function partitionByFiles(seeds, filesBy) {
348
+ const parent = new Map();
349
+ seeds.forEach((s) => parent.set(s, s));
350
+ const find = (x) => {
351
+ let root = x;
352
+ while (parent.get(root) !== root)
353
+ root = parent.get(root);
354
+ while (parent.get(x) !== root) {
355
+ const next = parent.get(x);
356
+ parent.set(x, root);
357
+ x = next;
358
+ }
359
+ return root;
360
+ };
361
+ const union = (a, b) => parent.set(find(a), find(b));
362
+ const fileOwner = new Map();
363
+ for (const s of seeds) {
364
+ for (const f of filesBy.get(s) ?? []) {
365
+ const owner = fileOwner.get(f);
366
+ if (owner)
367
+ union(owner, s);
368
+ else
369
+ fileOwner.set(f, s);
370
+ }
371
+ }
372
+ const groups = new Map();
373
+ for (const s of seeds) {
374
+ const r = find(s);
375
+ if (!groups.has(r))
376
+ groups.set(r, { handles: [], files: new Set() });
377
+ const g = groups.get(r);
378
+ g.handles.push(s);
379
+ for (const f of filesBy.get(s) ?? [])
380
+ g.files.add(f);
381
+ }
382
+ return [...groups.values()].map((g) => ({
383
+ handles: g.handles.sort(),
384
+ files: [...g.files].sort(),
385
+ }));
386
+ }
234
387
  const detailSchema = z.enum(['none', 'summary', 'full']);
235
388
  const typeSchema = z.enum(TYPE_NAMES);
236
389
  const statusSchema = z.enum(['planned', 'building', 'built', 'verified']);
390
+ const noteKindSchema = z.enum(['decision', 'gotcha', 'state', 'deviation', 'verified']);
391
+ const codeModeSchema = z.enum(['none', 'paths', 'direct']);
237
392
  const repoSchema = z
238
393
  .string()
239
394
  .optional()
240
395
  .describe('Target a connected repo by its connected_repos name (or a path). Omit to use the current repo.');
241
396
  export function buildServer(options = {}) {
242
- const server = new McpServer({ name: 'constellation', version: '0.2.1' }, { instructions: INSTRUCTIONS });
397
+ const server = new McpServer({ name: 'constellation', version: '0.2.2' }, { instructions: INSTRUCTIONS });
243
398
  server.registerPrompt('bootstrap_plan', {
244
399
  title: 'Bootstrap a plan from the codebase',
245
400
  description: 'Analyze this repository macro→micro and build (or extend) the Constellation plan: follow the data and the user/auth journeys, capture flows, diagrams, and state machines, ask the user what the code cannot answer, and flag gaps.',
@@ -349,21 +504,47 @@ export function buildServer(options = {}) {
349
504
  });
350
505
  server.registerTool('get_card', {
351
506
  annotations: { readOnlyHint: true },
352
- description: 'Fetch one card by handle, optionally with all connected cards hydrated. connected: "full" returns the complete frontmatter and body of every connected card — use it when about to work on an area.',
507
+ description: 'Fetch one card by handle, optionally with all connected cards hydrated. connected: "full" returns the complete frontmatter and body of every connected card — use it when about to work on an area. code: "paths" returns the resolved file paths the card is bound to (connected FILE cards plus code_refs); code: "direct" attaches their contents (capped, binaries/lockfiles/generated skipped) so a background coder starts from intent + current code in one call.',
353
508
  inputSchema: {
354
509
  handle: z.string(),
355
510
  connected: detailSchema.optional().describe('default: summary'),
511
+ code: codeModeSchema
512
+ .optional()
513
+ .describe('attach bound code: none (default) | paths | direct'),
514
+ notes_kind: noteKindSchema
515
+ .optional()
516
+ .describe('filter the returned card.notes to one kind'),
517
+ notes_limit: z
518
+ .number()
519
+ .int()
520
+ .min(1)
521
+ .max(100)
522
+ .optional()
523
+ .describe('return only the most recent N notes'),
356
524
  repo: repoSchema,
357
525
  },
358
- }, withPlan(async (root, { handle, connected }) => {
526
+ }, withPlan(async (root, { handle, connected, code, notes_kind, notes_limit }) => {
359
527
  const index = await loadPlan(root);
360
528
  const card = index.cards.get(handle.toUpperCase());
361
529
  if (!card)
362
530
  return fail('NOT_FOUND', `No card with handle ${handle}`);
363
- return ok({
364
- card: full(card),
531
+ let cardView = full(card);
532
+ if ((notes_kind || notes_limit) && Array.isArray(card.frontmatter.notes)) {
533
+ let notes = card.frontmatter.notes.filter((n) => Boolean(n) && typeof n === 'object');
534
+ if (notes_kind)
535
+ notes = notes.filter((n) => n.kind === notes_kind);
536
+ if (notes_limit)
537
+ notes = notes.slice(-notes_limit);
538
+ cardView = { ...cardView, frontmatter: { ...card.frontmatter, notes } };
539
+ }
540
+ const result = {
541
+ card: cardView,
365
542
  connected_cards: connectedCards(index, card.handle, connected ?? 'summary'),
366
- });
543
+ };
544
+ if (code && code !== 'none') {
545
+ result.code = await resolveCodeForCard(root, index, card, code);
546
+ }
547
+ return ok(result);
367
548
  }));
368
549
  server.registerTool('list_cards', {
369
550
  annotations: { readOnlyHint: true },
@@ -468,6 +649,112 @@ export function buildServer(options = {}) {
468
649
  const connections = index.connections.filter((c) => distance.has(c.a) && distance.has(c.b));
469
650
  return ok({ cards, connections, not_found: missing });
470
651
  }));
652
+ server.registerTool('assemble', {
653
+ annotations: { readOnlyHint: true },
654
+ description: 'Turn a set of cards (or the plan delta since a base) into a ready-to-work package: the seed cards plus their connected neighborhood (full), the code each is bound to (code: paths|direct), a heuristic build order (data → contracts → surfaces), and — the key bit — the seeds split into FILE-DISJOINT units so you can hand one sub-agent per unit with no risk of two agents editing the same file. Omit handles to assemble everything changed since base (default: the sync marker). This is the orchestration bridge: diff_plan + traverse + code attach in one call.',
655
+ inputSchema: {
656
+ handles: z
657
+ .array(z.string())
658
+ .optional()
659
+ .describe('seed handles; omit to use the plan delta since base'),
660
+ base: z
661
+ .string()
662
+ .optional()
663
+ .describe('base for the delta when handles is omitted (default: sync marker)'),
664
+ depth: z
665
+ .number()
666
+ .int()
667
+ .min(0)
668
+ .max(3)
669
+ .optional()
670
+ .describe('neighborhood depth around each seed (default: 1)'),
671
+ code: codeModeSchema.optional().describe('attach bound code per card (default: paths)'),
672
+ repo: repoSchema,
673
+ },
674
+ }, withPlan(async (root, { handles, base, depth, code }) => {
675
+ const index = await loadPlan(root);
676
+ let seeds;
677
+ let delta = null;
678
+ if (handles && handles.length > 0) {
679
+ seeds = [...new Set(handles.map((h) => h.toUpperCase()))].filter((h) => index.cards.has(h));
680
+ }
681
+ else {
682
+ let diff;
683
+ try {
684
+ diff = await diffPlan(root, base);
685
+ }
686
+ catch (err) {
687
+ return fail('BAD_BASE', `Could not diff against base ${base ?? '(marker/HEAD)'}: ${err instanceof Error ? err.message : String(err)}. Pass a reachable base sha, or omit it to use the sync marker.`);
688
+ }
689
+ delta = { base: diff.base, base_source: diff.base_source };
690
+ seeds = [...new Set(diff.changes.map((c) => c.handle))].filter((h) => index.cards.has(h));
691
+ }
692
+ if (seeds.length === 0) {
693
+ return ok({
694
+ base: delta,
695
+ seeds: [],
696
+ units: [],
697
+ note: handles
698
+ ? 'None of the given handles exist in the plan.'
699
+ : 'No plan changes since base — nothing to assemble.',
700
+ });
701
+ }
702
+ const maxDepth = depth ?? 1;
703
+ const distance = new Map();
704
+ let frontier = seeds;
705
+ for (const s of seeds)
706
+ distance.set(s, 0);
707
+ for (let d = 1; d <= maxDepth && frontier.length > 0; d++) {
708
+ const next = [];
709
+ for (const h of frontier) {
710
+ for (const n of index.connectedHandles.get(h) ?? []) {
711
+ if (distance.has(n) || !index.cards.has(n))
712
+ continue;
713
+ distance.set(n, d);
714
+ next.push(n);
715
+ }
716
+ }
717
+ frontier = next;
718
+ }
719
+ const reached = [...distance.keys()];
720
+ const codeMode = code ?? 'paths';
721
+ const filesBy = new Map();
722
+ for (const s of seeds) {
723
+ filesBy.set(s, boundPathsForCard(index, index.cards.get(s)).map((b) => b.path));
724
+ }
725
+ const partitions = partitionByFiles(seeds, filesBy);
726
+ const suggestedOrder = [...reached].sort((a, b) => tierOf(index.cards.get(a).type) - tierOf(index.cards.get(b).type) ||
727
+ a.localeCompare(b));
728
+ const units = [];
729
+ for (const part of partitions) {
730
+ const cards = [];
731
+ for (const h of part.handles) {
732
+ const card = index.cards.get(h);
733
+ const entry = {
734
+ ...full(card),
735
+ connected_cards: connectedCards(index, h, 'full'),
736
+ };
737
+ if (codeMode !== 'none') {
738
+ entry.code = await resolveCodeForCard(root, index, card, codeMode);
739
+ }
740
+ cards.push(entry);
741
+ }
742
+ units.push({ handles: part.handles, files: part.files, cards });
743
+ }
744
+ return ok({
745
+ base: delta,
746
+ seeds,
747
+ reached_handles: reached,
748
+ suggested_order: suggestedOrder,
749
+ units,
750
+ fanout: {
751
+ unit_count: units.length,
752
+ note: units.length > 1
753
+ ? `${units.length} file-disjoint units — assign one sub-agent each; no two share a bound file. Still assign each card to exactly one agent.`
754
+ : 'One unit — the seeds share bound files (or have none); do not split across agents.',
755
+ },
756
+ });
757
+ }));
471
758
  server.registerTool('describe_type', {
472
759
  annotations: { readOnlyHint: true },
473
760
  description: 'The card-type reference, served straight from this package. Call with no args for the catalog — all 17 types with their prefix, folder, and one-line purpose. Call with a type for everything needed to author one: the frontmatter JSON Schema (fields, which are required, descriptions) plus the golden example and authoring guidance. Use it before writing a card of a type you have not authored this session — it is the contract create_card/create_cards/update_card validate against (W002/W003), so you do not need the authoring skill loaded to get the fields right.',
@@ -699,9 +986,13 @@ export function buildServer(options = {}) {
699
986
  })
700
987
  .optional(),
701
988
  body: z.string().optional(),
989
+ if_mtime: z
990
+ .number()
991
+ .optional()
992
+ .describe('optional stale-write guard: current rounded file mtime from a client-side stat or viewer payload'),
702
993
  repo: repoSchema,
703
994
  },
704
- }, withPlan(async (root, { handle, patch, body }) => {
995
+ }, withPlan(async (root, { handle, patch, body, if_mtime }) => {
705
996
  const index = await loadPlan(root);
706
997
  const card = index.cards.get(handle.toUpperCase());
707
998
  if (!card)
@@ -713,6 +1004,12 @@ export function buildServer(options = {}) {
713
1004
  if (reserved.length > 0) {
714
1005
  return fail('INVALID_FIELDS', `fields cannot contain reserved keys: ${reserved.join(', ')}`);
715
1006
  }
1007
+ if (typeof if_mtime === 'number' && if_mtime !== 0) {
1008
+ const current = Math.round((await stat(card.filePath)).mtimeMs);
1009
+ if (current !== if_mtime) {
1010
+ return fail('STALE', `${card.handle} changed on disk`);
1011
+ }
1012
+ }
716
1013
  const frontmatter = patch
717
1014
  ? applyCardPatch(card.frontmatter, patch)
718
1015
  : undefined;
@@ -724,6 +1021,123 @@ export function buildServer(options = {}) {
724
1021
  issues: issuesForFile(lint.issues, card.relPath),
725
1022
  });
726
1023
  }));
1024
+ server.registerTool('append_note', {
1025
+ description: 'Append one typed note to a card\'s memory — append-only, NO full-body rewrite (cheap, so the honest path stays the cheap path). kind: decision (a choice + why) | gotcha (a non-obvious trap) | state (current built/live reality) | deviation (where code intentionally differs from the card) | verified (a verification note). Capture what the code can\'t say; do NOT paste code/DDL/signatures that live in the repo — link to them. Notes are queryable by kind (get_card notes_kind) and ordered newest-last.',
1026
+ inputSchema: {
1027
+ handle: z.string(),
1028
+ kind: noteKindSchema,
1029
+ text: z.string().min(1).max(4000),
1030
+ sha: z
1031
+ .string()
1032
+ .optional()
1033
+ .describe('optional git sha this note was recorded against'),
1034
+ repo: repoSchema,
1035
+ },
1036
+ }, withPlan(async (root, { handle, kind, text, sha }) => {
1037
+ const index = await loadPlan(root);
1038
+ const card = index.cards.get(handle.toUpperCase());
1039
+ if (!card)
1040
+ return fail('NOT_FOUND', `No card with handle ${handle}`);
1041
+ const note = { kind, text };
1042
+ if (sha)
1043
+ note.sha = sha;
1044
+ const frontmatter = withAppendedNote(card.frontmatter, note);
1045
+ await updateCardFile(card.filePath, { frontmatter });
1046
+ const lint = await lintPlan(root);
1047
+ const updated = lint.index.cards.get(card.handle);
1048
+ return ok({
1049
+ card: updated ? full(updated) : null,
1050
+ note_count: Array.isArray(updated?.frontmatter.notes)
1051
+ ? updated.frontmatter.notes.length
1052
+ : 0,
1053
+ issues: issuesForFile(lint.issues, card.relPath),
1054
+ });
1055
+ }));
1056
+ server.registerTool('edit_section', {
1057
+ description: 'Replace the content under one markdown heading in a card\'s body, keeping every other section byte-for-byte — a cheap, surgical alternative to rewriting the whole body. Match the heading by its text (case-insensitive, no #). Errors if no such heading exists (use update_card to set the whole body or add a section).',
1058
+ inputSchema: {
1059
+ handle: z.string(),
1060
+ section: z
1061
+ .string()
1062
+ .describe('heading text to replace under, e.g. "Notes" or "Current state"'),
1063
+ text: z.string().describe('new markdown content for that section (heading kept)'),
1064
+ repo: repoSchema,
1065
+ },
1066
+ }, withPlan(async (root, { handle, section, text }) => {
1067
+ const index = await loadPlan(root);
1068
+ const card = index.cards.get(handle.toUpperCase());
1069
+ if (!card)
1070
+ return fail('NOT_FOUND', `No card with handle ${handle}`);
1071
+ const body = replaceBodySection(card.body, section, text);
1072
+ if (body === null) {
1073
+ const headings = bodyHeadingTexts(card.body);
1074
+ const target = section.trim().replace(/^#+\s*/, '').toLowerCase();
1075
+ const matchCount = headings.filter((h) => h.toLowerCase() === target).length;
1076
+ if (matchCount > 1) {
1077
+ return fail('AMBIGUOUS_SECTION', `${card.handle} has ${matchCount} headings called "${section}"; edit_section can't tell them apart. Use update_card to set the whole body.`);
1078
+ }
1079
+ return fail('SECTION_NOT_FOUND', `No heading "${section}" in ${card.handle}. Headings present: ${headings.length ? headings.join(', ') : '(none)'}. Use update_card to set the whole body or add the section.`);
1080
+ }
1081
+ await updateCardFile(card.filePath, { body });
1082
+ const lint = await lintPlan(root);
1083
+ const updated = lint.index.cards.get(card.handle);
1084
+ return ok({
1085
+ card: updated ? full(updated) : null,
1086
+ issues: issuesForFile(lint.issues, card.relPath),
1087
+ });
1088
+ }));
1089
+ server.registerTool('set_verified', {
1090
+ description: 'Mark a card verified against the real code: stamp verified_sha (the git sha you checked it at, default HEAD) + verified_at, set status to verified, and optionally append a verified note. The verified_sha is the BASELINE for code-side drift (stale_report / check_sync): later, if the card\'s bound code changed since this sha, the claim is flagged for re-verification. This is durability, not distrust — verify only against code you actually checked.',
1091
+ inputSchema: {
1092
+ handle: z.string(),
1093
+ sha: z
1094
+ .string()
1095
+ .optional()
1096
+ .describe('git sha verified against (default: current HEAD)'),
1097
+ note: z
1098
+ .string()
1099
+ .optional()
1100
+ .describe('optional verification note appended to the card'),
1101
+ repo: repoSchema,
1102
+ },
1103
+ }, withPlan(async (root, { handle, sha, note }) => {
1104
+ const index = await loadPlan(root);
1105
+ const card = index.cards.get(handle.toUpperCase());
1106
+ if (!card)
1107
+ return fail('NOT_FOUND', `No card with handle ${handle}`);
1108
+ let resolvedSha = sha;
1109
+ let warning;
1110
+ if (!resolvedSha) {
1111
+ try {
1112
+ resolvedSha = await headSha(root);
1113
+ }
1114
+ catch {
1115
+ warning =
1116
+ 'Not a git repo (or no commits): stamped verified_at + status only. Drift detection needs a verified_sha baseline — pass sha or commit first.';
1117
+ }
1118
+ }
1119
+ const verifiedAt = new Date().toISOString();
1120
+ const fields = { verified_at: verifiedAt };
1121
+ if (resolvedSha)
1122
+ fields.verified_sha = resolvedSha;
1123
+ let frontmatter = applyCardPatch(card.frontmatter, { status: 'verified', fields });
1124
+ if (note) {
1125
+ const n = { kind: 'verified', text: note };
1126
+ if (resolvedSha)
1127
+ n.sha = resolvedSha;
1128
+ frontmatter = withAppendedNote(frontmatter, n);
1129
+ }
1130
+ await updateCardFile(card.filePath, { frontmatter });
1131
+ const lint = await lintPlan(root);
1132
+ const updated = lint.index.cards.get(card.handle);
1133
+ return ok({
1134
+ card: updated ? full(updated) : null,
1135
+ verified_sha: resolvedSha ?? null,
1136
+ verified_at: verifiedAt,
1137
+ warning,
1138
+ issues: issuesForFile(lint.issues, card.relPath),
1139
+ });
1140
+ }));
727
1141
  server.registerTool('delete_card', {
728
1142
  description: 'Delete a card file. Returns the handles that referenced it (their references are now dangling) plus resulting lint issues.',
729
1143
  inputSchema: { handle: z.string(), repo: repoSchema },
@@ -1003,6 +1417,54 @@ export function buildServer(options = {}) {
1003
1417
  : undefined,
1004
1418
  });
1005
1419
  }));
1420
+ server.registerTool('stale_report', {
1421
+ annotations: { readOnlyHint: true },
1422
+ description: 'Code-side drift: cards that claim something about code (status built/verified, or carrying a verified_sha) whose BOUND code changed since they were verified. Binding = directly-connected FILE cards (path:) + the card\'s own code_refs. Each card\'s baseline is its verified_sha, else base, else the sync marker. Reports changed_files and vanished missing_files per stale card, plus cards with no baseline to check against. This makes a "built/verified" claim re-verifiable instead of taken on faith. Feed the handles to traverse or assemble.',
1423
+ inputSchema: {
1424
+ base: z
1425
+ .string()
1426
+ .optional()
1427
+ .describe('fallback baseline sha for cards without verified_sha'),
1428
+ repo: repoSchema,
1429
+ },
1430
+ }, withPlan(async (root, { base }) => {
1431
+ const index = await loadPlan(root);
1432
+ const r = await computeStaleCards(root, index, base);
1433
+ return ok({
1434
+ checked: r.checked,
1435
+ stale_count: r.stale.length,
1436
+ stale: r.stale,
1437
+ no_baseline: r.no_baseline,
1438
+ });
1439
+ }));
1440
+ server.registerTool('check_sync', {
1441
+ annotations: { readOnlyHint: true },
1442
+ description: 'Definition-of-done check: one glanceable verdict on whether the plan and code are in sync. Combines the plan-global state (in-sync / drifted / dirty / never-synced) — plan changes and code commits since the marker, lint integrity, status rollup — with the per-card code-side drift from stale_report. Advisory only: the server reports, it cannot block; treat code changed without its bound cards re-verified as "not done yet".',
1443
+ inputSchema: {
1444
+ base: z
1445
+ .string()
1446
+ .optional()
1447
+ .describe('fallback baseline sha for per-card drift (default: sync marker)'),
1448
+ repo: repoSchema,
1449
+ },
1450
+ }, withPlan(async (root, { base }) => {
1451
+ const status = await computeSyncStatus(root);
1452
+ const index = await loadPlan(root);
1453
+ const r = await computeStaleCards(root, index, base);
1454
+ return ok({
1455
+ advisory: 'Advisory only — the MCP server reports sync state, it cannot block. Use as a definition-of-done gate before calling work complete.',
1456
+ state: status.state,
1457
+ marker: status.marker,
1458
+ plan_dirty: status.plan_dirty,
1459
+ plan_changes_since_marker: status.plan_changes_since_marker,
1460
+ code_commits_since_marker: status.code_commits_since_marker,
1461
+ integrity: status.integrity,
1462
+ status_rollup: status.status_rollup,
1463
+ total_cards: status.total_cards,
1464
+ stale_cards: r.stale,
1465
+ cards_without_baseline: r.no_baseline,
1466
+ });
1467
+ }));
1006
1468
  server.registerTool('start_viewer', {
1007
1469
  description: 'Start a local web server that renders this plan as a browsable, editable site, and return its URL (e.g. http://localhost:4747/). Idempotent: if the viewer is already running, returns the existing URL. The server runs until stop_viewer or until this MCP process exits. ALWAYS reply to the user with the returned url as a clickable link and state the port it bound to.',
1008
1470
  inputSchema: {