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
@@ -1,11 +1,19 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { Box, Text, useInput } from 'ink';
3
- import { theme } from './theme.js';
4
- import { useCIMode } from './CIContext.js';
1
+ import { Box, Text, useInput } from "ink";
2
+ import React, { useEffect, useState } from "react";
3
+ import { useCIMode } from "./CIContext.js";
4
+ import { theme } from "./theme.js";
5
5
  const CI_PROVIDERS = [
6
- { id: 'github', label: 'GitHub Actions', description: 'GitHub CI/CD with reusable workflows' },
7
- { id: 'gitlab', label: 'GitLab CI', description: 'GitLab CI/CD pipelines' },
8
- { id: 'woodpecker', label: 'Woodpecker CI', description: 'Container-native CI for Gitea/Forgejo' },
6
+ {
7
+ id: "github",
8
+ label: "GitHub Actions",
9
+ description: "GitHub CI/CD with reusable workflows",
10
+ },
11
+ { id: "gitlab", label: "GitLab CI", description: "GitLab CI/CD pipelines" },
12
+ {
13
+ id: "woodpecker",
14
+ label: "Woodpecker CI",
15
+ description: "Container-native CI for Gitea/Forgejo",
16
+ },
9
17
  ];
10
18
  export default function CISelector({ onConfirm }) {
11
19
  const isCI = useCIMode();
@@ -18,9 +26,9 @@ export default function CISelector({ onConfirm }) {
18
26
  }, [isCI]); // eslint-disable-line react-hooks/exhaustive-deps
19
27
  useInput((_, key) => {
20
28
  if (key.upArrow)
21
- setCursor(c => Math.max(0, c - 1));
29
+ setCursor((c) => Math.max(0, c - 1));
22
30
  if (key.downArrow)
23
- setCursor(c => Math.min(CI_PROVIDERS.length - 1, c + 1));
31
+ setCursor((c) => Math.min(CI_PROVIDERS.length - 1, c + 1));
24
32
  if (key.return) {
25
33
  onConfirm(CI_PROVIDERS[cursor].id);
26
34
  }
@@ -28,18 +36,18 @@ export default function CISelector({ onConfirm }) {
28
36
  return (React.createElement(Box, { flexDirection: "column" },
29
37
  React.createElement(Text, { bold: true }, "Select CI provider:"),
30
38
  React.createElement(Box, { marginTop: 1, flexDirection: "column", borderStyle: "single", borderLeft: true, borderRight: false, borderTop: false, borderBottom: false, borderColor: theme.muted, paddingLeft: 1 }, CI_PROVIDERS.map((p, i) => (React.createElement(Box, { key: p.id },
31
- React.createElement(Text, { color: i === cursor ? theme.primary : 'white' },
32
- i === cursor ? '\u25b6 ' : ' ',
33
- i === cursor ? '\u25c9' : '\u25cb',
39
+ React.createElement(Text, { color: i === cursor ? theme.primary : "white" },
40
+ i === cursor ? "\u25b6 " : " ",
41
+ i === cursor ? "\u25c9" : "\u25cb",
34
42
  " ",
35
43
  p.label),
36
44
  React.createElement(Text, { color: theme.muted, dimColor: true },
37
- " ",
45
+ " ",
38
46
  p.description))))),
39
47
  React.createElement(Box, { marginTop: 1, gap: 2 },
40
48
  React.createElement(Text, { color: theme.primary }, CI_PROVIDERS[cursor].label),
41
49
  React.createElement(Text, { color: theme.muted, dimColor: true },
42
- '\u2191\u2193',
43
- " navigate Enter confirm"))));
50
+ "\u2191\u2193",
51
+ " navigate Enter confirm"))));
44
52
  }
45
53
  //# sourceMappingURL=CISelector.js.map
@@ -1,3 +1,3 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
  export default function Doctor(): React.JSX.Element;
3
3
  //# sourceMappingURL=Doctor.d.ts.map
