synarcx 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 (288) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +90 -0
  3. package/bin/synarcx.js +3 -0
  4. package/dist/cli/index.d.ts +2 -0
  5. package/dist/cli/index.js +474 -0
  6. package/dist/commands/change.d.ts +35 -0
  7. package/dist/commands/change.js +278 -0
  8. package/dist/commands/completion.d.ts +72 -0
  9. package/dist/commands/completion.js +264 -0
  10. package/dist/commands/config.d.ts +36 -0
  11. package/dist/commands/config.js +552 -0
  12. package/dist/commands/feedback.d.ts +9 -0
  13. package/dist/commands/feedback.js +170 -0
  14. package/dist/commands/schema.d.ts +6 -0
  15. package/dist/commands/schema.js +870 -0
  16. package/dist/commands/show.d.ts +14 -0
  17. package/dist/commands/show.js +132 -0
  18. package/dist/commands/spec.d.ts +15 -0
  19. package/dist/commands/spec.js +226 -0
  20. package/dist/commands/validate.d.ts +24 -0
  21. package/dist/commands/validate.js +295 -0
  22. package/dist/commands/workflow/index.d.ts +17 -0
  23. package/dist/commands/workflow/index.js +12 -0
  24. package/dist/commands/workflow/instructions.d.ts +29 -0
  25. package/dist/commands/workflow/instructions.js +327 -0
  26. package/dist/commands/workflow/new-change.d.ts +11 -0
  27. package/dist/commands/workflow/new-change.js +45 -0
  28. package/dist/commands/workflow/schemas.d.ts +10 -0
  29. package/dist/commands/workflow/schemas.js +34 -0
  30. package/dist/commands/workflow/shared.d.ts +57 -0
  31. package/dist/commands/workflow/shared.js +117 -0
  32. package/dist/commands/workflow/status.d.ts +14 -0
  33. package/dist/commands/workflow/status.js +75 -0
  34. package/dist/commands/workflow/templates.d.ts +16 -0
  35. package/dist/commands/workflow/templates.js +69 -0
  36. package/dist/commands/workspace/open.d.ts +29 -0
  37. package/dist/commands/workspace/open.js +84 -0
  38. package/dist/commands/workspace/operations.d.ts +18 -0
  39. package/dist/commands/workspace/operations.js +461 -0
  40. package/dist/commands/workspace/selection.d.ts +5 -0
  41. package/dist/commands/workspace/selection.js +90 -0
  42. package/dist/commands/workspace/types.d.ts +83 -0
  43. package/dist/commands/workspace/types.js +36 -0
  44. package/dist/commands/workspace.d.ts +3 -0
  45. package/dist/commands/workspace.js +635 -0
  46. package/dist/core/archive.d.ts +11 -0
  47. package/dist/core/archive.js +319 -0
  48. package/dist/core/artifact-graph/graph.d.ts +56 -0
  49. package/dist/core/artifact-graph/graph.js +141 -0
  50. package/dist/core/artifact-graph/index.d.ts +8 -0
  51. package/dist/core/artifact-graph/index.js +14 -0
  52. package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
  53. package/dist/core/artifact-graph/instruction-loader.js +217 -0
  54. package/dist/core/artifact-graph/outputs.d.ts +14 -0
  55. package/dist/core/artifact-graph/outputs.js +39 -0
  56. package/dist/core/artifact-graph/resolver.d.ts +81 -0
  57. package/dist/core/artifact-graph/resolver.js +258 -0
  58. package/dist/core/artifact-graph/schema.d.ts +13 -0
  59. package/dist/core/artifact-graph/schema.js +108 -0
  60. package/dist/core/artifact-graph/state.d.ts +12 -0
  61. package/dist/core/artifact-graph/state.js +31 -0
  62. package/dist/core/artifact-graph/types.d.ts +45 -0
  63. package/dist/core/artifact-graph/types.js +43 -0
  64. package/dist/core/available-tools.d.ts +17 -0
  65. package/dist/core/available-tools.js +43 -0
  66. package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
  67. package/dist/core/command-generation/adapters/amazon-q.js +26 -0
  68. package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
  69. package/dist/core/command-generation/adapters/antigravity.js +26 -0
  70. package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
  71. package/dist/core/command-generation/adapters/auggie.js +27 -0
  72. package/dist/core/command-generation/adapters/bob.d.ts +14 -0
  73. package/dist/core/command-generation/adapters/bob.js +45 -0
  74. package/dist/core/command-generation/adapters/claude.d.ts +13 -0
  75. package/dist/core/command-generation/adapters/claude.js +50 -0
  76. package/dist/core/command-generation/adapters/cline.d.ts +14 -0
  77. package/dist/core/command-generation/adapters/cline.js +27 -0
  78. package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
  79. package/dist/core/command-generation/adapters/codebuddy.js +28 -0
  80. package/dist/core/command-generation/adapters/codex.d.ts +16 -0
  81. package/dist/core/command-generation/adapters/codex.js +39 -0
  82. package/dist/core/command-generation/adapters/continue.d.ts +13 -0
  83. package/dist/core/command-generation/adapters/continue.js +28 -0
  84. package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
  85. package/dist/core/command-generation/adapters/costrict.js +27 -0
  86. package/dist/core/command-generation/adapters/crush.d.ts +13 -0
  87. package/dist/core/command-generation/adapters/crush.js +30 -0
  88. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  89. package/dist/core/command-generation/adapters/cursor.js +44 -0
  90. package/dist/core/command-generation/adapters/factory.d.ts +13 -0
  91. package/dist/core/command-generation/adapters/factory.js +27 -0
  92. package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
  93. package/dist/core/command-generation/adapters/gemini.js +26 -0
  94. package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
  95. package/dist/core/command-generation/adapters/github-copilot.js +26 -0
  96. package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
  97. package/dist/core/command-generation/adapters/iflow.js +29 -0
  98. package/dist/core/command-generation/adapters/index.d.ts +32 -0
  99. package/dist/core/command-generation/adapters/index.js +32 -0
  100. package/dist/core/command-generation/adapters/junie.d.ts +13 -0
  101. package/dist/core/command-generation/adapters/junie.js +26 -0
  102. package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
  103. package/dist/core/command-generation/adapters/kilocode.js +23 -0
  104. package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
  105. package/dist/core/command-generation/adapters/kiro.js +26 -0
  106. package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
  107. package/dist/core/command-generation/adapters/lingma.js +30 -0
  108. package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
  109. package/dist/core/command-generation/adapters/opencode.js +27 -0
  110. package/dist/core/command-generation/adapters/pi.d.ts +18 -0
  111. package/dist/core/command-generation/adapters/pi.js +55 -0
  112. package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
  113. package/dist/core/command-generation/adapters/qoder.js +30 -0
  114. package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
  115. package/dist/core/command-generation/adapters/qwen.js +26 -0
  116. package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
  117. package/dist/core/command-generation/adapters/roocode.js +27 -0
  118. package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
  119. package/dist/core/command-generation/adapters/windsurf.js +51 -0
  120. package/dist/core/command-generation/generator.d.ts +21 -0
  121. package/dist/core/command-generation/generator.js +27 -0
  122. package/dist/core/command-generation/index.d.ts +22 -0
  123. package/dist/core/command-generation/index.js +24 -0
  124. package/dist/core/command-generation/registry.d.ts +36 -0
  125. package/dist/core/command-generation/registry.js +98 -0
  126. package/dist/core/command-generation/types.d.ts +56 -0
  127. package/dist/core/command-generation/types.js +8 -0
  128. package/dist/core/completions/command-registry.d.ts +7 -0
  129. package/dist/core/completions/command-registry.js +596 -0
  130. package/dist/core/completions/completion-provider.d.ts +71 -0
  131. package/dist/core/completions/completion-provider.js +129 -0
  132. package/dist/core/completions/factory.d.ts +64 -0
  133. package/dist/core/completions/factory.js +75 -0
  134. package/dist/core/completions/generators/bash-generator.d.ts +35 -0
  135. package/dist/core/completions/generators/bash-generator.js +230 -0
  136. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  137. package/dist/core/completions/generators/fish-generator.js +160 -0
  138. package/dist/core/completions/generators/powershell-generator.d.ts +36 -0
  139. package/dist/core/completions/generators/powershell-generator.js +266 -0
  140. package/dist/core/completions/generators/zsh-generator.d.ts +47 -0
  141. package/dist/core/completions/generators/zsh-generator.js +274 -0
  142. package/dist/core/completions/installers/bash-installer.d.ts +87 -0
  143. package/dist/core/completions/installers/bash-installer.js +318 -0
  144. package/dist/core/completions/installers/fish-installer.d.ts +43 -0
  145. package/dist/core/completions/installers/fish-installer.js +143 -0
  146. package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
  147. package/dist/core/completions/installers/powershell-installer.js +387 -0
  148. package/dist/core/completions/installers/zsh-installer.d.ts +117 -0
  149. package/dist/core/completions/installers/zsh-installer.js +421 -0
  150. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  151. package/dist/core/completions/templates/bash-templates.js +30 -0
  152. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  153. package/dist/core/completions/templates/fish-templates.js +45 -0
  154. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  155. package/dist/core/completions/templates/powershell-templates.js +34 -0
  156. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  157. package/dist/core/completions/templates/zsh-templates.js +45 -0
  158. package/dist/core/completions/types.d.ts +101 -0
  159. package/dist/core/completions/types.js +2 -0
  160. package/dist/core/config-prompts.d.ts +9 -0
  161. package/dist/core/config-prompts.js +34 -0
  162. package/dist/core/config-schema.d.ts +86 -0
  163. package/dist/core/config-schema.js +213 -0
  164. package/dist/core/config.d.ts +19 -0
  165. package/dist/core/config.js +38 -0
  166. package/dist/core/converters/json-converter.d.ts +6 -0
  167. package/dist/core/converters/json-converter.js +51 -0
  168. package/dist/core/global-config.d.ts +49 -0
  169. package/dist/core/global-config.js +124 -0
  170. package/dist/core/index.d.ts +3 -0
  171. package/dist/core/index.js +4 -0
  172. package/dist/core/init.d.ts +37 -0
  173. package/dist/core/init.js +585 -0
  174. package/dist/core/legacy-cleanup.d.ts +169 -0
  175. package/dist/core/legacy-cleanup.js +578 -0
  176. package/dist/core/list.d.ts +9 -0
  177. package/dist/core/list.js +172 -0
  178. package/dist/core/migration.d.ts +23 -0
  179. package/dist/core/migration.js +108 -0
  180. package/dist/core/parsers/change-parser.d.ts +13 -0
  181. package/dist/core/parsers/change-parser.js +197 -0
  182. package/dist/core/parsers/markdown-parser.d.ts +26 -0
  183. package/dist/core/parsers/markdown-parser.js +227 -0
  184. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  185. package/dist/core/parsers/requirement-blocks.js +201 -0
  186. package/dist/core/parsers/spec-structure.d.ts +9 -0
  187. package/dist/core/parsers/spec-structure.js +88 -0
  188. package/dist/core/profile-sync-drift.d.ts +38 -0
  189. package/dist/core/profile-sync-drift.js +197 -0
  190. package/dist/core/profiles.d.ts +26 -0
  191. package/dist/core/profiles.js +37 -0
  192. package/dist/core/project-config.d.ts +64 -0
  193. package/dist/core/project-config.js +224 -0
  194. package/dist/core/schemas/base.schema.d.ts +13 -0
  195. package/dist/core/schemas/base.schema.js +13 -0
  196. package/dist/core/schemas/change.schema.d.ts +73 -0
  197. package/dist/core/schemas/change.schema.js +31 -0
  198. package/dist/core/schemas/index.d.ts +4 -0
  199. package/dist/core/schemas/index.js +4 -0
  200. package/dist/core/schemas/spec.schema.d.ts +18 -0
  201. package/dist/core/schemas/spec.schema.js +15 -0
  202. package/dist/core/shared/index.d.ts +8 -0
  203. package/dist/core/shared/index.js +8 -0
  204. package/dist/core/shared/skill-generation.d.ts +49 -0
  205. package/dist/core/shared/skill-generation.js +90 -0
  206. package/dist/core/shared/tool-detection.d.ts +71 -0
  207. package/dist/core/shared/tool-detection.js +152 -0
  208. package/dist/core/specs-apply.d.ts +73 -0
  209. package/dist/core/specs-apply.js +393 -0
  210. package/dist/core/styles/palette.d.ts +7 -0
  211. package/dist/core/styles/palette.js +8 -0
  212. package/dist/core/templates/index.d.ts +8 -0
  213. package/dist/core/templates/index.js +9 -0
  214. package/dist/core/templates/skill-templates.d.ts +15 -0
  215. package/dist/core/templates/skill-templates.js +14 -0
  216. package/dist/core/templates/types.d.ts +19 -0
  217. package/dist/core/templates/types.js +5 -0
  218. package/dist/core/templates/workflows/analyze.d.ts +4 -0
  219. package/dist/core/templates/workflows/analyze.js +101 -0
  220. package/dist/core/templates/workflows/apply-change.d.ts +10 -0
  221. package/dist/core/templates/workflows/apply-change.js +308 -0
  222. package/dist/core/templates/workflows/archive-change.d.ts +10 -0
  223. package/dist/core/templates/workflows/archive-change.js +271 -0
  224. package/dist/core/templates/workflows/clarify.d.ts +4 -0
  225. package/dist/core/templates/workflows/clarify.js +108 -0
  226. package/dist/core/templates/workflows/debug.d.ts +4 -0
  227. package/dist/core/templates/workflows/debug.js +117 -0
  228. package/dist/core/templates/workflows/explore.d.ts +10 -0
  229. package/dist/core/templates/workflows/explore.js +479 -0
  230. package/dist/core/templates/workflows/propose.d.ts +10 -0
  231. package/dist/core/templates/workflows/propose.js +216 -0
  232. package/dist/core/templates/workflows/sync.d.ts +4 -0
  233. package/dist/core/templates/workflows/sync.js +108 -0
  234. package/dist/core/update.d.ts +82 -0
  235. package/dist/core/update.js +555 -0
  236. package/dist/core/validation/constants.d.ts +34 -0
  237. package/dist/core/validation/constants.js +40 -0
  238. package/dist/core/validation/types.d.ts +18 -0
  239. package/dist/core/validation/types.js +2 -0
  240. package/dist/core/validation/validator.d.ts +33 -0
  241. package/dist/core/validation/validator.js +418 -0
  242. package/dist/core/view.d.ts +8 -0
  243. package/dist/core/view.js +169 -0
  244. package/dist/core/workspace/foundation.d.ts +79 -0
  245. package/dist/core/workspace/foundation.js +367 -0
  246. package/dist/core/workspace/index.d.ts +5 -0
  247. package/dist/core/workspace/index.js +5 -0
  248. package/dist/core/workspace/link-input.d.ts +9 -0
  249. package/dist/core/workspace/link-input.js +32 -0
  250. package/dist/core/workspace/open-surface.d.ts +24 -0
  251. package/dist/core/workspace/open-surface.js +137 -0
  252. package/dist/core/workspace/openers.d.ts +21 -0
  253. package/dist/core/workspace/openers.js +119 -0
  254. package/dist/index.d.ts +3 -0
  255. package/dist/index.js +3 -0
  256. package/dist/prompts/searchable-multi-select.d.ts +28 -0
  257. package/dist/prompts/searchable-multi-select.js +159 -0
  258. package/dist/ui/ascii-patterns.d.ts +25 -0
  259. package/dist/ui/ascii-patterns.js +140 -0
  260. package/dist/ui/welcome-screen.d.ts +10 -0
  261. package/dist/ui/welcome-screen.js +144 -0
  262. package/dist/utils/change-metadata.d.ts +51 -0
  263. package/dist/utils/change-metadata.js +147 -0
  264. package/dist/utils/change-utils.d.ts +62 -0
  265. package/dist/utils/change-utils.js +122 -0
  266. package/dist/utils/command-references.d.ts +18 -0
  267. package/dist/utils/command-references.js +20 -0
  268. package/dist/utils/file-system.d.ts +41 -0
  269. package/dist/utils/file-system.js +301 -0
  270. package/dist/utils/index.d.ts +6 -0
  271. package/dist/utils/index.js +9 -0
  272. package/dist/utils/interactive.d.ts +18 -0
  273. package/dist/utils/interactive.js +21 -0
  274. package/dist/utils/item-discovery.d.ts +4 -0
  275. package/dist/utils/item-discovery.js +73 -0
  276. package/dist/utils/match.d.ts +3 -0
  277. package/dist/utils/match.js +22 -0
  278. package/dist/utils/shell-detection.d.ts +20 -0
  279. package/dist/utils/shell-detection.js +41 -0
  280. package/dist/utils/task-progress.d.ts +8 -0
  281. package/dist/utils/task-progress.js +36 -0
  282. package/package.json +76 -0
  283. package/schemas/synarcx/schema.yaml +153 -0
  284. package/schemas/synarcx/templates/design.md +19 -0
  285. package/schemas/synarcx/templates/proposal.md +23 -0
  286. package/schemas/synarcx/templates/spec.md +8 -0
  287. package/schemas/synarcx/templates/tasks.md +9 -0
  288. package/scripts/postinstall.js +83 -0
