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.
- 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 +384 -141
- 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 +10 -1
- package/dist/commands/plugin.js +92 -47
- 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 +11 -5
- package/dist/commands/security.js +216 -76
- package/dist/commands/skill-scanner.d.ts +63 -0
- package/dist/commands/skill-scanner.js +383 -0
- package/dist/commands/skills.d.ts +62 -5
- package/dist/commands/skills.js +439 -54
- 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 +1 -1
- package/dist/commands/tdd.js +21 -18
- 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 +15 -1
- package/dist/constants.js +161 -122
- package/dist/index.js +308 -98
- package/dist/lib/agent-skills.d.ts +36 -1
- package/dist/lib/agent-skills.js +168 -19
- 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 +13 -1
- package/dist/lib/claudemd.js +174 -24
- package/dist/lib/codex-export.d.ts +1 -1
- package/dist/lib/codex-export.js +29 -31
- package/dist/lib/common.d.ts +1 -1
- package/dist/lib/common.js +52 -44
- package/dist/lib/context.d.ts +17 -2
- package/dist/lib/context.js +142 -13
- 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 +9 -3
- package/dist/lib/plugin.js +128 -69
- 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 +134 -6
- 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 +86 -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 +6 -2
- package/dist/ui/OptionSelector.js +83 -32
- package/dist/ui/Plugin.d.ts +4 -3
- package/dist/ui/Plugin.js +78 -35
- package/dist/ui/Progress.d.ts +3 -3
- package/dist/ui/Progress.js +23 -22
- package/dist/ui/Skills.d.ts +2 -2
- package/dist/ui/Skills.js +61 -32
- 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/commands/security.d.ts.map +0 -1
- package/dist/commands/security.js.map +0 -1
- package/dist/commands/skills.d.ts.map +0 -1
- package/dist/commands/skills.js.map +0 -1
- package/dist/commands/tdd.d.ts.map +0 -1
- package/dist/commands/tdd.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/agent-skills.d.ts.map +0 -1
- package/dist/lib/agent-skills.js.map +0 -1
- package/dist/lib/claudemd.d.ts.map +0 -1
- package/dist/lib/claudemd.js.map +0 -1
- package/dist/lib/codex-export.d.ts.map +0 -1
- package/dist/lib/codex-export.js.map +0 -1
- package/dist/lib/common.d.ts.map +0 -1
- package/dist/lib/common.js.map +0 -1
- package/dist/lib/context.d.ts.map +0 -1
- package/dist/lib/context.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/Skills.d.ts.map +0 -1
- package/dist/ui/Skills.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
package/dist/lib/claudemd.js
CHANGED
|
@@ -1,47 +1,170 @@
|
|
|
1
|
-
import { STACK_CLAUDEMD_MAP } from
|
|
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[
|
|
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(
|
|
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(
|
|
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(
|
|
29
|
-
lines.push(
|
|
30
|
-
lines.push(
|
|
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(
|
|
79
|
+
lines.push("## Conventions");
|
|
35
80
|
lines.push(`- ${entry.conventions}`);
|
|
36
|
-
lines.push(
|
|
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(
|
|
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(
|
|
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(
|
|
182
|
+
modules.push("ai-sync");
|
|
60
183
|
if (options.sdd)
|
|
61
|
-
modules.push(
|
|
184
|
+
modules.push("sdd");
|
|
62
185
|
if (options.ghagga)
|
|
63
|
-
modules.push(
|
|
186
|
+
modules.push("ghagga");
|
|
64
187
|
if (options.mock)
|
|
65
|
-
modules.push(
|
|
188
|
+
modules.push("mock");
|
|
66
189
|
if (options.contextDir)
|
|
67
|
-
modules.push(
|
|
190
|
+
modules.push("context");
|
|
68
191
|
if (options.claudeMd)
|
|
69
|
-
modules.push(
|
|
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 {
|
|
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.
|
package/dist/lib/codex-export.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import path from
|
|
3
|
-
import {
|
|
4
|
-
import { parseFrontmatter } from
|
|
5
|
-
const DEFAULT_MODEL =
|
|
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[
|
|
16
|
-
if (typeof name !==
|
|
15
|
+
const name = parsed.data["name"];
|
|
16
|
+
if (typeof name !== "string" || !name)
|
|
17
17
|
return null;
|
|
18
|
-
const description = typeof parsed.data[
|
|
19
|
-
? parsed.data[
|
|
20
|
-
:
|
|
21
|
-
const model = typeof parsed.data[
|
|
22
|
-
? parsed.data[
|
|
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(
|
|
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:
|
|
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:
|
|
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:
|
|
69
|
+
return { success: false, error: "plugin has no skills to export" };
|
|
70
70
|
}
|
|
71
|
-
const codexDir = path.join(pluginDir,
|
|
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,
|
|
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,
|
|
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,
|
|
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:
|
|
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,
|
|
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
|
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
|
package/dist/lib/context.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import type { InitOptions, StackContextEntry } from
|
|
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
|