javi-forge 1.6.0 → 1.6.1

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 (231) hide show
  1. package/dist/commands/analyze.d.ts +1 -1
  2. package/dist/commands/analyze.js +15 -15
  3. package/dist/commands/atlassian-mcp.d.ts +42 -0
  4. package/dist/commands/atlassian-mcp.js +98 -0
  5. package/dist/commands/ci.d.ts +3 -3
  6. package/dist/commands/ci.js +185 -147
  7. package/dist/commands/crash-recovery.d.ts +34 -0
  8. package/dist/commands/crash-recovery.js +123 -0
  9. package/dist/commands/doctor.d.ts +2 -2
  10. package/dist/commands/doctor.js +113 -61
  11. package/dist/commands/harness-audit.d.ts +35 -0
  12. package/dist/commands/harness-audit.js +277 -0
  13. package/dist/commands/init.d.ts +1 -1
  14. package/dist/commands/init.js +384 -141
  15. package/dist/commands/llmstxt.d.ts +1 -1
  16. package/dist/commands/llmstxt.js +36 -34
  17. package/dist/commands/parallel-batch.d.ts +42 -0
  18. package/dist/commands/parallel-batch.js +90 -0
  19. package/dist/commands/plugin.d.ts +10 -1
  20. package/dist/commands/plugin.js +92 -47
  21. package/dist/commands/secret-scanner.d.ts +30 -0
  22. package/dist/commands/secret-scanner.js +272 -0
  23. package/dist/commands/security-analysis.d.ts +74 -0
  24. package/dist/commands/security-analysis.js +487 -0
  25. package/dist/commands/security.d.ts +11 -5
  26. package/dist/commands/security.js +216 -76
  27. package/dist/commands/skill-scanner.d.ts +63 -0
  28. package/dist/commands/skill-scanner.js +383 -0
  29. package/dist/commands/skills.d.ts +62 -5
  30. package/dist/commands/skills.js +439 -54
  31. package/dist/commands/supply-chain.d.ts +23 -0
  32. package/dist/commands/supply-chain.js +126 -0
  33. package/dist/commands/tdd-pipeline.d.ts +17 -0
  34. package/dist/commands/tdd-pipeline.js +144 -0
  35. package/dist/commands/tdd.d.ts +1 -1
  36. package/dist/commands/tdd.js +21 -18
  37. package/dist/commands/team-presets.d.ts +53 -0
  38. package/dist/commands/team-presets.js +201 -0
  39. package/dist/commands/workflow.d.ts +23 -0
  40. package/dist/commands/workflow.js +114 -0
  41. package/dist/constants.d.ts +15 -1
  42. package/dist/constants.js +161 -122
  43. package/dist/index.js +308 -98
  44. package/dist/lib/agent-skills.d.ts +36 -1
  45. package/dist/lib/agent-skills.js +168 -19
  46. package/dist/lib/auto-skill-install.d.ts +37 -0
  47. package/dist/lib/auto-skill-install.js +92 -0
  48. package/dist/lib/auto-wire.d.ts +20 -0
  49. package/dist/lib/auto-wire.js +240 -0
  50. package/dist/lib/claudemd.d.ts +13 -1
  51. package/dist/lib/claudemd.js +174 -24
  52. package/dist/lib/codex-export.d.ts +1 -1
  53. package/dist/lib/codex-export.js +29 -31
  54. package/dist/lib/common.d.ts +1 -1
  55. package/dist/lib/common.js +52 -44
  56. package/dist/lib/context.d.ts +17 -2
  57. package/dist/lib/context.js +142 -13
  58. package/dist/lib/docker.d.ts +1 -1
  59. package/dist/lib/docker.js +141 -112
  60. package/dist/lib/frontmatter.d.ts +1 -1
  61. package/dist/lib/frontmatter.js +29 -15
  62. package/dist/lib/plugin.d.ts +9 -3
  63. package/dist/lib/plugin.js +128 -69
  64. package/dist/lib/skill-publish.d.ts +40 -0
  65. package/dist/lib/skill-publish.js +146 -0
  66. package/dist/lib/stack-detector.d.ts +38 -0
  67. package/dist/lib/stack-detector.js +207 -0
  68. package/dist/lib/template.d.ts +16 -1
  69. package/dist/lib/template.js +46 -17
  70. package/dist/lib/workflow/discovery.d.ts +19 -0
  71. package/dist/lib/workflow/discovery.js +68 -0
  72. package/dist/lib/workflow/index.d.ts +5 -0
  73. package/dist/lib/workflow/index.js +5 -0
  74. package/dist/lib/workflow/parser.d.ts +16 -0
  75. package/dist/lib/workflow/parser.js +198 -0
  76. package/dist/lib/workflow/renderer.d.ts +9 -0
  77. package/dist/lib/workflow/renderer.js +152 -0
  78. package/dist/lib/workflow/validator.d.ts +10 -0
  79. package/dist/lib/workflow/validator.js +189 -0
  80. package/dist/tasks/index.d.ts +4 -0
  81. package/dist/tasks/index.js +4 -0
  82. package/dist/tasks/scaffold-tasks.d.ts +3 -0
  83. package/dist/tasks/scaffold-tasks.js +14 -0
  84. package/dist/tasks/task-id.d.ts +30 -0
  85. package/dist/tasks/task-id.js +55 -0
  86. package/dist/tasks/task-tracker.d.ts +15 -0
  87. package/dist/tasks/task-tracker.js +81 -0
  88. package/dist/types/index.d.ts +134 -6
  89. package/dist/types/index.js +11 -1
  90. package/dist/ui/AnalyzeUI.d.ts +1 -1
  91. package/dist/ui/AnalyzeUI.js +38 -39
  92. package/dist/ui/App.d.ts +5 -3
  93. package/dist/ui/App.js +86 -46
  94. package/dist/ui/AutoSkills.d.ts +9 -0
  95. package/dist/ui/AutoSkills.js +124 -0
  96. package/dist/ui/CI.d.ts +2 -2
  97. package/dist/ui/CI.js +24 -26
  98. package/dist/ui/CIContext.d.ts +1 -1
  99. package/dist/ui/CIContext.js +3 -2
  100. package/dist/ui/CISelector.d.ts +2 -2
  101. package/dist/ui/CISelector.js +23 -15
  102. package/dist/ui/Doctor.d.ts +1 -1
  103. package/dist/ui/Doctor.js +35 -29
  104. package/dist/ui/Header.d.ts +1 -1
  105. package/dist/ui/Header.js +14 -14
  106. package/dist/ui/HookProfileSelector.d.ts +9 -0
  107. package/dist/ui/HookProfileSelector.js +54 -0
  108. package/dist/ui/LlmsTxt.d.ts +1 -1
  109. package/dist/ui/LlmsTxt.js +31 -22
  110. package/dist/ui/MemorySelector.d.ts +2 -2
  111. package/dist/ui/MemorySelector.js +28 -16
  112. package/dist/ui/NameInput.d.ts +1 -1
  113. package/dist/ui/NameInput.js +21 -21
  114. package/dist/ui/OptionSelector.d.ts +6 -2
  115. package/dist/ui/OptionSelector.js +83 -32
  116. package/dist/ui/Plugin.d.ts +4 -3
  117. package/dist/ui/Plugin.js +78 -35
  118. package/dist/ui/Progress.d.ts +3 -3
  119. package/dist/ui/Progress.js +23 -22
  120. package/dist/ui/Skills.d.ts +2 -2
  121. package/dist/ui/Skills.js +61 -32
  122. package/dist/ui/StackSelector.d.ts +2 -2
  123. package/dist/ui/StackSelector.js +26 -16
  124. package/dist/ui/Summary.d.ts +3 -3
  125. package/dist/ui/Summary.js +60 -50
  126. package/dist/ui/Welcome.d.ts +1 -1
  127. package/dist/ui/Welcome.js +15 -16
  128. package/dist/ui/theme.d.ts +1 -1
  129. package/dist/ui/theme.js +6 -6
  130. package/package.json +9 -6
  131. package/templates/common/atlassian/mcp-atlassian-snippet.json +16 -0
  132. package/templates/common/repoforge/mcp-repoforge-snippet.json +11 -0
  133. package/templates/common/repoforge/repoforge.yaml +34 -0
  134. package/templates/github/deploy-docker-zero-downtime.yml +140 -0
  135. package/templates/github/repoforge-graph.yml +45 -0
  136. package/templates/gitlab/deploy-docker-zero-downtime.yml +57 -0
  137. package/templates/local-ai/.env.example +17 -0
  138. package/templates/local-ai/docker-compose.yml +95 -0
  139. package/templates/security-hooks/claude-settings-security.json +30 -0
  140. package/templates/security-hooks/commit-msg-signing +29 -0
  141. package/templates/security-hooks/pre-commit-permissions +74 -0
  142. package/templates/security-hooks/pre-commit-secrets +74 -0
  143. package/templates/security-hooks/pre-push-branch-protection +62 -0
  144. package/templates/security-hooks/pre-push-deps +83 -0
  145. package/templates/security-hooks/pre-push-signing +67 -0
  146. package/templates/woodpecker/deploy-docker-zero-downtime.yml +50 -0
  147. package/templates/workflows/ci-pipeline.dot +15 -0
  148. package/templates/workflows/feature-flow.dot +21 -0
  149. package/templates/workflows/release.dot +16 -0
  150. package/dist/__integration__/helpers.d.ts +0 -20
  151. package/dist/__integration__/helpers.d.ts.map +0 -1
  152. package/dist/__integration__/helpers.js +0 -31
  153. package/dist/__integration__/helpers.js.map +0 -1
  154. package/dist/commands/analyze.d.ts.map +0 -1
  155. package/dist/commands/analyze.js.map +0 -1
  156. package/dist/commands/ci.d.ts.map +0 -1
  157. package/dist/commands/ci.js.map +0 -1
  158. package/dist/commands/doctor.d.ts.map +0 -1
  159. package/dist/commands/doctor.js.map +0 -1
  160. package/dist/commands/init.d.ts.map +0 -1
  161. package/dist/commands/init.js.map +0 -1
  162. package/dist/commands/llmstxt.d.ts.map +0 -1
  163. package/dist/commands/llmstxt.js.map +0 -1
  164. package/dist/commands/plugin.d.ts.map +0 -1
  165. package/dist/commands/plugin.js.map +0 -1
  166. package/dist/commands/security.d.ts.map +0 -1
  167. package/dist/commands/security.js.map +0 -1
  168. package/dist/commands/skills.d.ts.map +0 -1
  169. package/dist/commands/skills.js.map +0 -1
  170. package/dist/commands/tdd.d.ts.map +0 -1
  171. package/dist/commands/tdd.js.map +0 -1
  172. package/dist/constants.d.ts.map +0 -1
  173. package/dist/constants.js.map +0 -1
  174. package/dist/index.d.ts.map +0 -1
  175. package/dist/index.js.map +0 -1
  176. package/dist/lib/agent-skills.d.ts.map +0 -1
  177. package/dist/lib/agent-skills.js.map +0 -1
  178. package/dist/lib/claudemd.d.ts.map +0 -1
  179. package/dist/lib/claudemd.js.map +0 -1
  180. package/dist/lib/codex-export.d.ts.map +0 -1
  181. package/dist/lib/codex-export.js.map +0 -1
  182. package/dist/lib/common.d.ts.map +0 -1
  183. package/dist/lib/common.js.map +0 -1
  184. package/dist/lib/context.d.ts.map +0 -1
  185. package/dist/lib/context.js.map +0 -1
  186. package/dist/lib/docker.d.ts.map +0 -1
  187. package/dist/lib/docker.js.map +0 -1
  188. package/dist/lib/frontmatter.d.ts.map +0 -1
  189. package/dist/lib/frontmatter.js.map +0 -1
  190. package/dist/lib/plugin.d.ts.map +0 -1
  191. package/dist/lib/plugin.js.map +0 -1
  192. package/dist/lib/template.d.ts.map +0 -1
  193. package/dist/lib/template.js.map +0 -1
  194. package/dist/types/index.d.ts.map +0 -1
  195. package/dist/types/index.js.map +0 -1
  196. package/dist/ui/AnalyzeUI.d.ts.map +0 -1
  197. package/dist/ui/AnalyzeUI.js.map +0 -1
  198. package/dist/ui/App.d.ts.map +0 -1
  199. package/dist/ui/App.js.map +0 -1
  200. package/dist/ui/CI.d.ts.map +0 -1
  201. package/dist/ui/CI.js.map +0 -1
  202. package/dist/ui/CIContext.d.ts.map +0 -1
  203. package/dist/ui/CIContext.js.map +0 -1
  204. package/dist/ui/CISelector.d.ts.map +0 -1
  205. package/dist/ui/CISelector.js.map +0 -1
  206. package/dist/ui/Doctor.d.ts.map +0 -1
  207. package/dist/ui/Doctor.js.map +0 -1
  208. package/dist/ui/Header.d.ts.map +0 -1
  209. package/dist/ui/Header.js.map +0 -1
  210. package/dist/ui/LlmsTxt.d.ts.map +0 -1
  211. package/dist/ui/LlmsTxt.js.map +0 -1
  212. package/dist/ui/MemorySelector.d.ts.map +0 -1
  213. package/dist/ui/MemorySelector.js.map +0 -1
  214. package/dist/ui/NameInput.d.ts.map +0 -1
  215. package/dist/ui/NameInput.js.map +0 -1
  216. package/dist/ui/OptionSelector.d.ts.map +0 -1
  217. package/dist/ui/OptionSelector.js.map +0 -1
  218. package/dist/ui/Plugin.d.ts.map +0 -1
  219. package/dist/ui/Plugin.js.map +0 -1
  220. package/dist/ui/Progress.d.ts.map +0 -1
  221. package/dist/ui/Progress.js.map +0 -1
  222. package/dist/ui/Skills.d.ts.map +0 -1
  223. package/dist/ui/Skills.js.map +0 -1
  224. package/dist/ui/StackSelector.d.ts.map +0 -1
  225. package/dist/ui/StackSelector.js.map +0 -1
  226. package/dist/ui/Summary.d.ts.map +0 -1
  227. package/dist/ui/Summary.js.map +0 -1
  228. package/dist/ui/Welcome.d.ts.map +0 -1
  229. package/dist/ui/Welcome.js.map +0 -1
  230. package/dist/ui/theme.d.ts.map +0 -1
  231. package/dist/ui/theme.js.map +0 -1