@@ -0,0 +1,227 @@
1
+ export class MarkdownParser {
2
+ lines;
3
+ codeFenceLineMask;
4
+ currentLine;
5
+ constructor(content) {
6
+ const normalized = MarkdownParser.normalizeContent(content);
7
+ this.lines = normalized.split('\n');
8
+ this.codeFenceLineMask = MarkdownParser.buildCodeFenceMask(this.lines);
9
+ this.currentLine = 0;
10
+ }
11
+ static normalizeContent(content) {
12
+ return content.replace(/\r\n?/g, '\n');
13
+ }
14
+ static buildCodeFenceMask(lines) {
15
+ const mask = new Array(lines.length).fill(false);
16
+ let activeFence = null;
17
+ for (let i = 0; i < lines.length; i++) {
18
+ const fence = MarkdownParser.getFenceMarker(lines[i]);
19
+ if (!activeFence) {
20
+ if (fence) {
21
+ activeFence = fence;
22
+ mask[i] = true;
23
+ }
24
+ continue;
25
+ }
26
+ mask[i] = true;
27
+ if (MarkdownParser.isClosingFence(lines[i], activeFence)) {
28
+ activeFence = null;
29
+ }
30
+ }
31
+ return mask;
32
+ }
33
+ static getFenceMarker(line) {
34
+ const fenceMatch = line.match(/^\s*(`{3,}|~{3,})/);
35
+ if (!fenceMatch) {
36
+ return null;
37
+ }
38
+ return {
39
+ marker: fenceMatch[1][0],
40
+ length: fenceMatch[1].length,
41
+ };
42
+ }
43
+ static isClosingFence(line, activeFence) {
44
+ const fenceMatch = line.match(/^\s*(`{3,}|~{3,})\s*$/);
45
+ return Boolean(fenceMatch &&
46
+ fenceMatch[1][0] === activeFence.marker &&
47
+ fenceMatch[1].length >= activeFence.length);
48
+ }
49
+ parseSpec(name) {
50
+ const sections = this.parseSections();
51
+ const purpose = this.findSection(sections, 'Purpose')?.content || '';
52
+ const requirementsSection = this.findSection(sections, 'Requirements');
53
+ if (!purpose) {
54
+ throw new Error('Spec must have a Purpose section');
55
+ }
56
+ if (!requirementsSection) {
57
+ throw new Error('Spec must have a Requirements section');
58
+ }
59
+ const requirements = this.parseRequirements(requirementsSection);
60
+ return {
61
+ name,
62
+ overview: purpose.trim(),
63
+ requirements,
64
+ metadata: {
65
+ version: '1.0.0',
66
+ format: 'synarcx',
67
+ },
68
+ };
69
+ }
70
+ parseChange(name) {
71
+ const sections = this.parseSections();
72
+ const why = this.findSection(sections, 'Why')?.content || '';
73
+ const whatChanges = this.findSection(sections, 'What Changes')?.content || '';
74
+ if (!why) {
75
+ throw new Error('Change must have a Why section');
76
+ }
77
+ if (!whatChanges) {
78
+ throw new Error('Change must have a What Changes section');
79
+ }
80
+ const deltas = this.parseDeltas(whatChanges);
81
+ return {
82
+ name,
83
+ why: why.trim(),
84
+ whatChanges: whatChanges.trim(),
85
+ deltas,
86
+ metadata: {
87
+ version: '1.0.0',
88
+ format: 'synarcx-change',
89
+ },
90
+ };
91
+ }
92
+ parseSections() {
93
+ const sections = [];
94
+ const stack = [];
95
+ for (let i = 0; i < this.lines.length; i++) {
96
+ const line = this.lines[i];
97
+ if (this.codeFenceLineMask[i]) {
98
+ continue;
99
+ }
100
+ const headerMatch = line.match(/^(#{1,6})\s+(.+)$/);
101
+ if (headerMatch) {
102
+ const level = headerMatch[1].length;
103
+ const title = headerMatch[2].trim();
104
+ const content = this.getContentUntilNextHeader(i + 1, level);
105
+ const section = {
106
+ level,
107
+ title,
108
+ content,
109
+ children: [],
110
+ };
111
+ while (stack.length > 0 && stack[stack.length - 1].level >= level) {
112
+ stack.pop();
113
+ }
114
+ if (stack.length === 0) {
115
+ sections.push(section);
116
+ }
117
+ else {
118
+ stack[stack.length - 1].children.push(section);
119
+ }
120
+ stack.push(section);
121
+ }
122
+ }
123
+ return sections;
124
+ }
125
+ getContentUntilNextHeader(startLine, currentLevel) {
126
+ const contentLines = [];
127
+ for (let i = startLine; i < this.lines.length; i++) {
128
+ const line = this.lines[i];
129
+ const headerMatch = this.codeFenceLineMask[i] ? null : line.match(/^(#{1,6})\s+/);
130
+ if (headerMatch && headerMatch[1].length <= currentLevel) {
131
+ break;
132
+ }
133
+ contentLines.push(line);
134
+ }
135
+ return contentLines.join('\n').trim();
136
+ }
137
+ findSection(sections, title) {
138
+ for (const section of sections) {
139
+ if (section.title.toLowerCase() === title.toLowerCase()) {
140
+ return section;
141
+ }
142
+ const child = this.findSection(section.children, title);
143
+ if (child) {
144
+ return child;
145
+ }
146
+ }
147
+ return undefined;
148
+ }
149
+ parseRequirements(section) {
150
+ const requirements = [];
151
+ for (const child of section.children) {
152
+ // Extract requirement text from first non-empty content line, fall back to heading
153
+ let text = child.title;
154
+ // Get content before any child sections (scenarios)
155
+ if (child.content.trim()) {
156
+ // Split content into lines and find content before any child headers
157
+ const lines = child.content.split('\n');
158
+ const contentBeforeChildren = [];
159
+ for (const line of lines) {
160
+ // Stop at child headers (scenarios start with ####)
161
+ if (line.trim().startsWith('#')) {
162
+ break;
163
+ }
164
+ contentBeforeChildren.push(line);
165
+ }
166
+ // Find first non-empty line
167
+ const directContent = contentBeforeChildren.join('\n').trim();
168
+ if (directContent) {
169
+ const firstLine = directContent.split('\n').find(l => l.trim());
170
+ if (firstLine) {
171
+ text = firstLine.trim();
172
+ }
173
+ }
174
+ }
175
+ const scenarios = this.parseScenarios(child);
176
+ requirements.push({
177
+ text,
178
+ scenarios,
179
+ });
180
+ }
181
+ return requirements;
182
+ }
183
+ parseScenarios(requirementSection) {
184
+ const scenarios = [];
185
+ for (const scenarioSection of requirementSection.children) {
186
+ // Store the raw text content of the scenario section
187
+ if (scenarioSection.content.trim()) {
188
+ scenarios.push({
189
+ rawText: scenarioSection.content
190
+ });
191
+ }
192
+ }
193
+ return scenarios;
194
+ }
195
+ parseDeltas(content) {
196
+ const deltas = [];
197
+ const lines = content.split('\n');
198
+ for (const line of lines) {
199
+ // Match both formats: **spec:** and **spec**:
200
+ const deltaMatch = line.match(/^\s*-\s*\*\*([^*:]+)(?::\*\*|\*\*:)\s*(.+)$/);
201
+ if (deltaMatch) {
202
+ const specName = deltaMatch[1].trim();
203
+ const description = deltaMatch[2].trim();
204
+ let operation = 'MODIFIED';
205
+ const lowerDesc = description.toLowerCase();
206
+ // Use word boundaries to avoid false matches (e.g., "address" matching "add")
207
+ // Check RENAMED first since it's more specific than patterns containing "new"
208
+ if (/\brename(s|d|ing)?\b/.test(lowerDesc) || /\brenamed\s+(to|from)\b/.test(lowerDesc)) {
209
+ operation = 'RENAMED';
210
+ }
211
+ else if (/\badd(s|ed|ing)?\b/.test(lowerDesc) || /\bcreate(s|d|ing)?\b/.test(lowerDesc) || /\bnew\b/.test(lowerDesc)) {
212
+ operation = 'ADDED';
213
+ }
214
+ else if (/\bremove(s|d|ing)?\b/.test(lowerDesc) || /\bdelete(s|d|ing)?\b/.test(lowerDesc)) {
215
+ operation = 'REMOVED';
216
+ }
217
+ deltas.push({
218
+ spec: specName,
219
+ operation,
220
+ description,
221
+ });
222
+ }
223
+ }
224
+ return deltas;
225
+ }
226
+ }
227
+ //# sourceMappingURL=markdown-parser.js.map
@@ -0,0 +1,37 @@
1
+ export interface RequirementBlock {
2
+ headerLine: string;
3
+ name: string;
4
+ raw: string;
5
+ }
6
+ export interface RequirementsSectionParts {
7
+ before: string;
8
+ headerLine: string;
9
+ preamble: string;
10
+ bodyBlocks: RequirementBlock[];
11
+ after: string;
12
+ }
13
+ export declare function normalizeRequirementName(name: string): string;
14
+ /**
15
+ * Extracts the Requirements section from a spec file and parses requirement blocks.
16
+ */
17
+ export declare function extractRequirementsSection(content: string): RequirementsSectionParts;
18
+ export interface DeltaPlan {
19
+ added: RequirementBlock[];
20
+ modified: RequirementBlock[];
21
+ removed: string[];
22
+ renamed: Array<{
23
+ from: string;
24
+ to: string;
25
+ }>;
26
+ sectionPresence: {
27
+ added: boolean;
28
+ modified: boolean;
29
+ removed: boolean;
30
+ renamed: boolean;
31
+ };
32
+ }
33
+ /**
34
+ * Parse a delta-formatted spec change file content into a DeltaPlan with raw blocks.
35
+ */
36
+ export declare function parseDeltaSpec(content: string): DeltaPlan;
37
+ //# sourceMappingURL=requirement-blocks.d.ts.map
@@ -0,0 +1,201 @@
1
+ export function normalizeRequirementName(name) {
2
+ return name.trim();
3
+ }
4
+ const REQUIREMENT_HEADER_REGEX = /^###\s*Requirement:\s*(.+)\s*$/i;
5
+ /**
6
+ * Extracts the Requirements section from a spec file and parses requirement blocks.
7
+ */
8
+ export function extractRequirementsSection(content) {
9
+ const normalized = normalizeLineEndings(content);
10
+ const lines = normalized.split('\n');
11
+ const reqHeaderIndex = lines.findIndex(l => /^##\s+Requirements\s*$/i.test(l));
12
+ if (reqHeaderIndex === -1) {
13
+ // No requirements section; create an empty one at the end
14
+ const before = content.trimEnd();
15
+ const headerLine = '## Requirements';
16
+ return {
17
+ before: before ? before + '\n\n' : '',
18
+ headerLine,
19
+ preamble: '',
20
+ bodyBlocks: [],
21
+ after: '\n',
22
+ };
23
+ }
24
+ // Find end of this section: next line that starts with '## ' at same or higher level
25
+ let endIndex = lines.length;
26
+ for (let i = reqHeaderIndex + 1; i < lines.length; i++) {
27
+ if (/^##\s+/.test(lines[i])) {
28
+ endIndex = i;
29
+ break;
30
+ }
31
+ }
32
+ const before = lines.slice(0, reqHeaderIndex).join('\n');
33
+ const headerLine = lines[reqHeaderIndex];
34
+ const sectionBodyLines = lines.slice(reqHeaderIndex + 1, endIndex);
35
+ // Parse requirement blocks within section body
36
+ const blocks = [];
37
+ let cursor = 0;
38
+ let preambleLines = [];
39
+ // Collect preamble lines until first requirement header
40
+ while (cursor < sectionBodyLines.length && !REQUIREMENT_HEADER_REGEX.test(sectionBodyLines[cursor])) {
41
+ preambleLines.push(sectionBodyLines[cursor]);
42
+ cursor++;
43
+ }
44
+ while (cursor < sectionBodyLines.length) {
45
+ const headerStart = cursor;
46
+ const headerLineCandidate = sectionBodyLines[cursor];
47
+ const headerMatch = headerLineCandidate.match(REQUIREMENT_HEADER_REGEX);
48
+ if (!headerMatch) {
49
+ // Not a requirement header; skip line defensively
50
+ cursor++;
51
+ continue;
52
+ }
53
+ const name = normalizeRequirementName(headerMatch[1]);
54
+ cursor++;
55
+ // Gather lines until next requirement header or end of section
56
+ const bodyLines = [headerLineCandidate];
57
+ while (cursor < sectionBodyLines.length && !REQUIREMENT_HEADER_REGEX.test(sectionBodyLines[cursor]) && !/^##\s+/.test(sectionBodyLines[cursor])) {
58
+ bodyLines.push(sectionBodyLines[cursor]);
59
+ cursor++;
60
+ }
61
+ const raw = bodyLines.join('\n').trimEnd();
62
+ blocks.push({ headerLine: headerLineCandidate, name, raw });
63
+ }
64
+ const after = lines.slice(endIndex).join('\n');
65
+ const preamble = preambleLines.join('\n').trimEnd();
66
+ return {
67
+ before: before.trimEnd() ? before + '\n' : before,
68
+ headerLine,
69
+ preamble,
70
+ bodyBlocks: blocks,
71
+ after: after.startsWith('\n') ? after : '\n' + after,
72
+ };
73
+ }
74
+ function normalizeLineEndings(content) {
75
+ return content.replace(/\r\n?/g, '\n');
76
+ }
77
+ /**
78
+ * Parse a delta-formatted spec change file content into a DeltaPlan with raw blocks.
79
+ */
80
+ export function parseDeltaSpec(content) {
81
+ const normalized = normalizeLineEndings(content);
82
+ const sections = splitTopLevelSections(normalized);
83
+ const addedLookup = getSectionCaseInsensitive(sections, 'ADDED Requirements');
84
+ const modifiedLookup = getSectionCaseInsensitive(sections, 'MODIFIED Requirements');
85
+ const removedLookup = getSectionCaseInsensitive(sections, 'REMOVED Requirements');
86
+ const renamedLookup = getSectionCaseInsensitive(sections, 'RENAMED Requirements');
87
+ const added = parseRequirementBlocksFromSection(addedLookup.body);
88
+ const modified = parseRequirementBlocksFromSection(modifiedLookup.body);
89
+ const removedNames = parseRemovedNames(removedLookup.body);
90
+ const renamedPairs = parseRenamedPairs(renamedLookup.body);
91
+ return {
92
+ added,
93
+ modified,
94
+ removed: removedNames,
95
+ renamed: renamedPairs,
96
+ sectionPresence: {
97
+ added: addedLookup.found,
98
+ modified: modifiedLookup.found,
99
+ removed: removedLookup.found,
100
+ renamed: renamedLookup.found,
101
+ },
102
+ };
103
+ }
104
+ function splitTopLevelSections(content) {
105
+ const lines = content.split('\n');
106
+ const result = {};
107
+ const indices = [];
108
+ for (let i = 0; i < lines.length; i++) {
109
+ const m = lines[i].match(/^(##)\s+(.+)$/);
110
+ if (m) {
111
+ const level = m[1].length; // only care for '##'
112
+ indices.push({ title: m[2].trim(), index: i, level });
113
+ }
114
+ }
115
+ for (let i = 0; i < indices.length; i++) {
116
+ const current = indices[i];
117
+ const next = indices[i + 1];
118
+ const body = lines.slice(current.index + 1, next ? next.index : lines.length).join('\n');
119
+ result[current.title] = body;
120
+ }
121
+ return result;
122
+ }
123
+ function getSectionCaseInsensitive(sections, desired) {
124
+ const target = desired.toLowerCase();
125
+ for (const [title, body] of Object.entries(sections)) {
126
+ if (title.toLowerCase() === target)
127
+ return { body, found: true };
128
+ }
129
+ return { body: '', found: false };
130
+ }
131
+ function parseRequirementBlocksFromSection(sectionBody) {
132
+ if (!sectionBody)
133
+ return [];
134
+ const lines = normalizeLineEndings(sectionBody).split('\n');
135
+ const blocks = [];
136
+ let i = 0;
137
+ while (i < lines.length) {
138
+ // Seek next requirement header
139
+ while (i < lines.length && !REQUIREMENT_HEADER_REGEX.test(lines[i]))
140
+ i++;
141
+ if (i >= lines.length)
142
+ break;
143
+ const headerLine = lines[i];
144
+ const m = headerLine.match(REQUIREMENT_HEADER_REGEX);
145
+ if (!m) {
146
+ i++;
147
+ continue;
148
+ }
149
+ const name = normalizeRequirementName(m[1]);
150
+ const buf = [headerLine];
151
+ i++;
152
+ while (i < lines.length && !REQUIREMENT_HEADER_REGEX.test(lines[i]) && !/^##\s+/.test(lines[i])) {
153
+ buf.push(lines[i]);
154
+ i++;
155
+ }
156
+ blocks.push({ headerLine, name, raw: buf.join('\n').trimEnd() });
157
+ }
158
+ return blocks;
159
+ }
160
+ function parseRemovedNames(sectionBody) {
161
+ if (!sectionBody)
162
+ return [];
163
+ const names = [];
164
+ const lines = normalizeLineEndings(sectionBody).split('\n');
165
+ for (const line of lines) {
166
+ const m = line.match(REQUIREMENT_HEADER_REGEX);
167
+ if (m) {
168
+ names.push(normalizeRequirementName(m[1]));
169
+ continue;
170
+ }
171
+ // Also support bullet list of headers
172
+ const bullet = line.match(/^\s*-\s*`?###\s*Requirement:\s*(.+?)`?\s*$/);
173
+ if (bullet) {
174
+ names.push(normalizeRequirementName(bullet[1]));
175
+ }
176
+ }
177
+ return names;
178
+ }
179
+ function parseRenamedPairs(sectionBody) {
180
+ if (!sectionBody)
181
+ return [];
182
+ const pairs = [];
183
+ const lines = normalizeLineEndings(sectionBody).split('\n');
184
+ let current = {};
185
+ for (const line of lines) {
186
+ const fromMatch = line.match(/^\s*-?\s*FROM:\s*`?###\s*Requirement:\s*(.+?)`?\s*$/);
187
+ const toMatch = line.match(/^\s*-?\s*TO:\s*`?###\s*Requirement:\s*(.+?)`?\s*$/);
188
+ if (fromMatch) {
189
+ current.from = normalizeRequirementName(fromMatch[1]);
190
+ }
191
+ else if (toMatch) {
192
+ current.to = normalizeRequirementName(toMatch[1]);
193
+ if (current.from && current.to) {
194
+ pairs.push({ from: current.from, to: current.to });
195
+ current = {};
196
+ }
197
+ }
198
+ }
199
+ return pairs;
200
+ }
201
+ //# sourceMappingURL=requirement-blocks.js.map
@@ -0,0 +1,9 @@
1
+ export interface MainSpecStructureIssue {
2
+ kind: 'delta-header' | 'requirement-outside-requirements';
3
+ line: number;
4
+ header: string;
5
+ message: string;
6
+ }
7
+ export declare function findMainSpecStructureIssues(content: string): MainSpecStructureIssue[];
8
+ export declare function stripFencedCodeBlocksPreservingLines(content: string): string;
9
+ //# sourceMappingURL=spec-structure.d.ts.map
@@ -0,0 +1,88 @@
1
+ const REQUIREMENTS_SECTION_HEADER = /^##\s+Requirements\s*$/i;
2
+ const TOP_LEVEL_SECTION_HEADER = /^##\s+/;
3
+ const DELTA_HEADER = /^##\s+(ADDED|MODIFIED|REMOVED|RENAMED)\s+Requirements\s*$/i;
4
+ const REQUIREMENT_HEADER = /^###\s+Requirement:\s*(.+)\s*$/i;
5
+ export function findMainSpecStructureIssues(content) {
6
+ const normalized = content.replace(/\r\n?/g, '\n');
7
+ const stripped = stripFencedCodeBlocksPreservingLines(normalized);
8
+ const lines = stripped.split('\n');
9
+ const issues = [];
10
+ const requirementsHeaderIndex = lines.findIndex(line => REQUIREMENTS_SECTION_HEADER.test(line));
11
+ let requirementsEndIndex = lines.length;
12
+ if (requirementsHeaderIndex !== -1) {
13
+ for (let i = requirementsHeaderIndex + 1; i < lines.length; i++) {
14
+ if (TOP_LEVEL_SECTION_HEADER.test(lines[i])) {
15
+ requirementsEndIndex = i;
16
+ break;
17
+ }
18
+ }
19
+ }
20
+ for (let i = 0; i < lines.length; i++) {
21
+ const line = lines[i];
22
+ const trimmed = line.trim();
23
+ if (!trimmed) {
24
+ continue;
25
+ }
26
+ if (DELTA_HEADER.test(line)) {
27
+ issues.push({
28
+ kind: 'delta-header',
29
+ line: i + 1,
30
+ header: trimmed,
31
+ message: `Main spec contains delta header "${trimmed}". ` +
32
+ 'Delta headers are only valid inside synspec/changes/<name>/specs/<capability>/spec.md ' +
33
+ 'and truncate the parsed ## Requirements section.',
34
+ });
35
+ continue;
36
+ }
37
+ const requirementMatch = line.match(REQUIREMENT_HEADER);
38
+ if (!requirementMatch) {
39
+ continue;
40
+ }
41
+ const insideRequirements = requirementsHeaderIndex !== -1 &&
42
+ i > requirementsHeaderIndex &&
43
+ i < requirementsEndIndex;
44
+ if (!insideRequirements) {
45
+ issues.push({
46
+ kind: 'requirement-outside-requirements',
47
+ line: i + 1,
48
+ header: trimmed,
49
+ message: `Requirement header "${trimmed}" appears outside the main ## Requirements section. ` +
50
+ 'Main specs only parse requirements inside that section, so this requirement is currently invisible to validate, list, and archive.',
51
+ });
52
+ }
53
+ }
54
+ return issues;
55
+ }
56
+ export function stripFencedCodeBlocksPreservingLines(content) {
57
+ const lines = content.split('\n');
58
+ const output = [];
59
+ let activeFence = null;
60
+ for (const line of lines) {
61
+ const fenceMatch = line.match(/^\s*(`{3,}|~{3,})(.*)$/);
62
+ if (!activeFence) {
63
+ if (fenceMatch) {
64
+ activeFence = {
65
+ marker: fenceMatch[1][0],
66
+ length: fenceMatch[1].length,
67
+ };
68
+ output.push('');
69
+ }
70
+ else {
71
+ output.push(line);
72
+ }
73
+ continue;
74
+ }
75
+ output.push('');
76
+ if (isClosingFence(line, activeFence)) {
77
+ activeFence = null;
78
+ }
79
+ }
80
+ return output.join('\n');
81
+ }
82
+ function isClosingFence(line, activeFence) {
83
+ const fenceMatch = line.match(/^\s*(`{3,}|~{3,})\s*$/);
84
+ return Boolean(fenceMatch &&
85
+ fenceMatch[1][0] === activeFence.marker &&
86
+ fenceMatch[1].length >= activeFence.length);
87
+ }
88
+ //# sourceMappingURL=spec-structure.js.map
@@ -0,0 +1,38 @@
1
+ import type { Delivery } from './global-config.js';
2
+ import { ALL_WORKFLOWS } from './profiles.js';
3
+ type WorkflowId = (typeof ALL_WORKFLOWS)[number];
4
+ /**
5
+ * Maps workflow IDs to their skill directory names.
6
+ */
7
+ export declare const WORKFLOW_TO_SKILL_DIR: Record<WorkflowId, string>;
8
+ /**
9
+ * Checks whether a tool has at least one generated synarcx command file.
10
+ */
11
+ export declare function toolHasAnyConfiguredCommand(projectPath: string, toolId: string): boolean;
12
+ /**
13
+ * Returns tools with at least one generated command file on disk.
14
+ */
15
+ export declare function getCommandConfiguredTools(projectPath: string): string[];
16
+ /**
17
+ * Returns tools that are configured via either skills or commands.
18
+ */
19
+ export declare function getConfiguredToolsForProfileSync(projectPath: string): string[];
20
+ /**
21
+ * Detects if a single tool has profile/delivery drift against the desired state.
22
+ *
23
+ * This function covers:
24
+ * - required artifacts missing for selected workflows
25
+ * - artifacts that should not exist for the selected delivery mode
26
+ * - artifacts for workflows that were deselected from the current profile
27
+ */
28
+ export declare function hasToolProfileOrDeliveryDrift(projectPath: string, toolId: string, desiredWorkflows: readonly string[], delivery: Delivery): boolean;
29
+ /**
30
+ * Returns configured tools that currently need a profile/delivery sync.
31
+ */
32
+ export declare function getToolsNeedingProfileSync(projectPath: string, desiredWorkflows: readonly string[], delivery: Delivery, configuredTools?: readonly string[]): string[];
33
+ /**
34
+ * Detects whether the current project has any profile/delivery drift.
35
+ */
36
+ export declare function hasProjectConfigDrift(projectPath: string, desiredWorkflows: readonly string[], delivery: Delivery): boolean;
37
+ export {};
38
+ //# sourceMappingURL=profile-sync-drift.d.ts.map