@magic-spells/constellation 0.1.0 → 0.2.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 (121) hide show
  1. package/README.md +41 -4
  2. package/dist/cli/index.js +62 -10
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/cli/update-check.d.ts +6 -0
  5. package/dist/cli/update-check.js +70 -0
  6. package/dist/cli/update-check.js.map +1 -0
  7. package/dist/{mcp → core}/git.d.ts +19 -0
  8. package/dist/{mcp → core}/git.js +59 -2
  9. package/dist/core/git.js.map +1 -0
  10. package/dist/core/index.d.ts +1 -0
  11. package/dist/core/index.js +1 -0
  12. package/dist/core/index.js.map +1 -1
  13. package/dist/core/repos.d.ts +40 -0
  14. package/dist/core/repos.js +93 -0
  15. package/dist/core/repos.js.map +1 -0
  16. package/dist/core/resolve.js +10 -1
  17. package/dist/core/resolve.js.map +1 -1
  18. package/dist/core/scaffold.d.ts +16 -3
  19. package/dist/core/scaffold.js +30 -7
  20. package/dist/core/scaffold.js.map +1 -1
  21. package/dist/core/sync.d.ts +28 -0
  22. package/dist/core/sync.js +85 -0
  23. package/dist/core/sync.js.map +1 -0
  24. package/dist/core/types.d.ts +12 -0
  25. package/dist/mcp/server.js +434 -38
  26. package/dist/mcp/server.js.map +1 -1
  27. package/dist/serve/server.js +28 -4
  28. package/dist/serve/server.js.map +1 -1
  29. package/docs/001-file-format.md +25 -0
  30. package/docs/002-mcp.md +56 -7
  31. package/examples/constellation/plan.md +1 -1
  32. package/package.json +3 -1
  33. package/schemas/plan.json +27 -0
  34. package/skill/SKILL.md +131 -1
  35. package/skill/methodology.md +228 -0
  36. package/skill/types/plan.md +19 -0
  37. package/viewer/dist/assets/{arc-Kj6pF3JI.js → arc-CMMRgIq9.js} +1 -1
  38. package/viewer/dist/assets/architecture-7EHR7CIX-Cbb-syEI.js +1 -0
  39. package/viewer/dist/assets/{architectureDiagram-3BPJPVTR-C5bZdErB.js → architectureDiagram-3BPJPVTR-CB5p_qlN.js} +1 -1
  40. package/viewer/dist/assets/{blockDiagram-GPEHLZMM-C1Q6l6fE.js → blockDiagram-GPEHLZMM-DpnMj_e6.js} +1 -1
  41. package/viewer/dist/assets/{c4Diagram-AAUBKEIU-BmM6Tmtq.js → c4Diagram-AAUBKEIU-f91ngVN8.js} +1 -1
  42. package/viewer/dist/assets/channel-C2bkEQHQ.js +1 -0
  43. package/viewer/dist/assets/{chunk-2J33WTMH-z09tLTpZ.js → chunk-2J33WTMH-y7Pz5tMO.js} +1 -1
  44. package/viewer/dist/assets/{chunk-3OPIFGDE-BynpXh1r.js → chunk-3OPIFGDE-Ir_ghIUQ.js} +1 -1
  45. package/viewer/dist/assets/{chunk-4BX2VUAB-CDOVuPyG.js → chunk-4BX2VUAB-BTPyM1ux.js} +1 -1
  46. package/viewer/dist/assets/{chunk-55IACEB6-nBwigOgn.js → chunk-55IACEB6-CtNd8e4Y.js} +1 -1
  47. package/viewer/dist/assets/{chunk-5ZQYHXKU-Bxe5xIy_.js → chunk-5ZQYHXKU-Dd3yz721.js} +1 -1
  48. package/viewer/dist/assets/{chunk-727SXJPM-DZmTgL68.js → chunk-727SXJPM-CAM8mGbv.js} +1 -1
  49. package/viewer/dist/assets/{chunk-AQP2D5EJ-B7wr_Owx.js → chunk-AQP2D5EJ-C3nW9Uve.js} +1 -1
  50. package/viewer/dist/assets/{chunk-BSJP7CBP-DbAKfVCK.js → chunk-BSJP7CBP-r6MRPvAH.js} +1 -1
  51. package/viewer/dist/assets/{chunk-CSCIHK7Q-C0rsBwqP.js → chunk-CSCIHK7Q-Cn-ZTxsS.js} +1 -1
  52. package/viewer/dist/assets/{chunk-FMBD7UC4-BAtzt0wv.js → chunk-FMBD7UC4-5axXeZJa.js} +1 -1
  53. package/viewer/dist/assets/{chunk-KSCS5N6A-CXXwf52I.js → chunk-KSCS5N6A-BwmNx0l0.js} +1 -1
  54. package/viewer/dist/assets/{chunk-L5ZTLDWV-DS4vRI1U.js → chunk-L5ZTLDWV-C2YNkUjB.js} +1 -1
  55. package/viewer/dist/assets/chunk-LZXEDZCA-CznuDgQD.js +2 -0
  56. package/viewer/dist/assets/{chunk-ND2GUHAM-CUSnPl8t.js → chunk-ND2GUHAM-CokDnghi.js} +1 -1
  57. package/viewer/dist/assets/{chunk-NZK2D7GU-Dh986nJk.js → chunk-NZK2D7GU-aaU0v4QE.js} +1 -1
  58. package/viewer/dist/assets/{chunk-O5CBEL6O-JAEZ_pS6.js → chunk-O5CBEL6O-ByfKhkZf.js} +1 -1
  59. package/viewer/dist/assets/chunk-QZHKN3VN-DJRjGeIo.js +1 -0
  60. package/viewer/dist/assets/chunk-WU5MYG2G-C63BVvr_.js +1 -0
  61. package/viewer/dist/assets/{chunk-XPW4576I-BwMZI0gv.js → chunk-XPW4576I-Amo3awtq.js} +1 -1
  62. package/viewer/dist/assets/classDiagram-4FO5ZUOK-z_bO1V-j.js +1 -0
  63. package/viewer/dist/assets/classDiagram-v2-Q7XG4LA2-z_bO1V-j.js +1 -0
  64. package/viewer/dist/assets/{cose-bilkent-S5V4N54A-NGC7gYHM.js → cose-bilkent-S5V4N54A-CO8yESCW.js} +1 -1
  65. package/viewer/dist/assets/{dagre-BM42HDAG-RD63uyvd.js → dagre-BM42HDAG-BnmNVNI2.js} +1 -1
  66. package/viewer/dist/assets/{diagram-2AECGRRQ-hwnqqCcb.js → diagram-2AECGRRQ-lcGXcbei.js} +1 -1
  67. package/viewer/dist/assets/{diagram-5GNKFQAL-q8EaoZSG.js → diagram-5GNKFQAL-Cj3-lPUt.js} +1 -1
  68. package/viewer/dist/assets/{diagram-KO2AKTUF-D4_5Qf-l.js → diagram-KO2AKTUF-CtXdRI4M.js} +1 -1
  69. package/viewer/dist/assets/{diagram-LMA3HP47-D8pwekFs.js → diagram-LMA3HP47-CIyLAzX7.js} +1 -1
  70. package/viewer/dist/assets/{diagram-OG6HWLK6-D9KinIWZ.js → diagram-OG6HWLK6-BwF4bQCv.js} +1 -1
  71. package/viewer/dist/assets/{dist-CFOOgrqc.js → dist-DzXuQd4N.js} +1 -1
  72. package/viewer/dist/assets/{erDiagram-TEJ5UH35-D0Wfq250.js → erDiagram-TEJ5UH35-DjwFw9yq.js} +1 -1
  73. package/viewer/dist/assets/eventmodeling-FCH6USID-BlKFmSzA.js +1 -0
  74. package/viewer/dist/assets/{flowDiagram-I6XJVG4X-Y2DY-Ze2.js → flowDiagram-I6XJVG4X-CzXbf7vQ.js} +1 -1
  75. package/viewer/dist/assets/{ganttDiagram-6RSMTGT7-BnqkeLVw.js → ganttDiagram-6RSMTGT7-BYcIhfmm.js} +1 -1
  76. package/viewer/dist/assets/{gitGraph-WXDBUCRP-Cft7usRT.js → gitGraph-WXDBUCRP-H8XeJ9QB.js} +1 -1
  77. package/viewer/dist/assets/{gitGraphDiagram-PVQCEYII-D-cYtraK.js → gitGraphDiagram-PVQCEYII-DtAPXKFK.js} +1 -1
  78. package/viewer/dist/assets/index-Bqs39Itl.css +2 -0
  79. package/viewer/dist/assets/index-DLPCG_Or.js +98 -0
  80. package/viewer/dist/assets/{info-J43DQDTF-Djc8Bx3F.js → info-J43DQDTF-BQScorZ0.js} +1 -1
  81. package/viewer/dist/assets/{infoDiagram-5YYISTIA-D-ehtyyJ.js → infoDiagram-5YYISTIA-Udl1omvH.js} +1 -1
  82. package/viewer/dist/assets/{ishikawaDiagram-YF4QCWOH-Ct3f6bH-.js → ishikawaDiagram-YF4QCWOH-VnfzT_hk.js} +1 -1
  83. package/viewer/dist/assets/{journeyDiagram-JHISSGLW-DXlULEmi.js → journeyDiagram-JHISSGLW-Btn4EVoD.js} +1 -1
  84. package/viewer/dist/assets/{kanban-definition-UN3LZRKU-3vE9h-R7.js → kanban-definition-UN3LZRKU-flOzWhPe.js} +1 -1
  85. package/viewer/dist/assets/{line-B8MygbLB.js → line-DJJ9BLuY.js} +1 -1
  86. package/viewer/dist/assets/{linear-CfMuM0B3.js → linear-C2SUy5ns.js} +1 -1
  87. package/viewer/dist/assets/{mermaid-parser.core-DzlZTbbh.js → mermaid-parser.core-xhSeYiZo.js} +2 -2
  88. package/viewer/dist/assets/{mermaid.core-IM-sPiyq.js → mermaid.core-DmeSIitY.js} +3 -3
  89. package/viewer/dist/assets/{mindmap-definition-RKZ34NQL-CMnpAq1T.js → mindmap-definition-RKZ34NQL-CCJcMKx1.js} +1 -1
  90. package/viewer/dist/assets/{packet-YPE3B663-D44AzgHh.js → packet-YPE3B663-DS8RscAk.js} +1 -1
  91. package/viewer/dist/assets/{pie-LRSECV5Y-DL8AVJH_.js → pie-LRSECV5Y-I2ZQhrNJ.js} +1 -1
  92. package/viewer/dist/assets/{pieDiagram-4H26LBE5-FvKK5jd7.js → pieDiagram-4H26LBE5-BS5HMs4j.js} +1 -1
  93. package/viewer/dist/assets/{quadrantDiagram-W4KKPZXB-CmjSkU8c.js → quadrantDiagram-W4KKPZXB-W4H8cw2_.js} +1 -1
  94. package/viewer/dist/assets/{radar-GUYGQ44K-BvfZTVyH.js → radar-GUYGQ44K-kf6QvSne.js} +1 -1
  95. package/viewer/dist/assets/{requirementDiagram-4Y6WPE33-BOjca3VH.js → requirementDiagram-4Y6WPE33-DSbuDQGQ.js} +1 -1
  96. package/viewer/dist/assets/{sankeyDiagram-5OEKKPKP-ANcjfNix.js → sankeyDiagram-5OEKKPKP-CH8Qr2vL.js} +1 -1
  97. package/viewer/dist/assets/{sequenceDiagram-3UESZ5HK-BLQ9AL7I.js → sequenceDiagram-3UESZ5HK-EugVcdad.js} +1 -1
  98. package/viewer/dist/assets/src-CM_9kdrU.js +1 -0
  99. package/viewer/dist/assets/{stateDiagram-AJRCARHV-D6CriBS6.js → stateDiagram-AJRCARHV-DiFl94Qy.js} +1 -1
  100. package/viewer/dist/assets/stateDiagram-v2-BHNVJYJU-BlJV8F13.js +1 -0
  101. package/viewer/dist/assets/{timeline-definition-PNZ67QCA-BNhWZ_DL.js → timeline-definition-PNZ67QCA-B0KW9GUN.js} +1 -1
  102. package/viewer/dist/assets/{treeView-BLDUP644-CY6Ph5Pu.js → treeView-BLDUP644-CAEY4mxq.js} +1 -1
  103. package/viewer/dist/assets/{treemap-LRROVOQU-DChSA_Qx.js → treemap-LRROVOQU-VVaEaTlU.js} +1 -1
  104. package/viewer/dist/assets/{vennDiagram-CIIHVFJN-C01WznAC.js → vennDiagram-CIIHVFJN-BSLGNfJd.js} +1 -1
  105. package/viewer/dist/assets/{wardley-L42UT6IY-BJ8uNoJu.js → wardley-L42UT6IY-C-5cXbAU.js} +1 -1
  106. package/viewer/dist/assets/{wardleyDiagram-YWT4CUSO-DwDEzlVm.js → wardleyDiagram-YWT4CUSO-COk4TVnQ.js} +1 -1
  107. package/viewer/dist/assets/{xychartDiagram-2RQKCTM6-BCvIDwU0.js → xychartDiagram-2RQKCTM6-CClGJLJp.js} +1 -1
  108. package/viewer/dist/index.html +3 -3
  109. package/dist/mcp/git.js.map +0 -1
  110. package/viewer/dist/assets/architecture-7EHR7CIX-CGfWeim3.js +0 -1
  111. package/viewer/dist/assets/channel-19IdUS_c.js +0 -1
  112. package/viewer/dist/assets/chunk-LZXEDZCA-CclT9MXr.js +0 -2
  113. package/viewer/dist/assets/chunk-QZHKN3VN-BKc_Kg2Z.js +0 -1
  114. package/viewer/dist/assets/chunk-WU5MYG2G-9ssTSMzt.js +0 -1
  115. package/viewer/dist/assets/classDiagram-4FO5ZUOK-DXv85WFd.js +0 -1
  116. package/viewer/dist/assets/classDiagram-v2-Q7XG4LA2-DXv85WFd.js +0 -1
  117. package/viewer/dist/assets/eventmodeling-FCH6USID-D3KRSuC1.js +0 -1
  118. package/viewer/dist/assets/index-CDR-riG2.css +0 -2
  119. package/viewer/dist/assets/index-DRPsTWe2.js +0 -98
  120. package/viewer/dist/assets/src-CAMdANUp.js +0 -1
  121. package/viewer/dist/assets/stateDiagram-v2-BHNVJYJU-DcTp66RQ.js +0 -1