package/dist/ui/Skills.js CHANGED
@@ -1,10 +1,10 @@
1
- import React, { useEffect, useState, useCallback } from 'react';
2
- import { Box, Text, useApp, useInput } from 'ink';
3
- import Spinner from 'ink-spinner';
4
- import { runSkillsDoctor } from '../commands/skills.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 { runSkillsDoctor } from "../commands/skills.js";
5
+ import { useCIMode } from "./CIContext.js";
6
+ import Header from "./Header.js";
7
+ import { theme } from "./theme.js";
8
8
  export default function Skills({ mode, budget, deep, skillsDir }) {
9
9
  const { exit } = useApp();
10
10
  const isCI = useCIMode();
@@ -16,10 +16,18 @@ export default function Skills({ mode, budget, deep, skillsDir }) {
16
16
  setResult(null);
17
17
  setError(null);
18
18
  runSkillsDoctor({ mode, budget, deep, skillsDir })
19
- .then(r => { setResult(r); setLoading(false); })
20
- .catch(e => { setError(String(e)); setLoading(false); });
19
+ .then((r) => {
20
+ setResult(r);
21
+ setLoading(false);
22
+ })
23
+ .catch((e) => {
24
+ setError(String(e));
25
+ setLoading(false);
26
+ });
21
27
  }, [mode, budget, deep, skillsDir]);
