javi-forge 1.5.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 (217) hide show
  1. package/README.md +191 -3
  2. package/ci-local/hooks/pre-push +17 -13
  3. package/dist/commands/analyze.d.ts +1 -1
  4. package/dist/commands/analyze.js +15 -15
  5. package/dist/commands/atlassian-mcp.d.ts +42 -0
  6. package/dist/commands/atlassian-mcp.js +98 -0
  7. package/dist/commands/ci.d.ts +3 -3
  8. package/dist/commands/ci.js +185 -147
  9. package/dist/commands/crash-recovery.d.ts +34 -0
  10. package/dist/commands/crash-recovery.js +123 -0
  11. package/dist/commands/doctor.d.ts +2 -2
  12. package/dist/commands/doctor.js +113 -61
  13. package/dist/commands/harness-audit.d.ts +35 -0
  14. package/dist/commands/harness-audit.js +277 -0
  15. package/dist/commands/init.d.ts +1 -1
  16. package/dist/commands/init.js +415 -118
  17. package/dist/commands/llmstxt.d.ts +1 -1
  18. package/dist/commands/llmstxt.js +36 -34
  19. package/dist/commands/parallel-batch.d.ts +42 -0
  20. package/dist/commands/parallel-batch.js +90 -0
  21. package/dist/commands/plugin.d.ts +26 -1
  22. package/dist/commands/plugin.js +138 -24
  23. package/dist/commands/secret-scanner.d.ts +30 -0
  24. package/dist/commands/secret-scanner.js +272 -0
  25. package/dist/commands/security-analysis.d.ts +74 -0
  26. package/dist/commands/security-analysis.js +487 -0
  27. package/dist/commands/security.d.ts +31 -0
  28. package/dist/commands/security.js +445 -0
  29. package/dist/commands/skill-scanner.d.ts +63 -0
  30. package/dist/commands/skill-scanner.js +383 -0
  31. package/dist/commands/skills.d.ts +139 -0
  32. package/dist/commands/skills.js +895 -0
  33. package/dist/commands/supply-chain.d.ts +23 -0
  34. package/dist/commands/supply-chain.js +126 -0
  35. package/dist/commands/tdd-pipeline.d.ts +17 -0
  36. package/dist/commands/tdd-pipeline.js +144 -0
  37. package/dist/commands/tdd.d.ts +21 -0
  38. package/dist/commands/tdd.js +120 -0
  39. package/dist/commands/team-presets.d.ts +53 -0
  40. package/dist/commands/team-presets.js +201 -0
  41. package/dist/commands/workflow.d.ts +23 -0
  42. package/dist/commands/workflow.js +114 -0
  43. package/dist/constants.d.ts +21 -0
  44. package/dist/constants.js +208 -37
  45. package/dist/index.js +400 -54
  46. package/dist/lib/agent-skills.d.ts +73 -0
  47. package/dist/lib/agent-skills.js +260 -0
  48. package/dist/lib/auto-skill-install.d.ts +37 -0
  49. package/dist/lib/auto-skill-install.js +92 -0
  50. package/dist/lib/auto-wire.d.ts +20 -0
  51. package/dist/lib/auto-wire.js +240 -0
  52. package/dist/lib/claudemd.d.ts +20 -0
  53. package/dist/lib/claudemd.js +222 -0
  54. package/dist/lib/codex-export.d.ts +16 -0
  55. package/dist/lib/codex-export.js +109 -0
  56. package/dist/lib/common.d.ts +1 -1
  57. package/dist/lib/common.js +52 -44
  58. package/dist/lib/context.d.ts +27 -0
  59. package/dist/lib/context.js +204 -0
  60. package/dist/lib/docker.d.ts +1 -1
  61. package/dist/lib/docker.js +141 -112
  62. package/dist/lib/frontmatter.d.ts +1 -1
  63. package/dist/lib/frontmatter.js +29 -15
  64. package/dist/lib/plugin.d.ts +19 -1
  65. package/dist/lib/plugin.js +174 -47
  66. package/dist/lib/skill-publish.d.ts +40 -0
  67. package/dist/lib/skill-publish.js +146 -0
  68. package/dist/lib/stack-detector.d.ts +38 -0
  69. package/dist/lib/stack-detector.js +207 -0
  70. package/dist/lib/template.d.ts +16 -1
  71. package/dist/lib/template.js +46 -17
  72. package/dist/lib/workflow/discovery.d.ts +19 -0
  73. package/dist/lib/workflow/discovery.js +68 -0
  74. package/dist/lib/workflow/index.d.ts +5 -0
  75. package/dist/lib/workflow/index.js +5 -0
  76. package/dist/lib/workflow/parser.d.ts +16 -0
  77. package/dist/lib/workflow/parser.js +198 -0
  78. package/dist/lib/workflow/renderer.d.ts +9 -0
  79. package/dist/lib/workflow/renderer.js +152 -0
  80. package/dist/lib/workflow/validator.d.ts +10 -0
  81. package/dist/lib/workflow/validator.js +189 -0
  82. package/dist/tasks/index.d.ts +4 -0
  83. package/dist/tasks/index.js +4 -0
  84. package/dist/tasks/scaffold-tasks.d.ts +3 -0
  85. package/dist/tasks/scaffold-tasks.js +14 -0
  86. package/dist/tasks/task-id.d.ts +30 -0
  87. package/dist/tasks/task-id.js +55 -0
  88. package/dist/tasks/task-tracker.d.ts +15 -0
  89. package/dist/tasks/task-tracker.js +81 -0
  90. package/dist/types/index.d.ts +252 -5
  91. package/dist/types/index.js +11 -1
  92. package/dist/ui/AnalyzeUI.d.ts +1 -1
  93. package/dist/ui/AnalyzeUI.js +38 -39
  94. package/dist/ui/App.d.ts +5 -3
  95. package/dist/ui/App.js +92 -46
  96. package/dist/ui/AutoSkills.d.ts +9 -0
  97. package/dist/ui/AutoSkills.js +124 -0
  98. package/dist/ui/CI.d.ts +2 -2
  99. package/dist/ui/CI.js +24 -26
  100. package/dist/ui/CIContext.d.ts +1 -1
  101. package/dist/ui/CIContext.js +3 -2
  102. package/dist/ui/CISelector.d.ts +2 -2
  103. package/dist/ui/CISelector.js +23 -15
  104. package/dist/ui/Doctor.d.ts +1 -1
  105. package/dist/ui/Doctor.js +35 -29
  106. package/dist/ui/Header.d.ts +1 -1
  107. package/dist/ui/Header.js +14 -14
  108. package/dist/ui/HookProfileSelector.d.ts +9 -0
  109. package/dist/ui/HookProfileSelector.js +54 -0
  110. package/dist/ui/LlmsTxt.d.ts +1 -1
  111. package/dist/ui/LlmsTxt.js +31 -22
  112. package/dist/ui/MemorySelector.d.ts +2 -2
  113. package/dist/ui/MemorySelector.js +28 -16
  114. package/dist/ui/NameInput.d.ts +1 -1
  115. package/dist/ui/NameInput.js +21 -21
  116. package/dist/ui/OptionSelector.d.ts +8 -2
  117. package/dist/ui/OptionSelector.js +83 -26
  118. package/dist/ui/Plugin.d.ts +4 -3
  119. package/dist/ui/Plugin.js +89 -29
  120. package/dist/ui/Progress.d.ts +3 -3
  121. package/dist/ui/Progress.js +23 -22
  122. package/dist/ui/Skills.d.ts +11 -0
  123. package/dist/ui/Skills.js +148 -0
  124. package/dist/ui/StackSelector.d.ts +2 -2
  125. package/dist/ui/StackSelector.js +26 -16
  126. package/dist/ui/Summary.d.ts +3 -3
  127. package/dist/ui/Summary.js +60 -50
  128. package/dist/ui/Welcome.d.ts +1 -1
  129. package/dist/ui/Welcome.js +15 -16
  130. package/dist/ui/theme.d.ts +1 -1
  131. package/dist/ui/theme.js +6 -6
  132. package/package.json +9 -6
  133. package/templates/common/atlassian/mcp-atlassian-snippet.json +16 -0
  134. package/templates/common/repoforge/mcp-repoforge-snippet.json +11 -0
  135. package/templates/common/repoforge/repoforge.yaml +34 -0
  136. package/templates/github/deploy-docker-zero-downtime.yml +140 -0
  137. package/templates/github/repoforge-graph.yml +45 -0
  138. package/templates/gitlab/deploy-docker-zero-downtime.yml +57 -0
  139. package/templates/local-ai/.env.example +17 -0
  140. package/templates/local-ai/docker-compose.yml +95 -0
  141. package/templates/security-hooks/claude-settings-security.json +30 -0
  142. package/templates/security-hooks/commit-msg-signing +29 -0
  143. package/templates/security-hooks/pre-commit-permissions +74 -0
  144. package/templates/security-hooks/pre-commit-secrets +74 -0
  145. package/templates/security-hooks/pre-push-branch-protection +62 -0
  146. package/templates/security-hooks/pre-push-deps +83 -0
  147. package/templates/security-hooks/pre-push-signing +67 -0
  148. package/templates/woodpecker/deploy-docker-zero-downtime.yml +50 -0
  149. package/templates/workflows/ci-pipeline.dot +15 -0
  150. package/templates/workflows/feature-flow.dot +21 -0
  151. package/templates/workflows/release.dot +16 -0
  152. package/dist/__integration__/helpers.d.ts +0 -20
  153. package/dist/__integration__/helpers.d.ts.map +0 -1
  154. package/dist/__integration__/helpers.js +0 -31
  155. package/dist/__integration__/helpers.js.map +0 -1
  156. package/dist/commands/analyze.d.ts.map +0 -1
  157. package/dist/commands/analyze.js.map +0 -1
  158. package/dist/commands/ci.d.ts.map +0 -1
  159. package/dist/commands/ci.js.map +0 -1
  160. package/dist/commands/doctor.d.ts.map +0 -1
  161. package/dist/commands/doctor.js.map +0 -1
  162. package/dist/commands/init.d.ts.map +0 -1
  163. package/dist/commands/init.js.map +0 -1
  164. package/dist/commands/llmstxt.d.ts.map +0 -1
  165. package/dist/commands/llmstxt.js.map +0 -1
  166. package/dist/commands/plugin.d.ts.map +0 -1
  167. package/dist/commands/plugin.js.map +0 -1
  168. package/dist/constants.d.ts.map +0 -1
  169. package/dist/constants.js.map +0 -1
  170. package/dist/index.d.ts.map +0 -1
  171. package/dist/index.js.map +0 -1
  172. package/dist/lib/common.d.ts.map +0 -1
  173. package/dist/lib/common.js.map +0 -1
  174. package/dist/lib/docker.d.ts.map +0 -1
  175. package/dist/lib/docker.js.map +0 -1
  176. package/dist/lib/frontmatter.d.ts.map +0 -1
  177. package/dist/lib/frontmatter.js.map +0 -1
  178. package/dist/lib/plugin.d.ts.map +0 -1
  179. package/dist/lib/plugin.js.map +0 -1
  180. package/dist/lib/template.d.ts.map +0 -1
  181. package/dist/lib/template.js.map +0 -1
  182. package/dist/types/index.d.ts.map +0 -1
  183. package/dist/types/index.js.map +0 -1
  184. package/dist/ui/AnalyzeUI.d.ts.map +0 -1
  185. package/dist/ui/AnalyzeUI.js.map +0 -1
  186. package/dist/ui/App.d.ts.map +0 -1
  187. package/dist/ui/App.js.map +0 -1
  188. package/dist/ui/CI.d.ts.map +0 -1
  189. package/dist/ui/CI.js.map +0 -1
  190. package/dist/ui/CIContext.d.ts.map +0 -1
  191. package/dist/ui/CIContext.js.map +0 -1
  192. package/dist/ui/CISelector.d.ts.map +0 -1
  193. package/dist/ui/CISelector.js.map +0 -1
  194. package/dist/ui/Doctor.d.ts.map +0 -1
  195. package/dist/ui/Doctor.js.map +0 -1
  196. package/dist/ui/Header.d.ts.map +0 -1
  197. package/dist/ui/Header.js.map +0 -1
  198. package/dist/ui/LlmsTxt.d.ts.map +0 -1
  199. package/dist/ui/LlmsTxt.js.map +0 -1
  200. package/dist/ui/MemorySelector.d.ts.map +0 -1
  201. package/dist/ui/MemorySelector.js.map +0 -1
  202. package/dist/ui/NameInput.d.ts.map +0 -1
  203. package/dist/ui/NameInput.js.map +0 -1
  204. package/dist/ui/OptionSelector.d.ts.map +0 -1
  205. package/dist/ui/OptionSelector.js.map +0 -1
  206. package/dist/ui/Plugin.d.ts.map +0 -1
  207. package/dist/ui/Plugin.js.map +0 -1
  208. package/dist/ui/Progress.d.ts.map +0 -1
  209. package/dist/ui/Progress.js.map +0 -1
  210. package/dist/ui/StackSelector.d.ts.map +0 -1
  211. package/dist/ui/StackSelector.js.map +0 -1
  212. package/dist/ui/Summary.d.ts.map +0 -1
  213. package/dist/ui/Summary.js.map +0 -1
  214. package/dist/ui/Welcome.d.ts.map +0 -1
  215. package/dist/ui/Welcome.js.map +0 -1
  216. package/dist/ui/theme.d.ts.map +0 -1
  217. package/dist/ui/theme.js.map +0 -1