package/dist/ui/Doctor.js CHANGED
@@ -1,14 +1,14 @@
1
- import React, { useEffect, useState, useCallback } from 'react';
2
- import { Box, Text, useApp, useInput } from 'ink';
3
- import Spinner from 'ink-spinner';
4
- import { runDoctor } from '../commands/doctor.js';
5
- import Header from './Header.js';
6
- import { theme } from './theme.js';
7
- import { useCIMode } from './CIContext.js';
1
+ import { Box, Text, useApp, useInput } from "ink";
2
+ import Spinner from "ink-spinner";
3
+ import React, { useCallback, useEffect, useState } from "react";
4
+ import { runDoctor } from "../commands/doctor.js";
5
+ import { useCIMode } from "./CIContext.js";
6
+ import Header from "./Header.js";
7
+ import { theme } from "./theme.js";
8
8
  const STATUS_ICON = {
9
- ok: '\u2713',
10
- fail: '\u2717',
11
- skip: '\u2013',
9
+ ok: "\u2713",
10
+ fail: "\u2717",
11
+ skip: "\u2013",
12
12
  };
13
13
  const STATUS_COLOR = {
14
14
  ok: theme.success,
@@ -26,10 +26,18 @@ export default function Doctor() {
26
26
  setResult(null);
27
27
  setError(null);
28
28
  runDoctor()
29
- .then(r => { setResult(r); setLoading(false); })
30
- .catch(e => { setError(String(e)); setLoading(false); });
29
+ .then((r) => {
30
+ setResult(r);
31
+ setLoading(false);
32
+ })
33
+ .catch((e) => {
34
+ setError(String(e));
35
+ setLoading(false);
36
+ });
31
37
  }, []);
32
- useEffect(() => { runCheck(); }, [runCheck]);
38
+ useEffect(() => {
39
+ runCheck();
40
+ }, [runCheck]);
33
41
  // Auto-exit in CI mode once loading finishes
34
42
  useEffect(() => {
35
43
  if (isCI && !loading) {
@@ -39,22 +47,22 @@ export default function Doctor() {
39
47
  return undefined;
40
48
  }, [isCI, loading, exit]);
41
49
  useInput((input, key) => {
42
- if (input.toLowerCase() === 'r')
50
+ if (input.toLowerCase() === "r")
43
51
  runCheck();
44
- if (input.toLowerCase() === 'q' || key.return || key.escape)
52
+ if (input.toLowerCase() === "q" || key.return || key.escape)
45
53
  exit();
46
54
  }, { isActive: !isCI });
47
55
  // Compute health score
48
- const allChecks = result?.sections.flatMap(s => s.checks) ?? [];
49
- const passed = allChecks.filter(c => c.status === 'ok').length;
50
- const total = allChecks.filter(c => c.status !== 'skip').length;
56
+ const allChecks = result?.sections.flatMap((s) => s.checks) ?? [];
57
+ const passed = allChecks.filter((c) => c.status === "ok").length;
58
+ const total = allChecks.filter((c) => c.status !== "skip").length;
51
59
  return (React.createElement(Box, { flexDirection: "column", padding: 1 },
52
60
  React.createElement(Header, { subtitle: "doctor" }),
53
61
  loading && (React.createElement(Text, { color: theme.warning },
54
62
  React.createElement(Spinner, { type: "dots" }),
55
- ' Running checks...')),
63
+ " Running checks...")),
56
64
  error && (React.createElement(Text, { color: theme.error },
57
- '\u2717',
65
+ "\u2717",
58
66
  " Error: ",
59
67
  error)),
60
68
  result && (React.createElement(Box, { flexDirection: "column" },
@@ -66,22 +74,20 @@ export default function Doctor() {
66
74
  total,
67
75
  " checks passed")),
68
76
  result.sections.map((section, si) => {
69
- const sectionHasFail = section.checks.some(c => c.status === 'fail');
77
+ const sectionHasFail = section.checks.some((c) => c.status === "fail");
70
78
  return (React.createElement(Box, { key: `section-${si}`, flexDirection: "column", marginBottom: 1 },
71
79
  React.createElement(Text, { bold: true, color: sectionHasFail ? theme.warning : theme.success },
72
- ' ',
80
+ " ",
73
81
  section.title),
74
82
  section.checks.map((check, ci) => (React.createElement(Box, { key: `section-${si}-check-${ci}-${check.label}` },
75
83
  React.createElement(Text, { color: STATUS_COLOR[check.status] },
76
- ' ',
84
+ " ",
77
85
  STATUS_ICON[check.status],
78
- ' ',
86
+ " ",
79
87
  check.label,
80
- check.detail
81
- ? React.createElement(Text, { color: theme.muted, dimColor: true },
82
- ' ',
83
- check.detail)
84
- : null))))));
88
+ check.detail ? (React.createElement(Text, { color: theme.muted, dimColor: true },
89
+ " ",
90
+ check.detail)) : null))))));
85
91
  }))),