22
- useEffect(() => { runCheck(); }, [runCheck]);
28
+ useEffect(() => {
29
+ runCheck();
30
+ }, [runCheck]);
23
31
  // Auto-exit in CI mode once loading finishes
24
32
  useEffect(() => {
25
33
  if (isCI && !loading) {
@@ -29,75 +37,96 @@ export default function Skills({ mode, budget, deep, skillsDir }) {
29
37
  return undefined;
30
38
  }, [isCI, loading, exit]);
31
39
  useInput((input, key) => {
32
- if (input.toLowerCase() === 'r')
40
+ if (input.toLowerCase() === "r")
33
41
  runCheck();
34
- if (input.toLowerCase() === 'q' || key.return || key.escape)
42
+ if (input.toLowerCase() === "q" || key.return || key.escape)
35
43
  exit();
36
44
  }, { isActive: !isCI });
37
- const subtitle = mode === 'budget' ? 'skills budget' : 'skills doctor';
45
+ const subtitle = mode === "budget" ? "skills budget" : "skills doctor";
38
46
  return (React.createElement(Box, { flexDirection: "column", padding: 1 },
39
47
  React.createElement(Header, { subtitle: subtitle }),
40
48
  loading && (React.createElement(Text, { color: theme.warning },
41
49
  React.createElement(Spinner, { type: "dots" }),
42
- ' Running skills analysis...')),
50
+ " Running skills analysis...")),
43
51
  error && (React.createElement(Text, { color: theme.error },
44
- '\u2717',
52
+ "\u2717",
45
53
  " Error: ",
46
54
  error)),
47
55
  result && (React.createElement(Box, { flexDirection: "column" },
48
56
  React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
49
57
  React.createElement(Text, { bold: true, color: result.budget.overBudget ? theme.warning : theme.success },
50
- ' ',
58
+ " ",
51
59
  "Context Budget"),
52
60
  React.createElement(Box, { marginLeft: 2 },
53
61
  React.createElement(Text, { color: result.budget.overBudget ? theme.warning : theme.success },
54
- result.budget.overBudget ? '\u2717' : '\u2713',
55
- ' ',
62
+ result.budget.overBudget ? "\u2717" : "\u2713",
63
+ " ",
56
64
  result.budget.totalTokens,
57
65
  " / ",
58
66
  result.budget.budget,
59
67
  " tokens",
60
- result.budget.overBudget ? ' (OVER BUDGET)' : '')),
61
- result.budget.entries.map(entry => (React.createElement(Box, { key: entry.skillName, marginLeft: 4 },
68
+ result.budget.overBudget ? " (OVER BUDGET)" : "")),
69
+ result.budget.entries.map((entry) => (React.createElement(Box, { key: entry.skillName, marginLeft: 4 },
62
70
  React.createElement(Text, { color: theme.muted }, entry.skillName),
63
71
  React.createElement(Text, { color: theme.muted, dimColor: true },
64
- ' ',
72
+ " ",
65
73
  "~",
66
74
  entry.tokens,
67
75
  " tokens")))),
68
76
  result.budget.suggestions.map((s, i) => (React.createElement(Box, { key: `suggestion-${i}`, marginLeft: 4 },
69
77
  React.createElement(Text, { color: theme.warning },
70
- '! ',
78
+ "! ",
71
79
  s))))),
80
+ result.budget.optimizations.length > 0 && (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
81
+ React.createElement(Text, { bold: true, color: theme.warning },
82
+ " ",
83
+ "Optimization Suggestions"),
84
+ result.budget.optimizations.map((opt, i) => (React.createElement(Box, { key: `opt-${i}`, flexDirection: "column", marginLeft: 4 },
85
+ React.createElement(Text, { color: opt.meetsbudget ? theme.success : theme.warning },
86
+ opt.meetsbudget ? "\u2713" : "~",
87
+ " Disable [",
88
+ opt.disableSkills.join(", "),
89
+ "] ",
90
+ "\u2192",
91
+ " save ~",
92
+ opt.tokensSaved,
93
+ " tokens (",
94
+ opt.remainingTokens,
95
+ " remaining)")))))),
72
96
  result.conflicts.length > 0 && (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
73
97
  React.createElement(Text, { bold: true, color: theme.error },
74
- ' ',
98
+ " ",
75
99
  "Conflicts (",
76
100
  result.conflicts.length,
77
101
  ")"),
78
102
  result.conflicts.map((c, i) => (React.createElement(Box, { key: `conflict-${i}`, flexDirection: "column", marginLeft: 4 },
79
103
  React.createElement(Text, { color: theme.error },
80
- '\u2717',
104
+ "\u2717",
81
105
  " ",
82
106
  c.ruleA.skillName,
83
107
  " vs ",
84
- c.ruleB.skillName),
108
+ c.ruleB.skillName,
109
+ React.createElement(Text, { color: theme.muted, dimColor: true },
110
+ " ",
111
+ "[",
112
+ c.kind,
113
+ "]")),
85
114
  React.createElement(Text, { color: theme.muted, dimColor: true },
86
- ' ',
115
+ " ",
87
116
  c.reason)))))),
88
117
  deep && result.conflicts.length === 0 && (React.createElement(Box, { marginLeft: 2, marginBottom: 1 },
89
118
  React.createElement(Text, { color: theme.success },
90
- '\u2713',
119
+ "\u2713",
91
120
  " No rule conflicts detected"))),
92
121
  result.duplicates.length > 0 && (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
93
122
  React.createElement(Text, { bold: true, color: theme.warning },
94
- ' ',
123
+ " ",
95
124
  "Potential Duplicates (",
96
125
  result.duplicates.length,
97
126
  ")"),
98
127
  result.duplicates.map((d, i) => (React.createElement(Box, { key: `dup-${i}`, flexDirection: "column", marginLeft: 4 },
99
128
  React.createElement(Text, { color: theme.warning },
100
- '~',
129
+ "~",
101
130
  " ",
102
131
  d.skillA,
103
132
  " + ",
@@ -106,12 +135,12 @@ export default function Skills({ mode, budget, deep, skillsDir }) {
106
135
  d.similarity,
107
136
  "% overlap)"),
108
137
  React.createElement(Text, { color: theme.muted, dimColor: true },
109
- ' ',
138
+ " ",
110
139
  "shared: ",
111
- d.sharedTriggers.slice(0, 3).join(', '))))))),
140
+ d.sharedTriggers.slice(0, 3).join(", "))))))),
112
141
  deep && result.duplicates.length === 0 && (React.createElement(Box, { marginLeft: 2, marginBottom: 1 },
113
142
  React.createElement(Text, { color: theme.success },
114
- '\u2713',
143
+ "\u2713",
115
144
  " No duplicate skills detected"))))),
