javi-forge 1.6.0 → 1.7.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 (322) hide show
  1. package/README.md +45 -1
  2. package/ci-local/README.md +56 -11
  3. package/ci-local/ci-local.ps1 +445 -0
  4. package/ci-local/ci-local.sh +52 -9
  5. package/ci-local/docker/python.Dockerfile +7 -0
  6. package/ci-local/hooks/commit-msg +120 -44
  7. package/ci-local/hooks/commit-msg.test.sh +286 -0
  8. package/ci-local/hooks/pre-commit +9 -1
  9. package/ci-local/hooks/pre-push +13 -2
  10. package/ci-local/install.ps1 +367 -0
  11. package/ci-local/install.sh +151 -5
  12. package/ci-local/uninstall.ps1 +85 -0
  13. package/ci-local/uninstall.sh +95 -0
  14. package/dist/cli/dispatch/ci.d.ts +12 -0
  15. package/dist/cli/dispatch/ci.js +38 -0
  16. package/dist/cli/dispatch/security.d.ts +11 -0
  17. package/dist/cli/dispatch/security.js +68 -0
  18. package/dist/cli/dispatch/simple-renderers.d.ts +16 -0
  19. package/dist/cli/dispatch/simple-renderers.js +65 -0
  20. package/dist/cli/dispatch/skill-publish.d.ts +15 -0
  21. package/dist/cli/dispatch/skill-publish.js +44 -0
  22. package/dist/cli/dispatch/skills-cmd.d.ts +13 -0
  23. package/dist/cli/dispatch/skills-cmd.js +93 -0
  24. package/dist/cli/dispatch/tdd.d.ts +11 -0
  25. package/dist/cli/dispatch/tdd.js +45 -0
  26. package/dist/cli/dispatch/types.d.ts +29 -0
  27. package/dist/cli/dispatch/types.js +2 -0
  28. package/dist/cli/dispatch/workflow.d.ts +11 -0
  29. package/dist/cli/dispatch/workflow.js +67 -0
  30. package/dist/cli/help.d.ts +127 -0
  31. package/dist/cli/help.js +138 -0
  32. package/dist/cli/runtime.d.ts +16 -0
  33. package/dist/cli/runtime.js +38 -0
  34. package/dist/cli/validators.d.ts +17 -0
  35. package/dist/cli/validators.js +35 -0
  36. package/dist/commands/analyze.d.ts +1 -1
  37. package/dist/commands/analyze.js +14 -16
  38. package/dist/commands/ci.d.ts +50 -3
  39. package/dist/commands/ci.js +537 -182
  40. package/dist/commands/doctor.d.ts +2 -2
  41. package/dist/commands/doctor.js +112 -62
  42. package/dist/commands/init/report.d.ts +13 -0
  43. package/dist/commands/init/report.js +13 -0
  44. package/dist/commands/init/steps/agent-skills.d.ts +13 -0
  45. package/dist/commands/init/steps/agent-skills.js +45 -0
  46. package/dist/commands/init/steps/ai-sync.d.ts +15 -0
  47. package/dist/commands/init/steps/ai-sync.js +62 -0
  48. package/dist/commands/init/steps/ci.d.ts +24 -0
  49. package/dist/commands/init/steps/ci.js +74 -0
  50. package/dist/commands/init/steps/claude-md.d.ts +14 -0
  51. package/dist/commands/init/steps/claude-md.js +54 -0
  52. package/dist/commands/init/steps/code-graph.d.ts +16 -0
  53. package/dist/commands/init/steps/code-graph.js +68 -0
  54. package/dist/commands/init/steps/context-dir.d.ts +13 -0
  55. package/dist/commands/init/steps/context-dir.js +47 -0
  56. package/dist/commands/init/steps/docker-deploy.d.ts +16 -0
  57. package/dist/commands/init/steps/docker-deploy.js +60 -0
  58. package/dist/commands/init/steps/ghagga.d.ts +15 -0
  59. package/dist/commands/init/steps/ghagga.js +58 -0
  60. package/dist/commands/init/steps/git.d.ts +25 -0
  61. package/dist/commands/init/steps/git.js +81 -0
  62. package/dist/commands/init/steps/gitignore.d.ts +13 -0
  63. package/dist/commands/init/steps/gitignore.js +39 -0
  64. package/dist/commands/init/steps/local-ai.d.ts +14 -0
  65. package/dist/commands/init/steps/local-ai.js +53 -0
  66. package/dist/commands/init/steps/manifest.d.ts +13 -0
  67. package/dist/commands/init/steps/manifest.js +58 -0
  68. package/dist/commands/init/steps/memory.d.ts +15 -0
  69. package/dist/commands/init/steps/memory.js +60 -0
  70. package/dist/commands/init/steps/mock.d.ts +13 -0
  71. package/dist/commands/init/steps/mock.js +64 -0
  72. package/dist/commands/init/steps/sdd.d.ts +12 -0
  73. package/dist/commands/init/steps/sdd.js +40 -0
  74. package/dist/commands/init/steps/security.d.ts +28 -0
  75. package/dist/commands/init/steps/security.js +103 -0
  76. package/dist/commands/init/types.d.ts +30 -0
  77. package/dist/commands/init/types.js +2 -0
  78. package/dist/commands/init.d.ts +5 -4
  79. package/dist/commands/init.js +42 -387
  80. package/dist/commands/llmstxt.d.ts +1 -1
  81. package/dist/commands/llmstxt.js +36 -34
  82. package/dist/commands/plugin.d.ts +10 -1
  83. package/dist/commands/plugin.js +92 -47
  84. package/dist/commands/security.d.ts +11 -5
  85. package/dist/commands/security.js +236 -77
  86. package/dist/commands/skills/analysis.d.ts +19 -0
  87. package/dist/commands/skills/analysis.js +211 -0
  88. package/dist/commands/skills/benchmark.d.ts +6 -0
  89. package/dist/commands/skills/benchmark.js +82 -0
  90. package/dist/commands/skills/constants.d.ts +10 -0
  91. package/dist/commands/skills/constants.js +27 -0
  92. package/dist/commands/skills/directives.d.ts +21 -0
  93. package/dist/commands/skills/directives.js +101 -0
  94. package/dist/commands/skills/parsing.d.ts +16 -0
  95. package/dist/commands/skills/parsing.js +108 -0
  96. package/dist/commands/skills/rules.d.ts +5 -0
  97. package/dist/commands/skills/rules.js +32 -0
  98. package/dist/commands/skills/scoring.d.ts +47 -0
  99. package/dist/commands/skills/scoring.js +306 -0
  100. package/dist/commands/skills.d.ts +8 -69
  101. package/dist/commands/skills.js +9 -490
  102. package/dist/commands/tdd-pipeline.d.ts +17 -0
  103. package/dist/commands/tdd-pipeline.js +144 -0
  104. package/dist/commands/tdd.d.ts +1 -1
  105. package/dist/commands/tdd.js +21 -18
  106. package/dist/commands/workflow.d.ts +23 -0
  107. package/dist/commands/workflow.js +116 -0
  108. package/dist/constants.d.ts +15 -1
  109. package/dist/constants.js +161 -122
  110. package/dist/index.js +43 -280
  111. package/dist/lib/agent-skills.d.ts +36 -1
  112. package/dist/lib/agent-skills.js +168 -19
  113. package/dist/lib/atlassian-mcp.d.ts +42 -0
  114. package/dist/lib/atlassian-mcp.js +98 -0
  115. package/dist/lib/auto-skill-install.d.ts +37 -0
  116. package/dist/lib/auto-skill-install.js +91 -0
  117. package/dist/lib/auto-wire.d.ts +20 -0
  118. package/dist/lib/auto-wire.js +240 -0
  119. package/dist/lib/ci-config.d.ts +65 -0
  120. package/dist/lib/ci-config.js +297 -0
  121. package/dist/lib/claudemd.d.ts +13 -1
  122. package/dist/lib/claudemd.js +174 -24
  123. package/dist/lib/codex-export.d.ts +1 -1
  124. package/dist/lib/codex-export.js +26 -32
  125. package/dist/lib/common.d.ts +1 -1
  126. package/dist/lib/common.js +52 -44
  127. package/dist/lib/context.d.ts +17 -2
  128. package/dist/lib/context.js +142 -13
  129. package/dist/lib/crash-recovery.d.ts +34 -0
  130. package/dist/lib/crash-recovery.js +123 -0
  131. package/dist/lib/docker.d.ts +23 -2
  132. package/dist/lib/docker.js +168 -131
  133. package/dist/lib/exec.d.ts +10 -0
  134. package/dist/lib/exec.js +11 -0
  135. package/dist/lib/frontmatter.d.ts +1 -1
  136. package/dist/lib/frontmatter.js +29 -15
  137. package/dist/lib/harness-audit.d.ts +35 -0
  138. package/dist/lib/harness-audit.js +277 -0
  139. package/dist/lib/parallel-batch.d.ts +42 -0
  140. package/dist/lib/parallel-batch.js +88 -0
  141. package/dist/lib/plugin.d.ts +9 -3
  142. package/dist/lib/plugin.js +127 -70
  143. package/dist/lib/secret-scanner.d.ts +30 -0
  144. package/dist/lib/secret-scanner.js +274 -0
  145. package/dist/lib/security-analysis.d.ts +74 -0
  146. package/dist/lib/security-analysis.js +489 -0
  147. package/dist/lib/skill-publish.d.ts +40 -0
  148. package/dist/lib/skill-publish.js +164 -0
  149. package/dist/lib/skill-scanner.d.ts +63 -0
  150. package/dist/lib/skill-scanner.js +383 -0
  151. package/dist/lib/stack-detector.d.ts +38 -0
  152. package/dist/lib/stack-detector.js +207 -0
  153. package/dist/lib/supply-chain.d.ts +23 -0
  154. package/dist/lib/supply-chain.js +126 -0
  155. package/dist/lib/team-presets.d.ts +53 -0
  156. package/dist/lib/team-presets.js +201 -0
  157. package/dist/lib/template.d.ts +16 -1
  158. package/dist/lib/template.js +46 -17
  159. package/dist/lib/workflow/discovery.d.ts +27 -0
  160. package/dist/lib/workflow/discovery.js +85 -0
  161. package/dist/lib/workflow/index.d.ts +5 -0
  162. package/dist/lib/workflow/index.js +5 -0
  163. package/dist/lib/workflow/parser.d.ts +16 -0
  164. package/dist/lib/workflow/parser.js +198 -0
  165. package/dist/lib/workflow/renderer.d.ts +9 -0
  166. package/dist/lib/workflow/renderer.js +152 -0
  167. package/dist/lib/workflow/validator.d.ts +10 -0
  168. package/dist/lib/workflow/validator.js +189 -0
  169. package/dist/tasks/index.d.ts +4 -0
  170. package/dist/tasks/index.js +4 -0
  171. package/dist/tasks/scaffold-tasks.d.ts +3 -0
  172. package/dist/tasks/scaffold-tasks.js +14 -0
  173. package/dist/tasks/task-id.d.ts +30 -0
  174. package/dist/tasks/task-id.js +59 -0
  175. package/dist/tasks/task-tracker.d.ts +15 -0
  176. package/dist/tasks/task-tracker.js +81 -0
  177. package/dist/types/index.d.ts +134 -6
  178. package/dist/types/index.js +11 -1
  179. package/dist/ui/AnalyzeUI.d.ts +1 -1
  180. package/dist/ui/AnalyzeUI.js +38 -39
  181. package/dist/ui/App.d.ts +5 -3
  182. package/dist/ui/App.js +86 -46
  183. package/dist/ui/AutoSkills.d.ts +9 -0
  184. package/dist/ui/AutoSkills.js +124 -0
  185. package/dist/ui/CI.d.ts +2 -2
  186. package/dist/ui/CI.js +24 -26
  187. package/dist/ui/CIContext.d.ts +1 -1
  188. package/dist/ui/CIContext.js +2 -2
  189. package/dist/ui/CISelector.d.ts +2 -2
  190. package/dist/ui/CISelector.js +23 -15
  191. package/dist/ui/Doctor.d.ts +1 -1
  192. package/dist/ui/Doctor.js +35 -29
  193. package/dist/ui/Header.d.ts +1 -1
  194. package/dist/ui/Header.js +14 -14
  195. package/dist/ui/HookProfileSelector.d.ts +9 -0
  196. package/dist/ui/HookProfileSelector.js +54 -0
  197. package/dist/ui/LlmsTxt.d.ts +1 -1
  198. package/dist/ui/LlmsTxt.js +31 -22
  199. package/dist/ui/MemorySelector.d.ts +2 -2
  200. package/dist/ui/MemorySelector.js +28 -16
  201. package/dist/ui/NameInput.d.ts +1 -1
  202. package/dist/ui/NameInput.js +21 -21
  203. package/dist/ui/OptionSelector.d.ts +6 -2
  204. package/dist/ui/OptionSelector.js +83 -32
  205. package/dist/ui/Plugin.d.ts +4 -3
  206. package/dist/ui/Plugin.js +78 -35
  207. package/dist/ui/Progress.d.ts +3 -3
  208. package/dist/ui/Progress.js +23 -22
  209. package/dist/ui/Skills.d.ts +2 -2
  210. package/dist/ui/Skills.js +61 -32
  211. package/dist/ui/StackSelector.d.ts +2 -2
  212. package/dist/ui/StackSelector.js +27 -17
  213. package/dist/ui/Summary.d.ts +3 -3
  214. package/dist/ui/Summary.js +60 -50
  215. package/dist/ui/Welcome.d.ts +1 -1
  216. package/dist/ui/Welcome.js +15 -16
  217. package/dist/ui/theme.d.ts +1 -1
  218. package/dist/ui/theme.js +6 -6
  219. package/lib/common.psm1 +167 -0
  220. package/lib/common.sh +30 -0
  221. package/package.json +46 -24
  222. package/templates/common/atlassian/mcp-atlassian-snippet.json +16 -0
  223. package/templates/common/repoforge/mcp-repoforge-snippet.json +11 -0
  224. package/templates/common/repoforge/repoforge.yaml +34 -0
  225. package/templates/github/deploy-docker-zero-downtime.yml +140 -0
  226. package/templates/github/repoforge-graph.yml +45 -0
  227. package/templates/gitlab/deploy-docker-zero-downtime.yml +57 -0
  228. package/templates/local-ai/.env.example +17 -0
  229. package/templates/local-ai/docker-compose.yml +95 -0
  230. package/templates/security-hooks/claude-settings-security.json +30 -0
  231. package/templates/security-hooks/commit-msg-signing +29 -0
  232. package/templates/security-hooks/pre-commit-permissions +74 -0
  233. package/templates/security-hooks/pre-commit-secrets +74 -0
  234. package/templates/security-hooks/pre-push-branch-protection +62 -0
  235. package/templates/security-hooks/pre-push-deps +83 -0
  236. package/templates/security-hooks/pre-push-signing +67 -0
  237. package/templates/woodpecker/deploy-docker-zero-downtime.yml +50 -0
  238. package/templates/workflows/ci-pipeline.dot +15 -0
  239. package/templates/workflows/feature-flow.dot +21 -0
  240. package/templates/workflows/release.dot +16 -0
  241. package/dist/__integration__/helpers.d.ts +0 -20
  242. package/dist/__integration__/helpers.d.ts.map +0 -1
  243. package/dist/__integration__/helpers.js +0 -31
  244. package/dist/__integration__/helpers.js.map +0 -1
  245. package/dist/commands/analyze.d.ts.map +0 -1
  246. package/dist/commands/analyze.js.map +0 -1
  247. package/dist/commands/ci.d.ts.map +0 -1
  248. package/dist/commands/ci.js.map +0 -1
  249. package/dist/commands/doctor.d.ts.map +0 -1
  250. package/dist/commands/doctor.js.map +0 -1
  251. package/dist/commands/init.d.ts.map +0 -1
  252. package/dist/commands/init.js.map +0 -1
  253. package/dist/commands/llmstxt.d.ts.map +0 -1
  254. package/dist/commands/llmstxt.js.map +0 -1
  255. package/dist/commands/plugin.d.ts.map +0 -1
  256. package/dist/commands/plugin.js.map +0 -1
  257. package/dist/commands/security.d.ts.map +0 -1
  258. package/dist/commands/security.js.map +0 -1
  259. package/dist/commands/skills.d.ts.map +0 -1
  260. package/dist/commands/skills.js.map +0 -1
  261. package/dist/commands/tdd.d.ts.map +0 -1
  262. package/dist/commands/tdd.js.map +0 -1
  263. package/dist/constants.d.ts.map +0 -1
  264. package/dist/constants.js.map +0 -1
  265. package/dist/index.d.ts.map +0 -1
  266. package/dist/index.js.map +0 -1
  267. package/dist/lib/agent-skills.d.ts.map +0 -1
  268. package/dist/lib/agent-skills.js.map +0 -1
  269. package/dist/lib/claudemd.d.ts.map +0 -1
  270. package/dist/lib/claudemd.js.map +0 -1
  271. package/dist/lib/codex-export.d.ts.map +0 -1
  272. package/dist/lib/codex-export.js.map +0 -1
  273. package/dist/lib/common.d.ts.map +0 -1
  274. package/dist/lib/common.js.map +0 -1
  275. package/dist/lib/context.d.ts.map +0 -1
  276. package/dist/lib/context.js.map +0 -1
  277. package/dist/lib/docker.d.ts.map +0 -1
  278. package/dist/lib/docker.js.map +0 -1
  279. package/dist/lib/frontmatter.d.ts.map +0 -1
  280. package/dist/lib/frontmatter.js.map +0 -1
  281. package/dist/lib/plugin.d.ts.map +0 -1
  282. package/dist/lib/plugin.js.map +0 -1
  283. package/dist/lib/template.d.ts.map +0 -1
  284. package/dist/lib/template.js.map +0 -1
  285. package/dist/types/index.d.ts.map +0 -1
  286. package/dist/types/index.js.map +0 -1
  287. package/dist/ui/AnalyzeUI.d.ts.map +0 -1
  288. package/dist/ui/AnalyzeUI.js.map +0 -1
  289. package/dist/ui/App.d.ts.map +0 -1
  290. package/dist/ui/App.js.map +0 -1
  291. package/dist/ui/CI.d.ts.map +0 -1
  292. package/dist/ui/CI.js.map +0 -1
  293. package/dist/ui/CIContext.d.ts.map +0 -1
  294. package/dist/ui/CIContext.js.map +0 -1
  295. package/dist/ui/CISelector.d.ts.map +0 -1
  296. package/dist/ui/CISelector.js.map +0 -1
  297. package/dist/ui/Doctor.d.ts.map +0 -1
  298. package/dist/ui/Doctor.js.map +0 -1
  299. package/dist/ui/Header.d.ts.map +0 -1
  300. package/dist/ui/Header.js.map +0 -1
  301. package/dist/ui/LlmsTxt.d.ts.map +0 -1
  302. package/dist/ui/LlmsTxt.js.map +0 -1
  303. package/dist/ui/MemorySelector.d.ts.map +0 -1
  304. package/dist/ui/MemorySelector.js.map +0 -1
  305. package/dist/ui/NameInput.d.ts.map +0 -1
  306. package/dist/ui/NameInput.js.map +0 -1
  307. package/dist/ui/OptionSelector.d.ts.map +0 -1
  308. package/dist/ui/OptionSelector.js.map +0 -1
  309. package/dist/ui/Plugin.d.ts.map +0 -1
  310. package/dist/ui/Plugin.js.map +0 -1
  311. package/dist/ui/Progress.d.ts.map +0 -1
  312. package/dist/ui/Progress.js.map +0 -1
  313. package/dist/ui/Skills.d.ts.map +0 -1
  314. package/dist/ui/Skills.js.map +0 -1
  315. package/dist/ui/StackSelector.d.ts.map +0 -1
  316. package/dist/ui/StackSelector.js.map +0 -1
  317. package/dist/ui/Summary.d.ts.map +0 -1
  318. package/dist/ui/Summary.js.map +0 -1
  319. package/dist/ui/Welcome.d.ts.map +0 -1
  320. package/dist/ui/Welcome.js.map +0 -1
  321. package/dist/ui/theme.d.ts.map +0 -1
  322. package/dist/ui/theme.js.map +0 -1
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Atlassian MCP pre-config — generates MCP server configuration
3
+ * for Jira and Confluence integration in scaffolded projects.
4
+ *
5
+ * Produces a config snippet that can be merged into .claude/settings.json
6
+ * or any AI agent's MCP configuration.
7
+ */
8
+ export interface AtlassianConfig {
9
+ confluenceUrl: string;
10
+ confluenceUsername: string;
11
+ jiraUrl: string;
12
+ jiraUsername: string;
13
+ }
14
+ export interface McpSnippet {
15
+ mcpServers: Record<string, {
16
+ command: string;
17
+ args: string[];
18
+ env: Record<string, string>;
19
+ }>;
20
+ }
21
+ /**
22
+ * Generate Atlassian MCP config snippet with user-provided values.
23
+ * Token placeholders remain as env vars for security.
24
+ */
25
+ export declare function generateAtlassianMcpConfig(config: AtlassianConfig): McpSnippet;
26
+ /**
27
+ * Generate a template snippet with placeholders (no user input needed).
28
+ */
29
+ export declare function generateTemplateMcpConfig(): McpSnippet;
30
+ /**
31
+ * Write the Atlassian MCP snippet to a project directory.
32
+ */
33
+ export declare function writeAtlassianMcpSnippet(projectDir: string, config?: AtlassianConfig): Promise<string>;
34
+ /**
35
+ * Merge Atlassian MCP config into an existing settings.json or MCP config file.
36
+ */
37
+ export declare function mergeIntoSettings(settingsPath: string, config: AtlassianConfig): Promise<void>;
38
+ /**
39
+ * Copy the template snippet from templates/common/atlassian/.
40
+ */
41
+ export declare function copyTemplateSnippet(projectDir: string): Promise<string | null>;
42
+ //# sourceMappingURL=atlassian-mcp.d.ts.map
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Atlassian MCP pre-config — generates MCP server configuration
3
+ * for Jira and Confluence integration in scaffolded projects.
4
+ *
5
+ * Produces a config snippet that can be merged into .claude/settings.json
6
+ * or any AI agent's MCP configuration.
7
+ */
8
+ import path from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ import fs from "fs-extra";
11
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ const TEMPLATES_DIR = path.resolve(__dirname, "../../templates");
13
+ /**
14
+ * Generate Atlassian MCP config snippet with user-provided values.
15
+ * Token placeholders remain as env vars for security.
16
+ */
17
+ export function generateAtlassianMcpConfig(config) {
18
+ return {
19
+ mcpServers: {
20
+ atlassian: {
21
+ command: "uvx",
22
+ args: ["mcp-atlassian"],
23
+ env: {
24
+ CONFLUENCE_URL: config.confluenceUrl,
25
+ CONFLUENCE_USERNAME: config.confluenceUsername,
26
+ CONFLUENCE_API_TOKEN: "${CONFLUENCE_API_TOKEN}",
27
+ JIRA_URL: config.jiraUrl,
28
+ JIRA_USERNAME: config.jiraUsername,
29
+ JIRA_API_TOKEN: "${JIRA_API_TOKEN}",
30
+ },
31
+ },
32
+ },
33
+ };
34
+ }
35
+ /**
36
+ * Generate a template snippet with placeholders (no user input needed).
37
+ */
38
+ export function generateTemplateMcpConfig() {
39
+ return {
40
+ mcpServers: {
41
+ atlassian: {
42
+ command: "uvx",
43
+ args: ["mcp-atlassian"],
44
+ env: {
45
+ CONFLUENCE_URL: "__CONFLUENCE_URL__",
46
+ CONFLUENCE_USERNAME: "__CONFLUENCE_USERNAME__",
47
+ CONFLUENCE_API_TOKEN: "__CONFLUENCE_API_TOKEN__",
48
+ JIRA_URL: "__JIRA_URL__",
49
+ JIRA_USERNAME: "__JIRA_USERNAME__",
50
+ JIRA_API_TOKEN: "__JIRA_API_TOKEN__",
51
+ },
52
+ },
53
+ },
54
+ };
55
+ }
56
+ /**
57
+ * Write the Atlassian MCP snippet to a project directory.
58
+ */
59
+ export async function writeAtlassianMcpSnippet(projectDir, config) {
60
+ const snippet = config
61
+ ? generateAtlassianMcpConfig(config)
62
+ : generateTemplateMcpConfig();
63
+ const destDir = path.join(projectDir, ".atlassian");
64
+ await fs.ensureDir(destDir);
65
+ const destFile = path.join(destDir, "mcp-config-snippet.json");
66
+ await fs.writeJson(destFile, snippet, { spaces: 2 });
67
+ return destFile;
68
+ }
69
+ /**
70
+ * Merge Atlassian MCP config into an existing settings.json or MCP config file.
71
+ */
72
+ export async function mergeIntoSettings(settingsPath, config) {
73
+ const snippet = generateAtlassianMcpConfig(config);
74
+ let existing = {};
75
+ if (await fs.pathExists(settingsPath)) {
76
+ existing = await fs.readJson(settingsPath);
77
+ }
78
+ const existingServers = existing.mcpServers ?? {};
79
+ existing.mcpServers = {
80
+ ...existingServers,
81
+ ...snippet.mcpServers,
82
+ };
83
+ await fs.writeJson(settingsPath, existing, { spaces: 2 });
84
+ }
85
+ /**
86
+ * Copy the template snippet from templates/common/atlassian/.
87
+ */
88
+ export async function copyTemplateSnippet(projectDir) {
89
+ const srcFile = path.join(TEMPLATES_DIR, "common", "atlassian", "mcp-atlassian-snippet.json");
90
+ if (!(await fs.pathExists(srcFile)))
91
+ return null;
92
+ const destDir = path.join(projectDir, ".atlassian");
93
+ await fs.ensureDir(destDir);
94
+ const destFile = path.join(destDir, "mcp-config-snippet.json");
95
+ await fs.copy(srcFile, destFile, { overwrite: true });
96
+ return destFile;
97
+ }
98
+ //# sourceMappingURL=atlassian-mcp.js.map
@@ -0,0 +1,37 @@
1
+ import type { StackDetectionResult } from "./stack-detector.js";
2
+ export interface SkillInstallResult {
3
+ /** Skills that were successfully installed (copied) */
4
+ installed: string[];
5
+ /** Skills that were already present */
6
+ skipped: string[];
7
+ /** Skills that were recommended but not found in the source */
8
+ notFound: string[];
9
+ /** The full detection result for reporting */
10
+ detection: StackDetectionResult;
11
+ }
12
+ export interface AutoInstallOptions {
13
+ /** Directory to scan for tech stack detection */
14
+ projectDir: string;
15
+ /** Source directory containing skill folders (default: ~/.claude/skills) */
16
+ skillsSourceDir?: string;
17
+ /** Target directory where skills are installed (default: ~/.claude/skills) */
18
+ skillsTargetDir?: string;
19
+ /** If true, skip actually copying files */
20
+ dryRun?: boolean;
21
+ }
22
+ /**
23
+ * Scan a project, detect its stack, and install matching AI skills.
24
+ *
25
+ * Skills are "installed" by verifying they exist in the source directory.
26
+ * Since javi-forge skills live in ~/.claude/skills/, this mainly validates
27
+ * that the recommended skills are available and reports which ones are missing.
28
+ *
29
+ * If skillsSourceDir !== skillsTargetDir, it copies skill folders from
30
+ * source to target (useful for project-local skill installation).
31
+ */
32
+ export declare function autoInstallSkills(options: AutoInstallOptions): Promise<SkillInstallResult>;
33
+ /**
34
+ * Get a human-readable summary of auto-install results.
35
+ */
36
+ export declare function formatAutoInstallSummary(result: SkillInstallResult): string;
37
+ //# sourceMappingURL=auto-skill-install.d.ts.map
@@ -0,0 +1,91 @@
1
+ import path from "node:path";
2
+ import fs from "fs-extra";
3
+ import { DEFAULT_SKILLS_DIR } from "../commands/skills/constants.js";
4
+ import { detectProjectStack } from "./stack-detector.js";
5
+ // ── Core ───────────────────────────────────────────────────────────────────
6
+ /**
7
+ * Scan a project, detect its stack, and install matching AI skills.
8
+ *
9
+ * Skills are "installed" by verifying they exist in the source directory.
10
+ * Since javi-forge skills live in ~/.claude/skills/, this mainly validates
11
+ * that the recommended skills are available and reports which ones are missing.
12
+ *
13
+ * If skillsSourceDir !== skillsTargetDir, it copies skill folders from
14
+ * source to target (useful for project-local skill installation).
15
+ */
16
+ export async function autoInstallSkills(options) {
17
+ const { projectDir, skillsSourceDir = DEFAULT_SKILLS_DIR, skillsTargetDir = DEFAULT_SKILLS_DIR, dryRun = false, } = options;
18
+ // 1. Detect project stack
19
+ const detection = await detectProjectStack(projectDir);
20
+ if (detection.recommendedSkills.length === 0) {
21
+ return {
22
+ installed: [],
23
+ skipped: [],
24
+ notFound: [],
25
+ detection,
26
+ };
27
+ }
28
+ const installed = [];
29
+ const skipped = [];
30
+ const notFound = [];
31
+ const sameDir = path.resolve(skillsSourceDir) === path.resolve(skillsTargetDir);
32
+ for (const skillName of detection.recommendedSkills) {
33
+ const sourcePath = path.join(skillsSourceDir, skillName);
34
+ const targetPath = path.join(skillsTargetDir, skillName);
35
+ const sourceSkillMd = path.join(sourcePath, "SKILL.md");
36
+ // Check if skill exists in source
37
+ if (!(await fs.pathExists(sourceSkillMd))) {
38
+ notFound.push(skillName);
39
+ continue;
40
+ }
41
+ // If same directory, skill is already "installed"
42
+ if (sameDir) {
43
+ skipped.push(skillName);
44
+ continue;
45
+ }
46
+ // Check if already present in target
47
+ const targetSkillMd = path.join(targetPath, "SKILL.md");
48
+ if (await fs.pathExists(targetSkillMd)) {
49
+ skipped.push(skillName);
50
+ continue;
51
+ }
52
+ // Copy skill to target
53
+ if (!dryRun) {
54
+ await fs.ensureDir(targetPath);
55
+ await fs.copy(sourcePath, targetPath, {
56
+ overwrite: false,
57
+ errorOnExist: false,
58
+ });
59
+ }
60
+ installed.push(skillName);
61
+ }
62
+ return { installed, skipped, notFound, detection };
63
+ }
64
+ /**
65
+ * Get a human-readable summary of auto-install results.
66
+ */
67
+ export function formatAutoInstallSummary(result) {
68
+ const lines = [];
69
+ if (result.detection.stack) {
70
+ lines.push(`Detected stack: ${result.detection.stack}`);
71
+ }
72
+ else {
73
+ lines.push("No stack detected");
74
+ }
75
+ if (result.detection.signals.length > 0) {
76
+ lines.push(`Signals: ${result.detection.signals.map((s) => s.signal).join(", ")}`);
77
+ }
78
+ const total = result.installed.length + result.skipped.length + result.notFound.length;
79
+ lines.push(`Recommended skills: ${total}`);
80
+ if (result.installed.length > 0) {
81
+ lines.push(` Installed: ${result.installed.join(", ")}`);
82
+ }
83
+ if (result.skipped.length > 0) {
84
+ lines.push(` Already present: ${result.skipped.join(", ")}`);
85
+ }
86
+ if (result.notFound.length > 0) {
87
+ lines.push(` Not found: ${result.notFound.join(", ")}`);
88
+ }
89
+ return lines.join("\n");
90
+ }
91
+ //# sourceMappingURL=auto-skill-install.js.map
@@ -0,0 +1,20 @@
1
+ import type { AutoWireResult, InstalledPlugin } from "../types/index.js";
2
+ /**
3
+ * Scan installed plugins in a project and wire their capabilities into
4
+ * the project's CLAUDE.md (skill/plugin entries) and .claude/settings.json
5
+ * (hooks). Idempotent — re-running produces the same result.
6
+ */
7
+ export declare function autoWirePlugins(projectDir: string, installedPlugins: InstalledPlugin[], options?: {
8
+ dryRun?: boolean;
9
+ }): Promise<AutoWireResult>;
10
+ /**
11
+ * Build the auto-wire section content for CLAUDE.md.
12
+ * Pure function — no I/O.
13
+ */
14
+ export declare function buildAutoWireSection(plugins: InstalledPlugin[]): string;
15
+ /**
16
+ * Remove the auto-wire section from CLAUDE.md content.
17
+ * Returns cleaned content.
18
+ */
19
+ export declare function removeAutoWireSection(content: string): string;
20
+ //# sourceMappingURL=auto-wire.d.ts.map
@@ -0,0 +1,240 @@
1
+ import path from "node:path";
2
+ import fs from "fs-extra";
3
+ // ── Markers ────────────────────────────────────────────────────────────────
4
+ const WIRE_START = "<!-- javi-forge:auto-wire:start -->";
5
+ const WIRE_END = "<!-- javi-forge:auto-wire:end -->";
6
+ // ── Public API ─────────────────────────────────────────────────────────────
7
+ /**
8
+ * Scan installed plugins in a project and wire their capabilities into
9
+ * the project's CLAUDE.md (skill/plugin entries) and .claude/settings.json
10
+ * (hooks). Idempotent — re-running produces the same result.
11
+ */
12
+ export async function autoWirePlugins(projectDir, installedPlugins, options = {}) {
13
+ const { dryRun = false } = options;
14
+ const wired = [];
15
+ const unwired = [];
16
+ const errors = [];
17
+ // ── Collect desired entries from plugin manifests ─────────────────────
18
+ const desiredSkills = [];
19
+ const desiredHooks = [];
20
+ for (const plugin of installedPlugins) {
21
+ const { manifest } = plugin;
22
+ if (!manifest)
23
+ continue;
24
+ // Skills → CLAUDE.md skill loader lines
25
+ for (const skill of manifest.skills ?? []) {
26
+ desiredSkills.push({
27
+ plugin: manifest.name,
28
+ target: "claude-md",
29
+ capability: "skill",
30
+ value: skill,
31
+ });
32
+ }
33
+ // Hooks → .claude/settings.json
34
+ for (const hook of manifest.hooks ?? []) {
35
+ desiredHooks.push({
36
+ plugin: manifest.name,
37
+ target: "settings-json",
38
+ capability: "hook",
39
+ value: hook,
40
+ });
41
+ }
42
+ }
43
+ // ── Wire skills into CLAUDE.md ───────────────────────────────────────
44
+ try {
45
+ const claudeResult = await wireClaudeMd(projectDir, desiredSkills, installedPlugins, dryRun);
46
+ wired.push(...claudeResult.wired);
47
+ unwired.push(...claudeResult.unwired);
48
+ }
49
+ catch (e) {
50
+ errors.push(`CLAUDE.md wiring failed: ${e instanceof Error ? e.message : String(e)}`);
51
+ }
52
+ // ── Wire hooks into .claude/settings.json ────────────────────────────
53
+ try {
54
+ const hooksResult = await wireSettingsJson(projectDir, desiredHooks, installedPlugins, dryRun);
55
+ wired.push(...hooksResult.wired);
56
+ unwired.push(...hooksResult.unwired);
57
+ }
58
+ catch (e) {
59
+ errors.push(`settings.json wiring failed: ${e instanceof Error ? e.message : String(e)}`);
60
+ }
61
+ return { wired, unwired, errors };
62
+ }
63
+ // ── CLAUDE.md Wiring ───────────────────────────────────────────────────────
64
+ /**
65
+ * Build the auto-wire section content for CLAUDE.md.
66
+ * Pure function — no I/O.
67
+ */
68
+ export function buildAutoWireSection(plugins) {
69
+ const lines = [];
70
+ lines.push(WIRE_START);
71
+ lines.push("");
72
+ lines.push("## Plugins (auto-wired)");
73
+ lines.push("");
74
+ for (const plugin of plugins) {
75
+ const { manifest } = plugin;
76
+ if (!manifest)
77
+ continue;
78
+ lines.push(`### ${manifest.name} v${manifest.version}`);
79
+ lines.push(`> ${manifest.description}`);
80
+ lines.push("");
81
+ // Skills
82
+ const skills = manifest.skills ?? [];
83
+ if (skills.length > 0) {
84
+ for (const skill of skills) {
85
+ lines.push(`- Load \`~/.claude/plugins/${manifest.name}/skills/${skill}/SKILL.md\` when working with ${skill}`);
86
+ }
87
+ lines.push("");
88
+ }
89
+ // Commands
90
+ const commands = manifest.commands ?? [];
91
+ if (commands.length > 0) {
92
+ lines.push("**Commands:**");
93
+ for (const cmd of commands) {
94
+ lines.push(`- \`/${cmd}\``);
95
+ }
96
+ lines.push("");
97
+ }
98
+ // Agents
99
+ const agents = manifest.agents ?? [];
100
+ if (agents.length > 0) {
101
+ lines.push("**Agents:**");
102
+ for (const agent of agents) {
103
+ lines.push(`- ${agent}`);
104
+ }
105
+ lines.push("");
106
+ }
107
+ }
108
+ lines.push(WIRE_END);
109
+ return lines.join("\n");
110
+ }
111
+ async function wireClaudeMd(projectDir, desiredSkills, plugins, dryRun) {
112
+ const claudeMdPath = path.join(projectDir, "CLAUDE.md");
113
+ const wired = [];
114
+ const unwired = [];
115
+ // If no plugins have capabilities, remove section if present
116
+ const pluginsWithCapabilities = plugins.filter((p) => {
117
+ const m = p.manifest;
118
+ if (!m)
119
+ return false;
120
+ return ((m.skills?.length ?? 0) > 0 ||
121
+ (m.commands?.length ?? 0) > 0 ||
122
+ (m.agents?.length ?? 0) > 0);
123
+ });
124
+ let content = "";
125
+ if (await fs.pathExists(claudeMdPath)) {
126
+ content = await fs.readFile(claudeMdPath, "utf-8");
127
+ }
128
+ // Remove existing auto-wire section (idempotent)
129
+ const cleaned = removeAutoWireSection(content);
130
+ if (pluginsWithCapabilities.length === 0) {
131
+ // Nothing to wire — if we cleaned something, that's an unwire
132
+ if (cleaned !== content && !dryRun) {
133
+ await fs.writeFile(claudeMdPath, cleaned, "utf-8");
134
+ }
135
+ return { wired, unwired };
136
+ }
137
+ // Build new section
138
+ const section = buildAutoWireSection(pluginsWithCapabilities);
139
+ const newContent = `${cleaned.trimEnd()}\n\n${section}\n`;
140
+ if (!dryRun) {
141
+ await fs.ensureDir(path.dirname(claudeMdPath));
142
+ await fs.writeFile(claudeMdPath, newContent, "utf-8");
143
+ }
144
+ // Track what was wired
145
+ for (const entry of desiredSkills) {
146
+ wired.push(entry);
147
+ }
148
+ for (const plugin of pluginsWithCapabilities) {
149
+ for (const cmd of plugin.manifest.commands ?? []) {
150
+ wired.push({
151
+ plugin: plugin.manifest.name,
152
+ target: "claude-md",
153
+ capability: "command",
154
+ value: cmd,
155
+ });
156
+ }
157
+ for (const agent of plugin.manifest.agents ?? []) {
158
+ wired.push({
159
+ plugin: plugin.manifest.name,
160
+ target: "claude-md",
161
+ capability: "agent",
162
+ value: agent,
163
+ });
164
+ }
165
+ }
166
+ return { wired, unwired };
167
+ }
168
+ // ── Settings.json Wiring ───────────────────────────────────────────────────
169
+ async function wireSettingsJson(projectDir, desiredHooks, _plugins, dryRun) {
170
+ const wired = [];
171
+ const unwired = [];
172
+ if (desiredHooks.length === 0)
173
+ return { wired, unwired };
174
+ const settingsPath = path.join(projectDir, ".claude", "settings.json");
175
+ let settings = {};
176
+ if (await fs.pathExists(settingsPath)) {
177
+ try {
178
+ settings = await fs.readJson(settingsPath);
179
+ }
180
+ catch {
181
+ settings = {};
182
+ }
183
+ }
184
+ // Ensure hooks object
185
+ const hooks = (settings.hooks ?? {});
186
+ const pluginHooks = (hooks["plugin-hooks"] ?? []);
187
+ const existingSet = new Set(pluginHooks);
188
+ for (const entry of desiredHooks) {
189
+ if (existingSet.has(entry.value)) {
190
+ // Already wired — skip (idempotent)
191
+ continue;
192
+ }
193
+ pluginHooks.push(entry.value);
194
+ existingSet.add(entry.value);
195
+ wired.push(entry);
196
+ }
197
+ // Detect hooks that belong to removed plugins
198
+ const _activePluginNames = new Set(desiredHooks.map((h) => h.plugin));
199
+ const cleanedHooks = pluginHooks.filter((h) => {
200
+ // Keep hooks that we just wired or that belong to active plugins
201
+ const belongsToActive = desiredHooks.some((d) => d.value === h);
202
+ if (!belongsToActive) {
203
+ unwired.push({
204
+ plugin: "unknown",
205
+ target: "settings-json",
206
+ capability: "hook",
207
+ value: h,
208
+ });
209
+ return false;
210
+ }
211
+ return true;
212
+ });
213
+ hooks["plugin-hooks"] = cleanedHooks;
214
+ settings.hooks = hooks;
215
+ if (!dryRun && (wired.length > 0 || unwired.length > 0)) {
216
+ await fs.ensureDir(path.dirname(settingsPath));
217
+ await fs.writeJson(settingsPath, settings, { spaces: 2 });
218
+ }
219
+ return { wired, unwired };
220
+ }
221
+ // ── Helpers ────────────────────────────────────────────────────────────────
222
+ /**
223
+ * Remove the auto-wire section from CLAUDE.md content.
224
+ * Returns cleaned content.
225
+ */
226
+ export function removeAutoWireSection(content) {
227
+ const startIdx = content.indexOf(WIRE_START);
228
+ if (startIdx === -1)
229
+ return content;
230
+ const endIdx = content.indexOf(WIRE_END);
231
+ if (endIdx === -1)
232
+ return content;
233
+ const before = content.slice(0, startIdx).trimEnd();
234
+ const after = content.slice(endIdx + WIRE_END.length).trimStart();
235
+ if (after) {
236
+ return `${before}\n\n${after}`;
237
+ }
238
+ return `${before}\n`;
239
+ }
240
+ //# sourceMappingURL=auto-wire.js.map
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Versioned mixed-runner CI config (`.javi-forge/ci.yaml`) — schema and loader.
3
+ *
4
+ * Hybrid repositories declare every required runner explicitly and in order.
5
+ * Single-stack repositories need no config: auto-detection stays the default.
6
+ *
7
+ * Validation is fail-closed: any schema violation produces a CIConfigError
8
+ * listing every problem, and no partially-valid config is ever returned.
9
+ * YAML parsing uses the `yaml` package, already a runtime dependency.
10
+ */
11
+ import type { Stack } from "../types/index.js";
12
+ export declare const CI_CONFIG_VERSION = 1;
13
+ /** Default config locations, in discovery order, relative to the project root. */
14
+ export declare const CI_CONFIG_CANDIDATES: readonly [".javi-forge/ci.yaml", ".javi-forge/ci.yml"];
15
+ export interface CIRunnerConfig {
16
+ /** Unique runner name (used in step ids and reports) */
17
+ name: string;
18
+ /** Toolchain stack — selects the default CI image and default commands */
19
+ stack: Stack;
20
+ /** Working directory relative to the project root (default: ".") */
21
+ directory: string;
22
+ /** Explicit container image (mutually exclusive with `buildContext`) */
23
+ image?: string;
24
+ /** Docker build context directory (mutually exclusive with `image`) */
25
+ buildContext?: string;
26
+ /** Dependency setup commands, run before lint/build/test */
27
+ setup: string[];
28
+ lint: string[];
29
+ build: string[];
30
+ test: string[];
31
+ security: string[];
32
+ /** Tools that must exist in the runner environment (validated fail-closed) */
33
+ requires: string[];
34
+ }
35
+ export interface CIConfig {
36
+ version: number;
37
+ runners: CIRunnerConfig[];
38
+ }
39
+ export interface CIConfigValidationError {
40
+ path: string;
41
+ message: string;
42
+ }
43
+ export declare class CIConfigError extends Error {
44
+ readonly errors: CIConfigValidationError[];
45
+ constructor(errors: CIConfigValidationError[], source?: string);
46
+ }
47
+ /** Stacks accepted by the CI config schema and the --stack override. */
48
+ export declare const CI_STACKS: readonly string[];
49
+ /**
50
+ * Parse and validate CI config YAML text. Throws CIConfigError listing every
51
+ * validation problem; never returns a partially valid config.
52
+ */
53
+ export declare function parseCIConfig(rawYaml: string, source?: string): CIConfig;
54
+ /**
55
+ * Load and validate a CI config file. Fails closed: a missing file or any
56
+ * validation error throws — no config is ever silently ignored.
57
+ */
58
+ export declare function loadCIConfig(configPath: string): Promise<CIConfig>;
59
+ /**
60
+ * Discover the default CI config for a project directory.
61
+ * Returns the config path, or null when the project has no config
62
+ * (single-stack auto-detection stays the default).
63
+ */
64
+ export declare function findCIConfig(projectDir: string): Promise<string | null>;
65
+ //# sourceMappingURL=ci-config.d.ts.map