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,217 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { getSchemaDir, resolveSchema } from './resolver.js';
4
+ import { ArtifactGraph } from './graph.js';
5
+ import { detectCompleted } from './state.js';
6
+ import { resolveSchemaForChange } from '../../utils/change-metadata.js';
7
+ import { FileSystemUtils } from '../../utils/file-system.js';
8
+ import { readProjectConfig, validateConfigRules } from '../project-config.js';
9
+ import { SYNSPEC_DIR_NAME } from '../config.js';
10
+ // Session-level cache for validation warnings (avoid repeating same warnings)
11
+ const shownWarnings = new Set();
12
+ /**
13
+ * Error thrown when loading a template fails.
14
+ */
15
+ export class TemplateLoadError extends Error {
16
+ templatePath;
17
+ constructor(message, templatePath) {
18
+ super(message);
19
+ this.templatePath = templatePath;
20
+ this.name = 'TemplateLoadError';
21
+ }
22
+ }
23
+ /**
24
+ * Loads a template from a schema's templates directory.
25
+ *
26
+ * @param schemaName - Schema name (e.g., "synarcx")
27
+ * @param templatePath - Relative path within the templates directory (e.g., "proposal.md")
28
+ * @param projectRoot - Optional project root for project-local schema resolution
29
+ * @returns The template content
30
+ * @throws TemplateLoadError if the template cannot be loaded
31
+ */
32
+ export function loadTemplate(schemaName, templatePath, projectRoot) {
33
+ const schemaDir = getSchemaDir(schemaName, projectRoot);
34
+ if (!schemaDir) {
35
+ throw new TemplateLoadError(`Schema '${schemaName}' not found`, templatePath);
36
+ }
37
+ const templatePathOnDisk = path.join(schemaDir, 'templates', templatePath);
38
+ if (!fs.existsSync(templatePathOnDisk)) {
39
+ throw new TemplateLoadError(`Template not found: ${templatePathOnDisk}`, templatePathOnDisk);
40
+ }
41
+ const fullPath = FileSystemUtils.canonicalizeExistingPath(templatePathOnDisk);
42
+ try {
43
+ return fs.readFileSync(fullPath, 'utf-8');
44
+ }
45
+ catch (err) {
46
+ const ioError = err instanceof Error ? err : new Error(String(err));
47
+ throw new TemplateLoadError(`Failed to read template: ${ioError.message}`, fullPath);
48
+ }
49
+ }
50
+ /**
51
+ * Loads change context combining graph and completion state.
52
+ *
53
+ * Schema resolution order:
54
+ * 1. Explicit schemaName parameter (if provided)
55
+ * 2. Schema from .synspec.yaml metadata (if exists in change directory)
56
+ * 3. Default 'synarcx'
57
+ *
58
+ * @param projectRoot - Project root directory
59
+ * @param changeName - Change name
60
+ * @param schemaName - Optional schema name override. If not provided, auto-detected from metadata.
61
+ * @returns Change context with graph, completed set, and metadata
62
+ */
63
+ export function loadChangeContext(projectRoot, changeName, schemaName) {
64
+ const changeDir = FileSystemUtils.canonicalizeExistingPath(path.join(projectRoot, SYNSPEC_DIR_NAME, 'changes', changeName));
65
+ // Resolve schema: explicit > metadata > default
66
+ const resolvedSchemaName = resolveSchemaForChange(changeDir, schemaName);
67
+ const schema = resolveSchema(resolvedSchemaName, projectRoot);
68
+ const graph = ArtifactGraph.fromSchema(schema);
69
+ const completed = detectCompleted(graph, changeDir);
70
+ return {
71
+ graph,
72
+ completed,
73
+ schemaName: resolvedSchemaName,
74
+ changeName,
75
+ changeDir,
76
+ projectRoot,
77
+ };
78
+ }
79
+ /**
80
+ * Generates enriched instructions for creating an artifact.
81
+ *
82
+ * Instruction injection order:
83
+ * 1. <context> - Project context from config (if present)
84
+ * 2. <rules> - Artifact-specific rules from config (if present)
85
+ * 3. <template> - Schema's template content
86
+ *
87
+ * @param context - Change context
88
+ * @param artifactId - Artifact ID to generate instructions for
89
+ * @param projectRoot - Project root directory (for reading config)
90
+ * @returns Enriched artifact instructions
91
+ * @throws Error if artifact not found
92
+ */
93
+ export function generateInstructions(context, artifactId, projectRoot) {
94
+ const artifact = context.graph.getArtifact(artifactId);
95
+ if (!artifact) {
96
+ throw new Error(`Artifact '${artifactId}' not found in schema '${context.schemaName}'`);
97
+ }
98
+ const templateContent = loadTemplate(context.schemaName, artifact.template, context.projectRoot);
99
+ const dependencies = getDependencyInfo(artifact, context.graph, context.completed);
100
+ const unlocks = getUnlockedArtifacts(context.graph, artifactId);
101
+ // Use projectRoot from context if not explicitly provided
102
+ const effectiveProjectRoot = projectRoot ?? context.projectRoot;
103
+ // Try to read project config for context and rules
104
+ let projectConfig = null;
105
+ if (effectiveProjectRoot) {
106
+ try {
107
+ projectConfig = readProjectConfig(effectiveProjectRoot);
108
+ }
109
+ catch {
110
+ // If config read fails, continue without config
111
+ }
112
+ }
113
+ // Validate rules artifact IDs if config has rules (only once per session)
114
+ if (projectConfig?.rules) {
115
+ const validArtifactIds = new Set(context.graph.getAllArtifacts().map((a) => a.id));
116
+ const warnings = validateConfigRules(projectConfig.rules, validArtifactIds, context.schemaName);
117
+ // Show each unique warning only once per session
118
+ for (const warning of warnings) {
119
+ if (!shownWarnings.has(warning)) {
120
+ console.warn(warning);
121
+ shownWarnings.add(warning);
122
+ }
123
+ }
124
+ }
125
+ // Extract context and rules as separate fields (not prepended to template)
126
+ const configContext = projectConfig?.context?.trim() || undefined;
127
+ const rulesForArtifact = projectConfig?.rules?.[artifactId];
128
+ const configRules = rulesForArtifact && rulesForArtifact.length > 0 ? rulesForArtifact : undefined;
129
+ return {
130
+ changeName: context.changeName,
131
+ artifactId: artifact.id,
132
+ schemaName: context.schemaName,
133
+ changeDir: context.changeDir,
134
+ outputPath: artifact.generates,
135
+ description: artifact.description,
136
+ instruction: artifact.instruction,
137
+ context: configContext,
138
+ rules: configRules,
139
+ template: templateContent,
140
+ dependencies,
141
+ unlocks,
142
+ };
143
+ }
144
+ /**
145
+ * Gets dependency info including paths and descriptions.
146
+ */
147
+ function getDependencyInfo(artifact, graph, completed) {
148
+ return artifact.requires.map(id => {
149
+ const depArtifact = graph.getArtifact(id);
150
+ return {
151
+ id,
152
+ done: completed.has(id),
153
+ path: depArtifact?.generates ?? id,
154
+ description: depArtifact?.description ?? '',
155
+ };
156
+ });
157
+ }
158
+ /**
159
+ * Gets artifacts that become available after completing the given artifact.
160
+ */
161
+ function getUnlockedArtifacts(graph, artifactId) {
162
+ const unlocks = [];
163
+ for (const artifact of graph.getAllArtifacts()) {
164
+ if (artifact.requires.includes(artifactId)) {
165
+ unlocks.push(artifact.id);
166
+ }
167
+ }
168
+ return unlocks.sort();
169
+ }
170
+ /**
171
+ * Formats the status of all artifacts in a change.
172
+ *
173
+ * @param context - Change context
174
+ * @returns Formatted change status
175
+ */
176
+ export function formatChangeStatus(context) {
177
+ // Load schema to get apply phase configuration
178
+ const schema = resolveSchema(context.schemaName, context.projectRoot);
179
+ const applyRequires = schema.apply?.requires ?? schema.artifacts.map(a => a.id);
180
+ const artifacts = context.graph.getAllArtifacts();
181
+ const ready = new Set(context.graph.getNextArtifacts(context.completed));
182
+ const blocked = context.graph.getBlocked(context.completed);
183
+ const artifactStatuses = artifacts.map(artifact => {
184
+ if (context.completed.has(artifact.id)) {
185
+ return {
186
+ id: artifact.id,
187
+ outputPath: artifact.generates,
188
+ status: 'done',
189
+ };
190
+ }
191
+ if (ready.has(artifact.id)) {
192
+ return {
193
+ id: artifact.id,
194
+ outputPath: artifact.generates,
195
+ status: 'ready',
196
+ };
197
+ }
198
+ return {
199
+ id: artifact.id,
200
+ outputPath: artifact.generates,
201
+ status: 'blocked',
202
+ missingDeps: blocked[artifact.id] ?? [],
203
+ };
204
+ });
205
+ // Sort by build order for consistent output
206
+ const buildOrder = context.graph.getBuildOrder();
207
+ const orderMap = new Map(buildOrder.map((id, idx) => [id, idx]));
208
+ artifactStatuses.sort((a, b) => (orderMap.get(a.id) ?? 0) - (orderMap.get(b.id) ?? 0));
209
+ return {
210
+ changeName: context.changeName,
211
+ schemaName: context.schemaName,
212
+ isComplete: context.graph.isComplete(context.completed),
213
+ applyRequires,
214
+ artifacts: artifactStatuses,
215
+ };
216
+ }
217
+ //# sourceMappingURL=instruction-loader.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Checks if a path contains glob pattern characters.
3
+ */
4
+ export declare function isGlobPattern(pattern: string): boolean;
5
+ /**
6
+ * Resolves an artifact's output path(s) to concrete files that currently exist.
7
+ * Returns absolute file paths. Glob matches are sorted for deterministic output.
8
+ */
9
+ export declare function resolveArtifactOutputs(changeDir: string, generates: string): string[];
10
+ /**
11
+ * Checks if an artifact has at least one resolved output file.
12
+ */
13
+ export declare function artifactOutputExists(changeDir: string, generates: string): boolean;
14
+ //# sourceMappingURL=outputs.d.ts.map
@@ -0,0 +1,39 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import fg from 'fast-glob';
4
+ import { FileSystemUtils } from '../../utils/file-system.js';
5
+ /**
6
+ * Checks if a path contains glob pattern characters.
7
+ */
8
+ export function isGlobPattern(pattern) {
9
+ return pattern.includes('*') || pattern.includes('?') || pattern.includes('[');
10
+ }
11
+ /**
12
+ * Resolves an artifact's output path(s) to concrete files that currently exist.
13
+ * Returns absolute file paths. Glob matches are sorted for deterministic output.
14
+ */
15
+ export function resolveArtifactOutputs(changeDir, generates) {
16
+ if (!isGlobPattern(generates)) {
17
+ const fullPath = path.join(changeDir, generates);
18
+ try {
19
+ return fs.statSync(fullPath).isFile()
20
+ ? [FileSystemUtils.canonicalizeExistingPath(fullPath)]
21
+ : [];
22
+ }
23
+ catch {
24
+ return [];
25
+ }
26
+ }
27
+ const normalizedPattern = FileSystemUtils.toPosixPath(generates);
28
+ const matches = fg
29
+ .sync(normalizedPattern, { cwd: changeDir, onlyFiles: true, absolute: true })
30
+ .map((match) => FileSystemUtils.canonicalizeExistingPath(path.normalize(match)));
31
+ return Array.from(new Set(matches)).sort();
32
+ }
33
+ /**
34
+ * Checks if an artifact has at least one resolved output file.
35
+ */
36
+ export function artifactOutputExists(changeDir, generates) {
37
+ return resolveArtifactOutputs(changeDir, generates).length > 0;
38
+ }
39
+ //# sourceMappingURL=outputs.js.map
@@ -0,0 +1,81 @@
1
+ import type { SchemaYaml } from './types.js';
2
+ /**
3
+ * Error thrown when loading a schema fails.
4
+ */
5
+ export declare class SchemaLoadError extends Error {
6
+ readonly schemaPath: string;
7
+ readonly cause?: Error | undefined;
8
+ constructor(message: string, schemaPath: string, cause?: Error | undefined);
9
+ }
10
+ /**
11
+ * Gets the package's built-in schemas directory path.
12
+ * Uses import.meta.url to resolve relative to the current module.
13
+ */
14
+ export declare function getPackageSchemasDir(): string;
15
+ /**
16
+ * Gets the user's schema override directory path.
17
+ */
18
+ export declare function getUserSchemasDir(): string;
19
+ /**
20
+ * Gets the project-local schemas directory path.
21
+ * @param projectRoot - The project root directory
22
+ * @returns The path to the project's schemas directory
23
+ */
24
+ export declare function getProjectSchemasDir(projectRoot: string): string;
25
+ /**
26
+ * Resolves a schema name to its directory path.
27
+ *
28
+ * Resolution order (when projectRoot is provided):
29
+ * 1. Project-local: <projectRoot>/synspec/schemas/<name>/schema.yaml
30
+ * 2. User override: ${XDG_DATA_HOME}/synarcx/schemas/<name>/schema.yaml
31
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
32
+ *
33
+ * When projectRoot is not provided, only user override and package built-in are checked
34
+ * (backward compatible behavior).
35
+ *
36
+ * @param name - Schema name (e.g., "synarcx")
37
+ * @param projectRoot - Optional project root directory for project-local schema resolution
38
+ * @returns The path to the schema directory, or null if not found
39
+ */
40
+ export declare function getSchemaDir(name: string, projectRoot?: string): string | null;
41
+ /**
42
+ * Resolves a schema name to a SchemaYaml object.
43
+ *
44
+ * Resolution order (when projectRoot is provided):
45
+ * 1. Project-local: <projectRoot>/synspec/schemas/<name>/schema.yaml
46
+ * 2. User override: ${XDG_DATA_HOME}/synarcx/schemas/<name>/schema.yaml
47
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
48
+ *
49
+ * When projectRoot is not provided, only user override and package built-in are checked
50
+ * (backward compatible behavior).
51
+ *
52
+ * @param name - Schema name (e.g., "synarcx")
53
+ * @param projectRoot - Optional project root directory for project-local schema resolution
54
+ * @returns The resolved schema object
55
+ * @throws Error if schema is not found in any location
56
+ */
57
+ export declare function resolveSchema(name: string, projectRoot?: string): SchemaYaml;
58
+ /**
59
+ * Lists all available schema names.
60
+ * Combines project-local, user override, and package built-in schemas.
61
+ *
62
+ * @param projectRoot - Optional project root directory for project-local schema resolution
63
+ */
64
+ export declare function listSchemas(projectRoot?: string): string[];
65
+ /**
66
+ * Schema info with metadata (name, description, artifacts).
67
+ */
68
+ export interface SchemaInfo {
69
+ name: string;
70
+ description: string;
71
+ artifacts: string[];
72
+ source: 'project' | 'user' | 'package';
73
+ }
74
+ /**
75
+ * Lists all available schemas with their descriptions and artifact lists.
76
+ * Useful for agent skills to present schema selection to users.
77
+ *
78
+ * @param projectRoot - Optional project root directory for project-local schema resolution
79
+ */
80
+ export declare function listSchemasWithInfo(projectRoot?: string): SchemaInfo[];
81
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1,258 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { getGlobalDataDir } from '../global-config.js';
5
+ import { parseSchema, SchemaValidationError } from './schema.js';
6
+ import { SYNSPEC_DIR_NAME } from '../config.js';
7
+ /**
8
+ * Error thrown when loading a schema fails.
9
+ */
10
+ export class SchemaLoadError extends Error {
11
+ schemaPath;
12
+ cause;
13
+ constructor(message, schemaPath, cause) {
14
+ super(message);
15
+ this.schemaPath = schemaPath;
16
+ this.cause = cause;
17
+ this.name = 'SchemaLoadError';
18
+ }
19
+ }
20
+ /**
21
+ * Gets the package's built-in schemas directory path.
22
+ * Uses import.meta.url to resolve relative to the current module.
23
+ */
24
+ export function getPackageSchemasDir() {
25
+ const currentFile = fileURLToPath(import.meta.url);
26
+ // Navigate from dist/core/artifact-graph/ to package root's schemas/
27
+ return path.join(path.dirname(currentFile), '..', '..', '..', 'schemas');
28
+ }
29
+ /**
30
+ * Gets the user's schema override directory path.
31
+ */
32
+ export function getUserSchemasDir() {
33
+ return path.join(getGlobalDataDir(), 'schemas');
34
+ }
35
+ /**
36
+ * Gets the project-local schemas directory path.
37
+ * @param projectRoot - The project root directory
38
+ * @returns The path to the project's schemas directory
39
+ */
40
+ export function getProjectSchemasDir(projectRoot) {
41
+ return path.join(projectRoot, SYNSPEC_DIR_NAME, 'schemas');
42
+ }
43
+ /**
44
+ * Resolves a schema name to its directory path.
45
+ *
46
+ * Resolution order (when projectRoot is provided):
47
+ * 1. Project-local: <projectRoot>/synspec/schemas/<name>/schema.yaml
48
+ * 2. User override: ${XDG_DATA_HOME}/synarcx/schemas/<name>/schema.yaml
49
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
50
+ *
51
+ * When projectRoot is not provided, only user override and package built-in are checked
52
+ * (backward compatible behavior).
53
+ *
54
+ * @param name - Schema name (e.g., "synarcx")
55
+ * @param projectRoot - Optional project root directory for project-local schema resolution
56
+ * @returns The path to the schema directory, or null if not found
57
+ */
58
+ export function getSchemaDir(name, projectRoot) {
59
+ // 1. Check project-local directory (if projectRoot provided)
60
+ if (projectRoot) {
61
+ const projectDir = path.join(getProjectSchemasDir(projectRoot), name);
62
+ const projectSchemaPath = path.join(projectDir, 'schema.yaml');
63
+ if (fs.existsSync(projectSchemaPath)) {
64
+ return projectDir;
65
+ }
66
+ }
67
+ // 2. Check user override directory
68
+ const userDir = path.join(getUserSchemasDir(), name);
69
+ const userSchemaPath = path.join(userDir, 'schema.yaml');
70
+ if (fs.existsSync(userSchemaPath)) {
71
+ return userDir;
72
+ }
73
+ // 3. Check package built-in directory
74
+ const packageDir = path.join(getPackageSchemasDir(), name);
75
+ const packageSchemaPath = path.join(packageDir, 'schema.yaml');
76
+ if (fs.existsSync(packageSchemaPath)) {
77
+ return packageDir;
78
+ }
79
+ return null;
80
+ }
81
+ /**
82
+ * Resolves a schema name to a SchemaYaml object.
83
+ *
84
+ * Resolution order (when projectRoot is provided):
85
+ * 1. Project-local: <projectRoot>/synspec/schemas/<name>/schema.yaml
86
+ * 2. User override: ${XDG_DATA_HOME}/synarcx/schemas/<name>/schema.yaml
87
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
88
+ *
89
+ * When projectRoot is not provided, only user override and package built-in are checked
90
+ * (backward compatible behavior).
91
+ *
92
+ * @param name - Schema name (e.g., "synarcx")
93
+ * @param projectRoot - Optional project root directory for project-local schema resolution
94
+ * @returns The resolved schema object
95
+ * @throws Error if schema is not found in any location
96
+ */
97
+ export function resolveSchema(name, projectRoot) {
98
+ // Normalize name (remove .yaml extension if provided)
99
+ const normalizedName = name.replace(/\.ya?ml$/, '');
100
+ const schemaDir = getSchemaDir(normalizedName, projectRoot);
101
+ if (!schemaDir) {
102
+ const availableSchemas = listSchemas(projectRoot);
103
+ throw new Error(`Schema '${normalizedName}' not found. Available schemas: ${availableSchemas.join(', ')}`);
104
+ }
105
+ const schemaPath = path.join(schemaDir, 'schema.yaml');
106
+ // Load and parse the schema
107
+ let content;
108
+ try {
109
+ content = fs.readFileSync(schemaPath, 'utf-8');
110
+ }
111
+ catch (err) {
112
+ const ioError = err instanceof Error ? err : new Error(String(err));
113
+ throw new SchemaLoadError(`Failed to read schema at '${schemaPath}': ${ioError.message}`, schemaPath, ioError);
114
+ }
115
+ try {
116
+ return parseSchema(content);
117
+ }
118
+ catch (err) {
119
+ if (err instanceof SchemaValidationError) {
120
+ throw new SchemaLoadError(`Invalid schema at '${schemaPath}': ${err.message}`, schemaPath, err);
121
+ }
122
+ const parseError = err instanceof Error ? err : new Error(String(err));
123
+ throw new SchemaLoadError(`Failed to parse schema at '${schemaPath}': ${parseError.message}`, schemaPath, parseError);
124
+ }
125
+ }
126
+ /**
127
+ * Lists all available schema names.
128
+ * Combines project-local, user override, and package built-in schemas.
129
+ *
130
+ * @param projectRoot - Optional project root directory for project-local schema resolution
131
+ */
132
+ export function listSchemas(projectRoot) {
133
+ const schemas = new Set();
134
+ // Add package built-in schemas
135
+ const packageDir = getPackageSchemasDir();
136
+ if (fs.existsSync(packageDir)) {
137
+ for (const entry of fs.readdirSync(packageDir, { withFileTypes: true })) {
138
+ if (entry.isDirectory()) {
139
+ const schemaPath = path.join(packageDir, entry.name, 'schema.yaml');
140
+ if (fs.existsSync(schemaPath)) {
141
+ schemas.add(entry.name);
142
+ }
143
+ }
144
+ }
145
+ }
146
+ // Add user override schemas (may override package schemas)
147
+ const userDir = getUserSchemasDir();
148
+ if (fs.existsSync(userDir)) {
149
+ for (const entry of fs.readdirSync(userDir, { withFileTypes: true })) {
150
+ if (entry.isDirectory()) {
151
+ const schemaPath = path.join(userDir, entry.name, 'schema.yaml');
152
+ if (fs.existsSync(schemaPath)) {
153
+ schemas.add(entry.name);
154
+ }
155
+ }
156
+ }
157
+ }
158
+ // Add project-local schemas (if projectRoot provided)
159
+ if (projectRoot) {
160
+ const projectDir = getProjectSchemasDir(projectRoot);
161
+ if (fs.existsSync(projectDir)) {
162
+ for (const entry of fs.readdirSync(projectDir, { withFileTypes: true })) {
163
+ if (entry.isDirectory()) {
164
+ const schemaPath = path.join(projectDir, entry.name, 'schema.yaml');
165
+ if (fs.existsSync(schemaPath)) {
166
+ schemas.add(entry.name);
167
+ }
168
+ }
169
+ }
170
+ }
171
+ }
172
+ return Array.from(schemas).sort();
173
+ }
174
+ /**
175
+ * Lists all available schemas with their descriptions and artifact lists.
176
+ * Useful for agent skills to present schema selection to users.
177
+ *
178
+ * @param projectRoot - Optional project root directory for project-local schema resolution
179
+ */
180
+ export function listSchemasWithInfo(projectRoot) {
181
+ const schemas = [];
182
+ const seenNames = new Set();
183
+ // Add project-local schemas first (highest priority, if projectRoot provided)
184
+ if (projectRoot) {
185
+ const projectDir = getProjectSchemasDir(projectRoot);
186
+ if (fs.existsSync(projectDir)) {
187
+ for (const entry of fs.readdirSync(projectDir, { withFileTypes: true })) {
188
+ if (entry.isDirectory()) {
189
+ const schemaPath = path.join(projectDir, entry.name, 'schema.yaml');
190
+ if (fs.existsSync(schemaPath)) {
191
+ try {
192
+ const schema = parseSchema(fs.readFileSync(schemaPath, 'utf-8'));
193
+ schemas.push({
194
+ name: entry.name,
195
+ description: schema.description || '',
196
+ artifacts: schema.artifacts.map((a) => a.id),
197
+ source: 'project',
198
+ });
199
+ seenNames.add(entry.name);
200
+ }
201
+ catch {
202
+ // Skip invalid schemas
203
+ }
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ // Add user override schemas (if not overridden by project)
210
+ const userDir = getUserSchemasDir();
211
+ if (fs.existsSync(userDir)) {
212
+ for (const entry of fs.readdirSync(userDir, { withFileTypes: true })) {
213
+ if (entry.isDirectory() && !seenNames.has(entry.name)) {
214
+ const schemaPath = path.join(userDir, entry.name, 'schema.yaml');
215
+ if (fs.existsSync(schemaPath)) {
216
+ try {
217
+ const schema = parseSchema(fs.readFileSync(schemaPath, 'utf-8'));
218
+ schemas.push({
219
+ name: entry.name,
220
+ description: schema.description || '',
221
+ artifacts: schema.artifacts.map((a) => a.id),
222
+ source: 'user',
223
+ });
224
+ seenNames.add(entry.name);
225
+ }
226
+ catch {
227
+ // Skip invalid schemas
228
+ }
229
+ }
230
+ }
231
+ }
232
+ }
233
+ // Add package built-in schemas (if not overridden by project or user)
234
+ const packageDir = getPackageSchemasDir();
235
+ if (fs.existsSync(packageDir)) {
236
+ for (const entry of fs.readdirSync(packageDir, { withFileTypes: true })) {
237
+ if (entry.isDirectory() && !seenNames.has(entry.name)) {
238
+ const schemaPath = path.join(packageDir, entry.name, 'schema.yaml');
239
+ if (fs.existsSync(schemaPath)) {
240
+ try {
241
+ const schema = parseSchema(fs.readFileSync(schemaPath, 'utf-8'));
242
+ schemas.push({
243
+ name: entry.name,
244
+ description: schema.description || '',
245
+ artifacts: schema.artifacts.map((a) => a.id),
246
+ source: 'package',
247
+ });
248
+ }
249
+ catch {
250
+ // Skip invalid schemas
251
+ }
252
+ }
253
+ }
254
+ }
255
+ }
256
+ return schemas.sort((a, b) => a.name.localeCompare(b.name));
257
+ }
258
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1,13 @@
1
+ import { type SchemaYaml } from './types.js';
2
+ export declare class SchemaValidationError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ /**
6
+ * Loads and validates an artifact schema from a YAML file.
7
+ */
8
+ export declare function loadSchema(filePath: string): SchemaYaml;
9
+ /**
10
+ * Parses and validates an artifact schema from YAML content.
11
+ */
12
+ export declare function parseSchema(yamlContent: string): SchemaYaml;
13
+ //# sourceMappingURL=schema.d.ts.map