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.
- package/README.md +191 -3
- package/ci-local/hooks/pre-push +17 -13
- package/dist/commands/analyze.d.ts +1 -1
- package/dist/commands/analyze.js +15 -15
- package/dist/commands/atlassian-mcp.d.ts +42 -0
- package/dist/commands/atlassian-mcp.js +98 -0
- package/dist/commands/ci.d.ts +3 -3
- package/dist/commands/ci.js +185 -147
- package/dist/commands/crash-recovery.d.ts +34 -0
- package/dist/commands/crash-recovery.js +123 -0
- package/dist/commands/doctor.d.ts +2 -2
- package/dist/commands/doctor.js +113 -61
- package/dist/commands/harness-audit.d.ts +35 -0
- package/dist/commands/harness-audit.js +277 -0
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +415 -118
- package/dist/commands/llmstxt.d.ts +1 -1
- package/dist/commands/llmstxt.js +36 -34
- package/dist/commands/parallel-batch.d.ts +42 -0
- package/dist/commands/parallel-batch.js +90 -0
- package/dist/commands/plugin.d.ts +26 -1
- package/dist/commands/plugin.js +138 -24
- package/dist/commands/secret-scanner.d.ts +30 -0
- package/dist/commands/secret-scanner.js +272 -0
- package/dist/commands/security-analysis.d.ts +74 -0
- package/dist/commands/security-analysis.js +487 -0
- package/dist/commands/security.d.ts +31 -0
- package/dist/commands/security.js +445 -0
- package/dist/commands/skill-scanner.d.ts +63 -0
- package/dist/commands/skill-scanner.js +383 -0
- package/dist/commands/skills.d.ts +139 -0
- package/dist/commands/skills.js +895 -0
- package/dist/commands/supply-chain.d.ts +23 -0
- package/dist/commands/supply-chain.js +126 -0
- package/dist/commands/tdd-pipeline.d.ts +17 -0
- package/dist/commands/tdd-pipeline.js +144 -0
- package/dist/commands/tdd.d.ts +21 -0
- package/dist/commands/tdd.js +120 -0
- package/dist/commands/team-presets.d.ts +53 -0
- package/dist/commands/team-presets.js +201 -0
- package/dist/commands/workflow.d.ts +23 -0
- package/dist/commands/workflow.js +114 -0
- package/dist/constants.d.ts +21 -0
- package/dist/constants.js +208 -37
- package/dist/index.js +400 -54
- package/dist/lib/agent-skills.d.ts +73 -0
- package/dist/lib/agent-skills.js +260 -0
- package/dist/lib/auto-skill-install.d.ts +37 -0
- package/dist/lib/auto-skill-install.js +92 -0
- package/dist/lib/auto-wire.d.ts +20 -0
- package/dist/lib/auto-wire.js +240 -0
- package/dist/lib/claudemd.d.ts +20 -0
- package/dist/lib/claudemd.js +222 -0
- package/dist/lib/codex-export.d.ts +16 -0
- package/dist/lib/codex-export.js +109 -0
- package/dist/lib/common.d.ts +1 -1
- package/dist/lib/common.js +52 -44
- package/dist/lib/context.d.ts +27 -0
- package/dist/lib/context.js +204 -0
- package/dist/lib/docker.d.ts +1 -1
- package/dist/lib/docker.js +141 -112
- package/dist/lib/frontmatter.d.ts +1 -1
- package/dist/lib/frontmatter.js +29 -15
- package/dist/lib/plugin.d.ts +19 -1
- package/dist/lib/plugin.js +174 -47
- package/dist/lib/skill-publish.d.ts +40 -0
- package/dist/lib/skill-publish.js +146 -0
- package/dist/lib/stack-detector.d.ts +38 -0
- package/dist/lib/stack-detector.js +207 -0
- package/dist/lib/template.d.ts +16 -1
- package/dist/lib/template.js +46 -17
- package/dist/lib/workflow/discovery.d.ts +19 -0
- package/dist/lib/workflow/discovery.js +68 -0
- package/dist/lib/workflow/index.d.ts +5 -0
- package/dist/lib/workflow/index.js +5 -0
- package/dist/lib/workflow/parser.d.ts +16 -0
- package/dist/lib/workflow/parser.js +198 -0
- package/dist/lib/workflow/renderer.d.ts +9 -0
- package/dist/lib/workflow/renderer.js +152 -0
- package/dist/lib/workflow/validator.d.ts +10 -0
- package/dist/lib/workflow/validator.js +189 -0
- package/dist/tasks/index.d.ts +4 -0
- package/dist/tasks/index.js +4 -0
- package/dist/tasks/scaffold-tasks.d.ts +3 -0
- package/dist/tasks/scaffold-tasks.js +14 -0
- package/dist/tasks/task-id.d.ts +30 -0
- package/dist/tasks/task-id.js +55 -0
- package/dist/tasks/task-tracker.d.ts +15 -0
- package/dist/tasks/task-tracker.js +81 -0
- package/dist/types/index.d.ts +252 -5
- package/dist/types/index.js +11 -1
- package/dist/ui/AnalyzeUI.d.ts +1 -1
- package/dist/ui/AnalyzeUI.js +38 -39
- package/dist/ui/App.d.ts +5 -3
- package/dist/ui/App.js +92 -46
- package/dist/ui/AutoSkills.d.ts +9 -0
- package/dist/ui/AutoSkills.js +124 -0
- package/dist/ui/CI.d.ts +2 -2
- package/dist/ui/CI.js +24 -26
- package/dist/ui/CIContext.d.ts +1 -1
- package/dist/ui/CIContext.js +3 -2
- package/dist/ui/CISelector.d.ts +2 -2
- package/dist/ui/CISelector.js +23 -15
- package/dist/ui/Doctor.d.ts +1 -1
- package/dist/ui/Doctor.js +35 -29
- package/dist/ui/Header.d.ts +1 -1
- package/dist/ui/Header.js +14 -14
- package/dist/ui/HookProfileSelector.d.ts +9 -0
- package/dist/ui/HookProfileSelector.js +54 -0
- package/dist/ui/LlmsTxt.d.ts +1 -1
- package/dist/ui/LlmsTxt.js +31 -22
- package/dist/ui/MemorySelector.d.ts +2 -2
- package/dist/ui/MemorySelector.js +28 -16
- package/dist/ui/NameInput.d.ts +1 -1
- package/dist/ui/NameInput.js +21 -21
- package/dist/ui/OptionSelector.d.ts +8 -2
- package/dist/ui/OptionSelector.js +83 -26
- package/dist/ui/Plugin.d.ts +4 -3
- package/dist/ui/Plugin.js +89 -29
- package/dist/ui/Progress.d.ts +3 -3
- package/dist/ui/Progress.js +23 -22
- package/dist/ui/Skills.d.ts +11 -0
- package/dist/ui/Skills.js +148 -0
- package/dist/ui/StackSelector.d.ts +2 -2
- package/dist/ui/StackSelector.js +26 -16
- package/dist/ui/Summary.d.ts +3 -3
- package/dist/ui/Summary.js +60 -50
- package/dist/ui/Welcome.d.ts +1 -1
- package/dist/ui/Welcome.js +15 -16
- package/dist/ui/theme.d.ts +1 -1
- package/dist/ui/theme.js +6 -6
- package/package.json +9 -6
- package/templates/common/atlassian/mcp-atlassian-snippet.json +16 -0
- package/templates/common/repoforge/mcp-repoforge-snippet.json +11 -0
- package/templates/common/repoforge/repoforge.yaml +34 -0
- package/templates/github/deploy-docker-zero-downtime.yml +140 -0
- package/templates/github/repoforge-graph.yml +45 -0
- package/templates/gitlab/deploy-docker-zero-downtime.yml +57 -0
- package/templates/local-ai/.env.example +17 -0
- package/templates/local-ai/docker-compose.yml +95 -0
- package/templates/security-hooks/claude-settings-security.json +30 -0
- package/templates/security-hooks/commit-msg-signing +29 -0
- package/templates/security-hooks/pre-commit-permissions +74 -0
- package/templates/security-hooks/pre-commit-secrets +74 -0
- package/templates/security-hooks/pre-push-branch-protection +62 -0
- package/templates/security-hooks/pre-push-deps +83 -0
- package/templates/security-hooks/pre-push-signing +67 -0
- package/templates/woodpecker/deploy-docker-zero-downtime.yml +50 -0
- package/templates/workflows/ci-pipeline.dot +15 -0
- package/templates/workflows/feature-flow.dot +21 -0
- package/templates/workflows/release.dot +16 -0
- package/dist/__integration__/helpers.d.ts +0 -20
- package/dist/__integration__/helpers.d.ts.map +0 -1
- package/dist/__integration__/helpers.js +0 -31
- package/dist/__integration__/helpers.js.map +0 -1
- package/dist/commands/analyze.d.ts.map +0 -1
- package/dist/commands/analyze.js.map +0 -1
- package/dist/commands/ci.d.ts.map +0 -1
- package/dist/commands/ci.js.map +0 -1
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/llmstxt.d.ts.map +0 -1
- package/dist/commands/llmstxt.js.map +0 -1
- package/dist/commands/plugin.d.ts.map +0 -1
- package/dist/commands/plugin.js.map +0 -1
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/common.d.ts.map +0 -1
- package/dist/lib/common.js.map +0 -1
- package/dist/lib/docker.d.ts.map +0 -1
- package/dist/lib/docker.js.map +0 -1
- package/dist/lib/frontmatter.d.ts.map +0 -1
- package/dist/lib/frontmatter.js.map +0 -1
- package/dist/lib/plugin.d.ts.map +0 -1
- package/dist/lib/plugin.js.map +0 -1
- package/dist/lib/template.d.ts.map +0 -1
- package/dist/lib/template.js.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/ui/AnalyzeUI.d.ts.map +0 -1
- package/dist/ui/AnalyzeUI.js.map +0 -1
- package/dist/ui/App.d.ts.map +0 -1
- package/dist/ui/App.js.map +0 -1
- package/dist/ui/CI.d.ts.map +0 -1
- package/dist/ui/CI.js.map +0 -1
- package/dist/ui/CIContext.d.ts.map +0 -1
- package/dist/ui/CIContext.js.map +0 -1
- package/dist/ui/CISelector.d.ts.map +0 -1
- package/dist/ui/CISelector.js.map +0 -1
- package/dist/ui/Doctor.d.ts.map +0 -1
- package/dist/ui/Doctor.js.map +0 -1
- package/dist/ui/Header.d.ts.map +0 -1
- package/dist/ui/Header.js.map +0 -1
- package/dist/ui/LlmsTxt.d.ts.map +0 -1
- package/dist/ui/LlmsTxt.js.map +0 -1
- package/dist/ui/MemorySelector.d.ts.map +0 -1
- package/dist/ui/MemorySelector.js.map +0 -1
- package/dist/ui/NameInput.d.ts.map +0 -1
- package/dist/ui/NameInput.js.map +0 -1
- package/dist/ui/OptionSelector.d.ts.map +0 -1
- package/dist/ui/OptionSelector.js.map +0 -1
- package/dist/ui/Plugin.d.ts.map +0 -1
- package/dist/ui/Plugin.js.map +0 -1
- package/dist/ui/Progress.d.ts.map +0 -1
- package/dist/ui/Progress.js.map +0 -1
- package/dist/ui/StackSelector.d.ts.map +0 -1
- package/dist/ui/StackSelector.js.map +0 -1
- package/dist/ui/Summary.d.ts.map +0 -1
- package/dist/ui/Summary.js.map +0 -1
- package/dist/ui/Welcome.d.ts.map +0 -1
- package/dist/ui/Welcome.js.map +0 -1
- package/dist/ui/theme.d.ts.map +0 -1
- package/dist/ui/theme.js.map +0 -1
|
@@ -0,0 +1,222 @@
|
|
|
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
|
+
};
|
|
47
|
+
// =============================================================================
|
|
48
|
+
// Internal helpers
|
|
49
|
+
// =============================================================================
|
|
50
|
+
function getStackClaudeMd(stack) {
|
|
51
|
+
return STACK_CLAUDEMD_MAP[stack] ?? STACK_CLAUDEMD_MAP["default"];
|
|
52
|
+
}
|
|
53
|
+
export function buildClaudeMd(projectName, stack, entry, contextDir, modules) {
|
|
54
|
+
const lines = [];
|
|
55
|
+
lines.push(`# ${projectName}`);
|
|
56
|
+
lines.push("");
|
|
57
|
+
// Stack section
|
|
58
|
+
lines.push("## Stack");
|
|
59
|
+
lines.push(`- **Language/Runtime**: ${stack}`);
|
|
60
|
+
lines.push(`- **Conventions**: ${entry.conventions}`);
|
|
61
|
+
lines.push(`- **Testing**: ${entry.testFramework}`);
|
|
62
|
+
lines.push("");
|
|
63
|
+
// Skills section
|
|
64
|
+
if (entry.skills.length > 0) {
|
|
65
|
+
lines.push("## Recommended Skills");
|
|
66
|
+
for (const skill of entry.skills) {
|
|
67
|
+
lines.push(`- Load \`~/.claude/skills/${skill}/SKILL.md\` before writing code`);
|
|
68
|
+
}
|
|
69
|
+
lines.push("");
|
|
70
|
+
}
|
|
71
|
+
// Project Context section (conditional on contextDir)
|
|
72
|
+
if (contextDir) {
|
|
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("");
|
|
77
|
+
}
|
|
78
|
+
// Conventions section
|
|
79
|
+
lines.push("## Conventions");
|
|
80
|
+
lines.push(`- ${entry.conventions}`);
|
|
81
|
+
lines.push("- Scaffolded with javi-forge — see `.javi-forge/manifest.json` for config");
|
|
82
|
+
lines.push("");
|
|
83
|
+
// Modules section
|
|
84
|
+
if (modules.length > 0) {
|
|
85
|
+
lines.push("## Modules");
|
|
86
|
+
lines.push(`- ${modules.join(", ")}`);
|
|
87
|
+
lines.push("");
|
|
88
|
+
}
|
|
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");
|
|
168
|
+
}
|
|
169
|
+
// =============================================================================
|
|
170
|
+
// Public API
|
|
171
|
+
// =============================================================================
|
|
172
|
+
/**
|
|
173
|
+
* Generate CLAUDE.md content from InitOptions metadata.
|
|
174
|
+
* Pure function — does NOT perform filesystem I/O.
|
|
175
|
+
*/
|
|
176
|
+
export function generateClaudeMd(options) {
|
|
177
|
+
const { projectName, stack, contextDir } = options;
|
|
178
|
+
const entry = getStackClaudeMd(stack);
|
|
179
|
+
// Collect enabled modules for listing
|
|
180
|
+
const modules = [];
|
|
181
|
+
if (options.aiSync)
|
|
182
|
+
modules.push("ai-sync");
|
|
183
|
+
if (options.sdd)
|
|
184
|
+
modules.push("sdd");
|
|
185
|
+
if (options.ghagga)
|
|
186
|
+
modules.push("ghagga");
|
|
187
|
+
if (options.mock)
|
|
188
|
+
modules.push("mock");
|
|
189
|
+
if (options.contextDir)
|
|
190
|
+
modules.push("context");
|
|
191
|
+
if (options.claudeMd)
|
|
192
|
+
modules.push("claude-md");
|
|
193
|
+
return buildClaudeMd(projectName, stack, entry, contextDir, modules);
|
|
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
|
+
}
|
|
222
|
+
//# sourceMappingURL=claudemd.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CodexExportResult, CodexTomlEntry } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Convert a SKILL.md raw content string into a CodexTomlEntry.
|
|
4
|
+
* Returns null if the file has no valid frontmatter or missing name.
|
|
5
|
+
*/
|
|
6
|
+
export declare function skillToCodexToml(raw: string): CodexTomlEntry | null;
|
|
7
|
+
/**
|
|
8
|
+
* Serialize a CodexTomlEntry to a TOML string.
|
|
9
|
+
*/
|
|
10
|
+
export declare function serializeToml(entry: CodexTomlEntry): string;
|
|
11
|
+
/**
|
|
12
|
+
* Export an installed plugin's SKILL.md files as Codex-compatible TOML subagent files.
|
|
13
|
+
* Writes .toml files to a `codex/` subdirectory inside the plugin directory.
|
|
14
|
+
*/
|
|
15
|
+
export declare function exportPluginAsCodexToml(name: string): Promise<CodexExportResult>;
|
|
16
|
+
//# sourceMappingURL=codex-export.d.ts.map
|
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
// ── Conversion ─────────────────────────────────────────────────────────────
|
|
7
|
+
/**
|
|
8
|
+
* Convert a SKILL.md raw content string into a CodexTomlEntry.
|
|
9
|
+
* Returns null if the file has no valid frontmatter or missing name.
|
|
10
|
+
*/
|
|
11
|
+
export function skillToCodexToml(raw) {
|
|
12
|
+
const parsed = parseFrontmatter(raw);
|
|
13
|
+
if (!parsed)
|
|
14
|
+
return null;
|
|
15
|
+
const name = parsed.data["name"];
|
|
16
|
+
if (typeof name !== "string" || !name)
|
|
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;
|
|
24
|
+
const instructions = description
|
|
25
|
+
? `${description}\n\n${parsed.content}`.trim()
|
|
26
|
+
: parsed.content.trim();
|
|
27
|
+
return { name, model, instructions };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Serialize a CodexTomlEntry to a TOML string.
|
|
31
|
+
*/
|
|
32
|
+
export function serializeToml(entry) {
|
|
33
|
+
const escapedName = escapeTomlString(entry.name);
|
|
34
|
+
const escapedModel = escapeTomlString(entry.model);
|
|
35
|
+
const escapedInstructions = escapeTomlMultiline(entry.instructions);
|
|
36
|
+
return [
|
|
37
|
+
`name = "${escapedName}"`,
|
|
38
|
+
`model = "${escapedModel}"`,
|
|
39
|
+
`instructions = """`,
|
|
40
|
+
escapedInstructions,
|
|
41
|
+
`"""`,
|
|
42
|
+
"",
|
|
43
|
+
].join("\n");
|
|
44
|
+
}
|
|
45
|
+
// ── File I/O ───────────────────────────────────────────────────────────────
|
|
46
|
+
/**
|
|
47
|
+
* Export an installed plugin's SKILL.md files as Codex-compatible TOML subagent files.
|
|
48
|
+
* Writes .toml files to a `codex/` subdirectory inside the plugin directory.
|
|
49
|
+
*/
|
|
50
|
+
export async function exportPluginAsCodexToml(name) {
|
|
51
|
+
const pluginDir = path.join(PLUGINS_DIR, name);
|
|
52
|
+
if (!(await fs.pathExists(pluginDir))) {
|
|
53
|
+
return { success: false, error: `plugin "${name}" is not installed` };
|
|
54
|
+
}
|
|
55
|
+
// Read plugin manifest for skill list
|
|
56
|
+
const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_FILE);
|
|
57
|
+
if (!(await fs.pathExists(manifestPath))) {
|
|
58
|
+
return { success: false, error: "plugin.json not found" };
|
|
59
|
+
}
|
|
60
|
+
let manifest;
|
|
61
|
+
try {
|
|
62
|
+
manifest = (await fs.readJson(manifestPath));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return { success: false, error: "invalid plugin.json" };
|
|
66
|
+
}
|
|
67
|
+
const skillNames = manifest.skills ?? [];
|
|
68
|
+
if (skillNames.length === 0) {
|
|
69
|
+
return { success: false, error: "plugin has no skills to export" };
|
|
70
|
+
}
|
|
71
|
+
const codexDir = path.join(pluginDir, "codex");
|
|
72
|
+
await fs.ensureDir(codexDir);
|
|
73
|
+
const writtenFiles = [];
|
|
74
|
+
for (const skillName of skillNames) {
|
|
75
|
+
const skillPath = path.join(pluginDir, "skills", skillName, "SKILL.md");
|
|
76
|
+
if (!(await fs.pathExists(skillPath)))
|
|
77
|
+
continue;
|
|
78
|
+
let raw;
|
|
79
|
+
try {
|
|
80
|
+
raw = await fs.readFile(skillPath, "utf-8");
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const entry = skillToCodexToml(raw);
|
|
86
|
+
if (!entry)
|
|
87
|
+
continue;
|
|
88
|
+
const toml = serializeToml(entry);
|
|
89
|
+
const outPath = path.join(codexDir, `${skillName}.toml`);
|
|
90
|
+
await fs.writeFile(outPath, toml, "utf-8");
|
|
91
|
+
writtenFiles.push(outPath);
|
|
92
|
+
}
|
|
93
|
+
if (writtenFiles.length === 0) {
|
|
94
|
+
return { success: false, error: "no skills with valid frontmatter found" };
|
|
95
|
+
}
|
|
96
|
+
return { success: true, files: writtenFiles };
|
|
97
|
+
}
|
|
98
|
+
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
99
|
+
function escapeTomlString(value) {
|
|
100
|
+
return value
|
|
101
|
+
.replace(/\\/g, "\\\\")
|
|
102
|
+
.replace(/"/g, '\\"')
|
|
103
|
+
.replace(/\n/g, "\\n");
|
|
104
|
+
}
|
|
105
|
+
function escapeTomlMultiline(value) {
|
|
106
|
+
// In TOML multiline basic strings ("""), only backslashes and triple quotes need escaping
|
|
107
|
+
return value.replace(/\\/g, "\\\\").replace(/"""/g, '"\\""');
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=codex-export.js.map
|
package/dist/lib/common.d.ts
CHANGED
package/dist/lib/common.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import path from
|
|
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(
|
|
10
|
+
if ((await exists("build.gradle")) || (await exists("build.gradle.kts"))) {
|
|
11
11
|
const javaVersion = await detectJavaVersion(projectDir);
|
|
12
|
-
return { stackType:
|
|
12
|
+
return { stackType: "java-gradle", buildTool: "gradle", javaVersion };
|
|
13
13
|
}
|
|
14
14
|
// Java — Maven
|
|
15
|
-
if (await exists(
|
|
15
|
+
if (await exists("pom.xml")) {
|
|
16
16
|
const javaVersion = await detectJavaVersion(projectDir);
|
|
17
|
-
return { stackType:
|
|
17
|
+
return { stackType: "java-maven", buildTool: "maven", javaVersion };
|
|
18
18
|
}
|
|
19
19
|
// Node.js
|
|
20
|
-
if (await exists(
|
|
21
|
-
const pkg = await fs
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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(
|
|
36
|
-
return { stackType:
|
|
43
|
+
if (await exists("go.mod")) {
|
|
44
|
+
return { stackType: "go", buildTool: "go" };
|
|
37
45
|
}
|
|
38
46
|
// Rust
|
|
39
|
-
if (await exists(
|
|
40
|
-
return { stackType:
|
|
47
|
+
if (await exists("Cargo.toml")) {
|
|
48
|
+
return { stackType: "rust", buildTool: "cargo" };
|
|
41
49
|
}
|
|
42
50
|
// Elixir
|
|
43
|
-
if (await exists(
|
|
44
|
-
return { stackType:
|
|
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,
|
|
59
|
+
const gradleFile = path.join(projectDir, "build.gradle");
|
|
52
60
|
if (await fs.pathExists(gradleFile)) {
|
|
53
|
-
const content = await fs.readFile(gradleFile,
|
|
54
|
-
const match = content.match(/sourceCompatibility\s*=\s*['"]?(\d+)/)
|
|
55
|
-
|
|
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,
|
|
68
|
+
const ktsFile = path.join(projectDir, "build.gradle.kts");
|
|
61
69
|
if (await fs.pathExists(ktsFile)) {
|
|
62
|
-
const content = await fs.readFile(ktsFile,
|
|
63
|
-
const match = content.match(/jvmTarget\s*=\s*['"](\d+)['"]/)
|
|
64
|
-
|
|
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,
|
|
77
|
+
const pomFile = path.join(projectDir, "pom.xml");
|
|
70
78
|
if (await fs.pathExists(pomFile)) {
|
|
71
|
-
const content = await fs.readFile(pomFile,
|
|
72
|
-
const match = content.match(/<java\.version>(\d+)</)
|
|
73
|
-
|
|
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,
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { InitOptions, StackContextEntry } from "../types/index.js";
|
|
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[], 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[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Generate .context/ directory content from InitOptions metadata.
|
|
11
|
+
* Pure function — does NOT perform filesystem I/O.
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateContextDir(options: InitOptions): Promise<{
|
|
14
|
+
index: string;
|
|
15
|
+
summary: string;
|
|
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>;
|
|
27
|
+
//# sourceMappingURL=context.d.ts.map
|