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
@@ -1,47 +1,170 @@
1
- import { STACK_CLAUDEMD_MAP } from '../constants.js';
1
+ import { STACK_CLAUDEMD_MAP } from "../constants.js";
2
+ // =============================================================================
3
+ // Architecture pattern mapping (signal → patterns)
4
+ // =============================================================================
5
+ const ARCHITECTURE_PATTERNS = {
6
+ "react-19": [
7
+ "Container-Presentational pattern",
8
+ "Atomic Design for component hierarchy",
9
+ ],
10
+ "nextjs-15": [
11
+ "App Router file-based routing",
12
+ "Server Components by default, client opt-in",
13
+ ],
14
+ "django-drf": ["ViewSets + Serializers", "URL namespace per app"],
15
+ "zustand-5": [
16
+ "Slice pattern for store modules",
17
+ "Selectors for derived state",
18
+ ],
19
+ typescript: [
20
+ "Strict mode enabled",
21
+ "Prefer interfaces for public APIs, types for unions",
22
+ ],
23
+ "tailwind-4": ["Utility-first CSS", "Use `cn()` for conditional classes"],
24
+ "zod-4": [
25
+ "Schema-first validation",
26
+ "Infer types from schemas with `z.infer`",
27
+ ],
28
+ playwright: [
29
+ "Page Object Model for E2E tests",
30
+ "Locator-based selectors over CSS",
31
+ ],
32
+ pytest: ["Fixtures for setup/teardown", "Parametrize for data-driven tests"],
33
+ "ai-sdk-5": [
34
+ "Streaming responses by default",
35
+ "Tool calling with structured schemas",
36
+ ],
37
+ };
38
+ // =============================================================================
39
+ // Plugin instruction mapping (detected skill → plugin hints)
40
+ // =============================================================================
41
+ const PLUGIN_INSTRUCTIONS = {
42
+ "react-19": "Check `~/.claude/plugins/` for merge-checks and mermaid diagram support",
43
+ "nextjs-15": "Check `~/.claude/plugins/` for merge-checks and mermaid diagram support",
44
+ typescript: "Run `javi-forge skills doctor` to validate skill compatibility",
45
+ playwright: "Use `javi-forge tdd` for test-driven development workflow",
46
+ };
2
47
  // =============================================================================
3
48
  // Internal helpers
4
49
  // =============================================================================
5
50
  function getStackClaudeMd(stack) {
6
- return STACK_CLAUDEMD_MAP[stack] ?? STACK_CLAUDEMD_MAP['default'];
51
+ return STACK_CLAUDEMD_MAP[stack] ?? STACK_CLAUDEMD_MAP["default"];
7
52
  }