@@ -1,3 +1,16 @@
1
- export declare const STARTER_PLAN = "---\nname: Project plan\n---\n\n# Project Plan\n\n## Current state\n\n- (what exists, what is in flight)\n\n## Conventions\n\n- (project-wide rules cards should follow)\n\n## Last synced\n\nCode has not been reconciled against this plan yet.\n";
2
- /** Create constellation/ with a starter plan.md. Throws if it already exists. */
3
- export declare function initPlan(targetDir: string): Promise<string>;
1
+ /** Turn a folder slug into a human-readable project name: pyramid-server Pyramid Server. */
2
+ export declare function titleCaseFromSlug(slug: string): string;
3
+ /** The starter plan.md body, parameterized by the project's display name. */
4
+ export declare function starterPlan(name: string): string;
5
+ /**
6
+ * Create constellation/ with a starter plan.md. Throws if it already exists.
7
+ * The project name defaults to a title-cased version of the target folder
8
+ * (so pyramid-server → "Pyramid Server"); pass opts.name to override it. The
9
+ * resolved name is returned so callers can echo / confirm it.
10
+ */
11
+ export declare function initPlan(targetDir: string, opts?: {
12
+ name?: string;
13
+ }): Promise<{
14
+ root: string;
15
+ name: string;
16
+ }>;
@@ -1,7 +1,20 @@
1
1
  import { access, mkdir, writeFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
- export const STARTER_PLAN = `---
4
- name: Project plan
3
+ /** Turn a folder slug into a human-readable project name: pyramid-server → Pyramid Server. */
4
+ export function titleCaseFromSlug(slug) {
5
+ return slug
6
+ .replace(/[-_]+/g, ' ') // kebab / snake → spaces
7
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2') // split camelCase
8
+ .trim()
9
+ .split(/\s+/)
10
+ .filter(Boolean)
11
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
12
+ .join(' ');
13
+ }
14
+ /** The starter plan.md body, parameterized by the project's display name. */
15
+ export function starterPlan(name) {
16
+ return `---
17
+ name: ${name}
5
18
  ---
6
19
 
7
20
  # Project Plan
@@ -18,9 +31,19 @@ name: Project plan
18
31
 
19
32
  Code has not been reconciled against this plan yet.
20
33
  `;
21
- /** Create constellation/ with a starter plan.md. Throws if it already exists. */
22
- export async function initPlan(targetDir) {
23
- const root = path.resolve(targetDir, 'constellation');
34
+ }
35
+ /**
36
+ * Create constellation/ with a starter plan.md. Throws if it already exists.
37
+ * The project name defaults to a title-cased version of the target folder
38
+ * (so pyramid-server → "Pyramid Server"); pass opts.name to override it. The
39
+ * resolved name is returned so callers can echo / confirm it.
40
+ */
41
+ export async function initPlan(targetDir, opts = {}) {
42
+ const resolvedTarget = path.resolve(targetDir);
43
+ const root = path.join(resolvedTarget, 'constellation');
44
+ const name = opts.name?.trim() ||
45
+ titleCaseFromSlug(path.basename(resolvedTarget)) ||
46
+ 'Project plan';
24
47
  try {
25
48
  await access(root);
26
49
  throw new Error(`${root} already exists`);
@@ -30,7 +53,7 @@ export async function initPlan(targetDir) {
30
53
  throw err;
31
54
  }
32
55
  await mkdir(root, { recursive: true });
33
- await writeFile(path.join(root, 'plan.md'), STARTER_PLAN, { flag: 'wx' });
34
- return root;
56
+ await writeFile(path.join(root, 'plan.md'), starterPlan(name), { flag: 'wx' });
57
+ return { root, name };
35
58
  }
36
59
  //# sourceMappingURL=scaffold.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/core/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;CAiB3B,CAAC;AAEF,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,SAAiB;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,iBAAiB,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YAAE,MAAM,GAAG,CAAC;IAChF,CAAC;IACD,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1E,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/core/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,8FAA8F;AAC9F,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI;SACR,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,yBAAyB;SAChD,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,kBAAkB;SACzD,IAAI,EAAE;SACN,KAAK,CAAC,KAAK,CAAC;SACZ,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAClD,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO;QACD,IAAI;;;;;;;;;;;;;;;;CAgBX,CAAC;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,SAAiB,EACjB,OAA0B,EAAE;IAE5B,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;IACxD,MAAM,IAAI,GACR,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE;QACjB,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAChD,cAAc,CAAC;IACjB,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,iBAAiB,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YAAE,MAAM,GAAG,CAAC;IAChF,CAAC;IACD,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/E,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { type SyncActivity, type SyncPoint } from './git.js';
2
+ export type SyncState = 'in-sync' | 'drifted' | 'dirty' | 'never-synced' | 'no-git';
3
+ export interface SyncStatus {
4
+ state: SyncState;
5
+ marker: SyncPoint | null;
6
+ plan_dirty: boolean;
7
+ plan_changes_since_marker: number;
8
+ code_commits_since_marker: number;
9
+ integrity: {
10
+ errors: number;
11
+ warnings: number;
12
+ orphans: number;
13
+ };
14
+ status_rollup: Record<string, number>;
15
+ total_cards: number;
16
+ activity: SyncActivity[];
17
+ }
18
+ /**
19
+ * The plan's freshness/trust state, computed live from git + lint on every call —
20
+ * never stored, so it cannot go stale or lie. Composes the sync marker
21
+ * (.sync.json), working-tree state, drift since the marker, lint integrity, the
22
+ * card-status rollup, and recent plan activity into one glanceable verdict. When
23
+ * the plan isn't in a git repo, returns `state: 'no-git'` (the viewer hides the
24
+ * freshness pill) but still reports the git-independent lint + rollup.
25
+ */
26
+ export declare function computeSyncStatus(planRoot: string, options?: {
27
+ activityLimit?: number;
28
+ }): Promise<SyncStatus>;
@@ -0,0 +1,85 @@
1
+ import { countCodeCommitsSince, diffPlan, planDirty, readSyncPoint, recentPlanActivity, } from './git.js';
2
+ import { lintPlan } from './lint.js';
3
+ const STATUS_KEYS = ['planned', 'building', 'built', 'verified'];
4
+ /**
5
+ * The plan's freshness/trust state, computed live from git + lint on every call —
6
+ * never stored, so it cannot go stale or lie. Composes the sync marker
7
+ * (.sync.json), working-tree state, drift since the marker, lint integrity, the
8
+ * card-status rollup, and recent plan activity into one glanceable verdict. When
9
+ * the plan isn't in a git repo, returns `state: 'no-git'` (the viewer hides the
10
+ * freshness pill) but still reports the git-independent lint + rollup.
11
+ */
12
+ export async function computeSyncStatus(planRoot, options = {}) {
13
+ const lint = await lintPlan(planRoot);
14
+ const orphans = [...lint.index.cards.keys()].filter((h) => (lint.index.connectedHandles.get(h)?.size ?? 0) === 0);
15
+ const status_rollup = { none: 0 };
16
+ for (const key of STATUS_KEYS)
17
+ status_rollup[key] = 0;
18
+ for (const card of lint.index.cards.values()) {
19
+ const key = card.status ?? 'none';
20
+ status_rollup[key] = (status_rollup[key] ?? 0) + 1;
21
+ }
22
+ const base = {
23
+ integrity: {
24
+ errors: lint.errors.length,
25
+ warnings: lint.warnings.length,
26
+ orphans: orphans.length,
27
+ },
28
+ status_rollup,
29
+ total_cards: lint.index.cards.size,
30
+ };
31
+ let marker = null;
32
+ let plan_dirty = false;
33
+ let plan_changes_since_marker = 0;
34
+ let code_commits_since_marker = 0;
35
+ let activity = [];
36
+ try {
37
+ marker = await readSyncPoint(planRoot);
38
+ plan_dirty = await planDirty(planRoot);
39
+ activity = await recentPlanActivity(planRoot, options.activityLimit ?? 6);
40
+ if (marker) {
41
+ try {
42
+ const diff = await diffPlan(planRoot, marker.synced_sha, 'HEAD');
43
+ plan_changes_since_marker = diff.changes.length;
44
+ }
45
+ catch {
46
+ // marker sha unreachable (e.g. rebased history) — leave 0
47
+ }
48
+ try {
49
+ code_commits_since_marker = await countCodeCommitsSince(planRoot, marker.synced_sha);
50
+ }
51
+ catch {
52
+ // ignore — drift count is best-effort
53
+ }
54
+ }
55
+ }
56
+ catch {
57
+ // repoRootFor threw → not a git repo; no freshness signal is available.
58
+ return {
59
+ state: 'no-git',
60
+ marker: null,
61
+ plan_dirty: false,
62
+ plan_changes_since_marker: 0,
63
+ code_commits_since_marker: 0,
64
+ activity: [],
65
+ ...base,
66
+ };
67
+ }
68
+ const state = !marker
69
+ ? 'never-synced'
70
+ : plan_changes_since_marker > 0 || code_commits_since_marker > 0
71
+ ? 'drifted'
72
+ : plan_dirty
73
+ ? 'dirty'
74
+ : 'in-sync';
75
+ return {
76
+ state,
77
+ marker,
78
+ plan_dirty,
79
+ plan_changes_since_marker,
80
+ code_commits_since_marker,
81
+ activity,
82
+ ...base,
83
+ };
84
+ }
85
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/core/sync.ts"],"names":[],"mappings":"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"}
@@ -29,6 +29,18 @@ export interface Connection {
29
29
  a: string;
30
30
  b: string;
31
31
  }
32
+ /**
33
+ * A sibling repo declared in PLAN-PROJECT `connected_repos`. A repo-level link
34
+ * only — never a card connection. The path is local topology (relative to the
35
+ * repo root, or absolute) and is never validated by lint.
36
+ */
37
+ export interface ConnectedRepo {
38
+ /** Lowercase id used as the `repo` selector. */
39
+ name: string;
40
+ /** Path to the connected repo's root, relative to this repo's root (or absolute). */
41
+ path: string;
42
+ description?: string;
43
+ }
32
44
  export type Severity = 'error' | 'warning';
33
45
  export interface Issue {
34
46
  severity: Severity;