116
145
  !loading && (React.createElement(Box, { marginTop: 1 },
117
146
  React.createElement(Text, { color: theme.muted, dimColor: true }, "Press r to refresh, q to quit")))));
@@ -1,5 +1,5 @@
1
- import React from 'react';
2
- import type { Stack } from '../types/index.js';
1
+ import React from "react";
2
+ import type { Stack } from "../types/index.js";
3
3
  interface Props {
4
4
  projectDir: string;
5
5
  onConfirm: (stack: Stack) => void;
@@ -1,9 +1,17 @@
1
- import React, { useState, useEffect, useRef } from 'react';
2
- import { Box, Text, useInput } from 'ink';
3
- import { detectStack, STACK_LABELS } from '../lib/common.js';
4
- import { theme } from './theme.js';
5
- import { useCIMode } from './CIContext.js';
6
- const ALL_STACKS = ['node', 'python', 'go', 'rust', 'java-gradle', 'java-maven', 'elixir'];
1
+ import { Box, Text, useInput } from "ink";
2
+ import React, { useEffect, useRef, useState } from "react";
3
+ import { detectStack, STACK_LABELS } from "../lib/common.js";
4
+ import { useCIMode } from "./CIContext.js";
5
+ import { theme } from "./theme.js";
6
+ const ALL_STACKS = [
7
+ "node",
8
+ "python",
9
+ "go",
10
+ "rust",
11
+ "java-gradle",
12
+ "java-maven",
13
+ "elixir",
14
+ ];
7
15
  export default function StackSelector({ projectDir, onConfirm }) {
8
16
  const isCI = useCIMode();
9
17
  const autoConfirmed = useRef(false);
@@ -11,7 +19,7 @@ export default function StackSelector({ projectDir, onConfirm }) {
11
19
  const [detectedStack, setDetectedStack] = useState(null);
12
20
  const [detecting, setDetecting] = useState(true);
13
21
  useEffect(() => {
14
- detectStack(projectDir).then(result => {
22
+ detectStack(projectDir).then((result) => {
15
23
  if (result) {
16
24
  setDetectedStack(result.stackType);
17
25
  const idx = ALL_STACKS.indexOf(result.stackType);
@@ -32,9 +40,9 @@ export default function StackSelector({ projectDir, onConfirm }) {
32
40
  if (detecting)
33
41
  return;
34
42
  if (key.upArrow)
35
- setCursor(c => Math.max(0, c - 1));
43
+ setCursor((c) => Math.max(0, c - 1));
36
44
  if (key.downArrow)
37
- setCursor(c => Math.min(ALL_STACKS.length - 1, c + 1));
45
+ setCursor((c) => Math.min(ALL_STACKS.length - 1, c + 1));
38
46
  if (key.return) {
39
47
  onConfirm(ALL_STACKS[cursor]);
40
48
  }
@@ -46,20 +54,22 @@ export default function StackSelector({ projectDir, onConfirm }) {
46
54
  return (React.createElement(Box, { flexDirection: "column" },
47
55
  React.createElement(Text, { bold: true }, "Select project stack:"),
48
56
  detectedStack && (React.createElement(Text, { color: theme.success },
49
- ' ',
57
+ " ",
50
58
  "Auto-detected: ",
51
59
  STACK_LABELS[detectedStack])),
52
60
  React.createElement(Box, { marginTop: 1, flexDirection: "column", borderStyle: "single", borderLeft: true, borderRight: false, borderTop: false, borderBottom: false, borderColor: theme.muted, paddingLeft: 1 }, ALL_STACKS.map((stack, i) => (React.createElement(Box, { key: stack },
53
- React.createElement(Text, { color: i === cursor ? theme.primary : 'white' },
54
- i === cursor ? '\u25b6 ' : ' ',
55
- stack === detectedStack ? '\u25c9' : '\u25cb',
61
+ React.createElement(Text, { color: i === cursor ? theme.primary : "white" },
62
+ i === cursor ? "\u25b6 " : " ",
63
+ stack === detectedStack ? "\u25c9" : "\u25cb",
56
64
  " ",
57
65
  STACK_LABELS[stack],
58
- stack === detectedStack && (React.createElement(Text, { color: theme.success, dimColor: true }, " (detected)"))))))),
66
+ stack === detectedStack && (React.createElement(Text, { color: theme.success, dimColor: true },
67
+ " ",
68
+ "(detected)"))))))),
59
69
  React.createElement(Box, { marginTop: 1, gap: 2 },
60
70
  React.createElement(Text, { color: theme.primary }, STACK_LABELS[ALL_STACKS[cursor]]),
61
71
  React.createElement(Text, { color: theme.muted, dimColor: true },
62
- '\u2191\u2193',
63
- " navigate Enter confirm"))));
72
+ "\u2191\u2193",
73
+ " navigate Enter confirm"))));
64
74
  }
65
75
  //# sourceMappingURL=StackSelector.js.map
@@ -1,5 +1,5 @@
1
- import React from 'react';
2
- import type { InitStep } from '../types/index.js';
1
+ import React from "react";
2
+ import type { InitStep } from "../types/index.js";
3
3
  interface Props {
4
4
  steps: InitStep[];
5
5
  dryRun: boolean;
@@ -7,6 +7,6 @@ interface Props {
7
7
  stack?: string;
8
8
  elapsedMs?: number;
9
9
  }
10
- export default function Summary({ steps, dryRun, projectName, stack, elapsedMs }: Props): React.JSX.Element;
10
+ export default function Summary({ steps, dryRun, projectName, stack, elapsedMs, }: Props): React.JSX.Element;
11
11
  export {};
12
12
  //# sourceMappingURL=Summary.d.ts.map
@@ -1,29 +1,35 @@
1
- import React, { useEffect } from 'react';
2
- import { Box, Text, useApp, useInput } from 'ink';
3
- import { theme } from './theme.js';
4
- import { useCIMode } from './CIContext.js';
1
+ import { Box, Text, useApp, useInput } from "ink";
2
+ import React, { useEffect } from "react";
3
+ import { useCIMode } from "./CIContext.js";
4
+ import { theme } from "./theme.js";
5
5
  /** Map stack to the install command hint */
6
6
  function getInstallHint(stack) {
7
7
  switch (stack) {
8
- case 'node': return 'pnpm install';
9
- case 'python': return 'pip install -r requirements.txt';
10
- case 'go': return 'go mod tidy';
11
- case 'rust': return 'cargo build';
12
- case 'java-gradle': return './gradlew build';
13
- case 'java-maven': return 'mvn install';
14
- case 'elixir': return 'mix deps.get';
15
- default: return null;
8
+ case "node":
9
+ return "pnpm install";
10
+ case "python":
11
+ return "pip install -r requirements.txt";
12
+ case "go":
13
+ return "go mod tidy";
14
+ case "rust":
15
+ return "cargo build";
16
+ case "java-gradle":
17
+ return "./gradlew build";
18
+ case "java-maven":
19
+ return "mvn install";
20
+ case "elixir":
21
+ return "mix deps.get";
22
+ default:
23
+ return null;
16
24
  }
17
25
  }
18
- export default function Summary({ steps, dryRun, projectName, stack, elapsedMs }) {
26
+ export default function Summary({ steps, dryRun, projectName, stack, elapsedMs, }) {
19
27
  const { exit } = useApp();
20
28
  const isCI = useCIMode();
21
- const done = steps.filter(s => s.status === 'done').length;
22
- const skipped = steps.filter(s => s.status === 'skipped').length;
23
- const errors = steps.filter(s => s.status === 'error');
24
- const elapsed = elapsedMs != null
25
- ? `${(elapsedMs / 1000).toFixed(1)}s`
26
- : null;
29
+ const done = steps.filter((s) => s.status === "done").length;
30
+ const skipped = steps.filter((s) => s.status === "skipped").length;
31
+ const errors = steps.filter((s) => s.status === "error");
32
+ const elapsed = elapsedMs != null ? `${(elapsedMs / 1000).toFixed(1)}s` : null;
27
33
  // Auto-exit in CI mode
28
34
  useEffect(() => {
29
35
  if (isCI) {
@@ -39,75 +45,79 @@ export default function Summary({ steps, dryRun, projectName, stack, elapsedMs }
39
45
  const installHint = getInstallHint(stack);
40
46
  return (React.createElement(Box, { flexDirection: "column" },
41
47
  React.createElement(Text, { bold: true, color: errors.length > 0 ? theme.warning : theme.success },
42
- dryRun ? '\u25cb Dry run complete' : '\u2713 Project scaffolded',
48
+ dryRun ? "\u25cb Dry run complete" : "\u2713 Project scaffolded",
43
49
  elapsed && React.createElement(Text, { color: theme.muted },
44
- " Completed in ",
50
+ " Completed in ",
45
51
  elapsed)),
46
52
  React.createElement(Box, { marginTop: 1 },
47
- React.createElement(Text, { color: theme.muted }, " Project: "),
53
+ React.createElement(Text, { color: theme.muted }, " Project: "),
48
54
  React.createElement(Text, { color: theme.primary, bold: true }, projectName),
49
55
  stack && React.createElement(Text, { color: theme.muted },
50
- " (",
56
+ " (",
51
57
  stack,
52
58
  ")")),
53
59
  dryRun && (React.createElement(Box, { marginTop: 1 },
54
- React.createElement(Text, { color: theme.warning, bold: true }, " No changes were made (dry run)"))),
55
- React.createElement(Box, { marginTop: 1, flexDirection: "column" }, steps.map(step => (React.createElement(Box, { key: step.id, marginLeft: 2 }, step.status === 'done' ? (React.createElement(Text, { color: theme.success },
56
- '\u2713',
60
+ React.createElement(Text, { color: theme.warning, bold: true },
61
+ " ",
62
+ "No changes were made (dry run)"))),
63
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, steps.map((step) => (React.createElement(Box, { key: step.id, marginLeft: 2 }, step.status === "done" ? (React.createElement(Text, { color: theme.success },
64
+ "\u2713",
57
65
  " ",
58
66
  step.label,
59
- step.detail ? React.createElement(Text, { color: theme.muted, dimColor: true },
60
- " ",
61
- step.detail) : null)) : step.status === 'skipped' ? (React.createElement(Text, { color: theme.muted },
62
- '\u2013',
67
+ step.detail ? (React.createElement(Text, { color: theme.muted, dimColor: true },
68
+ " ",
69
+ step.detail)) : null)) : step.status === "skipped" ? (React.createElement(Text, { color: theme.muted },
70
+ "\u2013",
63
71
  " ",
64
72
  step.label,
65
73
  step.detail ? React.createElement(Text, { dimColor: true },
66
- " ",
67
- step.detail) : null)) : step.status === 'error' ? (React.createElement(Text, { color: theme.error },
68
- '\u2717',
74
+ " ",
75
+ step.detail) : null)) : step.status === "error" ? (React.createElement(Text, { color: theme.error },
76
+ "\u2717",
69
77
  " ",
70
78
  step.label,
71
- step.detail ? React.createElement(Text, { color: theme.muted, dimColor: true },
72
- " ",
73
- step.detail) : null)) : null)))),
79
+ step.detail ? (React.createElement(Text, { color: theme.muted, dimColor: true },
80
+ " ",
81
+ step.detail)) : null)) : null)))),
74
82
  React.createElement(Box, { marginTop: 1, flexDirection: "column" },
75
83
  React.createElement(Text, { color: theme.success },
76
- " ",
77
- '\u2713',
84
+ " ",
85
+ "\u2713",
78
86
  " ",
79
87
  done,
80
88
  " steps completed"),
81
89
  skipped > 0 && (React.createElement(Text, { color: theme.muted },
82
- " ",
83
- '\u2013',
90
+ " ",
91
+ "\u2013",
84
92
  " ",
85
93
  skipped,
86
94
  " steps skipped")),
87
95
  errors.length > 0 && (React.createElement(Box, { flexDirection: "column" },
88
96
  React.createElement(Text, { color: theme.error },
89
- " ",
90
- '\u2717',
97
+ " ",
98
+ "\u2717",
91
99
  " ",
92
100
  errors.length,
93
101
  " errors:"),
94
- errors.map(e => (React.createElement(Text, { key: `err-${e.id}`, color: theme.error },
95
- " ",
96
- '\u2022',
102
+ errors.map((e) => (React.createElement(Text, { key: `err-${e.id}`, color: theme.error },
103
+ " ",
104
+ "\u2022",
97
105
  " ",
98
106
  e.label,
99
107
  ": ",
100
108
  e.detail)))))),
101
109
  !dryRun && errors.length === 0 && (React.createElement(Box, { marginTop: 1, flexDirection: "column" },
102
- React.createElement(Text, { color: theme.muted, bold: true }, " Next steps:"),
110
+ React.createElement(Text, { color: theme.muted, bold: true },
111
+ " ",
112
+ "Next steps:"),
103
113
  React.createElement(Text, { color: theme.primary },
104
- " cd ",
114
+ " cd ",
105
115
  projectName),
106
116
  installHint && React.createElement(Text, { color: theme.primary },
107
- " ",
117
+ " ",
108
118
  installHint),
109
- React.createElement(Text, { color: theme.primary }, " npx javi-ai sync"),
110
- React.createElement(Text, { color: theme.primary }, " javi-forge doctor"))),
119
+ React.createElement(Text, { color: theme.primary }, " npx javi-ai sync"),
120
+ React.createElement(Text, { color: theme.primary }, " javi-forge doctor"))),
111
121
  React.createElement(Box, { marginTop: 1 },
112
122
  React.createElement(Text, { color: theme.muted, dimColor: true }, "Press Enter to exit"))));
113
123
  }
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
  interface Props {
3
3
  onDone: () => void;
4
4
  }
@@ -1,9 +1,9 @@
1
- import React, { useEffect } from 'react';
2
- import { Box, Text } from 'ink';
3
- import Spinner from 'ink-spinner';
4
- import Header from './Header.js';
5
- import { theme } from './theme.js';
6
- import { useCIMode } from './CIContext.js';
1
+ import { Box, Text } from "ink";
2
+ import Spinner from "ink-spinner";
3
+ import React, { useEffect } from "react";
4
+ import { useCIMode } from "./CIContext.js";
5
+ import Header from "./Header.js";
6
+ import { theme } from "./theme.js";
7
7
  export default function Welcome({ onDone }) {
8
8
  const isCI = useCIMode();
9
9
  useEffect(() => {
@@ -18,28 +18,27 @@ export default function Welcome({ onDone }) {
18
18
  React.createElement(Box, { marginTop: 1, flexDirection: "column" },
19
19
  React.createElement(Text, null,
20
20
  React.createElement(Text, { color: theme.primary },
21
- '\u25c6',
22
- " Templates "),
21
+ "\u25c6",
22
+ " Templates "),
23
23
  React.createElement(Text, { color: theme.muted }, " Go, Java, Node, Python, Rust CI")),
24
24
  React.createElement(Text, null,
25
25
  React.createElement(Text, { color: theme.success },
26
- '\u25c6',
27
- " Memory "),
26
+ "\u25c6",
27
+ " Memory "),
28
28
  React.createElement(Text, { color: theme.muted }, " Engram, Obsidian Brain")),
29
29
  React.createElement(Text, null,
30
30
  React.createElement(Text, { color: theme.accent },
31
- '\u25c6',
32
- " SDD "),
31
+ "\u25c6",
32
+ " SDD "),
33
33
  React.createElement(Text, { color: theme.muted }, " Spec-Driven Development")),
34
34
  React.createElement(Text, null,
35
35
  React.createElement(Text, { color: theme.warning },
36
- '\u25c6',
37
- " Review "),
36
+ "\u25c6",
37
+ " Review "),
38
38
  React.createElement(Text, { color: theme.muted }, " GHAGGA code review"))),
39
39
  React.createElement(Box, { marginTop: 1 },
40
40
  React.createElement(Text, { color: theme.muted },
41
41
  React.createElement(Spinner, { type: "dots" }),
42
- ' ',
43
- "Detecting your environment...")))));
42
+ " Detecting your environment...")))));
44
43
  }