8
53
  export function buildClaudeMd(projectName, stack, entry, contextDir, modules) {
9
54
  const lines = [];
10
55
  lines.push(`# ${projectName}`);
11
- lines.push('');
56
+ lines.push("");
12
57
  // Stack section
13
- lines.push('## Stack');
58
+ lines.push("## Stack");
14
59
  lines.push(`- **Language/Runtime**: ${stack}`);
15
60
  lines.push(`- **Conventions**: ${entry.conventions}`);
16
61
  lines.push(`- **Testing**: ${entry.testFramework}`);
17
- lines.push('');
62
+ lines.push("");
18
63
  // Skills section
19
64
  if (entry.skills.length > 0) {
20
- lines.push('## Recommended Skills');
65
+ lines.push("## Recommended Skills");
21
66
  for (const skill of entry.skills) {
22
67
  lines.push(`- Load \`~/.claude/skills/${skill}/SKILL.md\` before writing code`);
23
68
  }
24
- lines.push('');
69
+ lines.push("");
25
70
  }
26
71
  // Project Context section (conditional on contextDir)
27
72
  if (contextDir) {
28
- lines.push('## Project Context');
29
- lines.push('- See `.context/INDEX.md` for file structure and entry points');
30
- lines.push('- See `.context/summary.md` for project overview');
31
- lines.push('');
73
+ lines.push("## Project Context");
74
+ lines.push("- See `.context/INDEX.md` for file structure and entry points");
75
+ lines.push("- See `.context/summary.md` for project overview");
76
+ lines.push("");
32
77
  }
33
78
  // Conventions section
34
- lines.push('## Conventions');
79
+ lines.push("## Conventions");
35
80
  lines.push(`- ${entry.conventions}`);
36
- lines.push('- Scaffolded with javi-forge — see `.javi-forge/manifest.json` for config');
37
- lines.push('');
81
+ lines.push("- Scaffolded with javi-forge — see `.javi-forge/manifest.json` for config");
82
+ lines.push("");
38
83
  // Modules section
39
84
  if (modules.length > 0) {
40
- lines.push('## Modules');
41
- lines.push(`- ${modules.join(', ')}`);
42
- lines.push('');
85
+ lines.push("## Modules");
86
+ lines.push(`- ${modules.join(", ")}`);
87
+ lines.push("");
43
88
  }
44
- return lines.join('\n');
89
+ return lines.join("\n");
90
+ }
91
+ /**
92
+ * Build an enriched CLAUDE.md using detected skills, architecture patterns,
93
+ * and plugin instructions. Pure function — no I/O.
94
+ */
95
+ export function buildSmartClaudeMd(projectName, stack, entry, detectedSkills, contextDir, modules) {
96
+ const lines = [];
97
+ // Merge: detected skills + static entry skills (deduplicated)
98
+ const allSkills = [...new Set([...detectedSkills, ...entry.skills])].sort();
99
+ lines.push(`# ${projectName}`);
100
+ lines.push("");
101
+ // Stack section
102
+ lines.push("## Stack");
103
+ lines.push(`- **Language/Runtime**: ${stack}`);
104
+ lines.push(`- **Conventions**: ${entry.conventions}`);
105
+ lines.push(`- **Testing**: ${entry.testFramework}`);
106
+ lines.push("");
107
+ // Skills section — auto-detected + static
108
+ if (allSkills.length > 0) {
109
+ lines.push("## Skills (auto-detected)");
110
+ lines.push("");
111
+ lines.push("Load these skill files BEFORE writing code in this project:");
112
+ lines.push("");
113
+ for (const skill of allSkills) {
114
+ lines.push(`- \`~/.claude/skills/${skill}/SKILL.md\``);
115
+ }
116
+ lines.push("");
117
+ }
118
+ // Architecture patterns section — derived from detected skills
119
+ const patterns = [];
120
+ for (const skill of allSkills) {
121
+ const skillPatterns = ARCHITECTURE_PATTERNS[skill];
122
+ if (skillPatterns) {
123
+ patterns.push(...skillPatterns);
124
+ }
125
+ }
126
+ if (patterns.length > 0) {
127
+ lines.push("## Architecture Patterns");
128
+ lines.push("");
129
+ for (const pattern of patterns) {
130
+ lines.push(`- ${pattern}`);
131
+ }
132
+ lines.push("");
133
+ }
134
+ // Project Context section
135
+ if (contextDir) {
136
+ lines.push("## Project Context");
137
+ lines.push("- See `.context/INDEX.md` for file structure and entry points");
138
+ lines.push("- See `.context/summary.md` for project overview");
139
+ lines.push("");
140
+ }
141
+ // Conventions section
142
+ lines.push("## Conventions");
143
+ lines.push(`- ${entry.conventions}`);
144
+ lines.push("- Scaffolded with javi-forge — see `.javi-forge/manifest.json` for config");
145
+ lines.push("");
146
+ // Plugin instructions — derived from detected skills
147
+ const pluginHints = new Set();
148
+ for (const skill of allSkills) {
149
+ const hint = PLUGIN_INSTRUCTIONS[skill];
150
+ if (hint)
151
+ pluginHints.add(hint);
152
+ }
153
+ if (pluginHints.size > 0) {
154
+ lines.push("## Plugins");
155
+ lines.push("");
156
+ for (const hint of pluginHints) {
157
+ lines.push(`- ${hint}`);
158
+ }
159
+ lines.push("");
160
+ }
161
+ // Modules section
162
+ if (modules.length > 0) {
163
+ lines.push("## Modules");
164
+ lines.push(`- ${modules.join(", ")}`);
165
+ lines.push("");
166
+ }
167
+ return lines.join("\n");
45
168
  }
46
169
  // =============================================================================
47
170
  // Public API
@@ -56,17 +179,44 @@ export function generateClaudeMd(options) {
56
179
  // Collect enabled modules for listing
57
180
  const modules = [];
58
181
  if (options.aiSync)
59
- modules.push('ai-sync');
182
+ modules.push("ai-sync");
60
183
  if (options.sdd)
61
- modules.push('sdd');
184
+ modules.push("sdd");
62
185
  if (options.ghagga)
63
- modules.push('ghagga');
186
+ modules.push("ghagga");
64
187
  if (options.mock)
65
- modules.push('mock');
188
+ modules.push("mock");
66
189
  if (options.contextDir)
67
- modules.push('context');
190
+ modules.push("context");
68
191
  if (options.claudeMd)
69
- modules.push('claude-md');
192
+ modules.push("claude-md");
70
193
  return buildClaudeMd(projectName, stack, entry, contextDir, modules);
71
194
  }
195
+ /**
196
+ * Generate a project-aware CLAUDE.md using stack detection results.
197
+ * Falls back to static generation if no detection result provided.
198
+ * Pure function — does NOT perform filesystem I/O.
199
+ */
200
+ export function generateSmartClaudeMd(options, detection) {
201
+ // Fallback: no detection result, use static generation
202
+ if (!detection || detection.recommendedSkills.length === 0) {
203
+ return generateClaudeMd(options);
204
+ }
205
+ const { projectName, stack, contextDir } = options;
206
+ const entry = getStackClaudeMd(stack);
207
+ const modules = [];
208
+ if (options.aiSync)
209
+ modules.push("ai-sync");
210
+ if (options.sdd)
211
+ modules.push("sdd");
212
+ if (options.ghagga)
213
+ modules.push("ghagga");
214
+ if (options.mock)
215
+ modules.push("mock");
216
+ if (options.contextDir)
217
+ modules.push("context");
218
+ if (options.claudeMd)
219
+ modules.push("claude-md");
220
+ return buildSmartClaudeMd(projectName, stack, entry, detection.recommendedSkills, contextDir, modules);
221
+ }
72
222
  //# sourceMappingURL=claudemd.js.map