86
92
  !loading && (React.createElement(Box, { marginTop: 1 },
87
93
  React.createElement(Text, { color: theme.muted, dimColor: true }, "Press r to refresh, q to quit")))));
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
  interface Props {
3
3
  subtitle?: string;
4
4
  dryRun?: boolean;
package/dist/ui/Header.js CHANGED
@@ -1,30 +1,30 @@
1
- import React from 'react';
2
- import { Box, Text } from 'ink';
3
- import { theme } from './theme.js';
4
- const TITLE = '\u2726 javi-forge Project scaffolding';
1
+ import { Box, Text } from "ink";
2
+ import React from "react";
3
+ import { theme } from "./theme.js";
4
+ const TITLE = "\u2726 javi-forge Project scaffolding";
5
5
  // Fixed inner width (characters between the box walls)
6
6
  const BOX_WIDTH = 41;
7
7
  function pad(content) {
8
8
  const len = [...content].length; // unicode-safe length
9
9
  const spaces = BOX_WIDTH - len;
10
- return content + ' '.repeat(Math.max(0, spaces));
10
+ return content + " ".repeat(Math.max(0, spaces));
11
11
  }
12
12
  export default function Header({ subtitle, dryRun }) {
13
- const top = '\u256d' + '\u2500'.repeat(BOX_WIDTH) + '\u256e';
14
- const bottom = '\u2570' + '\u2500'.repeat(BOX_WIDTH) + '\u256f';
15
- const titleLine = pad(' ' + TITLE + ' ');
16
- const subLine = subtitle ? pad(' ' + subtitle + ' ') : null;
13
+ const top = `\u256d${"\u2500".repeat(BOX_WIDTH)}\u256e`;
14
+ const bottom = `\u2570${"\u2500".repeat(BOX_WIDTH)}\u256f`;
15
+ const titleLine = pad(` ${TITLE} `);
16
+ const subLine = subtitle ? pad(` ${subtitle} `) : null;
17
17
  return (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
18
18
  React.createElement(Text, { color: theme.muted }, top),
19
19
  React.createElement(Box, null,
20
- React.createElement(Text, { color: theme.muted }, '\u2502'),
20
+ React.createElement(Text, { color: theme.muted }, "\u2502"),
21
21
  React.createElement(Text, { bold: true, color: theme.primary }, titleLine),
22
- React.createElement(Text, { color: theme.muted }, '\u2502')),
22
+ React.createElement(Text, { color: theme.muted }, "\u2502")),
23
23
  subLine && (React.createElement(Box, null,
24
- React.createElement(Text, { color: theme.muted }, '\u2502'),
24
+ React.createElement(Text, { color: theme.muted }, "\u2502"),
25
25
  React.createElement(Text, { color: theme.muted }, subLine),
26
- React.createElement(Text, { color: theme.muted }, '\u2502'))),
26
+ React.createElement(Text, { color: theme.muted }, "\u2502"))),
27
27
  React.createElement(Text, { color: theme.muted }, bottom),
28
- dryRun && (React.createElement(Text, { color: theme.warning }, " [DRY RUN]"))));
28
+ dryRun && React.createElement(Text, { color: theme.warning }, " [DRY RUN]")));
29
29
  }