@@ -0,0 +1,148 @@
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
+ export default function Skills({ mode, budget, deep, skillsDir }) {
9
+ const { exit } = useApp();
10
+ const isCI = useCIMode();
11
+ const [result, setResult] = useState(null);
12
+ const [error, setError] = useState(null);
13
+ const [loading, setLoading] = useState(true);
14
+ const runCheck = useCallback(() => {
15
+ setLoading(true);
16
+ setResult(null);
17
+ setError(null);
18
+ runSkillsDoctor({ mode, budget, deep, skillsDir })
19
+ .then((r) => {
20
+ setResult(r);
21
+ setLoading(false);
22
+ })
23
+ .catch((e) => {
24
+ setError(String(e));
25
+ setLoading(false);
26
+ });
27
+ }, [mode, budget, deep, skillsDir]);
28
+ useEffect(() => {
29
+ runCheck();
30
+ }, [runCheck]);
31
+ // Auto-exit in CI mode once loading finishes
32
+ useEffect(() => {
33
+ if (isCI && !loading) {
34
+ const t = setTimeout(() => exit(), 100);
35
+ return () => clearTimeout(t);
36
+ }
37
+ return undefined;
38
+ }, [isCI, loading, exit]);
39
+ useInput((input, key) => {
40
+ if (input.toLowerCase() === "r")
41
+ runCheck();
42
+ if (input.toLowerCase() === "q" || key.return || key.escape)
43
+ exit();
44
+ }, { isActive: !isCI });
45
+ const subtitle = mode === "budget" ? "skills budget" : "skills doctor";
46
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
47
+ React.createElement(Header, { subtitle: subtitle }),
48
+ loading && (React.createElement(Text, { color: theme.warning },
49
+ React.createElement(Spinner, { type: "dots" }),
50
+ " Running skills analysis...")),
51
+ error && (React.createElement(Text, { color: theme.error },
52
+ "\u2717",
53
+ " Error: ",
54
+ error)),
55
+ result && (React.createElement(Box, { flexDirection: "column" },
56
+ React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
57
+ React.createElement(Text, { bold: true, color: result.budget.overBudget ? theme.warning : theme.success },
58
+ " ",
59
+ "Context Budget"),
60
+ React.createElement(Box, { marginLeft: 2 },
61
+ React.createElement(Text, { color: result.budget.overBudget ? theme.warning : theme.success },
62
+ result.budget.overBudget ? "\u2717" : "\u2713",
63
+ " ",
64
+ result.budget.totalTokens,
65
+ " / ",
66
+ result.budget.budget,
67
+ " tokens",
68
+ result.budget.overBudget ? " (OVER BUDGET)" : "")),
69
+ result.budget.entries.map((entry) => (React.createElement(Box, { key: entry.skillName, marginLeft: 4 },
70
+ React.createElement(Text, { color: theme.muted }, entry.skillName),
71
+ React.createElement(Text, { color: theme.muted, dimColor: true },
72
+ " ",
73
+ "~",
74
+ entry.tokens,
75
+ " tokens")))),
76
+ result.budget.suggestions.map((s, i) => (React.createElement(Box, { key: `suggestion-${i}`, marginLeft: 4 },
77
+ React.createElement(Text, { color: theme.warning },
78
+ "! ",
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)")))))),
96
+ result.conflicts.length > 0 && (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
97
+ React.createElement(Text, { bold: true, color: theme.error },
98
+ " ",
99
+ "Conflicts (",
100
+ result.conflicts.length,
101
+ ")"),
102
+ result.conflicts.map((c, i) => (React.createElement(Box, { key: `conflict-${i}`, flexDirection: "column", marginLeft: 4 },
103
+ React.createElement(Text, { color: theme.error },
104
+ "\u2717",
105
+ " ",
106
+ c.ruleA.skillName,
107
+ " vs ",
108
+ c.ruleB.skillName,
109
+ React.createElement(Text, { color: theme.muted, dimColor: true },
110
+ " ",
111
+ "[",
112
+ c.kind,
113
+ "]")),
114
+ React.createElement(Text, { color: theme.muted, dimColor: true },
115
+ " ",
116
+ c.reason)))))),
117
+ deep && result.conflicts.length === 0 && (React.createElement(Box, { marginLeft: 2, marginBottom: 1 },
118
+ React.createElement(Text, { color: theme.success },
119
+ "\u2713",
120
+ " No rule conflicts detected"))),
121
+ result.duplicates.length > 0 && (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
122
+ React.createElement(Text, { bold: true, color: theme.warning },
123
+ " ",
124
+ "Potential Duplicates (",
125
+ result.duplicates.length,
126
+ ")"),
127
+ result.duplicates.map((d, i) => (React.createElement(Box, { key: `dup-${i}`, flexDirection: "column", marginLeft: 4 },
128
+ React.createElement(Text, { color: theme.warning },
129
+ "~",
130
+ " ",
131
+ d.skillA,
132
+ " + ",
133
+ d.skillB,
134
+ " (",
135
+ d.similarity,
136
+ "% overlap)"),
137
+ React.createElement(Text, { color: theme.muted, dimColor: true },
138
+ " ",
139
+ "shared: ",
140
+ d.sharedTriggers.slice(0, 3).join(", "))))))),
141
+ deep && result.duplicates.length === 0 && (React.createElement(Box, { marginLeft: 2, marginBottom: 1 },
142
+ React.createElement(Text, { color: theme.success },
143
+ "\u2713",
144
+ " No duplicate skills detected"))))),
145
+ !loading && (React.createElement(Box, { marginTop: 1 },
146
+ React.createElement(Text, { color: theme.muted, dimColor: true }, "Press r to refresh, q to quit")))));
147
+ }
148
+ //# sourceMappingURL=Skills.js.map
@@ -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.5.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