@@ -1,4 +1,4 @@
1
- import type { CodexTomlEntry, CodexExportResult } from '../types/index.js';
1
+ import type { CodexExportResult, CodexTomlEntry } from "../types/index.js";
2
2
  /**
3
3
  * Convert a SKILL.md raw content string into a CodexTomlEntry.
4
4
  * Returns null if the file has no valid frontmatter or missing name.
@@ -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 fs from "fs-extra";
2
+ import path from "path";
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,14 +12,14 @@ 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']
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
23
  : DEFAULT_MODEL;
24
24
  const instructions = description
25
25
  ? `${description}\n\n${parsed.content}`.trim()
@@ -39,8 +39,8 @@ export function serializeToml(entry) {
39
39
  `instructions = """`,
40
40
  escapedInstructions,
41
41
  `"""`,
42
- '',
43
- ].join('\n');
42
+ "",
43
+ ].join("\n");
44
44
  }
45
45
  // ── File I/O ───────────────────────────────────────────────────────────────
46
46
  /**
@@ -49,35 +49,35 @@ export function serializeToml(entry) {
49
49
  */
50
50
  export async function exportPluginAsCodexToml(name) {
51
51
  const pluginDir = path.join(PLUGINS_DIR, name);
52
- if (!await fs.pathExists(pluginDir)) {
52
+ if (!(await fs.pathExists(pluginDir))) {
53
53
  return { success: false, error: `plugin "${name}" is not installed` };
54
54
  }
55
55
  // Read plugin manifest for skill list
56
56
  const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_FILE);
57
- if (!await fs.pathExists(manifestPath)) {
58
- return { success: false, error: 'plugin.json not found' };
57
+ if (!(await fs.pathExists(manifestPath))) {
58
+ return { success: false, error: "plugin.json not found" };
59
59
  }
60
60
  let manifest;
61
61
  try {
62
- manifest = await fs.readJson(manifestPath);
62
+ manifest = (await fs.readJson(manifestPath));
63
63
  }
64
64
  catch {
65
- return { success: false, error: 'invalid plugin.json' };
65
+ return { success: false, error: "invalid plugin.json" };
66
66
  }
67
67
  const skillNames = manifest.skills ?? [];
68
68
  if (skillNames.length === 0) {
69
- return { success: false, error: 'plugin has no skills to export' };
69
+ return { success: false, error: "plugin has no skills to export" };
70
70
  }
71
- const codexDir = path.join(pluginDir, 'codex');
71
+ const codexDir = path.join(pluginDir, "codex");
72
72
  await fs.ensureDir(codexDir);
73
73
  const writtenFiles = [];
74
74
  for (const skillName of skillNames) {
75
- const skillPath = path.join(pluginDir, 'skills', skillName, 'SKILL.md');
76
- if (!await fs.pathExists(skillPath))
75
+ const skillPath = path.join(pluginDir, "skills", skillName, "SKILL.md");
76
+ if (!(await fs.pathExists(skillPath)))
77
77
  continue;
78
78
  let raw;
79
79
  try {
80
- raw = await fs.readFile(skillPath, 'utf-8');
80
+ raw = await fs.readFile(skillPath, "utf-8");
81
81
  }
82
82
  catch {
83
83
  continue;
@@ -87,25 +87,23 @@ export async function exportPluginAsCodexToml(name) {
87
87
  continue;
88
88
  const toml = serializeToml(entry);
89
89
  const outPath = path.join(codexDir, `${skillName}.toml`);
90
- await fs.writeFile(outPath, toml, 'utf-8');
90
+ await fs.writeFile(outPath, toml, "utf-8");
91
91
  writtenFiles.push(outPath);
92
92
  }
93
93
  if (writtenFiles.length === 0) {
94
- return { success: false, error: 'no skills with valid frontmatter found' };
94
+ return { success: false, error: "no skills with valid frontmatter found" };
95
95
  }
96
96
  return { success: true, files: writtenFiles };
97
97
  }
98
98
  // ── Helpers ────────────────────────────────────────────────────────────────
99
99
  function escapeTomlString(value) {
100
100
  return value
101
- .replace(/\\/g, '\\\\')
101
+ .replace(/\\/g, "\\\\")
102
102
  .replace(/"/g, '\\"')
103
- .replace(/\n/g, '\\n');
103
+ .replace(/\n/g, "\\n");
104
104
  }
105
105
  function escapeTomlMultiline(value) {
106
106
  // In TOML multiline basic strings ("""), only backslashes and triple quotes need escaping
107
- return value
108
- .replace(/\\/g, '\\\\')
109
- .replace(/"""/g, '"\\"\"');
107
+ return value.replace(/\\/g, "\\\\").replace(/"""/g, '"\\""');
110
108
  }
111
109
  //# 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 fs from "fs-extra";
2
+ import path from "path";
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