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,8 +1,8 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
3
- import { PLUGINS_DIR, PLUGIN_MANIFEST_FILE } from '../constants.js';
4
- import { parseFrontmatter } from './frontmatter.js';
5
- const DEFAULT_MODEL = 'o4-mini';
1
+ import path from "node:path";
2
+ import fs from "fs-extra";
3
+ import { PLUGIN_MANIFEST_FILE, PLUGINS_DIR } from "../constants.js";
4
+ import { parseFrontmatter } from "./frontmatter.js";
5
+ const DEFAULT_MODEL = "o4-mini";
6
6
  // ── Conversion ─────────────────────────────────────────────────────────────
7
7
  /**
8
8
  * Convert a SKILL.md raw content string into a CodexTomlEntry.
@@ -12,15 +12,11 @@ export function skillToCodexToml(raw) {
12
12
  const parsed = parseFrontmatter(raw);
13
13
  if (!parsed)
14
14
  return null;
15
- const name = parsed.data['name'];
16
- if (typeof name !== 'string' || !name)
15
+ const name = parsed.data.name;
16
+ if (typeof name !== "string" || !name)
17
17
  return null;
18
- const description = typeof parsed.data['description'] === 'string'
19
- ? parsed.data['description']
20
- : '';
21
- const model = typeof parsed.data['model'] === 'string'
22
- ? parsed.data['model']
23
- : DEFAULT_MODEL;
18
+ const description = typeof parsed.data.description === "string" ? parsed.data.description : "";
19
+ const model = typeof parsed.data.model === "string" ? parsed.data.model : DEFAULT_MODEL;
24
20
  const instructions = description
25
21
  ? `${description}\n\n${parsed.content}`.trim()
26
22
  : parsed.content.trim();
@@ -39,8 +35,8 @@ export function serializeToml(entry) {
39
35
  `instructions = """`,
40
36
  escapedInstructions,
41
37
  `"""`,
42
- '',
43
- ].join('\n');
38
+ "",
39
+ ].join("\n");
44
40
  }
45
41
  // ── File I/O ───────────────────────────────────────────────────────────────
46
42
  /**
@@ -49,35 +45,35 @@ export function serializeToml(entry) {
49
45
  */