45
44
  //# sourceMappingURL=Welcome.js.map
@@ -6,5 +6,5 @@ export declare const theme: {
6
6
  readonly muted: "gray";
7
7
  readonly accent: "magenta";
8
8
  };
9
- export type ThemeColor = typeof theme[keyof typeof theme];
9
+ export type ThemeColor = (typeof theme)[keyof typeof theme];
10
10
  //# sourceMappingURL=theme.d.ts.map
package/dist/ui/theme.js CHANGED
@@ -1,9 +1,9 @@
1
1
  export const theme = {
2
- primary: '#f97316', // orange
3
- success: 'green',
4
- warning: 'yellow',
5
- error: 'red',
6
- muted: 'gray',
7
- accent: 'magenta',
2
+ primary: "#f97316", // orange
3
+ success: "green",
4
+ warning: "yellow",
5
+ error: "red",
6
+ muted: "gray",
7
+ accent: "magenta",
8
8
  };
9
9
  //# sourceMappingURL=theme.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "javi-forge",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "Project scaffolding and AI-ready CI bootstrap",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,19 +14,21 @@
14
14
  "test": "vitest run",
15
15
  "test:watch": "vitest",
16
16
  "test:coverage": "vitest run --coverage",
17
- "test:mutation": "stryker run"
17
+ "test:mutation": "stryker run",
18
+ "package:check": "npm pack --dry-run --json --cache /tmp/javi-forge-npm-pack-cache > /tmp/javi-forge-pack.json && node scripts/verify-package-contents.mjs /tmp/javi-forge-pack.json"
18
19
  },
