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
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { CI_LOCAL_DIR } from "../../../constants.js";
|
|
4
|
+
import { execFileAsync } from "../../../lib/exec.js";
|
|
5
|
+
import { report } from "../report.js";
|
|
6
|
+
/**
|
|
7
|
+
* Step 1: Initialize git repository.
|
|
8
|
+
*
|
|
9
|
+
* - If .git is missing, runs `git init` in the project dir.
|
|
10
|
+
* - If .git already exists, reports "done" with detail "already exists".
|
|
11
|
+
* - In dry-run, skips the actual `git init` call but still reports.
|
|
12
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
13
|
+
*
|
|
14
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 1 of 6).
|
|
15
|
+
*/
|
|
16
|
+
export const stepGitInit = async (ctx) => {
|
|
17
|
+
const { projectDir, dryRun, onStep } = ctx;
|
|
18
|
+
const stepId = "git-init";
|
|
19
|
+
report(onStep, stepId, "Initialize git repository", "running");
|
|
20
|
+
try {
|
|
21
|
+
const gitDir = path.join(projectDir, ".git");
|
|
22
|
+
if (!(await fs.pathExists(gitDir))) {
|
|
23
|
+
if (!dryRun) {
|
|
24
|
+
await execFileAsync("git", ["init"], { cwd: projectDir });
|
|
25
|
+
}
|
|
26
|
+
report(onStep, stepId, "Initialize git repository", "done", "initialized");
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
report(onStep, stepId, "Initialize git repository", "done", "already exists");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
report(onStep, stepId, "Initialize git repository", "error", String(e));
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Step 2: Configure git hooks path.
|
|
38
|
+
*
|
|
39
|
+
* - Copies templates/ci-local/ → <project>/ci-local/ (no overwrite).
|
|
40
|
+
* - chmod 0755 on hook files.
|
|
41
|
+
* - Sets git config core.hooksPath to ci-local/hooks.
|
|
42
|
+
* - Skips entirely when CI_LOCAL_DIR template is missing.
|
|
43
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
44
|
+
*
|
|
45
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 1 of 6).
|
|
46
|
+
*/
|
|
47
|
+
export const stepGitHooks = async (ctx) => {
|
|
48
|
+
const { projectDir, dryRun, onStep } = ctx;
|
|
49
|
+
const stepId = "git-hooks";
|
|
50
|
+
report(onStep, stepId, "Configure git hooks path", "running");
|
|
51
|
+
try {
|
|
52
|
+
const ciLocalSrc = CI_LOCAL_DIR;
|
|
53
|
+
const ciLocalDest = path.join(projectDir, "ci-local");
|
|
54
|
+
if (await fs.pathExists(ciLocalSrc)) {
|
|
55
|
+
if (!dryRun) {
|
|
56
|
+
await fs.copy(ciLocalSrc, ciLocalDest, {
|
|
57
|
+
overwrite: false,
|
|
58
|
+
errorOnExist: false,
|
|
59
|
+
});
|
|
60
|
+
// Set core.hooksPath to ci-local/hooks
|
|
61
|
+
const hooksDir = path.join(ciLocalDest, "hooks");
|
|
62
|
+
if (await fs.pathExists(hooksDir)) {
|
|
63
|
+
// Ensure hooks are executable
|
|
64
|
+
const hookFiles = await fs.readdir(hooksDir);
|
|
65
|
+
for (const hook of hookFiles) {
|
|
66
|
+
await fs.chmod(path.join(hooksDir, hook), 0o755);
|
|
67
|
+
}
|
|
68
|
+
await execFileAsync("git", ["config", "core.hooksPath", "ci-local/hooks"], { cwd: projectDir });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
report(onStep, stepId, "Configure git hooks path", "done", "ci-local/hooks");
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
report(onStep, stepId, "Configure git hooks path", "skipped", "no ci-local dir");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
report(onStep, stepId, "Configure git hooks path", "error", String(e));
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StepFn } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Step 4: Generate .gitignore.
|
|
4
|
+
*
|
|
5
|
+
* - Copies <FORGE_ROOT>/.gitignore.template → <project>/.gitignore if absent.
|
|
6
|
+
* - If destination already exists, reports "done" with detail "already exists".
|
|
7
|
+
* - If template is missing, reports "skipped" with detail "no template".
|
|
8
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
9
|
+
*
|
|
10
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 2 of 6).
|
|
11
|
+
*/
|
|
12
|
+
export declare const stepGitignore: StepFn;
|
|
13
|
+
//# sourceMappingURL=gitignore.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { FORGE_ROOT } from "../../../constants.js";
|
|
4
|
+
import { report } from "../report.js";
|
|
5
|
+
/**
|
|
6
|
+
* Step 4: Generate .gitignore.
|
|
7
|
+
*
|
|
8
|
+
* - Copies <FORGE_ROOT>/.gitignore.template → <project>/.gitignore if absent.
|
|
9
|
+
* - If destination already exists, reports "done" with detail "already exists".
|
|
10
|
+
* - If template is missing, reports "skipped" with detail "no template".
|
|
11
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
12
|
+
*
|
|
13
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 2 of 6).
|
|
14
|
+
*/
|
|
15
|
+
export const stepGitignore = async (ctx) => {
|
|
16
|
+
const { projectDir, dryRun, onStep } = ctx;
|
|
17
|
+
const stepId = "gitignore";
|
|
18
|
+
report(onStep, stepId, "Generate .gitignore", "running");
|
|
19
|
+
try {
|
|
20
|
+
const templatePath = path.join(FORGE_ROOT, ".gitignore.template");
|
|
21
|
+
const dest = path.join(projectDir, ".gitignore");
|
|
22
|
+
if ((await fs.pathExists(templatePath)) && !(await fs.pathExists(dest))) {
|
|
23
|
+
if (!dryRun) {
|
|
24
|
+
await fs.copy(templatePath, dest);
|
|
25
|
+
}
|
|
26
|
+
report(onStep, stepId, "Generate .gitignore", "done", "from template");
|
|
27
|
+
}
|
|
28
|
+
else if (await fs.pathExists(dest)) {
|
|
29
|
+
report(onStep, stepId, "Generate .gitignore", "done", "already exists");
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
report(onStep, stepId, "Generate .gitignore", "skipped", "no template");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
report(onStep, stepId, "Generate .gitignore", "error", String(e));
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=gitignore.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { StepFn } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Step 16: Scaffold local AI dev stack.
|
|
4
|
+
*
|
|
5
|
+
* - When options.localAi is false, reports "skipped".
|
|
6
|
+
* - When LOCAL_AI_TEMPLATE_DIR is missing, reports "error".
|
|
7
|
+
* - Otherwise copies docker-compose.yml and .env.example -> .env.local-ai
|
|
8
|
+
* (both skip if the destination already exists).
|
|
9
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
10
|
+
*
|
|
11
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 5 of 6).
|
|
12
|
+
*/
|
|
13
|
+
export declare const stepLocalAi: StepFn;
|
|
14
|
+
//# sourceMappingURL=local-ai.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { LOCAL_AI_TEMPLATE_DIR } from "../../../constants.js";
|
|
4
|
+
import { report } from "../report.js";
|
|
5
|
+
/**
|
|
6
|
+
* Step 16: Scaffold local AI dev stack.
|
|
7
|
+
*
|
|
8
|
+
* - When options.localAi is false, reports "skipped".
|
|
9
|
+
* - When LOCAL_AI_TEMPLATE_DIR is missing, reports "error".
|
|
10
|
+
* - Otherwise copies docker-compose.yml and .env.example -> .env.local-ai
|
|
11
|
+
* (both skip if the destination already exists).
|
|
12
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
13
|
+
*
|
|
14
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 5 of 6).
|
|
15
|
+
*/
|
|
16
|
+
export const stepLocalAi = async (ctx) => {
|
|
17
|
+
const { projectDir, dryRun, onStep, options } = ctx;
|
|
18
|
+
const stepId = "local-ai";
|
|
19
|
+
report(onStep, stepId, "Scaffold local AI dev stack", "running");
|
|
20
|
+
try {
|
|
21
|
+
if (options.localAi) {
|
|
22
|
+
if (await fs.pathExists(LOCAL_AI_TEMPLATE_DIR)) {
|
|
23
|
+
const composeDest = path.join(projectDir, "docker-compose.yml");
|
|
24
|
+
const envDest = path.join(projectDir, ".env.local-ai");
|
|
25
|
+
if (!dryRun) {
|
|
26
|
+
// Copy docker-compose.yml (skip if exists)
|
|
27
|
+
if (!(await fs.pathExists(composeDest))) {
|
|
28
|
+
await fs.copy(path.join(LOCAL_AI_TEMPLATE_DIR, "docker-compose.yml"), composeDest);
|
|
29
|
+
}
|
|
30
|
+
// Copy .env.example as .env.local-ai
|
|
31
|
+
const envSrc = path.join(LOCAL_AI_TEMPLATE_DIR, ".env.example");
|
|
32
|
+
if ((await fs.pathExists(envSrc)) &&
|
|
33
|
+
!(await fs.pathExists(envDest))) {
|
|
34
|
+
await fs.copy(envSrc, envDest);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
report(onStep, stepId, "Scaffold local AI dev stack", "done", dryRun
|
|
38
|
+
? "dry-run: would create docker-compose.yml + .env.local-ai"
|
|
39
|
+
: "docker-compose.yml + .env.local-ai");
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
report(onStep, stepId, "Scaffold local AI dev stack", "error", "local-ai template not found");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
report(onStep, stepId, "Scaffold local AI dev stack", "skipped", "not selected");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
report(onStep, stepId, "Scaffold local AI dev stack", "error", String(e));
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=local-ai.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StepFn } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Step 18: Write the forge manifest under .javi-forge/manifest.json.
|
|
4
|
+
*
|
|
5
|
+
* - In dry-run mode, reports what would be written without touching disk.
|
|
6
|
+
* - Otherwise materialises .javi-forge/, computes the modules array from
|
|
7
|
+
* selected options, and writes manifest.json (overwriting any existing).
|
|
8
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
9
|
+
*
|
|
10
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 6 of 6).
|
|
11
|
+
*/
|
|
12
|
+
export declare const stepManifest: StepFn;
|
|
13
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { ensureDirExists } from "../../../lib/common.js";
|
|
4
|
+
import { report } from "../report.js";
|
|
5
|
+
/**
|
|
6
|
+
* Step 18: Write the forge manifest under .javi-forge/manifest.json.
|
|
7
|
+
*
|
|
8
|
+
* - In dry-run mode, reports what would be written without touching disk.
|
|
9
|
+
* - Otherwise materialises .javi-forge/, computes the modules array from
|
|
10
|
+
* selected options, and writes manifest.json (overwriting any existing).
|
|
11
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
12
|
+
*
|
|
13
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 6 of 6).
|
|
14
|
+
*/
|
|
15
|
+
export const stepManifest = async (ctx) => {
|
|
16
|
+
const { projectDir, dryRun, onStep, options } = ctx;
|
|
17
|
+
const { stack, ciProvider, memory, aiSync, sdd, ghagga, contextDir, claudeMd, securityHooks, projectName, dockerDeploy, codeGraph, localAi, } = options;
|
|
18
|
+
const stepId = "manifest";
|
|
19
|
+
report(onStep, stepId, "Write forge manifest", "running");
|
|
20
|
+
try {
|
|
21
|
+
if (!dryRun) {
|
|
22
|
+
const manifestDir = path.join(projectDir, ".javi-forge");
|
|
23
|
+
await ensureDirExists(manifestDir);
|
|
24
|
+
const manifest = {
|
|
25
|
+
version: "0.1.0",
|
|
26
|
+
projectName,
|
|
27
|
+
stack,
|
|
28
|
+
ciProvider,
|
|
29
|
+
memory,
|
|
30
|
+
createdAt: new Date().toISOString(),
|
|
31
|
+
updatedAt: new Date().toISOString(),
|
|
32
|
+
modules: [
|
|
33
|
+
...(memory !== "none" ? [memory] : []),
|
|
34
|
+
...(ghagga ? ["ghagga"] : []),
|
|
35
|
+
...(sdd ? ["sdd"] : []),
|
|
36
|
+
...(aiSync ? ["ai-config"] : []),
|
|
37
|
+
...(contextDir ? ["context"] : []),
|
|
38
|
+
...(claudeMd ? ["claude-md"] : []),
|
|
39
|
+
...(dockerDeploy ? ["docker-deploy"] : []),
|
|
40
|
+
...(securityHooks ? ["security-hooks"] : []),
|
|
41
|
+
...(codeGraph ? ["code-graph"] : []),
|
|
42
|
+
...(localAi ? ["local-ai"] : []),
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
await fs.writeJson(path.join(manifestDir, "manifest.json"), manifest, {
|
|
46
|
+
spaces: 2,
|
|
47
|
+
});
|
|
48
|
+
report(onStep, stepId, "Write forge manifest", "done", ".javi-forge/manifest.json");
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
report(onStep, stepId, "Write forge manifest", "done", "dry-run: would write .javi-forge/manifest.json");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
report(onStep, stepId, "Write forge manifest", "error", String(e));
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { StepFn } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Step 6: Install memory module.
|
|
4
|
+
*
|
|
5
|
+
* - If memory === "none", reports "skipped".
|
|
6
|
+
* - Otherwise copies <MODULES_DIR>/<memory>/ → <project>/.javi-forge/modules/<memory>/.
|
|
7
|
+
* - For engram specifically, copies .mcp-config-snippet.json to project root
|
|
8
|
+
* replacing __PROJECT_NAME__ placeholders.
|
|
9
|
+
* - If the module source dir is missing, reports "error" with "module not found".
|
|
10
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
11
|
+
*
|
|
12
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 2 of 6).
|
|
13
|
+
*/
|
|
14
|
+
export declare const stepMemory: StepFn;
|
|
15
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { MODULES_DIR } from "../../../constants.js";
|
|
4
|
+
import { ensureDirExists } from "../../../lib/common.js";
|
|
5
|
+
import { report } from "../report.js";
|
|
6
|
+
/**
|
|
7
|
+
* Step 6: Install memory module.
|
|
8
|
+
*
|
|
9
|
+
* - If memory === "none", reports "skipped".
|
|
10
|
+
* - Otherwise copies <MODULES_DIR>/<memory>/ → <project>/.javi-forge/modules/<memory>/.
|
|
11
|
+
* - For engram specifically, copies .mcp-config-snippet.json to project root
|
|
12
|
+
* replacing __PROJECT_NAME__ placeholders.
|
|
13
|
+
* - If the module source dir is missing, reports "error" with "module not found".
|
|
14
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
15
|
+
*
|
|
16
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 2 of 6).
|
|
17
|
+
*/
|
|
18
|
+
export const stepMemory = async (ctx) => {
|
|
19
|
+
const { projectDir, dryRun, onStep, options } = ctx;
|
|
20
|
+
const { memory, projectName } = options;
|
|
21
|
+
const stepId = "memory";
|
|
22
|
+
report(onStep, stepId, `Install memory module: ${memory}`, "running");
|
|
23
|
+
try {
|
|
24
|
+
if (memory !== "none") {
|
|
25
|
+
const moduleSrc = path.join(MODULES_DIR, memory);
|
|
26
|
+
if (await fs.pathExists(moduleSrc)) {
|
|
27
|
+
if (!dryRun) {
|
|
28
|
+
// Copy module files to project
|
|
29
|
+
const moduleDest = path.join(projectDir, ".javi-forge", "modules", memory);
|
|
30
|
+
await ensureDirExists(moduleDest);
|
|
31
|
+
await fs.copy(moduleSrc, moduleDest, {
|
|
32
|
+
overwrite: false,
|
|
33
|
+
errorOnExist: false,
|
|
34
|
+
});
|
|
35
|
+
// If engram, copy .mcp-config-snippet.json to project with placeholder replacement
|
|
36
|
+
if (memory === "engram") {
|
|
37
|
+
const snippetSrc = path.join(moduleSrc, ".mcp-config-snippet.json");
|
|
38
|
+
if (await fs.pathExists(snippetSrc)) {
|
|
39
|
+
const snippetDest = path.join(projectDir, ".mcp-config-snippet.json");
|
|
40
|
+
let content = await fs.readFile(snippetSrc, "utf-8");
|
|
41
|
+
content = content.replace(/__PROJECT_NAME__/g, projectName);
|
|
42
|
+
await fs.writeFile(snippetDest, content, "utf-8");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
report(onStep, stepId, `Install memory module: ${memory}`, "done");
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
report(onStep, stepId, `Install memory module: ${memory}`, "error", "module not found");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
report(onStep, stepId, `Install memory module: ${memory}`, "skipped", "none selected");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
report(onStep, stepId, `Install memory module: ${memory}`, "error", String(e));
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StepFn } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Step 10: Configure mock-first mode.
|
|
4
|
+
*
|
|
5
|
+
* - When options.mock is false, reports "skipped".
|
|
6
|
+
* - Otherwise writes .env.example (and .env from it) with mock values, only if
|
|
7
|
+
* the targets do not already exist.
|
|
8
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
9
|
+
*
|
|
10
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 3 of 6).
|
|
11
|
+
*/
|
|
12
|
+
export declare const stepMock: StepFn;
|
|
13
|
+
//# sourceMappingURL=mock.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { report } from "../report.js";
|
|
4
|
+
// Mock environment template — written verbatim to .env.example and .env
|
|
5
|
+
// when mock-first mode is enabled. Preserved byte-for-byte from init.ts baseline.
|
|
6
|
+
const envExample = `# Mock environment — no real API keys required
|
|
7
|
+
# Copy to .env to use: cp .env.example .env
|
|
8
|
+
|
|
9
|
+
# Database
|
|
10
|
+
DATABASE_URL=postgresql://mock:mock@localhost:5432/mock_db
|
|
11
|
+
|
|
12
|
+
# Auth
|
|
13
|
+
JWT_SECRET=mock-jwt-secret-for-local-development
|
|
14
|
+
SESSION_SECRET=mock-session-secret
|
|
15
|
+
|
|
16
|
+
# External APIs (mock mode — no real calls)
|
|
17
|
+
MOCK_MODE=true
|
|
18
|
+
API_KEY=mock-api-key-not-real
|
|
19
|
+
STRIPE_KEY=sk_test_mock_not_real
|
|
20
|
+
SENDGRID_KEY=SG.mock_not_real
|
|
21
|
+
|
|
22
|
+
# Feature flags
|
|
23
|
+
ENABLE_ANALYTICS=false
|
|
24
|
+
ENABLE_EMAILS=false
|
|
25
|
+
ENABLE_WEBHOOKS=false
|
|
26
|
+
`;
|
|
27
|
+
/**
|
|
28
|
+
* Step 10: Configure mock-first mode.
|
|
29
|
+
*
|
|
30
|
+
* - When options.mock is false, reports "skipped".
|
|
31
|
+
* - Otherwise writes .env.example (and .env from it) with mock values, only if
|
|
32
|
+
* the targets do not already exist.
|
|
33
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
34
|
+
*
|
|
35
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 3 of 6).
|
|
36
|
+
*/
|
|
37
|
+
export const stepMock = async (ctx) => {
|
|
38
|
+
const { projectDir, dryRun, onStep, options } = ctx;
|
|
39
|
+
const stepId = "mock";
|
|
40
|
+
if (options.mock) {
|
|
41
|
+
report(onStep, stepId, "Configure mock-first mode", "running");
|
|
42
|
+
try {
|
|
43
|
+
if (!dryRun) {
|
|
44
|
+
const envExamplePath = path.join(projectDir, ".env.example");
|
|
45
|
+
if (!(await fs.pathExists(envExamplePath))) {
|
|
46
|
+
await fs.writeFile(envExamplePath, envExample, "utf-8");
|
|
47
|
+
}
|
|
48
|
+
// Create .env from example
|
|
49
|
+
const envPath = path.join(projectDir, ".env");
|
|
50
|
+
if (!(await fs.pathExists(envPath))) {
|
|
51
|
+
await fs.writeFile(envPath, envExample, "utf-8");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
report(onStep, stepId, "Configure mock-first mode", "done", ".env.example + .env with mock values");
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
report(onStep, stepId, "Configure mock-first mode", "error", String(e));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
report(onStep, stepId, "Configure mock-first mode", "skipped", "not selected");
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=mock.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StepFn } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Step 8: Set up SDD (openspec/) scaffolding.
|
|
4
|
+
*
|
|
5
|
+
* - When sdd is false, reports "skipped".
|
|
6
|
+
* - Otherwise ensures openspec/ exists and writes a default README.md if absent.
|
|
7
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
8
|
+
*
|
|
9
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 3 of 6).
|
|
10
|
+
*/
|
|
11
|
+
export declare const stepSDD: StepFn;
|
|
12
|
+
//# sourceMappingURL=sdd.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { ensureDirExists } from "../../../lib/common.js";
|
|
4
|
+
import { report } from "../report.js";
|
|
5
|
+
/**
|
|
6
|
+
* Step 8: Set up SDD (openspec/) scaffolding.
|
|
7
|
+
*
|
|
8
|
+
* - When sdd is false, reports "skipped".
|
|
9
|
+
* - Otherwise ensures openspec/ exists and writes a default README.md if absent.
|
|
10
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
11
|
+
*
|
|
12
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 3 of 6).
|
|
13
|
+
*/
|
|
14
|
+
export const stepSDD = async (ctx) => {
|
|
15
|
+
const { projectDir, dryRun, onStep, options } = ctx;
|
|
16
|
+
const { sdd, projectName } = options;
|
|
17
|
+
const stepId = "sdd";
|
|
18
|
+
report(onStep, stepId, "Set up SDD (openspec/)", "running");
|
|
19
|
+
try {
|
|
20
|
+
if (sdd) {
|
|
21
|
+
if (!dryRun) {
|
|
22
|
+
const openspecDir = path.join(projectDir, "openspec");
|
|
23
|
+
await ensureDirExists(openspecDir);
|
|
24
|
+
// Create a README if none exists
|
|
25
|
+
const readmePath = path.join(openspecDir, "README.md");
|
|
26
|
+
if (!(await fs.pathExists(readmePath))) {
|
|
27
|
+
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");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
report(onStep, stepId, "Set up SDD (openspec/)", "done");
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
report(onStep, stepId, "Set up SDD (openspec/)", "skipped", "not selected");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
report(onStep, stepId, "Set up SDD (openspec/)", "error", String(e));
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=sdd.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { StepFn } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Step 14: Scaffold security hooks.
|
|
4
|
+
*
|
|
5
|
+
* - When options.securityHooks is false, reports "skipped".
|
|
6
|
+
* - When SECURITY_HOOKS_DIR templates are missing, reports "error".
|
|
7
|
+
* - Otherwise copies the 6-layer git security hooks into
|
|
8
|
+
* ci-local/hooks/security/ (skipping existing files, chmod 0755) and copies
|
|
9
|
+
* the kiteguard-style runtime settings to .claude/settings.json when absent.
|
|
10
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
11
|
+
*
|
|
12
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 5 of 6).
|
|
13
|
+
* Grouped with stepHookProfile for cohesion — both manage ci-local/hooks/.
|
|
14
|
+
*/
|
|
15
|
+
export declare const stepSecurityHooks: StepFn;
|
|
16
|
+
/**
|
|
17
|
+
* Step 14b: Write hook reliability profile.
|
|
18
|
+
*
|
|
19
|
+
* - When options.securityHooks is false, reports "skipped".
|
|
20
|
+
* - Otherwise writes ci-local/hooks/profile.json with the resolved profile
|
|
21
|
+
* (defaults to "standard" when hookProfile is undefined).
|
|
22
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
23
|
+
*
|
|
24
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 5 of 6).
|
|
25
|
+
* Grouped with stepSecurityHooks for cohesion — both manage ci-local/hooks/.
|
|
26
|
+
*/
|
|
27
|
+
export declare const stepHookProfile: StepFn;
|
|
28
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { SECURITY_HOOKS_DIR } from "../../../constants.js";
|
|
4
|
+
import { ensureDirExists } from "../../../lib/common.js";
|
|
5
|
+
import { report } from "../report.js";
|
|
6
|
+
/**
|
|
7
|
+
* Step 14: Scaffold security hooks.
|
|
8
|
+
*
|
|
9
|
+
* - When options.securityHooks is false, reports "skipped".
|
|
10
|
+
* - When SECURITY_HOOKS_DIR templates are missing, reports "error".
|
|
11
|
+
* - Otherwise copies the 6-layer git security hooks into
|
|
12
|
+
* ci-local/hooks/security/ (skipping existing files, chmod 0755) and copies
|
|
13
|
+
* the kiteguard-style runtime settings to .claude/settings.json when absent.
|
|
14
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
15
|
+
*
|
|
16
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 5 of 6).
|
|
17
|
+
* Grouped with stepHookProfile for cohesion — both manage ci-local/hooks/.
|
|
18
|
+
*/
|
|
19
|
+
export const stepSecurityHooks = async (ctx) => {
|
|
20
|
+
const { projectDir, dryRun, onStep, options } = ctx;
|
|
21
|
+
const { securityHooks } = options;
|
|
22
|
+
const stepId = "security-hooks";
|
|
23
|
+
report(onStep, stepId, "Scaffold security hooks", "running");
|
|
24
|
+
try {
|
|
25
|
+
if (securityHooks) {
|
|
26
|
+
if (await fs.pathExists(SECURITY_HOOKS_DIR)) {
|
|
27
|
+
if (!dryRun) {
|
|
28
|
+
// Copy 6-layer git security hooks into ci-local/hooks/security/
|
|
29
|
+
const secHooksDest = path.join(projectDir, "ci-local", "hooks", "security");
|
|
30
|
+
await ensureDirExists(secHooksDest);
|
|
31
|
+
const hookFiles = await fs.readdir(SECURITY_HOOKS_DIR);
|
|
32
|
+
const gitHooks = hookFiles.filter((f) => !f.endsWith(".json"));
|
|
33
|
+
for (const hook of gitHooks) {
|
|
34
|
+
const src = path.join(SECURITY_HOOKS_DIR, hook);
|
|
35
|
+
const dest = path.join(secHooksDest, hook);
|
|
36
|
+
await fs.copy(src, dest, { overwrite: false });
|
|
37
|
+
await fs.chmod(dest, 0o755);
|
|
38
|
+
}
|
|
39
|
+
// Copy runtime security settings (kiteguard-style) to .claude/
|
|
40
|
+
const settingsSrc = path.join(SECURITY_HOOKS_DIR, "claude-settings-security.json");
|
|
41
|
+
if (await fs.pathExists(settingsSrc)) {
|
|
42
|
+
const claudeDir = path.join(projectDir, ".claude");
|
|
43
|
+
await ensureDirExists(claudeDir);
|
|
44
|
+
const settingsDest = path.join(claudeDir, "settings.json");
|
|
45
|
+
if (!(await fs.pathExists(settingsDest))) {
|
|
46
|
+
await fs.copy(settingsSrc, settingsDest);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
report(onStep, stepId, "Scaffold security hooks", "done", dryRun
|
|
51
|
+
? "dry-run: would scaffold security hooks"
|
|
52
|
+
: "6 git layers + runtime hooks");
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
report(onStep, stepId, "Scaffold security hooks", "error", "security-hooks templates not found");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
report(onStep, stepId, "Scaffold security hooks", "skipped", "not selected");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
report(onStep, stepId, "Scaffold security hooks", "error", String(e));
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Step 14b: Write hook reliability profile.
|
|
68
|
+
*
|
|
69
|
+
* - When options.securityHooks is false, reports "skipped".
|
|
70
|
+
* - Otherwise writes ci-local/hooks/profile.json with the resolved profile
|
|
71
|
+
* (defaults to "standard" when hookProfile is undefined).
|
|
72
|
+
* - Errors are swallowed and reported as status:"error" — never thrown.
|
|
73
|
+
*
|
|
74
|
+
* Extracted VERBATIM from src/commands/init.ts (PR 5 of 6).
|
|
75
|
+
* Grouped with stepSecurityHooks for cohesion — both manage ci-local/hooks/.
|
|
76
|
+
*/
|
|
77
|
+
export const stepHookProfile = async (ctx) => {
|
|
78
|
+
const { projectDir, dryRun, onStep, options } = ctx;
|
|
79
|
+
const { securityHooks, hookProfile } = options;
|
|
80
|
+
const stepId = "hook-profile";
|
|
81
|
+
report(onStep, stepId, "Write hook reliability profile", "running");
|
|
82
|
+
try {
|
|
83
|
+
if (securityHooks) {
|
|
84
|
+
if (!dryRun) {
|
|
85
|
+
const hooksDir = path.join(projectDir, "ci-local", "hooks");
|
|
86
|
+
await ensureDirExists(hooksDir);
|
|
87
|
+
const profilePath = path.join(hooksDir, "profile.json");
|
|
88
|
+
const resolvedProfile = hookProfile ?? "standard";
|
|
89
|
+
await fs.writeJson(profilePath, { profile: resolvedProfile }, { spaces: 2 });
|
|
90
|
+
}
|
|
91
|
+
report(onStep, stepId, "Write hook reliability profile", "done", dryRun
|
|
92
|
+
? `dry-run: would write profile.json (${hookProfile ?? "standard"})`
|
|
93
|
+
: `ci-local/hooks/profile.json (${hookProfile ?? "standard"})`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
report(onStep, stepId, "Write hook reliability profile", "skipped", "security hooks not selected");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
report(onStep, stepId, "Write hook reliability profile", "error", String(e));
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { InitOptions, InitStep } from "../../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Callback invoked by each step to report progress.
|
|
4
|
+
* Steps emit at least 2 events: status:"running" followed by a terminal status
|
|
5
|
+
* ("done" | "skipped" | "error").
|
|
6
|
+
*/
|
|
7
|
+
export type StepCallback = (step: InitStep) => void;
|
|
8
|
+
/**
|
|
9
|
+
* Context passed to every step. Built once by initProject and shared
|
|
10
|
+
* across all extracted step functions.
|
|
11
|
+
*
|
|
12
|
+
* Fields are intentionally minimal:
|
|
13
|
+
* - `options`: full InitOptions (steps can read any flag they need)
|
|
14
|
+
* - `projectDir`: convenience alias for options.projectDir
|
|
15
|
+
* - `dryRun`: convenience alias for options.dryRun
|
|
16
|
+
* - `onStep`: the progress callback (passed to report())
|
|
17
|
+
*/
|
|
18
|
+
export type StepContext = {
|
|
19
|
+
options: InitOptions;
|
|
20
|
+
projectDir: string;
|
|
21
|
+
dryRun: boolean;
|
|
22
|
+
onStep: StepCallback;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Step function signature. All step* functions follow this shape.
|
|
26
|
+
* Returns a promise that resolves when the step is complete
|
|
27
|
+
* (success, skipped, or recovered error — steps must NOT throw).
|
|
28
|
+
*/
|
|
29
|
+
export type StepFn = (ctx: StepContext) => Promise<void>;
|
|
30
|
+
//# sourceMappingURL=types.d.ts.map
|