50
46
  export async function exportPluginAsCodexToml(name) {
51
47
  const pluginDir = path.join(PLUGINS_DIR, name);
52
- if (!await fs.pathExists(pluginDir)) {
48
+ if (!(await fs.pathExists(pluginDir))) {
53
49
  return { success: false, error: `plugin "${name}" is not installed` };
54
50
  }
55
51
  // Read plugin manifest for skill list
56
52
  const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_FILE);
57
- if (!await fs.pathExists(manifestPath)) {
58
- return { success: false, error: 'plugin.json not found' };
53
+ if (!(await fs.pathExists(manifestPath))) {
54
+ return { success: false, error: "plugin.json not found" };
59
55
  }
60
56
  let manifest;
61
57
  try {
62
- manifest = await fs.readJson(manifestPath);
58
+ manifest = (await fs.readJson(manifestPath));
63
59
  }
64
60
  catch {
65
- return { success: false, error: 'invalid plugin.json' };
61
+ return { success: false, error: "invalid plugin.json" };
66
62
  }
67
63
  const skillNames = manifest.skills ?? [];
68
64
  if (skillNames.length === 0) {
69
- return { success: false, error: 'plugin has no skills to export' };
65
+ return { success: false, error: "plugin has no skills to export" };
70
66
  }
71
- const codexDir = path.join(pluginDir, 'codex');
67
+ const codexDir = path.join(pluginDir, "codex");
72
68
  await fs.ensureDir(codexDir);
73
69
  const writtenFiles = [];
74
70
  for (const skillName of skillNames) {
75
- const skillPath = path.join(pluginDir, 'skills', skillName, 'SKILL.md');
76
- if (!await fs.pathExists(skillPath))
71
+ const skillPath = path.join(pluginDir, "skills", skillName, "SKILL.md");
72
+ if (!(await fs.pathExists(skillPath)))
77
73
  continue;
78
74
  let raw;
79
75
  try {
80
- raw = await fs.readFile(skillPath, 'utf-8');
76
+ raw = await fs.readFile(skillPath, "utf-8");
81
77
  }
82
78
  catch {
83
79
  continue;
@@ -87,25 +83,23 @@ export async function exportPluginAsCodexToml(name) {
87
83
  continue;
88
84
  const toml = serializeToml(entry);
89
85
  const outPath = path.join(codexDir, `${skillName}.toml`);
90
- await fs.writeFile(outPath, toml, 'utf-8');
86
+ await fs.writeFile(outPath, toml, "utf-8");
91
87
  writtenFiles.push(outPath);
92
88
  }
93
89
  if (writtenFiles.length === 0) {
94
- return { success: false, error: 'no skills with valid frontmatter found' };
90
+ return { success: false, error: "no skills with valid frontmatter found" };
95
91
  }
96
92
  return { success: true, files: writtenFiles };
97
93
  }
98
94
  // ── Helpers ────────────────────────────────────────────────────────────────
99
95
  function escapeTomlString(value) {
100
96
  return value
101
- .replace(/\\/g, '\\\\')
97
+ .replace(/\\/g, "\\\\")
102
98
  .replace(/"/g, '\\"')
103
- .replace(/\n/g, '\\n');
99
+ .replace(/\n/g, "\\n");
104
100
  }
105
101
  function escapeTomlMultiline(value) {
106
102
  // In TOML multiline basic strings ("""), only backslashes and triple quotes need escaping
107
- return value
108
- .replace(/\\/g, '\\\\')
109
- .replace(/"""/g, '"\\"\"');
103
+ return value.replace(/\\/g, "\\\\").replace(/"""/g, '"\\""');
110
104
  }
111
105
  //# sourceMappingURL=codex-export.js.map
@@ -1,4 +1,4 @@
1
- import type { Stack, StackDetection } from '../types/index.js';
1
+ import type { Stack, StackDetection } from "../types/index.js";
2
2
  /**
3
3
  * Detect the project stack by looking for well-known build/config files.
4
4
  * Returns the first match (precedence order matters).
@@ -1,5 +1,5 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
1
+ import path from "node:path";
2
+ import fs from "fs-extra";
3
3
  /**
4
4
  * Detect the project stack by looking for well-known build/config files.
5
5
  * Returns the first match (precedence order matters).
@@ -7,70 +7,78 @@ import path from 'path';
7
7
  export async function detectStack(projectDir) {
8
8
  const exists = async (file) => fs.pathExists(path.join(projectDir, file));
9
9
  // Java — Gradle
10
- if (await exists('build.gradle') || await exists('build.gradle.kts')) {
10
+ if ((await exists("build.gradle")) || (await exists("build.gradle.kts"))) {
11
11
  const javaVersion = await detectJavaVersion(projectDir);
12
- return { stackType: 'java-gradle', buildTool: 'gradle', javaVersion };
12
+ return { stackType: "java-gradle", buildTool: "gradle", javaVersion };
13
13
  }
14
14
  // Java — Maven
15
- if (await exists('pom.xml')) {
15
+ if (await exists("pom.xml")) {
16
16
  const javaVersion = await detectJavaVersion(projectDir);
17
- return { stackType: 'java-maven', buildTool: 'maven', javaVersion };
17
+ return { stackType: "java-maven", buildTool: "maven", javaVersion };
18
18
  }
19
19
  // Node.js
20
- if (await exists('package.json')) {
21
- const pkg = await fs.readJson(path.join(projectDir, 'package.json')).catch(() => ({}));
22
- const buildTool = await exists('pnpm-lock.yaml') ? 'pnpm'
23
- : await exists('yarn.lock') ? 'yarn'
24
- : 'npm';
25
- return { stackType: 'node', buildTool };
20
+ if (await exists("package.json")) {
21
+ const _pkg = await fs
22
+ .readJson(path.join(projectDir, "package.json"))
23
+ .catch(() => ({}));
24
+ const buildTool = (await exists("pnpm-lock.yaml"))
25
+ ? "pnpm"
26
+ : (await exists("yarn.lock"))
27
+ ? "yarn"
28
+ : "npm";
29
+ return { stackType: "node", buildTool };
26
30
  }
27
31
  // Python
28
- if (await exists('pyproject.toml') || await exists('requirements.txt') || await exists('setup.py')) {
29
- const buildTool = await exists('pyproject.toml') ? 'pyproject'
30
- : await exists('Pipfile') ? 'pipenv'
31
- : 'pip';
32
- return { stackType: 'python', buildTool };
32
+ if ((await exists("pyproject.toml")) ||
33
+ (await exists("requirements.txt")) ||
34
+ (await exists("setup.py"))) {
35
+ const buildTool = (await exists("pyproject.toml"))
36
+ ? "pyproject"
37
+ : (await exists("Pipfile"))
38
+ ? "pipenv"
39
+ : "pip";
40
+ return { stackType: "python", buildTool };
33
41
  }
34
42
  // Go
35
- if (await exists('go.mod')) {
36
- return { stackType: 'go', buildTool: 'go' };
43
+ if (await exists("go.mod")) {
44
+ return { stackType: "go", buildTool: "go" };
37
45
  }
38
46
  // Rust
39
- if (await exists('Cargo.toml')) {
40
- return { stackType: 'rust', buildTool: 'cargo' };
47
+ if (await exists("Cargo.toml")) {
48
+ return { stackType: "rust", buildTool: "cargo" };
41
49
  }
42
50
  // Elixir
43
- if (await exists('mix.exs')) {
44
- return { stackType: 'elixir', buildTool: 'mix' };
51
+ if (await exists("mix.exs")) {
52
+ return { stackType: "elixir", buildTool: "mix" };
45
53
  }
46
54
  return null;
47
55
  }
48
56
  /** Try to detect Java version from gradle or maven config */
49
57
  async function detectJavaVersion(projectDir) {
50
58
  // Try build.gradle
51
- const gradleFile = path.join(projectDir, 'build.gradle');
59
+ const gradleFile = path.join(projectDir, "build.gradle");
52
60
  if (await fs.pathExists(gradleFile)) {
53
- const content = await fs.readFile(gradleFile, 'utf-8');
54
- const match = content.match(/sourceCompatibility\s*=\s*['"]?(\d+)/)
55
- || content.match(/JavaVersion\.VERSION_(\d+)/);
61
+ const content = await fs.readFile(gradleFile, "utf-8");
62
+ const match = content.match(/sourceCompatibility\s*=\s*['"]?(\d+)/) ||
63
+ content.match(/JavaVersion\.VERSION_(\d+)/);
56
64
  if (match)
57
65
  return match[1];
58
66
  }
59
67
  // Try build.gradle.kts
60
- const ktsFile = path.join(projectDir, 'build.gradle.kts');
68
+ const ktsFile = path.join(projectDir, "build.gradle.kts");
61
69
  if (await fs.pathExists(ktsFile)) {
62
- const content = await fs.readFile(ktsFile, 'utf-8');
63
- const match = content.match(/jvmTarget\s*=\s*['"](\d+)['"]/)
64
- || content.match(/JavaVersion\.VERSION_(\d+)/);
70
+ const content = await fs.readFile(ktsFile, "utf-8");
71
+ const match = content.match(/jvmTarget\s*=\s*['"](\d+)['"]/) ||
72
+ content.match(/JavaVersion\.VERSION_(\d+)/);
65
73
  if (match)
66
74
  return match[1];
67
75
  }
68
76
  // Try pom.xml
69
- const pomFile = path.join(projectDir, 'pom.xml');
77
+ const pomFile = path.join(projectDir, "pom.xml");
70
78
  if (await fs.pathExists(pomFile)) {
71
- const content = await fs.readFile(pomFile, 'utf-8');
72
- const match = content.match(/<java\.version>(\d+)</)
73
- || content.match(/<maven\.compiler\.source>(\d+)</);
79
+ const content = await fs.readFile(pomFile, "utf-8");
80
+ const match = content.match(/<java\.version>(\d+)</) ||
81
+ content.match(/<maven\.compiler\.source>(\d+)</);
74
82
  if (match)
75
83
  return match[1];
76
84
  }
@@ -90,22 +98,22 @@ export async function ensureDirExists(dirPath) {
90
98
  }
91
99
  /** Check if a directory is a git repository */
92
100
  export async function isGitRepo(dir) {
93
- return fs.pathExists(path.join(dir, '.git'));
101
+ return fs.pathExists(path.join(dir, ".git"));
94
102
  }
95
103
  /** Resolve the forge assets root (the package root directory) */
96
104
  export function getForgeRoot() {
97
105
  // When running from dist/, go up one level
98
106
  const thisDir = path.dirname(new URL(import.meta.url).pathname);
99
- return path.resolve(thisDir, '..');
107
+ return path.resolve(thisDir, "..");
100
108
  }
101
109
  /** Stack display names */
102
110
  export const STACK_LABELS = {
103
- 'node': 'Node.js / TypeScript',
104
- 'python': 'Python',
105
- 'go': 'Go',
106
- 'rust': 'Rust',
107
- 'java-gradle': 'Java (Gradle)',
108
- 'java-maven': 'Java (Maven)',
109
- 'elixir': 'Elixir',
111
+ node: "Node.js / TypeScript",
112
+ python: "Python",
113
+ go: "Go",
114
+ rust: "Rust",
115
+ "java-gradle": "Java (Gradle)",
116
+ "java-maven": "Java (Maven)",
117
+ elixir: "Elixir",
110
118
  };
111
119
  //# sourceMappingURL=common.js.map
@@ -1,6 +1,11 @@
1
- import type { InitOptions, StackContextEntry } from '../types/index.js';
1
+ import type { InitOptions, StackContextEntry } from "../types/index.js";
2
2
  export declare function buildIndexMd(projectName: string, stackCtx: StackContextEntry, ciProvider: string, memory: string): string;
3
- export declare function buildSummaryMd(projectName: string, stack: string, ciProvider: string, memory: string, modules: string[]): string;
3
+ export declare function buildSummaryMd(projectName: string, stack: string, ciProvider: string, memory: string, modules: string[], dependencies?: string[]): string;
4
+ /**
5
+ * Detect top-level dependencies from project manifest files.
6
+ * Returns up to 10 dependency names (key deps only, not devDeps).
7
+ */
8
+ export declare function detectDependencies(projectDir: string, stack: string): Promise<string[]>;
4
9
  /**
5
10
  * Generate .context/ directory content from InitOptions metadata.
6
11
  * Pure function — does NOT perform filesystem I/O.
@@ -9,4 +14,14 @@ export declare function generateContextDir(options: InitOptions): Promise<{
9
14
  index: string;
10
15
  summary: string;
11
16
  }>;
17
+ /**
18
+ * Refresh .context/ directory from the forge manifest and live project state.
19
+ * Reads manifest, detects current dependencies, regenerates INDEX.md + summary.md.
20
+ * Returns null if the project is not forge-managed or has no .context/ dir.
21
+ */
22
+ export declare function refreshContextDir(projectDir: string): Promise<{
23
+ index: string;
24
+ summary: string;
25
+ updated: boolean;
26
+ } | null>;
12
27
  //# sourceMappingURL=context.d.ts.map
@@ -1,14 +1,16 @@
1
- import { STACK_CONTEXT_MAP } from '../constants.js';
1
+ import path from "node:path";
2
+ import fs from "fs-extra";
3
+ import { STACK_CONTEXT_MAP } from "../constants.js";
2
4
  // =============================================================================
3
5
  // Internal helpers
4
6
  // =============================================================================
5
7
  function getStackContext(stack) {
6
- return STACK_CONTEXT_MAP[stack] ?? STACK_CONTEXT_MAP['default'];
8
+ return STACK_CONTEXT_MAP[stack] ?? STACK_CONTEXT_MAP.default;
7
9
  }
8
10
  export function buildIndexMd(projectName, stackCtx, ciProvider, memory) {
9
- return `# ${projectName} — File Index
11
+ return `# ${projectName} — Project Index
10
12
 
11
- ## Directory Structure
13
+ ## Structure
12
14
 
13
15
  \`\`\`
14
16
  ${stackCtx.tree}
@@ -20,13 +22,14 @@ ${stackCtx.tree}
20
22
 
21
23
  ## Conventions
22
24
 
23
- - **Stack conventions**: ${stackCtx.conventions}
25
+ - **Stack**: ${stackCtx.conventions}
24
26
  - **CI**: ${ciProvider}
25
27
  - **Memory**: ${memory}
26
28
  `;
27
29
  }
28
- export function buildSummaryMd(projectName, stack, ciProvider, memory, modules) {
29
- const modulesList = modules.length > 0 ? modules.join(', ') : 'none';
30
+ export function buildSummaryMd(projectName, stack, ciProvider, memory, modules, dependencies = []) {
31
+ const modulesList = modules.length > 0 ? modules.join(", ") : "none";
32
+ const depsList = dependencies.length > 0 ? dependencies.join(", ") : "none detected";
30
33
  return `# ${projectName}
31
34
 
32
35
  ## Overview
@@ -35,10 +38,11 @@ ${stack}-based project scaffolded with javi-forge.
35
38
 
36
39
  ## Stack
37
40
 
38
- - **Language/Runtime**: ${stack}
41
+ - **Runtime**: ${stack}
39
42
  - **CI**: ${ciProvider}
40
43
  - **Memory**: ${memory}
41
44
  - **Modules**: ${modulesList}
45
+ - **Dependencies**: ${depsList}
42
46
 
43
47
  ## Key Decisions
44
48
 
@@ -47,6 +51,99 @@ ${stack}-based project scaffolded with javi-forge.
47
51
  `;
48
52
  }
49
53
  // =============================================================================
54
+ // Dependency detection
55
+ // =============================================================================
56
+ /**
57
+ * Detect top-level dependencies from project manifest files.
58
+ * Returns up to 10 dependency names (key deps only, not devDeps).
59
+ */
60
+ export async function detectDependencies(projectDir, stack) {
61
+ const MAX_DEPS = 10;
62
+ try {
63
+ switch (stack) {
64
+ case "node": {
65
+ const pkgPath = path.join(projectDir, "package.json");
66
+ if (!(await fs.pathExists(pkgPath)))
67
+ return [];
68
+ const pkg = await fs.readJson(pkgPath).catch(() => ({}));
69
+ const deps = Object.keys(pkg.dependencies ?? {});
70
+ return deps.slice(0, MAX_DEPS);
71
+ }
72
+ case "python": {
73
+ const pyprojectPath = path.join(projectDir, "pyproject.toml");
74
+ if (await fs.pathExists(pyprojectPath)) {
75
+ const content = await fs.readFile(pyprojectPath, "utf-8");
76
+ const match = content.match(/dependencies\s*=\s*\[([\s\S]*?)\]/);
77
+ if (match?.[1]) {
78
+ const deps = match[1]
79
+ .split("\n")
80
+ .map((l) => l.replace(/[",]/g, "").trim())
81
+ .filter((l) => l.length > 0 && !l.startsWith("#"))
82
+ .map((l) => l.split(/[>=<~!]/)[0].trim())
83
+ .filter(Boolean);
84
+ return deps.slice(0, MAX_DEPS);
85
+ }
86
+ }
87
+ const reqPath = path.join(projectDir, "requirements.txt");
88
+ if (await fs.pathExists(reqPath)) {
89
+ const content = await fs.readFile(reqPath, "utf-8");
90
+ const deps = content
91
+ .split("\n")
92
+ .map((l) => l.trim())
93
+ .filter((l) => l.length > 0 && !l.startsWith("#") && !l.startsWith("-"))
94
+ .map((l) => l.split(/[>=<~!]/)[0].trim())
95
+ .filter(Boolean);
96
+ return deps.slice(0, MAX_DEPS);
97
+ }
98
+ return [];
99
+ }
100
+ case "go": {
101
+ const goModPath = path.join(projectDir, "go.mod");
102
+ if (!(await fs.pathExists(goModPath)))
103
+ return [];
104
+ const content = await fs.readFile(goModPath, "utf-8");
105
+ const requireBlock = content.match(/require\s*\(([\s\S]*?)\)/);
106
+ if (requireBlock?.[1]) {
107
+ const deps = requireBlock[1]
108
+ .split("\n")
109
+ .map((l) => l.trim())
110
+ .filter((l) => l.length > 0 && !l.startsWith("//"))
111
+ .map((l) => {
112
+ const parts = l.split(/\s+/);
113
+ const mod = parts[0] ?? "";
114
+ return mod.split("/").pop() ?? mod;
115
+ })
116
+ .filter(Boolean);
117
+ return deps.slice(0, MAX_DEPS);
118
+ }
119
+ return [];
120
+ }
121
+ case "rust": {
122
+ const cargoPath = path.join(projectDir, "Cargo.toml");
123
+ if (!(await fs.pathExists(cargoPath)))
124
+ return [];
125
+ const content = await fs.readFile(cargoPath, "utf-8");
126
+ const depsSection = content.match(/\[dependencies\]([\s\S]*?)(?=\n\[|$)/);
127
+ if (depsSection?.[1]) {
128
+ const deps = depsSection[1]
129
+ .split("\n")
130
+ .map((l) => l.trim())
131
+ .filter((l) => l.length > 0 && !l.startsWith("#"))
132
+ .map((l) => l.split(/\s*=/)[0].trim())
133
+ .filter(Boolean);
134
+ return deps.slice(0, MAX_DEPS);
135
+ }
136
+ return [];
137
+ }
138
+ default:
139
+ return [];
140
+ }
141
+ }
142
+ catch {
143
+ return [];
144
+ }
145
+ }
146
+ // =============================================================================
50
147
  // Public API
51
148
  // =============================================================================
52
149
  /**
@@ -59,17 +156,49 @@ export async function generateContextDir(options) {
59
156
  // Collect enabled modules for summary
60
157
  const modules = [];
61
158
  if (options.aiSync)
62
- modules.push('ai-sync');
159
+ modules.push("ai-sync");
63
160
  if (options.sdd)
64
- modules.push('sdd');
161
+ modules.push("sdd");
65
162
  if (options.ghagga)
66
- modules.push('ghagga');
163
+ modules.push("ghagga");
67
164
  if (options.mock)
68
- modules.push('mock');
165
+ modules.push("mock");
69
166
  if (options.contextDir)
70
- modules.push('context');
167
+ modules.push("context");
71
168
  const index = buildIndexMd(projectName, stackCtx, ciProvider, memory);
72
169
  const summary = buildSummaryMd(projectName, stack, ciProvider, memory, modules);
73
170
  return { index, summary };
74
171
  }
172
+ /**
173
+ * Refresh .context/ directory from the forge manifest and live project state.
174
+ * Reads manifest, detects current dependencies, regenerates INDEX.md + summary.md.
175
+ * Returns null if the project is not forge-managed or has no .context/ dir.
176
+ */
177
+ export async function refreshContextDir(projectDir) {
178
+ const manifestPath = path.join(projectDir, ".javi-forge", "manifest.json");
179
+ const contextDirPath = path.join(projectDir, ".context");
180
+ // Only refresh if forge-managed and .context/ exists
181
+ if (!(await fs.pathExists(manifestPath)) ||
182
+ !(await fs.pathExists(contextDirPath))) {
183
+ return null;
184
+ }
185
+ let manifest;
186
+ try {
187
+ manifest = (await fs.readJson(manifestPath));
188
+ }
189
+ catch {
190
+ return null;
191
+ }
192
+ const stackCtx = getStackContext(manifest.stack);
193
+ const dependencies = await detectDependencies(projectDir, manifest.stack);
194
+ const index = buildIndexMd(manifest.projectName, stackCtx, manifest.ciProvider, manifest.memory);
195
+ const summary = buildSummaryMd(manifest.projectName, manifest.stack, manifest.ciProvider, manifest.memory, manifest.modules, dependencies);
196
+ // Write updated files
197
+ await fs.writeFile(path.join(contextDirPath, "INDEX.md"), index, "utf-8");
198
+ await fs.writeFile(path.join(contextDirPath, "summary.md"), summary, "utf-8");
199
+ // Update manifest timestamp
200
+ manifest.updatedAt = new Date().toISOString();
201
+ await fs.writeJson(manifestPath, manifest, { spaces: 2 });
202
+ return { index, summary, updated: true };
203
+ }
75
204
  //# sourceMappingURL=context.js.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Crash recovery — reconstruct pipeline state from git commit history
3
+ * when checkpoint files are corrupted or lost. Git is the single
4
+ * source of truth for what was actually done.
5
+ */
6
+ export interface RecoveredTask {
7
+ commitHash: string;
8
+ message: string;
9
+ timestamp: string;
10
+ filesChanged: string[];
11
+ taskId: string | null;
12
+ phase: string | null;
13
+ }
14
+ export interface RecoveryReport {
15
+ branch: string;
16
+ totalCommits: number;
17
+ tasks: RecoveredTask[];
18
+ phases: Record<string, number>;
19
+ lastActivity: string | null;
20
+ }
21
+ export declare function getGitLog(projectDir: string, options?: {
22
+ maxCommits?: number;
23
+ since?: string;
24
+ }): Promise<string>;
25
+ export declare function getCurrentBranch(projectDir: string): Promise<string>;
26
+ export declare function parseCommitPhase(message: string): string | null;
27
+ export declare function extractTaskId(message: string): string | null;
28
+ export declare function parseGitLog(raw: string): RecoveredTask[];
29
+ export declare function recoverFromGit(projectDir: string, options?: {
30
+ maxCommits?: number;
31
+ since?: string;
32
+ }): Promise<RecoveryReport>;
33
+ export declare function formatRecovery(report: RecoveryReport): string;
34
+ //# sourceMappingURL=crash-recovery.d.ts.map