19
20
  "files": [
20
- "dist/",
21
+ "dist/**/*.js",
22
+ "dist/**/*.d.ts",
23
+ "!dist/__integration__/**",
24
+ "!dist/e2e/**",
21
25
  "ci-local/",
22
26
  "modules/",
23
27
  "templates/",
24
28
  "workflows/",
25
29
  "lib/",
26
- "!dist/**/*.test.*",
27
- "!dist/**/__snapshots__",
28
- "package.json",
29
30
  "README.md",
31
+ "LICENSE*",
30
32
  ".gitignore.template"
31
33
  ],
32
34
  "author": "JNZader",
@@ -64,6 +66,7 @@
64
66
  "@types/update-notifier": "^6.0.8",
65
67
  "@vitest/coverage-v8": "^4.1.0",
66
68
  "conventional-changelog-conventionalcommits": "^9.3.0",
69
+ "ink-testing-library": "^4.0.0",
67
70
  "semantic-release": "^25.0.3",
68
71
  "tsx": "^4.21.0",
69
72
  "typescript": "^5.9.3",
@@ -0,0 +1,16 @@
1
+ {
2
+ "mcpServers": {
3
+ "atlassian": {
4
+ "command": "uvx",
5
+ "args": ["mcp-atlassian"],
6
+ "env": {
7
+ "CONFLUENCE_URL": "__CONFLUENCE_URL__",
8
+ "CONFLUENCE_USERNAME": "__CONFLUENCE_USERNAME__",
9
+ "CONFLUENCE_API_TOKEN": "__CONFLUENCE_API_TOKEN__",
10
+ "JIRA_URL": "__JIRA_URL__",
11
+ "JIRA_USERNAME": "__JIRA_USERNAME__",
12
+ "JIRA_API_TOKEN": "__JIRA_API_TOKEN__"
13
+ }
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "repoforge": {
4
+ "command": "npx",
5
+ "args": ["-y", "repoforge", "mcp"],
6
+ "env": {
7
+ "REPOFORGE_PROJECT": "__PROJECT_NAME__"
8
+ }
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,34 @@
1
+ # ===========================================
2
+ # RepoForge Graph Configuration
3
+ # ===========================================
4
+ # Docs: https://github.com/JNZader/repoforge
5
+ # ===========================================
6
+
7
+ graph:
8
+ # Graph type: calls | imports | dependencies
9
+ type: calls
10
+
11
+ # Output format: json | dot | mermaid
12
+ output: json
13
+
14
+ # Where to store the generated graph artifact
15
+ artifact: .repoforge/call-graph.json
16
+
17
+ # Directories to include (globs supported)
18
+ include:
19
+ - src/**
20
+
21
+ # Directories to exclude
22
+ exclude:
23
+ - node_modules/**
24
+ - dist/**
25
+ - coverage/**
26
+ - '**/*.test.*'
27
+ - '**/*.spec.*'
28
+
29
+ query:
30
+ # Enable MCP-based code intelligence queries
31
+ mcp: true
32
+
33
+ # Max depth for transitive dependency lookups
34
+ max_depth: 5