30
30
  //# sourceMappingURL=Header.js.map
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ import type { HookProfile } from "../types/index.js";
3
+ interface Props {
4
+ onConfirm: (profile: HookProfile) => void;
5
+ presetProfile?: HookProfile;
6
+ }
7
+ export default function HookProfileSelector({ onConfirm, presetProfile, }: Props): React.JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=HookProfileSelector.d.ts.map
@@ -0,0 +1,54 @@
1
+ import { Box, Text, useInput } from "ink";
2
+ import React, { useEffect, useState } from "react";
3
+ import { HOOK_PROFILES } from "../constants.js";
4
+ import { useCIMode } from "./CIContext.js";
5
+ import { theme } from "./theme.js";
6
+ const PROFILES = Object.entries(HOOK_PROFILES).map(([id, meta]) => ({
7
+ id,
8
+ label: meta.label,
9
+ description: meta.description,
10
+ }));
11
+ // Default selection index (standard = index 1)
12
+ const DEFAULT_INDEX = 1;
13
+ export default function HookProfileSelector({ onConfirm, presetProfile, }) {
14
+ const isCI = useCIMode();
15
+ const [cursor, setCursor] = useState(() => {
16
+ if (presetProfile) {
17
+ const idx = PROFILES.findIndex((p) => p.id === presetProfile);
18
+ return idx >= 0 ? idx : DEFAULT_INDEX;
19
+ }
20
+ return DEFAULT_INDEX;
21
+ });
22
+ // Auto-confirm in CI mode with default
23
+ useEffect(() => {
24
+ if (isCI) {
25
+ onConfirm(PROFILES[cursor].id);
26
+ }
27
+ }, [isCI]); // eslint-disable-line react-hooks/exhaustive-deps
28
+ useInput((_, key) => {
29
+ if (key.upArrow)
30
+ setCursor((c) => Math.max(0, c - 1));
31
+ if (key.downArrow)
32
+ setCursor((c) => Math.min(PROFILES.length - 1, c + 1));
33
+ if (key.return) {
34
+ onConfirm(PROFILES[cursor].id);
35
+ }
36
+ }, { isActive: !isCI });
37
+ return (React.createElement(Box, { flexDirection: "column" },
38
+ React.createElement(Text, { bold: true }, "Select hook reliability profile:"),
39
+ React.createElement(Box, { marginTop: 1, flexDirection: "column", borderStyle: "single", borderLeft: true, borderRight: false, borderTop: false, borderBottom: false, borderColor: theme.muted, paddingLeft: 1 }, PROFILES.map((p, i) => (React.createElement(Box, { key: p.id },
40
+ React.createElement(Text, { color: i === cursor ? theme.primary : "white" },
41
+ i === cursor ? "\u25b6 " : " ",
42
+ i === cursor ? "\u25c9" : "\u25cb",
43
+ " ",
44
+ p.label),
45
+ React.createElement(Text, { color: theme.muted, dimColor: true },
46
+ " ",
47
+ p.description))))),
48
+ React.createElement(Box, { marginTop: 1, gap: 2 },
49
+ React.createElement(Text, { color: theme.primary }, PROFILES[cursor].label),
50
+ React.createElement(Text, { color: theme.muted, dimColor: true },
51
+ "\u2191\u2193",
52
+ " navigate Enter confirm"))));
53
+ }
54
+ //# sourceMappingURL=HookProfileSelector.js.map
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
  interface Props {
3
3
  projectDir: string;
4
4
  dryRun: boolean;
@@ -1,17 +1,19 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { Box, Text } from 'ink';
3
- import Spinner from 'ink-spinner';
4
- import { generateLlmsTxt } from '../commands/llmstxt.js';
5
- import { theme } from './theme.js';
1
+ import { Box, Text } from "ink";
2
+ import Spinner from "ink-spinner";
3
+ import React, { useEffect, useState } from "react";
4
+ import { generateLlmsTxt } from "../commands/llmstxt.js";
5
+ import { theme } from "./theme.js";
6
6
  const STATUS_ICON = {
7
- done: '\u2713', error: '\u2717', skipped: '\u2013',
7
+ done: "\u2713",
8
+ error: "\u2717",
9
+ skipped: "\u2013",
8
10
  };
9
11
  export default function LlmsTxt({ projectDir, dryRun }) {
10
12
  const [steps, setSteps] = useState([]);
11
13
  const [done, setDone] = useState(false);
12
14
  const onStep = (step) => {
13
- setSteps(prev => {
14
- const idx = prev.findIndex(s => s.id === step.id);
15
+ setSteps((prev) => {
16
+ const idx = prev.findIndex((s) => s.id === step.id);
15
17
  if (idx >= 0) {
16
18
  const n = [...prev];
17
19
  n[idx] = step;
@@ -22,7 +24,12 @@ export default function LlmsTxt({ projectDir, dryRun }) {
22
24
  };
23
25
  useEffect(() => {
24
26
  generateLlmsTxt(projectDir, dryRun, onStep)
25
- .catch(e => onStep({ id: 'fatal', label: 'Error', status: 'error', detail: String(e) }))
27
+ .catch((e) => onStep({
28
+ id: "fatal",
29
+ label: "Error",
30
+ status: "error",
31
+ detail: String(e),
32
+ }))
26
33
  .finally(() => setDone(true));
27
34
  }, [projectDir, dryRun]);
28
35
  return (React.createElement(Box, { flexDirection: "column", padding: 1 },
@@ -30,19 +37,21 @@ export default function LlmsTxt({ projectDir, dryRun }) {
30
37
  React.createElement(Text, { bold: true, color: theme.primary }, "javi-forge"),
31
38
  React.createElement(Text, null, " llms-txt"),
32
39
  dryRun && React.createElement(Text, { color: theme.warning }, " (dry-run)")),
33
- steps.map(s => (React.createElement(Box, { key: s.id, marginLeft: 2 }, s.status === 'running'
34
- ? React.createElement(Text, { color: theme.warning },
35
- React.createElement(Spinner, { type: "dots" }),
40
+ steps.map((s) => (React.createElement(Box, { key: s.id, marginLeft: 2 }, s.status === "running" ? (React.createElement(Text, { color: theme.warning },
41
+ React.createElement(Spinner, { type: "dots" }),
42
+ " ",
43
+ s.label)) : (React.createElement(Text, { color: s.status === "done"
44
+ ? theme.success
45
+ : s.status === "error"
46
+ ? theme.error
47
+ : theme.muted },
48
+ STATUS_ICON[s.status],
49
+ " ",
50
+ s.label,
51
+ s.detail ? (React.createElement(Text, { color: theme.muted, dimColor: true },
36
52
  " ",
37
- s.label)
38
- : React.createElement(Text, { color: s.status === 'done' ? theme.success : s.status === 'error' ? theme.error : theme.muted },
39
- STATUS_ICON[s.status],
40
- " ",
41
- s.label,
42
- s.detail ? React.createElement(Text, { color: theme.muted, dimColor: true },
43
- " ",
44
- s.detail) : null)))),
45
- done && React.createElement(Box, { marginTop: 1 },
46
- React.createElement(Text, { color: theme.muted }, "Done."))));
53
+ s.detail)) : null))))),
54
+ done && (React.createElement(Box, { marginTop: 1 },
55
+ React.createElement(Text, { color: theme.muted }, "Done.")))));
47
56
  }
48
57
  //# sourceMappingURL=LlmsTxt.js.map
@@ -1,5 +1,5 @@
1
- import React from 'react';
2
- import type { MemoryOption } from '../types/index.js';
1
+ import React from "react";
2
+ import type { MemoryOption } from "../types/index.js";
3
3
  interface Props {
4
4
  onConfirm: (memory: MemoryOption) => void;
5
5
  }
@@ -1,12 +1,24 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { Box, Text, useInput } from 'ink';
3
- import { theme } from './theme.js';
4
- import { useCIMode } from './CIContext.js';
1
+ import { Box, Text, useInput } from "ink";
2
+ import React, { useEffect, useState } from "react";
3
+ import { useCIMode } from "./CIContext.js";
4
+ import { theme } from "./theme.js";
5
5
  const MEMORY_OPTIONS = [
6
- { id: 'engram', label: 'Engram', description: 'SQLite-backed persistent memory with MCP' },
7
- { id: 'obsidian-brain', label: 'Obsidian Brain', description: 'Obsidian vault with Kanban + Dataview' },
8
- { id: 'memory-simple', label: 'Simple Memory', description: 'File-based .project/ memory' },
9
- { id: 'none', label: 'None', description: 'Skip memory module' },
6
+ {
7
+ id: "engram",
8
+ label: "Engram",
9
+ description: "SQLite-backed persistent memory with MCP",
10
+ },
11
+ {
12
+ id: "obsidian-brain",
13
+ label: "Obsidian Brain",
14
+ description: "Obsidian vault with Kanban + Dataview",
15
+ },
16
+ {
17
+ id: "memory-simple",
18
+ label: "Simple Memory",
19
+ description: "File-based .project/ memory",
20
+ },
21
+ { id: "none", label: "None", description: "Skip memory module" },
10
22
  ];
11
23
  export default function MemorySelector({ onConfirm }) {
12
24
  const isCI = useCIMode();
@@ -19,9 +31,9 @@ export default function MemorySelector({ onConfirm }) {
19
31
  }, [isCI]); // eslint-disable-line react-hooks/exhaustive-deps
20
32
  useInput((_, key) => {
21
33
  if (key.upArrow)
22
- setCursor(c => Math.max(0, c - 1));
34
+ setCursor((c) => Math.max(0, c - 1));
23
35
  if (key.downArrow)
24
- setCursor(c => Math.min(MEMORY_OPTIONS.length - 1, c + 1));
36
+ setCursor((c) => Math.min(MEMORY_OPTIONS.length - 1, c + 1));
25
37
  if (key.return) {
26
38
  onConfirm(MEMORY_OPTIONS[cursor].id);
27
39
  }
@@ -29,18 +41,18 @@ export default function MemorySelector({ onConfirm }) {
29
41
  return (React.createElement(Box, { flexDirection: "column" },
30
42
  React.createElement(Text, { bold: true }, "Select memory module:"),
31
43
  React.createElement(Box, { marginTop: 1, flexDirection: "column", borderStyle: "single", borderLeft: true, borderRight: false, borderTop: false, borderBottom: false, borderColor: theme.muted, paddingLeft: 1 }, MEMORY_OPTIONS.map((m, i) => (React.createElement(Box, { key: m.id },
32
- React.createElement(Text, { color: i === cursor ? theme.primary : 'white' },
33
- i === cursor ? '\u25b6 ' : ' ',
34
- i === cursor ? '\u25c9' : '\u25cb',
44
+ React.createElement(Text, { color: i === cursor ? theme.primary : "white" },
45
+ i === cursor ? "\u25b6 " : " ",
46
+ i === cursor ? "\u25c9" : "\u25cb",
35
47
  " ",
36
48
  m.label),
37
49
  React.createElement(Text, { color: theme.muted, dimColor: true },
38
- " ",
50
+ " ",
39
51
  m.description))))),
40
52
  React.createElement(Box, { marginTop: 1, gap: 2 },
41
53
  React.createElement(Text, { color: theme.primary }, MEMORY_OPTIONS[cursor].label),
42
54
  React.createElement(Text, { color: theme.muted, dimColor: true },
43
- '\u2191\u2193',
44
- " navigate Enter confirm"))));
55
+ "\u2191\u2193",
56
+ " navigate Enter confirm"))));
45
57
  }
46
58
  //# sourceMappingURL=MemorySelector.js.map
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
  interface Props {
3
3
  defaultName: string;
4
4
  onConfirm: (name: string, dir: string) => void;
@@ -1,20 +1,20 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { Box, Text, useInput } from 'ink';
3
- import path from 'path';
4
- import { theme } from './theme.js';
5
- import { useCIMode } from './CIContext.js';
1
+ import path from "node:path";
2
+ import { Box, Text, useInput } from "ink";
3
+ import React, { useEffect, useState } from "react";
4
+ import { useCIMode } from "./CIContext.js";
5
+ import { theme } from "./theme.js";
6
6
  const VALID_NAME = /^[a-z0-9][a-z0-9._-]*$/;
7
7
  function validateName(name) {
8
8
  if (name.length === 0)
9
- return 'Name cannot be empty';
9
+ return "Name cannot be empty";
10
10
  if (name !== name.toLowerCase())
11
- return 'Use lowercase only';
12
- if (name.includes(' '))
13
- return 'No spaces allowed (use - or _)';
11
+ return "Use lowercase only";
12
+ if (name.includes(" "))
13
+ return "No spaces allowed (use - or _)";
14
14
  if (!VALID_NAME.test(name))
15
- return 'Use lowercase letters, numbers, hyphens, dots';
15
+ return "Use lowercase letters, numbers, hyphens, dots";
16
16
  if (name.length > 60)
17
- return 'Name too long (max 60 chars)';
17
+ return "Name too long (max 60 chars)";
18
18
  return null;
19
19
  }
20
20
  export default function NameInput({ defaultName, onConfirm }) {
@@ -23,7 +23,7 @@ export default function NameInput({ defaultName, onConfirm }) {
23
23
  const trimmed = value.trim();
24
24
  const error = validateName(trimmed);
25
25
  const isValid = error === null && trimmed.length > 0;
26
- const targetDir = path.resolve(process.cwd(), trimmed || '.');
26
+ const targetDir = path.resolve(process.cwd(), trimmed || ".");
27
27
  // Auto-confirm in CI mode
28
28
  useEffect(() => {
29
29
  if (isCI && isValid) {
@@ -35,33 +35,33 @@ export default function NameInput({ defaultName, onConfirm }) {
35
35
  onConfirm(trimmed, targetDir);
36
36
  }
37
37
  else if (key.backspace || key.delete) {
38
- setValue(v => v.slice(0, -1));
38
+ setValue((v) => v.slice(0, -1));
39
39
  }
40
40
  else if (input && !key.ctrl && !key.meta) {
41
- setValue(v => v + input);
41
+ setValue((v) => v + input);
42
42
  }
43
43
  }, { isActive: !isCI });
44
44
  return (React.createElement(Box, { flexDirection: "column" },
45
45
  React.createElement(Text, { bold: true }, "Project name:"),
46
46
  React.createElement(Box, { marginTop: 1 },
47
47
  React.createElement(Text, { color: isValid ? theme.primary : theme.error },
48
- '\u25b6',
48
+ "\u25b6",
49
49
  " "),
50
50
  React.createElement(Text, null, value),
51
- React.createElement(Text, { color: theme.muted }, '\u2588')),
51
+ React.createElement(Text, { color: theme.muted }, "\u2588")),
52
52
  trimmed.length > 0 && error && (React.createElement(Box, { marginTop: 1 },
53
53
  React.createElement(Text, { color: theme.error },
54
- " ",
55
- '\u2717',
54
+ " ",
55
+ "\u2717",
56
56
  " ",
57
57
  error))),
58
58
  isValid && (React.createElement(Box, { marginTop: 1 },
59
59
  React.createElement(Text, { color: theme.success },
60
- " ",
61
- '\u2713',
60
+ " ",
61
+ "\u2713",
62
62
  " Valid name"))),
63
63
  React.createElement(Box, { marginTop: 1 },
64
- React.createElement(Text, { color: theme.muted }, " Will create: "),
64
+ React.createElement(Text, { color: theme.muted }, " Will create: "),
65
65
  React.createElement(Text, { color: isValid ? theme.primary : theme.muted, dimColor: !isValid }, targetDir)),
66
66
  React.createElement(Box, { marginTop: 1 },
67
67
  React.createElement(Text, { color: theme.muted, dimColor: true }, "Enter to confirm"))));
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
  interface Props {
3
3
  onConfirm: (selected: {
4
4
  aiSync: boolean;
@@ -6,9 +6,13 @@ interface Props {
6
6
  contextDir: boolean;
7
7
  claudeMd: boolean;
8
8
  ghagga: boolean;
9
+ securityHooks: boolean;
10
+ codeGraph: boolean;
11
+ localAi: boolean;
9
12
  }) => void;
10
13
  presetGhagga?: boolean;
14
+ presetLocalAi?: boolean;
11
15
  }
12
- export default function OptionSelector({ onConfirm, presetGhagga }: Props): React.JSX.Element;
16
+ export default function OptionSelector({ onConfirm, presetGhagga, presetLocalAi, }: Props): React.JSX.Element;
13
17
  export {};
14
18
  //# sourceMappingURL=OptionSelector.d.ts.map