javi-forge 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -1
- package/ci-local/README.md +56 -11
- package/ci-local/ci-local.ps1 +445 -0
- package/ci-local/ci-local.sh +52 -9
- package/ci-local/docker/python.Dockerfile +7 -0
- package/ci-local/hooks/commit-msg +120 -44
- package/ci-local/hooks/commit-msg.test.sh +286 -0
- package/ci-local/hooks/pre-commit +9 -1
- package/ci-local/hooks/pre-push +13 -2
- package/ci-local/install.ps1 +367 -0
- package/ci-local/install.sh +151 -5
- package/ci-local/uninstall.ps1 +85 -0
- package/ci-local/uninstall.sh +95 -0
- package/dist/cli/dispatch/ci.d.ts +12 -0
- package/dist/cli/dispatch/ci.js +38 -0
- package/dist/cli/dispatch/security.d.ts +11 -0
- package/dist/cli/dispatch/security.js +68 -0
- package/dist/cli/dispatch/simple-renderers.d.ts +16 -0
- package/dist/cli/dispatch/simple-renderers.js +65 -0
- package/dist/cli/dispatch/skill-publish.d.ts +15 -0
- package/dist/cli/dispatch/skill-publish.js +44 -0
- package/dist/cli/dispatch/skills-cmd.d.ts +13 -0
- package/dist/cli/dispatch/skills-cmd.js +93 -0
- package/dist/cli/dispatch/tdd.d.ts +11 -0
- package/dist/cli/dispatch/tdd.js +45 -0
- package/dist/cli/dispatch/types.d.ts +29 -0
- package/dist/cli/dispatch/types.js +2 -0
- package/dist/cli/dispatch/workflow.d.ts +11 -0
- package/dist/cli/dispatch/workflow.js +67 -0
- package/dist/cli/help.d.ts +127 -0
- package/dist/cli/help.js +138 -0
- package/dist/cli/runtime.d.ts +16 -0
- package/dist/cli/runtime.js +38 -0
- package/dist/cli/validators.d.ts +17 -0
- package/dist/cli/validators.js +35 -0
- package/dist/commands/analyze.js +1 -3
- package/dist/commands/ci.d.ts +47 -0
- package/dist/commands/ci.js +380 -63
- package/dist/commands/doctor.js +2 -4
- package/dist/commands/init/report.d.ts +13 -0
- package/dist/commands/init/report.js +13 -0
- package/dist/commands/init/steps/agent-skills.d.ts +13 -0
- package/dist/commands/init/steps/agent-skills.js +45 -0
- package/dist/commands/init/steps/ai-sync.d.ts +15 -0
- package/dist/commands/init/steps/ai-sync.js +62 -0
- package/dist/commands/init/steps/ci.d.ts +24 -0
- package/dist/commands/init/steps/ci.js +74 -0
- package/dist/commands/init/steps/claude-md.d.ts +14 -0
- package/dist/commands/init/steps/claude-md.js +54 -0
- package/dist/commands/init/steps/code-graph.d.ts +16 -0
- package/dist/commands/init/steps/code-graph.js +68 -0
- package/dist/commands/init/steps/context-dir.d.ts +13 -0
- package/dist/commands/init/steps/context-dir.js +47 -0
- package/dist/commands/init/steps/docker-deploy.d.ts +16 -0
- package/dist/commands/init/steps/docker-deploy.js +60 -0
- package/dist/commands/init/steps/ghagga.d.ts +15 -0
- package/dist/commands/init/steps/ghagga.js +58 -0
- package/dist/commands/init/steps/git.d.ts +25 -0
- package/dist/commands/init/steps/git.js +81 -0
- package/dist/commands/init/steps/gitignore.d.ts +13 -0
- package/dist/commands/init/steps/gitignore.js +39 -0
- package/dist/commands/init/steps/local-ai.d.ts +14 -0
- package/dist/commands/init/steps/local-ai.js +53 -0
- package/dist/commands/init/steps/manifest.d.ts +13 -0
- package/dist/commands/init/steps/manifest.js +58 -0
- package/dist/commands/init/steps/memory.d.ts +15 -0
- package/dist/commands/init/steps/memory.js +60 -0
- package/dist/commands/init/steps/mock.d.ts +13 -0
- package/dist/commands/init/steps/mock.js +64 -0
- package/dist/commands/init/steps/sdd.d.ts +12 -0
- package/dist/commands/init/steps/sdd.js +40 -0
- package/dist/commands/init/steps/security.d.ts +28 -0
- package/dist/commands/init/steps/security.js +103 -0
- package/dist/commands/init/types.d.ts +30 -0
- package/dist/commands/init/types.js +2 -0
- package/dist/commands/init.d.ts +5 -4
- package/dist/commands/init.js +42 -630
- package/dist/commands/llmstxt.js +1 -1
- package/dist/commands/plugin.js +1 -1
- package/dist/commands/security.js +23 -4
- package/dist/commands/skills/analysis.d.ts +19 -0
- package/dist/commands/skills/analysis.js +211 -0
- package/dist/commands/skills/benchmark.d.ts +6 -0
- package/dist/commands/skills/benchmark.js +82 -0
- package/dist/commands/skills/constants.d.ts +10 -0
- package/dist/commands/skills/constants.js +27 -0
- package/dist/commands/skills/directives.d.ts +21 -0
- package/dist/commands/skills/directives.js +101 -0
- package/dist/commands/skills/parsing.d.ts +16 -0
- package/dist/commands/skills/parsing.js +108 -0
- package/dist/commands/skills/rules.d.ts +5 -0
- package/dist/commands/skills/rules.js +32 -0
- package/dist/commands/skills/scoring.d.ts +47 -0
- package/dist/commands/skills/scoring.js +306 -0
- package/dist/commands/skills.d.ts +7 -125
- package/dist/commands/skills.js +8 -874
- package/dist/commands/tdd-pipeline.js +1 -1
- package/dist/commands/tdd.js +1 -1
- package/dist/commands/workflow.js +2 -0
- package/dist/constants.js +2 -2
- package/dist/index.js +26 -473
- package/dist/lib/agent-skills.js +1 -1
- package/dist/{commands → lib}/atlassian-mcp.js +2 -2
- package/dist/lib/auto-skill-install.js +2 -3
- package/dist/lib/auto-wire.js +7 -7
- package/dist/lib/ci-config.d.ts +65 -0
- package/dist/lib/ci-config.js +297 -0
- package/dist/lib/claudemd.js +1 -1
- package/dist/lib/codex-export.js +4 -8
- package/dist/lib/common.js +2 -2
- package/dist/lib/context.js +2 -2
- package/dist/{commands → lib}/crash-recovery.js +4 -4
- package/dist/lib/docker.d.ts +22 -1
- package/dist/lib/docker.js +57 -49
- package/dist/lib/exec.d.ts +10 -0
- package/dist/lib/exec.js +11 -0
- package/dist/lib/frontmatter.js +2 -2
- package/dist/{commands → lib}/harness-audit.js +1 -1
- package/dist/{commands → lib}/parallel-batch.js +1 -3
- package/dist/lib/plugin.js +2 -4
- package/dist/{commands → lib}/secret-scanner.js +3 -1
- package/dist/{commands → lib}/security-analysis.js +4 -2
- package/dist/lib/skill-publish.js +23 -5
- package/dist/{commands → lib}/skill-scanner.d.ts +1 -1
- package/dist/{commands → lib}/skill-scanner.js +3 -3
- package/dist/lib/stack-detector.js +3 -3
- package/dist/{commands → lib}/supply-chain.js +1 -1
- package/dist/lib/template.js +2 -2
- package/dist/lib/workflow/discovery.d.ts +8 -0
- package/dist/lib/workflow/discovery.js +18 -1
- package/dist/lib/workflow/parser.js +15 -15
- package/dist/lib/workflow/validator.js +4 -4
- package/dist/tasks/index.d.ts +3 -3
- package/dist/tasks/index.js +3 -3
- package/dist/tasks/scaffold-tasks.d.ts +1 -1
- package/dist/tasks/scaffold-tasks.js +10 -10
- package/dist/tasks/task-id.d.ts +1 -1
- package/dist/tasks/task-id.js +9 -5
- package/dist/tasks/task-tracker.d.ts +1 -1
- package/dist/tasks/task-tracker.js +7 -7
- package/dist/ui/App.js +1 -1
- package/dist/ui/CIContext.js +1 -2
- package/dist/ui/Header.js +4 -4
- package/dist/ui/NameInput.js +1 -1
- package/dist/ui/Progress.d.ts +1 -1
- package/dist/ui/Progress.js +1 -1
- package/dist/ui/StackSelector.js +1 -1
- package/lib/common.psm1 +167 -0
- package/lib/common.sh +30 -0
- package/package.json +38 -19
- /package/dist/{commands → lib}/atlassian-mcp.d.ts +0 -0
- /package/dist/{commands → lib}/crash-recovery.d.ts +0 -0
- /package/dist/{commands → lib}/harness-audit.d.ts +0 -0
- /package/dist/{commands → lib}/parallel-batch.d.ts +0 -0
- /package/dist/{commands → lib}/secret-scanner.d.ts +0 -0
- /package/dist/{commands → lib}/security-analysis.d.ts +0 -0
- /package/dist/{commands → lib}/supply-chain.d.ts +0 -0
- /package/dist/{commands → lib}/team-presets.d.ts +0 -0
- /package/dist/{commands → lib}/team-presets.js +0 -0
package/dist/commands/init.js
CHANGED
|
@@ -1,640 +1,52 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
1
|
+
import { ensureDirExists } from "../lib/common.js";
|
|
2
|
+
import { stepAgentSkills } from "./init/steps/agent-skills.js";
|
|
3
|
+
import { stepAISync } from "./init/steps/ai-sync.js";
|
|
4
|
+
import { stepCITemplate, stepDependabot } from "./init/steps/ci.js";
|
|
5
|
+
import { stepClaudeMd } from "./init/steps/claude-md.js";
|
|
6
|
+
import { stepCodeGraph } from "./init/steps/code-graph.js";
|
|
7
|
+
import { stepContextDir } from "./init/steps/context-dir.js";
|
|
8
|
+
import { stepDockerDeploy } from "./init/steps/docker-deploy.js";
|
|
9
|
+
import { stepGhagga } from "./init/steps/ghagga.js";
|
|
10
|
+
import { stepGitHooks, stepGitInit } from "./init/steps/git.js";
|
|
11
|
+
import { stepGitignore } from "./init/steps/gitignore.js";
|
|
12
|
+
import { stepLocalAi } from "./init/steps/local-ai.js";
|
|
13
|
+
import { stepManifest } from "./init/steps/manifest.js";
|
|
14
|
+
import { stepMemory } from "./init/steps/memory.js";
|
|
15
|
+
import { stepMock } from "./init/steps/mock.js";
|
|
16
|
+
import { stepSDD } from "./init/steps/sdd.js";
|
|
17
|
+
import { stepHookProfile, stepSecurityHooks } from "./init/steps/security.js";
|
|
15
18
|
/**
|
|
16
19
|
* Main init orchestrator: bootstraps a project with CI, git hooks,
|
|
17
|
-
* memory module, AI config sync, SDD, and
|
|
20
|
+
* memory module, AI config sync, SDD, ghagga, and friends.
|
|
21
|
+
*
|
|
22
|
+
* Pure dispatch: every step lives in src/commands/init/steps/.
|
|
18
23
|
*/
|
|
19
24
|
export async function initProject(options, onStep) {
|
|
20
|
-
const { projectDir,
|
|
25
|
+
const { projectDir, dryRun } = options;
|
|
21
26
|
// Ensure project directory exists before any steps
|
|
22
27
|
if (!dryRun && projectDir) {
|
|
23
28
|
await ensureDirExists(projectDir);
|
|
24
29
|
}
|
|
25
|
-
//
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
const ciLocalSrc = CI_LOCAL_DIR;
|
|
48
|
-
const ciLocalDest = path.join(projectDir, "ci-local");
|
|
49
|
-
if (await fs.pathExists(ciLocalSrc)) {
|
|
50
|
-
if (!dryRun) {
|
|
51
|
-
await fs.copy(ciLocalSrc, ciLocalDest, {
|
|
52
|
-
overwrite: false,
|
|
53
|
-
errorOnExist: false,
|
|
54
|
-
});
|
|
55
|
-
// Set core.hooksPath to ci-local/hooks
|
|
56
|
-
const hooksDir = path.join(ciLocalDest, "hooks");
|
|
57
|
-
if (await fs.pathExists(hooksDir)) {
|
|
58
|
-
// Ensure hooks are executable
|
|
59
|
-
const hookFiles = await fs.readdir(hooksDir);
|
|
60
|
-
for (const hook of hookFiles) {
|
|
61
|
-
await fs.chmod(path.join(hooksDir, hook), 0o755);
|
|
62
|
-
}
|
|
63
|
-
await execFileAsync("git", ["config", "core.hooksPath", "ci-local/hooks"], { cwd: projectDir });
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
report(onStep, stepHooks, "Configure git hooks path", "done", "ci-local/hooks");
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
report(onStep, stepHooks, "Configure git hooks path", "skipped", "no ci-local dir");
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
catch (e) {
|
|
73
|
-
report(onStep, stepHooks, "Configure git hooks path", "error", String(e));
|
|
74
|
-
}
|
|
75
|
-
// ── Step 3: Copy CI template ──────────────────────────────────────────────
|
|
76
|
-
const stepCI = "ci-template";
|
|
77
|
-
report(onStep, stepCI, `Copy ${ciProvider} CI workflow`, "running");
|
|
78
|
-
try {
|
|
79
|
-
const ciContent = await generateCIWorkflow(stack, ciProvider);
|
|
80
|
-
if (ciContent) {
|
|
81
|
-
const dest = path.join(projectDir, getCIDestination(ciProvider));
|
|
82
|
-
if (!dryRun) {
|
|
83
|
-
await backupIfExists(dest);
|
|
84
|
-
await ensureDirExists(path.dirname(dest));
|
|
85
|
-
await fs.writeFile(dest, ciContent, "utf-8");
|
|
86
|
-
}
|
|
87
|
-
report(onStep, stepCI, `Copy ${ciProvider} CI workflow`, "done", getCIDestination(ciProvider));
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
report(onStep, stepCI, `Copy ${ciProvider} CI workflow`, "skipped", `no template for ${stack}`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
catch (e) {
|
|
94
|
-
report(onStep, stepCI, `Copy ${ciProvider} CI workflow`, "error", String(e));
|
|
95
|
-
}
|
|
96
|
-
// ── Step 4: Generate .gitignore ───────────────────────────────────────────
|
|
97
|
-
const stepGitignore = "gitignore";
|
|
98
|
-
report(onStep, stepGitignore, "Generate .gitignore", "running");
|
|
99
|
-
try {
|
|
100
|
-
const templatePath = path.join(FORGE_ROOT, ".gitignore.template");
|
|
101
|
-
const dest = path.join(projectDir, ".gitignore");
|
|
102
|
-
if ((await fs.pathExists(templatePath)) && !(await fs.pathExists(dest))) {
|
|
103
|
-
if (!dryRun) {
|
|
104
|
-
await fs.copy(templatePath, dest);
|
|
105
|
-
}
|
|
106
|
-
report(onStep, stepGitignore, "Generate .gitignore", "done", "from template");
|
|
107
|
-
}
|
|
108
|
-
else if (await fs.pathExists(dest)) {
|
|
109
|
-
report(onStep, stepGitignore, "Generate .gitignore", "done", "already exists");
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
report(onStep, stepGitignore, "Generate .gitignore", "skipped", "no template");
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
catch (e) {
|
|
116
|
-
report(onStep, stepGitignore, "Generate .gitignore", "error", String(e));
|
|
117
|
-
}
|
|
118
|
-
// ── Step 5: Generate dependabot.yml ───────────────────────────────────────
|
|
119
|
-
const stepDeps = "dependabot";
|
|
120
|
-
report(onStep, stepDeps, "Generate dependabot.yml", "running");
|
|
121
|
-
try {
|
|
122
|
-
if (ciProvider === "github") {
|
|
123
|
-
const content = await generateDependabotYml([stack], true);
|
|
124
|
-
const dest = path.join(projectDir, ".github", "dependabot.yml");
|
|
125
|
-
if (!dryRun) {
|
|
126
|
-
await backupIfExists(dest);
|
|
127
|
-
await ensureDirExists(path.dirname(dest));
|
|
128
|
-
await fs.writeFile(dest, content, "utf-8");
|
|
129
|
-
}
|
|
130
|
-
report(onStep, stepDeps, "Generate dependabot.yml", "done");
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
report(onStep, stepDeps, "Generate dependabot.yml", "skipped", `not needed for ${ciProvider}`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
catch (e) {
|
|
137
|
-
report(onStep, stepDeps, "Generate dependabot.yml", "error", String(e));
|
|
138
|
-
}
|
|
139
|
-
// ── Step 6: Install memory module ─────────────────────────────────────────
|
|
140
|
-
const stepMem = "memory";
|
|
141
|
-
report(onStep, stepMem, `Install memory module: ${memory}`, "running");
|
|
142
|
-
try {
|
|
143
|
-
if (memory !== "none") {
|
|
144
|
-
const moduleSrc = path.join(MODULES_DIR, memory);
|
|
145
|
-
if (await fs.pathExists(moduleSrc)) {
|
|
146
|
-
if (!dryRun) {
|
|
147
|
-
// Copy module files to project
|
|
148
|
-
const moduleDest = path.join(projectDir, ".javi-forge", "modules", memory);
|
|
149
|
-
await ensureDirExists(moduleDest);
|
|
150
|
-
await fs.copy(moduleSrc, moduleDest, {
|
|
151
|
-
overwrite: false,
|
|
152
|
-
errorOnExist: false,
|
|
153
|
-
});
|
|
154
|
-
// If engram, copy .mcp-config-snippet.json to project with placeholder replacement
|
|
155
|
-
if (memory === "engram") {
|
|
156
|
-
const snippetSrc = path.join(moduleSrc, ".mcp-config-snippet.json");
|
|
157
|
-
if (await fs.pathExists(snippetSrc)) {
|
|
158
|
-
const snippetDest = path.join(projectDir, ".mcp-config-snippet.json");
|
|
159
|
-
let content = await fs.readFile(snippetSrc, "utf-8");
|
|
160
|
-
content = content.replace(/__PROJECT_NAME__/g, projectName);
|
|
161
|
-
await fs.writeFile(snippetDest, content, "utf-8");
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
report(onStep, stepMem, `Install memory module: ${memory}`, "done");
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
report(onStep, stepMem, `Install memory module: ${memory}`, "error", "module not found");
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
report(onStep, stepMem, `Install memory module: ${memory}`, "skipped", "none selected");
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
catch (e) {
|
|
176
|
-
report(onStep, stepMem, `Install memory module: ${memory}`, "error", String(e));
|
|
177
|
-
}
|
|
178
|
-
// ── Step 7: AI config sync (delegated to javi-ai) ──────────────────────────
|
|
179
|
-
const stepAI = "ai-sync";
|
|
180
|
-
report(onStep, stepAI, "Sync AI config via javi-ai", "running");
|
|
181
|
-
try {
|
|
182
|
-
if (aiSync) {
|
|
183
|
-
if (!dryRun) {
|
|
184
|
-
try {
|
|
185
|
-
const { stderr } = await execFileAsync("npx", ["javi-ai", "sync", "--project-dir", projectDir, "--target", "all"], {
|
|
186
|
-
cwd: projectDir,
|
|
187
|
-
timeout: 120_000,
|
|
188
|
-
});
|
|
189
|
-
// javi-ai may exit 0 but crash (e.g. Ink raw mode error) — detect via stderr
|
|
190
|
-
if (stderr &&
|
|
191
|
-
(stderr.includes("Raw mode is not supported") ||
|
|
192
|
-
stderr.includes("ERROR"))) {
|
|
193
|
-
report(onStep, stepAI, "Sync AI config via javi-ai", "error", "javi-ai crashed. Run manually: npx javi-ai sync --project-dir . --target all");
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
report(onStep, stepAI, "Sync AI config via javi-ai", "done", "javi-ai sync --target all");
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
catch (syncErr) {
|
|
200
|
-
const msg = syncErr instanceof Error ? syncErr.message : String(syncErr);
|
|
201
|
-
if (msg.includes("ENOENT") ||
|
|
202
|
-
msg.includes("not found") ||
|
|
203
|
-
msg.includes("ERR_MODULE_NOT_FOUND")) {
|
|
204
|
-
report(onStep, stepAI, "Sync AI config via javi-ai", "error", "javi-ai not found. Install with: npm install -g javi-ai (or run npx javi-ai sync manually)");
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
report(onStep, stepAI, "Sync AI config via javi-ai", "error", msg);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
report(onStep, stepAI, "Sync AI config via javi-ai", "done", "dry-run: would run javi-ai sync --target all");
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
report(onStep, stepAI, "Sync AI config via javi-ai", "skipped", "not selected");
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
catch (e) {
|
|
220
|
-
report(onStep, stepAI, "Sync AI config via javi-ai", "error", String(e));
|
|
221
|
-
}
|
|
222
|
-
// ── Step 8: SDD (Spec-Driven Development) ─────────────────────────────────
|
|
223
|
-
const stepSDD = "sdd";
|
|
224
|
-
report(onStep, stepSDD, "Set up SDD (openspec/)", "running");
|
|
225
|
-
try {
|
|
226
|
-
if (sdd) {
|
|
227
|
-
if (!dryRun) {
|
|
228
|
-
const openspecDir = path.join(projectDir, "openspec");
|
|
229
|
-
await ensureDirExists(openspecDir);
|
|
230
|
-
// Create a README if none exists
|
|
231
|
-
const readmePath = path.join(openspecDir, "README.md");
|
|
232
|
-
if (!(await fs.pathExists(readmePath))) {
|
|
233
|
-
await fs.writeFile(readmePath, `# openspec/\n\nSpec-Driven Development artifacts for ${projectName}.\n\nSee: /sdd:new <name> to start a new change.\n`, "utf-8");
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
report(onStep, stepSDD, "Set up SDD (openspec/)", "done");
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
report(onStep, stepSDD, "Set up SDD (openspec/)", "skipped", "not selected");
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
catch (e) {
|
|
243
|
-
report(onStep, stepSDD, "Set up SDD (openspec/)", "error", String(e));
|
|
244
|
-
}
|
|
245
|
-
// ── Step 9: GHAGGA ────────────────────────────────────────────────────────
|
|
246
|
-
const stepGhagga = "ghagga";
|
|
247
|
-
report(onStep, stepGhagga, "Install GHAGGA review system", "running");
|
|
248
|
-
try {
|
|
249
|
-
if (ghagga) {
|
|
250
|
-
const ghaggaSrc = path.join(MODULES_DIR, "ghagga");
|
|
251
|
-
if (await fs.pathExists(ghaggaSrc)) {
|
|
252
|
-
if (!dryRun) {
|
|
253
|
-
const ghaggaDest = path.join(projectDir, ".javi-forge", "modules", "ghagga");
|
|
254
|
-
await ensureDirExists(ghaggaDest);
|
|
255
|
-
await fs.copy(ghaggaSrc, ghaggaDest, {
|
|
256
|
-
overwrite: false,
|
|
257
|
-
errorOnExist: false,
|
|
258
|
-
});
|
|
259
|
-
// Copy ghagga caller workflow to CI provider location
|
|
260
|
-
if (ciProvider === "github") {
|
|
261
|
-
const workflowSrc = path.join(FORGE_ROOT, "templates", "github", "ghagga-review.yml");
|
|
262
|
-
if (await fs.pathExists(workflowSrc)) {
|
|
263
|
-
const workflowDest = path.join(projectDir, ".github", "workflows", "ghagga-review.yml");
|
|
264
|
-
await ensureDirExists(path.dirname(workflowDest));
|
|
265
|
-
await fs.copy(workflowSrc, workflowDest, { overwrite: false });
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
report(onStep, stepGhagga, "Install GHAGGA review system", "done");
|
|
270
|
-
}
|
|
271
|
-
else {
|
|
272
|
-
report(onStep, stepGhagga, "Install GHAGGA review system", "error", "module not found");
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
report(onStep, stepGhagga, "Install GHAGGA review system", "skipped", "not selected");
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
catch (e) {
|
|
280
|
-
report(onStep, stepGhagga, "Install GHAGGA review system", "error", String(e));
|
|
281
|
-
}
|
|
282
|
-
// ── Step 10: Mock-first mode ───────────────────────────────────────────────
|
|
283
|
-
const stepMock = "mock";
|
|
284
|
-
if (options.mock) {
|
|
285
|
-
report(onStep, stepMock, "Configure mock-first mode", "running");
|
|
286
|
-
try {
|
|
287
|
-
if (!dryRun) {
|
|
288
|
-
// Create .env.example with mock values
|
|
289
|
-
const envExample = `# Mock environment — no real API keys required
|
|
290
|
-
# Copy to .env to use: cp .env.example .env
|
|
291
|
-
|
|
292
|
-
# Database
|
|
293
|
-
DATABASE_URL=postgresql://mock:mock@localhost:5432/mock_db
|
|
294
|
-
|
|
295
|
-
# Auth
|
|
296
|
-
JWT_SECRET=mock-jwt-secret-for-local-development
|
|
297
|
-
SESSION_SECRET=mock-session-secret
|
|
298
|
-
|
|
299
|
-
# External APIs (mock mode — no real calls)
|
|
300
|
-
MOCK_MODE=true
|
|
301
|
-
API_KEY=mock-api-key-not-real
|
|
302
|
-
STRIPE_KEY=sk_test_mock_not_real
|
|
303
|
-
SENDGRID_KEY=SG.mock_not_real
|
|
304
|
-
|
|
305
|
-
# Feature flags
|
|
306
|
-
ENABLE_ANALYTICS=false
|
|
307
|
-
ENABLE_EMAILS=false
|
|
308
|
-
ENABLE_WEBHOOKS=false
|
|
309
|
-
`;
|
|
310
|
-
const envExamplePath = path.join(projectDir, ".env.example");
|
|
311
|
-
if (!(await fs.pathExists(envExamplePath))) {
|
|
312
|
-
await fs.writeFile(envExamplePath, envExample, "utf-8");
|
|
313
|
-
}
|
|
314
|
-
// Create .env from example
|
|
315
|
-
const envPath = path.join(projectDir, ".env");
|
|
316
|
-
if (!(await fs.pathExists(envPath))) {
|
|
317
|
-
await fs.writeFile(envPath, envExample, "utf-8");
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
report(onStep, stepMock, "Configure mock-first mode", "done", ".env.example + .env with mock values");
|
|
321
|
-
}
|
|
322
|
-
catch (e) {
|
|
323
|
-
report(onStep, stepMock, "Configure mock-first mode", "error", String(e));
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
report(onStep, stepMock, "Configure mock-first mode", "skipped", "not selected");
|
|
328
|
-
}
|
|
329
|
-
// ── Step 11: Generate .context/ directory ──────────────────────────────────
|
|
330
|
-
const stepContext = "context-dir";
|
|
331
|
-
report(onStep, stepContext, "Generate .context/ directory", "running");
|
|
332
|
-
try {
|
|
333
|
-
if (contextDir) {
|
|
334
|
-
const contextDirPath = path.join(projectDir, ".context");
|
|
335
|
-
if (await fs.pathExists(contextDirPath)) {
|
|
336
|
-
report(onStep, stepContext, "Generate .context/ directory", "done", "already exists");
|
|
337
|
-
}
|
|
338
|
-
else {
|
|
339
|
-
if (!dryRun) {
|
|
340
|
-
const { index, summary } = await generateContextDir(options);
|
|
341
|
-
await ensureDirExists(contextDirPath);
|
|
342
|
-
await fs.writeFile(path.join(contextDirPath, "INDEX.md"), index, "utf-8");
|
|
343
|
-
await fs.writeFile(path.join(contextDirPath, "summary.md"), summary, "utf-8");
|
|
344
|
-
}
|
|
345
|
-
report(onStep, stepContext, "Generate .context/ directory", "done", dryRun
|
|
346
|
-
? "dry-run: would generate .context/"
|
|
347
|
-
: ".context/INDEX.md + summary.md");
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
else {
|
|
351
|
-
report(onStep, stepContext, "Generate .context/ directory", "skipped", "not selected");
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
catch (e) {
|
|
355
|
-
report(onStep, stepContext, "Generate .context/ directory", "error", String(e));
|
|
356
|
-
}
|
|
357
|
-
// ── Step 12: Generate CLAUDE.md (smart: project-aware) ─────────────────────
|
|
358
|
-
const stepClaudeMd = "claude-md";
|
|
359
|
-
report(onStep, stepClaudeMd, "Generate CLAUDE.md", "running");
|
|
360
|
-
try {
|
|
361
|
-
if (claudeMd) {
|
|
362
|
-
const claudeMdPath = path.join(projectDir, "CLAUDE.md");
|
|
363
|
-
if (await fs.pathExists(claudeMdPath)) {
|
|
364
|
-
report(onStep, stepClaudeMd, "Generate CLAUDE.md", "done", "already exists");
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
if (!dryRun) {
|
|
368
|
-
// Detect project stack for smart CLAUDE.md generation
|
|
369
|
-
const detection = await detectProjectStack(projectDir).catch(() => null);
|
|
370
|
-
const content = generateSmartClaudeMd(options, detection);
|
|
371
|
-
await fs.writeFile(claudeMdPath, content, "utf-8");
|
|
372
|
-
const skillCount = detection?.recommendedSkills.length ?? 0;
|
|
373
|
-
report(onStep, stepClaudeMd, "Generate CLAUDE.md", "done", skillCount > 0
|
|
374
|
-
? `CLAUDE.md (${skillCount} skills detected)`
|
|
375
|
-
: "CLAUDE.md");
|
|
376
|
-
}
|
|
377
|
-
else {
|
|
378
|
-
report(onStep, stepClaudeMd, "Generate CLAUDE.md", "done", "dry-run: would generate CLAUDE.md");
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
else {
|
|
383
|
-
report(onStep, stepClaudeMd, "Generate CLAUDE.md", "skipped", "not selected");
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
catch (e) {
|
|
387
|
-
report(onStep, stepClaudeMd, "Generate CLAUDE.md", "error", String(e));
|
|
388
|
-
}
|
|
389
|
-
// ── Step 13: Docker zero-downtime deploy ───────────────────────────────────
|
|
390
|
-
const stepDeploy = "docker-deploy";
|
|
391
|
-
report(onStep, stepDeploy, "Scaffold Docker zero-downtime deploy", "running");
|
|
392
|
-
try {
|
|
393
|
-
if (options.dockerDeploy) {
|
|
394
|
-
const deployDest = getDeployDestination(ciProvider);
|
|
395
|
-
if (deployDest) {
|
|
396
|
-
const fullDest = path.join(projectDir, deployDest);
|
|
397
|
-
if (await fs.pathExists(fullDest)) {
|
|
398
|
-
report(onStep, stepDeploy, "Scaffold Docker zero-downtime deploy", "done", "already exists");
|
|
399
|
-
}
|
|
400
|
-
else {
|
|
401
|
-
const serviceName = options.dockerServiceName || "app";
|
|
402
|
-
const content = await generateDeployWorkflow(ciProvider, serviceName);
|
|
403
|
-
if (content) {
|
|
404
|
-
if (!dryRun) {
|
|
405
|
-
await backupIfExists(fullDest);
|
|
406
|
-
await ensureDirExists(path.dirname(fullDest));
|
|
407
|
-
await fs.writeFile(fullDest, content, "utf-8");
|
|
408
|
-
}
|
|
409
|
-
report(onStep, stepDeploy, "Scaffold Docker zero-downtime deploy", "done", dryRun ? `dry-run: would create ${deployDest}` : deployDest);
|
|
410
|
-
}
|
|
411
|
-
else {
|
|
412
|
-
report(onStep, stepDeploy, "Scaffold Docker zero-downtime deploy", "error", `no deploy template for ${ciProvider}`);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
else {
|
|
417
|
-
report(onStep, stepDeploy, "Scaffold Docker zero-downtime deploy", "error", `no deploy destination for ${ciProvider}`);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
else {
|
|
421
|
-
report(onStep, stepDeploy, "Scaffold Docker zero-downtime deploy", "skipped", "not selected");
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
catch (e) {
|
|
425
|
-
report(onStep, stepDeploy, "Scaffold Docker zero-downtime deploy", "error", String(e));
|
|
426
|
-
}
|
|
427
|
-
// ── Step 14: Security hooks scaffold ────────────────────────────────────────
|
|
428
|
-
const stepSecurity = "security-hooks";
|
|
429
|
-
report(onStep, stepSecurity, "Scaffold security hooks", "running");
|
|
430
|
-
try {
|
|
431
|
-
if (securityHooks) {
|
|
432
|
-
if (await fs.pathExists(SECURITY_HOOKS_DIR)) {
|
|
433
|
-
if (!dryRun) {
|
|
434
|
-
// Copy 6-layer git security hooks into ci-local/hooks/security/
|
|
435
|
-
const secHooksDest = path.join(projectDir, "ci-local", "hooks", "security");
|
|
436
|
-
await ensureDirExists(secHooksDest);
|
|
437
|
-
const hookFiles = await fs.readdir(SECURITY_HOOKS_DIR);
|
|
438
|
-
const gitHooks = hookFiles.filter((f) => !f.endsWith(".json"));
|
|
439
|
-
for (const hook of gitHooks) {
|
|
440
|
-
const src = path.join(SECURITY_HOOKS_DIR, hook);
|
|
441
|
-
const dest = path.join(secHooksDest, hook);
|
|
442
|
-
await fs.copy(src, dest, { overwrite: false });
|
|
443
|
-
await fs.chmod(dest, 0o755);
|
|
444
|
-
}
|
|
445
|
-
// Copy runtime security settings (kiteguard-style) to .claude/
|
|
446
|
-
const settingsSrc = path.join(SECURITY_HOOKS_DIR, "claude-settings-security.json");
|
|
447
|
-
if (await fs.pathExists(settingsSrc)) {
|
|
448
|
-
const claudeDir = path.join(projectDir, ".claude");
|
|
449
|
-
await ensureDirExists(claudeDir);
|
|
450
|
-
const settingsDest = path.join(claudeDir, "settings.json");
|
|
451
|
-
if (!(await fs.pathExists(settingsDest))) {
|
|
452
|
-
await fs.copy(settingsSrc, settingsDest);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
report(onStep, stepSecurity, "Scaffold security hooks", "done", dryRun
|
|
457
|
-
? "dry-run: would scaffold security hooks"
|
|
458
|
-
: "6 git layers + runtime hooks");
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
report(onStep, stepSecurity, "Scaffold security hooks", "error", "security-hooks templates not found");
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
else {
|
|
465
|
-
report(onStep, stepSecurity, "Scaffold security hooks", "skipped", "not selected");
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
catch (e) {
|
|
469
|
-
report(onStep, stepSecurity, "Scaffold security hooks", "error", String(e));
|
|
470
|
-
}
|
|
471
|
-
// ── Step 14b: Write hook profile ─────────────────────────────────────────────
|
|
472
|
-
const stepHookProfile = "hook-profile";
|
|
473
|
-
report(onStep, stepHookProfile, "Write hook reliability profile", "running");
|
|
474
|
-
try {
|
|
475
|
-
if (securityHooks) {
|
|
476
|
-
if (!dryRun) {
|
|
477
|
-
const hooksDir = path.join(projectDir, "ci-local", "hooks");
|
|
478
|
-
await ensureDirExists(hooksDir);
|
|
479
|
-
const profilePath = path.join(hooksDir, "profile.json");
|
|
480
|
-
const resolvedProfile = hookProfile ?? "standard";
|
|
481
|
-
await fs.writeJson(profilePath, { profile: resolvedProfile }, { spaces: 2 });
|
|
482
|
-
}
|
|
483
|
-
report(onStep, stepHookProfile, "Write hook reliability profile", "done", dryRun
|
|
484
|
-
? `dry-run: would write profile.json (${hookProfile ?? "standard"})`
|
|
485
|
-
: `ci-local/hooks/profile.json (${hookProfile ?? "standard"})`);
|
|
486
|
-
}
|
|
487
|
-
else {
|
|
488
|
-
report(onStep, stepHookProfile, "Write hook reliability profile", "skipped", "security hooks not selected");
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
catch (e) {
|
|
492
|
-
report(onStep, stepHookProfile, "Write hook reliability profile", "error", String(e));
|
|
493
|
-
}
|
|
494
|
-
// ── Step 15: RepoForge code graph scaffolding ───────────────────────────────
|
|
495
|
-
const stepGraph = "code-graph";
|
|
496
|
-
report(onStep, stepGraph, "Scaffold RepoForge code graph", "running");
|
|
497
|
-
try {
|
|
498
|
-
if (options.codeGraph) {
|
|
499
|
-
if (!dryRun) {
|
|
500
|
-
// 1. Copy .repoforge.yaml config
|
|
501
|
-
const repoforgeConfigSrc = path.join(TEMPLATES_DIR, "common", "repoforge", "repoforge.yaml");
|
|
502
|
-
const repoforgeConfigDest = path.join(projectDir, ".repoforge.yaml");
|
|
503
|
-
if (!(await fs.pathExists(repoforgeConfigDest))) {
|
|
504
|
-
await fs.copy(repoforgeConfigSrc, repoforgeConfigDest);
|
|
505
|
-
}
|
|
506
|
-
// 2. Ensure .repoforge/ output dir exists
|
|
507
|
-
await ensureDirExists(path.join(projectDir, ".repoforge"));
|
|
508
|
-
// 3. Copy CI workflow for graph generation (GitHub only)
|
|
509
|
-
if (ciProvider === "github") {
|
|
510
|
-
const graphWorkflowSrc = path.join(TEMPLATES_DIR, "github", "repoforge-graph.yml");
|
|
511
|
-
if (await fs.pathExists(graphWorkflowSrc)) {
|
|
512
|
-
const graphWorkflowDest = path.join(projectDir, ".github", "workflows", "repoforge-graph.yml");
|
|
513
|
-
await ensureDirExists(path.dirname(graphWorkflowDest));
|
|
514
|
-
await backupIfExists(graphWorkflowDest);
|
|
515
|
-
await fs.copy(graphWorkflowSrc, graphWorkflowDest, {
|
|
516
|
-
overwrite: false,
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
// 4. Copy MCP config snippet for repoforge code intelligence
|
|
521
|
-
const mcpSnippetSrc = path.join(TEMPLATES_DIR, "common", "repoforge", "mcp-repoforge-snippet.json");
|
|
522
|
-
if (await fs.pathExists(mcpSnippetSrc)) {
|
|
523
|
-
const mcpSnippetDest = path.join(projectDir, ".repoforge", "mcp-config-snippet.json");
|
|
524
|
-
let content = await fs.readFile(mcpSnippetSrc, "utf-8");
|
|
525
|
-
content = content.replace(/__PROJECT_NAME__/g, projectName);
|
|
526
|
-
await fs.writeFile(mcpSnippetDest, content, "utf-8");
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
report(onStep, stepGraph, "Scaffold RepoForge code graph", "done", dryRun
|
|
530
|
-
? "dry-run: would scaffold .repoforge.yaml + CI + MCP"
|
|
531
|
-
: ".repoforge.yaml + CI + MCP snippet");
|
|
532
|
-
}
|
|
533
|
-
else {
|
|
534
|
-
report(onStep, stepGraph, "Scaffold RepoForge code graph", "skipped", "not selected");
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
catch (e) {
|
|
538
|
-
report(onStep, stepGraph, "Scaffold RepoForge code graph", "error", String(e));
|
|
539
|
-
}
|
|
540
|
-
// ── Step 16: Local AI dev stack ────────────────────────────────────────────
|
|
541
|
-
const stepLocalAi = "local-ai";
|
|
542
|
-
report(onStep, stepLocalAi, "Scaffold local AI dev stack", "running");
|
|
543
|
-
try {
|
|
544
|
-
if (options.localAi) {
|
|
545
|
-
if (await fs.pathExists(LOCAL_AI_TEMPLATE_DIR)) {
|
|
546
|
-
const composeDest = path.join(projectDir, "docker-compose.yml");
|
|
547
|
-
const envDest = path.join(projectDir, ".env.local-ai");
|
|
548
|
-
if (!dryRun) {
|
|
549
|
-
// Copy docker-compose.yml (skip if exists)
|
|
550
|
-
if (!(await fs.pathExists(composeDest))) {
|
|
551
|
-
await fs.copy(path.join(LOCAL_AI_TEMPLATE_DIR, "docker-compose.yml"), composeDest);
|
|
552
|
-
}
|
|
553
|
-
// Copy .env.example as .env.local-ai
|
|
554
|
-
const envSrc = path.join(LOCAL_AI_TEMPLATE_DIR, ".env.example");
|
|
555
|
-
if ((await fs.pathExists(envSrc)) &&
|
|
556
|
-
!(await fs.pathExists(envDest))) {
|
|
557
|
-
await fs.copy(envSrc, envDest);
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
report(onStep, stepLocalAi, "Scaffold local AI dev stack", "done", dryRun
|
|
561
|
-
? "dry-run: would create docker-compose.yml + .env.local-ai"
|
|
562
|
-
: "docker-compose.yml + .env.local-ai");
|
|
563
|
-
}
|
|
564
|
-
else {
|
|
565
|
-
report(onStep, stepLocalAi, "Scaffold local AI dev stack", "error", "local-ai template not found");
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
else {
|
|
569
|
-
report(onStep, stepLocalAi, "Scaffold local AI dev stack", "skipped", "not selected");
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
catch (e) {
|
|
573
|
-
report(onStep, stepLocalAi, "Scaffold local AI dev stack", "error", String(e));
|
|
574
|
-
}
|
|
575
|
-
// ── Step 17: Generate Agent Skills manifest (skills.json) ─────────────────
|
|
576
|
-
const stepSkills = "agent-skills";
|
|
577
|
-
report(onStep, stepSkills, "Generate Agent Skills manifest (skills.json)", "running");
|
|
578
|
-
try {
|
|
579
|
-
if (!dryRun) {
|
|
580
|
-
const skillsManifest = {
|
|
581
|
-
name: projectName,
|
|
582
|
-
version: "0.1.0",
|
|
583
|
-
description: `Agent Skills manifest for ${projectName}`,
|
|
584
|
-
skills: [],
|
|
585
|
-
};
|
|
586
|
-
const skillsJsonPath = path.join(projectDir, AGENT_SKILLS_MANIFEST_FILE);
|
|
587
|
-
if (!(await fs.pathExists(skillsJsonPath))) {
|
|
588
|
-
await fs.writeJson(skillsJsonPath, skillsManifest, { spaces: 2 });
|
|
589
|
-
report(onStep, stepSkills, "Generate Agent Skills manifest (skills.json)", "done", AGENT_SKILLS_MANIFEST_FILE);
|
|
590
|
-
}
|
|
591
|
-
else {
|
|
592
|
-
report(onStep, stepSkills, "Generate Agent Skills manifest (skills.json)", "done", "already exists");
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
else {
|
|
596
|
-
report(onStep, stepSkills, "Generate Agent Skills manifest (skills.json)", "done", `dry-run: would generate ${AGENT_SKILLS_MANIFEST_FILE}`);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
catch (e) {
|
|
600
|
-
report(onStep, stepSkills, "Generate Agent Skills manifest (skills.json)", "error", String(e));
|
|
601
|
-
}
|
|
602
|
-
// ── Step 18: Write manifest ───────────────────────────────────────────────
|
|
603
|
-
const stepManifest = "manifest";
|
|
604
|
-
report(onStep, stepManifest, "Write forge manifest", "running");
|
|
605
|
-
try {
|
|
606
|
-
if (!dryRun) {
|
|
607
|
-
const manifestDir = path.join(projectDir, ".javi-forge");
|
|
608
|
-
await ensureDirExists(manifestDir);
|
|
609
|
-
const manifest = {
|
|
610
|
-
version: "0.1.0",
|
|
611
|
-
projectName,
|
|
612
|
-
stack,
|
|
613
|
-
ciProvider,
|
|
614
|
-
memory,
|
|
615
|
-
createdAt: new Date().toISOString(),
|
|
616
|
-
updatedAt: new Date().toISOString(),
|
|
617
|
-
modules: [
|
|
618
|
-
...(memory !== "none" ? [memory] : []),
|
|
619
|
-
...(ghagga ? ["ghagga"] : []),
|
|
620
|
-
...(sdd ? ["sdd"] : []),
|
|
621
|
-
...(aiSync ? ["ai-config"] : []),
|
|
622
|
-
...(contextDir ? ["context"] : []),
|
|
623
|
-
...(claudeMd ? ["claude-md"] : []),
|
|
624
|
-
...(options.dockerDeploy ? ["docker-deploy"] : []),
|
|
625
|
-
...(securityHooks ? ["security-hooks"] : []),
|
|
626
|
-
...(options.codeGraph ? ["code-graph"] : []),
|
|
627
|
-
...(options.localAi ? ["local-ai"] : []),
|
|
628
|
-
],
|
|
629
|
-
};
|
|
630
|
-
await fs.writeJson(path.join(manifestDir, "manifest.json"), manifest, {
|
|
631
|
-
spaces: 2,
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
report(onStep, stepManifest, "Write forge manifest", "done", ".javi-forge/manifest.json");
|
|
635
|
-
}
|
|
636
|
-
catch (e) {
|
|
637
|
-
report(onStep, stepManifest, "Write forge manifest", "error", String(e));
|
|
638
|
-
}
|
|
30
|
+
// Shared context passed to every step.
|
|
31
|
+
const ctx = { options, projectDir, dryRun, onStep };
|
|
32
|
+
await stepGitInit(ctx);
|
|
33
|
+
await stepGitHooks(ctx);
|
|
34
|
+
await stepCITemplate(ctx);
|
|
35
|
+
await stepGitignore(ctx);
|
|
36
|
+
await stepDependabot(ctx);
|
|
37
|
+
await stepMemory(ctx);
|
|
38
|
+
await stepAISync(ctx);
|
|
39
|
+
await stepSDD(ctx);
|
|
40
|
+
await stepGhagga(ctx);
|
|
41
|
+
await stepMock(ctx);
|
|
42
|
+
await stepContextDir(ctx);
|
|
43
|
+
await stepClaudeMd(ctx);
|
|
44
|
+
await stepDockerDeploy(ctx);
|
|
45
|
+
await stepSecurityHooks(ctx);
|
|
46
|
+
await stepHookProfile(ctx);
|
|
47
|
+
await stepCodeGraph(ctx);
|
|
48
|
+
await stepLocalAi(ctx);
|
|
49
|
+
await stepAgentSkills(ctx);
|
|
50
|
+
await stepManifest(ctx);
|
|
639
51
|
}
|
|
640
52
|
//# sourceMappingURL=init.js.map
|