javi-forge 1.6.0 → 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.d.ts +1 -1
- package/dist/commands/analyze.js +14 -16
- package/dist/commands/ci.d.ts +50 -3
- package/dist/commands/ci.js +537 -182
- package/dist/commands/doctor.d.ts +2 -2
- package/dist/commands/doctor.js +112 -62
- 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 -387
- package/dist/commands/llmstxt.d.ts +1 -1
- package/dist/commands/llmstxt.js +36 -34
- package/dist/commands/plugin.d.ts +10 -1
- package/dist/commands/plugin.js +92 -47
- package/dist/commands/security.d.ts +11 -5
- package/dist/commands/security.js +236 -77
- 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 +8 -69
- package/dist/commands/skills.js +9 -490
- 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/workflow.d.ts +23 -0
- package/dist/commands/workflow.js +116 -0
- package/dist/constants.d.ts +15 -1
- package/dist/constants.js +161 -122
- package/dist/index.js +43 -280
- package/dist/lib/agent-skills.d.ts +36 -1
- package/dist/lib/agent-skills.js +168 -19
- package/dist/lib/atlassian-mcp.d.ts +42 -0
- package/dist/lib/atlassian-mcp.js +98 -0
- package/dist/lib/auto-skill-install.d.ts +37 -0
- package/dist/lib/auto-skill-install.js +91 -0
- package/dist/lib/auto-wire.d.ts +20 -0
- package/dist/lib/auto-wire.js +240 -0
- package/dist/lib/ci-config.d.ts +65 -0
- package/dist/lib/ci-config.js +297 -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 +26 -32
- 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/crash-recovery.d.ts +34 -0
- package/dist/lib/crash-recovery.js +123 -0
- package/dist/lib/docker.d.ts +23 -2
- package/dist/lib/docker.js +168 -131
- package/dist/lib/exec.d.ts +10 -0
- package/dist/lib/exec.js +11 -0
- package/dist/lib/frontmatter.d.ts +1 -1
- package/dist/lib/frontmatter.js +29 -15
- package/dist/lib/harness-audit.d.ts +35 -0
- package/dist/lib/harness-audit.js +277 -0
- package/dist/lib/parallel-batch.d.ts +42 -0
- package/dist/lib/parallel-batch.js +88 -0
- package/dist/lib/plugin.d.ts +9 -3
- package/dist/lib/plugin.js +127 -70
- package/dist/lib/secret-scanner.d.ts +30 -0
- package/dist/lib/secret-scanner.js +274 -0
- package/dist/lib/security-analysis.d.ts +74 -0
- package/dist/lib/security-analysis.js +489 -0
- package/dist/lib/skill-publish.d.ts +40 -0
- package/dist/lib/skill-publish.js +164 -0
- package/dist/lib/skill-scanner.d.ts +63 -0
- package/dist/lib/skill-scanner.js +383 -0
- package/dist/lib/stack-detector.d.ts +38 -0
- package/dist/lib/stack-detector.js +207 -0
- package/dist/lib/supply-chain.d.ts +23 -0
- package/dist/lib/supply-chain.js +126 -0
- package/dist/lib/team-presets.d.ts +53 -0
- package/dist/lib/team-presets.js +201 -0
- package/dist/lib/template.d.ts +16 -1
- package/dist/lib/template.js +46 -17
- package/dist/lib/workflow/discovery.d.ts +27 -0
- package/dist/lib/workflow/discovery.js +85 -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 +59 -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 +2 -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 +27 -17
- 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/lib/common.psm1 +167 -0
- package/lib/common.sh +30 -0
- package/package.json +46 -24
- 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
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atlassian MCP pre-config — generates MCP server configuration
|
|
3
|
+
* for Jira and Confluence integration in scaffolded projects.
|
|
4
|
+
*
|
|
5
|
+
* Produces a config snippet that can be merged into .claude/settings.json
|
|
6
|
+
* or any AI agent's MCP configuration.
|
|
7
|
+
*/
|
|
8
|
+
export interface AtlassianConfig {
|
|
9
|
+
confluenceUrl: string;
|
|
10
|
+
confluenceUsername: string;
|
|
11
|
+
jiraUrl: string;
|
|
12
|
+
jiraUsername: string;
|
|
13
|
+
}
|
|
14
|
+
export interface McpSnippet {
|
|
15
|
+
mcpServers: Record<string, {
|
|
16
|
+
command: string;
|
|
17
|
+
args: string[];
|
|
18
|
+
env: Record<string, string>;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generate Atlassian MCP config snippet with user-provided values.
|
|
23
|
+
* Token placeholders remain as env vars for security.
|
|
24
|
+
*/
|
|
25
|
+
export declare function generateAtlassianMcpConfig(config: AtlassianConfig): McpSnippet;
|
|
26
|
+
/**
|
|
27
|
+
* Generate a template snippet with placeholders (no user input needed).
|
|
28
|
+
*/
|
|
29
|
+
export declare function generateTemplateMcpConfig(): McpSnippet;
|
|
30
|
+
/**
|
|
31
|
+
* Write the Atlassian MCP snippet to a project directory.
|
|
32
|
+
*/
|
|
33
|
+
export declare function writeAtlassianMcpSnippet(projectDir: string, config?: AtlassianConfig): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Merge Atlassian MCP config into an existing settings.json or MCP config file.
|
|
36
|
+
*/
|
|
37
|
+
export declare function mergeIntoSettings(settingsPath: string, config: AtlassianConfig): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Copy the template snippet from templates/common/atlassian/.
|
|
40
|
+
*/
|
|
41
|
+
export declare function copyTemplateSnippet(projectDir: string): Promise<string | null>;
|
|
42
|
+
//# sourceMappingURL=atlassian-mcp.d.ts.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atlassian MCP pre-config — generates MCP server configuration
|
|
3
|
+
* for Jira and Confluence integration in scaffolded projects.
|
|
4
|
+
*
|
|
5
|
+
* Produces a config snippet that can be merged into .claude/settings.json
|
|
6
|
+
* or any AI agent's MCP configuration.
|
|
7
|
+
*/
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import fs from "fs-extra";
|
|
11
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const TEMPLATES_DIR = path.resolve(__dirname, "../../templates");
|
|
13
|
+
/**
|
|
14
|
+
* Generate Atlassian MCP config snippet with user-provided values.
|
|
15
|
+
* Token placeholders remain as env vars for security.
|
|
16
|
+
*/
|
|
17
|
+
export function generateAtlassianMcpConfig(config) {
|
|
18
|
+
return {
|
|
19
|
+
mcpServers: {
|
|
20
|
+
atlassian: {
|
|
21
|
+
command: "uvx",
|
|
22
|
+
args: ["mcp-atlassian"],
|
|
23
|
+
env: {
|
|
24
|
+
CONFLUENCE_URL: config.confluenceUrl,
|
|
25
|
+
CONFLUENCE_USERNAME: config.confluenceUsername,
|
|
26
|
+
CONFLUENCE_API_TOKEN: "${CONFLUENCE_API_TOKEN}",
|
|
27
|
+
JIRA_URL: config.jiraUrl,
|
|
28
|
+
JIRA_USERNAME: config.jiraUsername,
|
|
29
|
+
JIRA_API_TOKEN: "${JIRA_API_TOKEN}",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generate a template snippet with placeholders (no user input needed).
|
|
37
|
+
*/
|
|
38
|
+
export function generateTemplateMcpConfig() {
|
|
39
|
+
return {
|
|
40
|
+
mcpServers: {
|
|
41
|
+
atlassian: {
|
|
42
|
+
command: "uvx",
|
|
43
|
+
args: ["mcp-atlassian"],
|
|
44
|
+
env: {
|
|
45
|
+
CONFLUENCE_URL: "__CONFLUENCE_URL__",
|
|
46
|
+
CONFLUENCE_USERNAME: "__CONFLUENCE_USERNAME__",
|
|
47
|
+
CONFLUENCE_API_TOKEN: "__CONFLUENCE_API_TOKEN__",
|
|
48
|
+
JIRA_URL: "__JIRA_URL__",
|
|
49
|
+
JIRA_USERNAME: "__JIRA_USERNAME__",
|
|
50
|
+
JIRA_API_TOKEN: "__JIRA_API_TOKEN__",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Write the Atlassian MCP snippet to a project directory.
|
|
58
|
+
*/
|
|
59
|
+
export async function writeAtlassianMcpSnippet(projectDir, config) {
|
|
60
|
+
const snippet = config
|
|
61
|
+
? generateAtlassianMcpConfig(config)
|
|
62
|
+
: generateTemplateMcpConfig();
|
|
63
|
+
const destDir = path.join(projectDir, ".atlassian");
|
|
64
|
+
await fs.ensureDir(destDir);
|
|
65
|
+
const destFile = path.join(destDir, "mcp-config-snippet.json");
|
|
66
|
+
await fs.writeJson(destFile, snippet, { spaces: 2 });
|
|
67
|
+
return destFile;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Merge Atlassian MCP config into an existing settings.json or MCP config file.
|
|
71
|
+
*/
|
|
72
|
+
export async function mergeIntoSettings(settingsPath, config) {
|
|
73
|
+
const snippet = generateAtlassianMcpConfig(config);
|
|
74
|
+
let existing = {};
|
|
75
|
+
if (await fs.pathExists(settingsPath)) {
|
|
76
|
+
existing = await fs.readJson(settingsPath);
|
|
77
|
+
}
|
|
78
|
+
const existingServers = existing.mcpServers ?? {};
|
|
79
|
+
existing.mcpServers = {
|
|
80
|
+
...existingServers,
|
|
81
|
+
...snippet.mcpServers,
|
|
82
|
+
};
|
|
83
|
+
await fs.writeJson(settingsPath, existing, { spaces: 2 });
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Copy the template snippet from templates/common/atlassian/.
|
|
87
|
+
*/
|
|
88
|
+
export async function copyTemplateSnippet(projectDir) {
|
|
89
|
+
const srcFile = path.join(TEMPLATES_DIR, "common", "atlassian", "mcp-atlassian-snippet.json");
|
|
90
|
+
if (!(await fs.pathExists(srcFile)))
|
|
91
|
+
return null;
|
|
92
|
+
const destDir = path.join(projectDir, ".atlassian");
|
|
93
|
+
await fs.ensureDir(destDir);
|
|
94
|
+
const destFile = path.join(destDir, "mcp-config-snippet.json");
|
|
95
|
+
await fs.copy(srcFile, destFile, { overwrite: true });
|
|
96
|
+
return destFile;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=atlassian-mcp.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { StackDetectionResult } from "./stack-detector.js";
|
|
2
|
+
export interface SkillInstallResult {
|
|
3
|
+
/** Skills that were successfully installed (copied) */
|
|
4
|
+
installed: string[];
|
|
5
|
+
/** Skills that were already present */
|
|
6
|
+
skipped: string[];
|
|
7
|
+
/** Skills that were recommended but not found in the source */
|
|
8
|
+
notFound: string[];
|
|
9
|
+
/** The full detection result for reporting */
|
|
10
|
+
detection: StackDetectionResult;
|
|
11
|
+
}
|
|
12
|
+
export interface AutoInstallOptions {
|
|
13
|
+
/** Directory to scan for tech stack detection */
|
|
14
|
+
projectDir: string;
|
|
15
|
+
/** Source directory containing skill folders (default: ~/.claude/skills) */
|
|
16
|
+
skillsSourceDir?: string;
|
|
17
|
+
/** Target directory where skills are installed (default: ~/.claude/skills) */
|
|
18
|
+
skillsTargetDir?: string;
|
|
19
|
+
/** If true, skip actually copying files */
|
|
20
|
+
dryRun?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Scan a project, detect its stack, and install matching AI skills.
|
|
24
|
+
*
|
|
25
|
+
* Skills are "installed" by verifying they exist in the source directory.
|
|
26
|
+
* Since javi-forge skills live in ~/.claude/skills/, this mainly validates
|
|
27
|
+
* that the recommended skills are available and reports which ones are missing.
|
|
28
|
+
*
|
|
29
|
+
* If skillsSourceDir !== skillsTargetDir, it copies skill folders from
|
|
30
|
+
* source to target (useful for project-local skill installation).
|
|
31
|
+
*/
|
|
32
|
+
export declare function autoInstallSkills(options: AutoInstallOptions): Promise<SkillInstallResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Get a human-readable summary of auto-install results.
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatAutoInstallSummary(result: SkillInstallResult): string;
|
|
37
|
+
//# sourceMappingURL=auto-skill-install.d.ts.map
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { DEFAULT_SKILLS_DIR } from "../commands/skills/constants.js";
|
|
4
|
+
import { detectProjectStack } from "./stack-detector.js";
|
|
5
|
+
// ── Core ───────────────────────────────────────────────────────────────────
|
|
6
|
+
/**
|
|
7
|
+
* Scan a project, detect its stack, and install matching AI skills.
|
|
8
|
+
*
|
|
9
|
+
* Skills are "installed" by verifying they exist in the source directory.
|
|
10
|
+
* Since javi-forge skills live in ~/.claude/skills/, this mainly validates
|
|
11
|
+
* that the recommended skills are available and reports which ones are missing.
|
|
12
|
+
*
|
|
13
|
+
* If skillsSourceDir !== skillsTargetDir, it copies skill folders from
|
|
14
|
+
* source to target (useful for project-local skill installation).
|
|
15
|
+
*/
|
|
16
|
+
export async function autoInstallSkills(options) {
|
|
17
|
+
const { projectDir, skillsSourceDir = DEFAULT_SKILLS_DIR, skillsTargetDir = DEFAULT_SKILLS_DIR, dryRun = false, } = options;
|
|
18
|
+
// 1. Detect project stack
|
|
19
|
+
const detection = await detectProjectStack(projectDir);
|
|
20
|
+
if (detection.recommendedSkills.length === 0) {
|
|
21
|
+
return {
|
|
22
|
+
installed: [],
|
|
23
|
+
skipped: [],
|
|
24
|
+
notFound: [],
|
|
25
|
+
detection,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const installed = [];
|
|
29
|
+
const skipped = [];
|
|
30
|
+
const notFound = [];
|
|
31
|
+
const sameDir = path.resolve(skillsSourceDir) === path.resolve(skillsTargetDir);
|
|
32
|
+
for (const skillName of detection.recommendedSkills) {
|
|
33
|
+
const sourcePath = path.join(skillsSourceDir, skillName);
|
|
34
|
+
const targetPath = path.join(skillsTargetDir, skillName);
|
|
35
|
+
const sourceSkillMd = path.join(sourcePath, "SKILL.md");
|
|
36
|
+
// Check if skill exists in source
|
|
37
|
+
if (!(await fs.pathExists(sourceSkillMd))) {
|
|
38
|
+
notFound.push(skillName);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// If same directory, skill is already "installed"
|
|
42
|
+
if (sameDir) {
|
|
43
|
+
skipped.push(skillName);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
// Check if already present in target
|
|
47
|
+
const targetSkillMd = path.join(targetPath, "SKILL.md");
|
|
48
|
+
if (await fs.pathExists(targetSkillMd)) {
|
|
49
|
+
skipped.push(skillName);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
// Copy skill to target
|
|
53
|
+
if (!dryRun) {
|
|
54
|
+
await fs.ensureDir(targetPath);
|
|
55
|
+
await fs.copy(sourcePath, targetPath, {
|
|
56
|
+
overwrite: false,
|
|
57
|
+
errorOnExist: false,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
installed.push(skillName);
|
|
61
|
+
}
|
|
62
|
+
return { installed, skipped, notFound, detection };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get a human-readable summary of auto-install results.
|
|
66
|
+
*/
|
|
67
|
+
export function formatAutoInstallSummary(result) {
|
|
68
|
+
const lines = [];
|
|
69
|
+
if (result.detection.stack) {
|
|
70
|
+
lines.push(`Detected stack: ${result.detection.stack}`);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
lines.push("No stack detected");
|
|
74
|
+
}
|
|
75
|
+
if (result.detection.signals.length > 0) {
|
|
76
|
+
lines.push(`Signals: ${result.detection.signals.map((s) => s.signal).join(", ")}`);
|
|
77
|
+
}
|
|
78
|
+
const total = result.installed.length + result.skipped.length + result.notFound.length;
|
|
79
|
+
lines.push(`Recommended skills: ${total}`);
|
|
80
|
+
if (result.installed.length > 0) {
|
|
81
|
+
lines.push(` Installed: ${result.installed.join(", ")}`);
|
|
82
|
+
}
|
|
83
|
+
if (result.skipped.length > 0) {
|
|
84
|
+
lines.push(` Already present: ${result.skipped.join(", ")}`);
|
|
85
|
+
}
|
|
86
|
+
if (result.notFound.length > 0) {
|
|
87
|
+
lines.push(` Not found: ${result.notFound.join(", ")}`);
|
|
88
|
+
}
|
|
89
|
+
return lines.join("\n");
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=auto-skill-install.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AutoWireResult, InstalledPlugin } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Scan installed plugins in a project and wire their capabilities into
|
|
4
|
+
* the project's CLAUDE.md (skill/plugin entries) and .claude/settings.json
|
|
5
|
+
* (hooks). Idempotent — re-running produces the same result.
|
|
6
|
+
*/
|
|
7
|
+
export declare function autoWirePlugins(projectDir: string, installedPlugins: InstalledPlugin[], options?: {
|
|
8
|
+
dryRun?: boolean;
|
|
9
|
+
}): Promise<AutoWireResult>;
|
|
10
|
+
/**
|
|
11
|
+
* Build the auto-wire section content for CLAUDE.md.
|
|
12
|
+
* Pure function — no I/O.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildAutoWireSection(plugins: InstalledPlugin[]): string;
|
|
15
|
+
/**
|
|
16
|
+
* Remove the auto-wire section from CLAUDE.md content.
|
|
17
|
+
* Returns cleaned content.
|
|
18
|
+
*/
|
|
19
|
+
export declare function removeAutoWireSection(content: string): string;
|
|
20
|
+
//# sourceMappingURL=auto-wire.d.ts.map
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
// ── Markers ────────────────────────────────────────────────────────────────
|
|
4
|
+
const WIRE_START = "<!-- javi-forge:auto-wire:start -->";
|
|
5
|
+
const WIRE_END = "<!-- javi-forge:auto-wire:end -->";
|
|
6
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
7
|
+
/**
|
|
8
|
+
* Scan installed plugins in a project and wire their capabilities into
|
|
9
|
+
* the project's CLAUDE.md (skill/plugin entries) and .claude/settings.json
|
|
10
|
+
* (hooks). Idempotent — re-running produces the same result.
|
|
11
|
+
*/
|
|
12
|
+
export async function autoWirePlugins(projectDir, installedPlugins, options = {}) {
|
|
13
|
+
const { dryRun = false } = options;
|
|
14
|
+
const wired = [];
|
|
15
|
+
const unwired = [];
|
|
16
|
+
const errors = [];
|
|
17
|
+
// ── Collect desired entries from plugin manifests ─────────────────────
|
|
18
|
+
const desiredSkills = [];
|
|
19
|
+
const desiredHooks = [];
|
|
20
|
+
for (const plugin of installedPlugins) {
|
|
21
|
+
const { manifest } = plugin;
|
|
22
|
+
if (!manifest)
|
|
23
|
+
continue;
|
|
24
|
+
// Skills → CLAUDE.md skill loader lines
|
|
25
|
+
for (const skill of manifest.skills ?? []) {
|
|
26
|
+
desiredSkills.push({
|
|
27
|
+
plugin: manifest.name,
|
|
28
|
+
target: "claude-md",
|
|
29
|
+
capability: "skill",
|
|
30
|
+
value: skill,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
// Hooks → .claude/settings.json
|
|
34
|
+
for (const hook of manifest.hooks ?? []) {
|
|
35
|
+
desiredHooks.push({
|
|
36
|
+
plugin: manifest.name,
|
|
37
|
+
target: "settings-json",
|
|
38
|
+
capability: "hook",
|
|
39
|
+
value: hook,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// ── Wire skills into CLAUDE.md ───────────────────────────────────────
|
|
44
|
+
try {
|
|
45
|
+
const claudeResult = await wireClaudeMd(projectDir, desiredSkills, installedPlugins, dryRun);
|
|
46
|
+
wired.push(...claudeResult.wired);
|
|
47
|
+
unwired.push(...claudeResult.unwired);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
errors.push(`CLAUDE.md wiring failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
51
|
+
}
|
|
52
|
+
// ── Wire hooks into .claude/settings.json ────────────────────────────
|
|
53
|
+
try {
|
|
54
|
+
const hooksResult = await wireSettingsJson(projectDir, desiredHooks, installedPlugins, dryRun);
|
|
55
|
+
wired.push(...hooksResult.wired);
|
|
56
|
+
unwired.push(...hooksResult.unwired);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
errors.push(`settings.json wiring failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
60
|
+
}
|
|
61
|
+
return { wired, unwired, errors };
|
|
62
|
+
}
|
|
63
|
+
// ── CLAUDE.md Wiring ───────────────────────────────────────────────────────
|
|
64
|
+
/**
|
|
65
|
+
* Build the auto-wire section content for CLAUDE.md.
|
|
66
|
+
* Pure function — no I/O.
|
|
67
|
+
*/
|
|
68
|
+
export function buildAutoWireSection(plugins) {
|
|
69
|
+
const lines = [];
|
|
70
|
+
lines.push(WIRE_START);
|
|
71
|
+
lines.push("");
|
|
72
|
+
lines.push("## Plugins (auto-wired)");
|
|
73
|
+
lines.push("");
|
|
74
|
+
for (const plugin of plugins) {
|
|
75
|
+
const { manifest } = plugin;
|
|
76
|
+
if (!manifest)
|
|
77
|
+
continue;
|
|
78
|
+
lines.push(`### ${manifest.name} v${manifest.version}`);
|
|
79
|
+
lines.push(`> ${manifest.description}`);
|
|
80
|
+
lines.push("");
|
|
81
|
+
// Skills
|
|
82
|
+
const skills = manifest.skills ?? [];
|
|
83
|
+
if (skills.length > 0) {
|
|
84
|
+
for (const skill of skills) {
|
|
85
|
+
lines.push(`- Load \`~/.claude/plugins/${manifest.name}/skills/${skill}/SKILL.md\` when working with ${skill}`);
|
|
86
|
+
}
|
|
87
|
+
lines.push("");
|
|
88
|
+
}
|
|
89
|
+
// Commands
|
|
90
|
+
const commands = manifest.commands ?? [];
|
|
91
|
+
if (commands.length > 0) {
|
|
92
|
+
lines.push("**Commands:**");
|
|
93
|
+
for (const cmd of commands) {
|
|
94
|
+
lines.push(`- \`/${cmd}\``);
|
|
95
|
+
}
|
|
96
|
+
lines.push("");
|
|
97
|
+
}
|
|
98
|
+
// Agents
|
|
99
|
+
const agents = manifest.agents ?? [];
|
|
100
|
+
if (agents.length > 0) {
|
|
101
|
+
lines.push("**Agents:**");
|
|
102
|
+
for (const agent of agents) {
|
|
103
|
+
lines.push(`- ${agent}`);
|
|
104
|
+
}
|
|
105
|
+
lines.push("");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
lines.push(WIRE_END);
|
|
109
|
+
return lines.join("\n");
|
|
110
|
+
}
|
|
111
|
+
async function wireClaudeMd(projectDir, desiredSkills, plugins, dryRun) {
|
|
112
|
+
const claudeMdPath = path.join(projectDir, "CLAUDE.md");
|
|
113
|
+
const wired = [];
|
|
114
|
+
const unwired = [];
|
|
115
|
+
// If no plugins have capabilities, remove section if present
|
|
116
|
+
const pluginsWithCapabilities = plugins.filter((p) => {
|
|
117
|
+
const m = p.manifest;
|
|
118
|
+
if (!m)
|
|
119
|
+
return false;
|
|
120
|
+
return ((m.skills?.length ?? 0) > 0 ||
|
|
121
|
+
(m.commands?.length ?? 0) > 0 ||
|
|
122
|
+
(m.agents?.length ?? 0) > 0);
|
|
123
|
+
});
|
|
124
|
+
let content = "";
|
|
125
|
+
if (await fs.pathExists(claudeMdPath)) {
|
|
126
|
+
content = await fs.readFile(claudeMdPath, "utf-8");
|
|
127
|
+
}
|
|
128
|
+
// Remove existing auto-wire section (idempotent)
|
|
129
|
+
const cleaned = removeAutoWireSection(content);
|
|
130
|
+
if (pluginsWithCapabilities.length === 0) {
|
|
131
|
+
// Nothing to wire — if we cleaned something, that's an unwire
|
|
132
|
+
if (cleaned !== content && !dryRun) {
|
|
133
|
+
await fs.writeFile(claudeMdPath, cleaned, "utf-8");
|
|
134
|
+
}
|
|
135
|
+
return { wired, unwired };
|
|
136
|
+
}
|
|
137
|
+
// Build new section
|
|
138
|
+
const section = buildAutoWireSection(pluginsWithCapabilities);
|
|
139
|
+
const newContent = `${cleaned.trimEnd()}\n\n${section}\n`;
|
|
140
|
+
if (!dryRun) {
|
|
141
|
+
await fs.ensureDir(path.dirname(claudeMdPath));
|
|
142
|
+
await fs.writeFile(claudeMdPath, newContent, "utf-8");
|
|
143
|
+
}
|
|
144
|
+
// Track what was wired
|
|
145
|
+
for (const entry of desiredSkills) {
|
|
146
|
+
wired.push(entry);
|
|
147
|
+
}
|
|
148
|
+
for (const plugin of pluginsWithCapabilities) {
|
|
149
|
+
for (const cmd of plugin.manifest.commands ?? []) {
|
|
150
|
+
wired.push({
|
|
151
|
+
plugin: plugin.manifest.name,
|
|
152
|
+
target: "claude-md",
|
|
153
|
+
capability: "command",
|
|
154
|
+
value: cmd,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
for (const agent of plugin.manifest.agents ?? []) {
|
|
158
|
+
wired.push({
|
|
159
|
+
plugin: plugin.manifest.name,
|
|
160
|
+
target: "claude-md",
|
|
161
|
+
capability: "agent",
|
|
162
|
+
value: agent,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { wired, unwired };
|
|
167
|
+
}
|
|
168
|
+
// ── Settings.json Wiring ───────────────────────────────────────────────────
|
|
169
|
+
async function wireSettingsJson(projectDir, desiredHooks, _plugins, dryRun) {
|
|
170
|
+
const wired = [];
|
|
171
|
+
const unwired = [];
|
|
172
|
+
if (desiredHooks.length === 0)
|
|
173
|
+
return { wired, unwired };
|
|
174
|
+
const settingsPath = path.join(projectDir, ".claude", "settings.json");
|
|
175
|
+
let settings = {};
|
|
176
|
+
if (await fs.pathExists(settingsPath)) {
|
|
177
|
+
try {
|
|
178
|
+
settings = await fs.readJson(settingsPath);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
settings = {};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Ensure hooks object
|
|
185
|
+
const hooks = (settings.hooks ?? {});
|
|
186
|
+
const pluginHooks = (hooks["plugin-hooks"] ?? []);
|
|
187
|
+
const existingSet = new Set(pluginHooks);
|
|
188
|
+
for (const entry of desiredHooks) {
|
|
189
|
+
if (existingSet.has(entry.value)) {
|
|
190
|
+
// Already wired — skip (idempotent)
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
pluginHooks.push(entry.value);
|
|
194
|
+
existingSet.add(entry.value);
|
|
195
|
+
wired.push(entry);
|
|
196
|
+
}
|
|
197
|
+
// Detect hooks that belong to removed plugins
|
|
198
|
+
const _activePluginNames = new Set(desiredHooks.map((h) => h.plugin));
|
|
199
|
+
const cleanedHooks = pluginHooks.filter((h) => {
|
|
200
|
+
// Keep hooks that we just wired or that belong to active plugins
|
|
201
|
+
const belongsToActive = desiredHooks.some((d) => d.value === h);
|
|
202
|
+
if (!belongsToActive) {
|
|
203
|
+
unwired.push({
|
|
204
|
+
plugin: "unknown",
|
|
205
|
+
target: "settings-json",
|
|
206
|
+
capability: "hook",
|
|
207
|
+
value: h,
|
|
208
|
+
});
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
return true;
|
|
212
|
+
});
|
|
213
|
+
hooks["plugin-hooks"] = cleanedHooks;
|
|
214
|
+
settings.hooks = hooks;
|
|
215
|
+
if (!dryRun && (wired.length > 0 || unwired.length > 0)) {
|
|
216
|
+
await fs.ensureDir(path.dirname(settingsPath));
|
|
217
|
+
await fs.writeJson(settingsPath, settings, { spaces: 2 });
|
|
218
|
+
}
|
|
219
|
+
return { wired, unwired };
|
|
220
|
+
}
|
|
221
|
+
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
222
|
+
/**
|
|
223
|
+
* Remove the auto-wire section from CLAUDE.md content.
|
|
224
|
+
* Returns cleaned content.
|
|
225
|
+
*/
|
|
226
|
+
export function removeAutoWireSection(content) {
|
|
227
|
+
const startIdx = content.indexOf(WIRE_START);
|
|
228
|
+
if (startIdx === -1)
|
|
229
|
+
return content;
|
|
230
|
+
const endIdx = content.indexOf(WIRE_END);
|
|
231
|
+
if (endIdx === -1)
|
|
232
|
+
return content;
|
|
233
|
+
const before = content.slice(0, startIdx).trimEnd();
|
|
234
|
+
const after = content.slice(endIdx + WIRE_END.length).trimStart();
|
|
235
|
+
if (after) {
|
|
236
|
+
return `${before}\n\n${after}`;
|
|
237
|
+
}
|
|
238
|
+
return `${before}\n`;
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=auto-wire.js.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Versioned mixed-runner CI config (`.javi-forge/ci.yaml`) — schema and loader.
|
|
3
|
+
*
|
|
4
|
+
* Hybrid repositories declare every required runner explicitly and in order.
|
|
5
|
+
* Single-stack repositories need no config: auto-detection stays the default.
|
|
6
|
+
*
|
|
7
|
+
* Validation is fail-closed: any schema violation produces a CIConfigError
|
|
8
|
+
* listing every problem, and no partially-valid config is ever returned.
|
|
9
|
+
* YAML parsing uses the `yaml` package, already a runtime dependency.
|
|
10
|
+
*/
|
|
11
|
+
import type { Stack } from "../types/index.js";
|
|
12
|
+
export declare const CI_CONFIG_VERSION = 1;
|
|
13
|
+
/** Default config locations, in discovery order, relative to the project root. */
|
|
14
|
+
export declare const CI_CONFIG_CANDIDATES: readonly [".javi-forge/ci.yaml", ".javi-forge/ci.yml"];
|
|
15
|
+
export interface CIRunnerConfig {
|
|
16
|
+
/** Unique runner name (used in step ids and reports) */
|
|
17
|
+
name: string;
|
|
18
|
+
/** Toolchain stack — selects the default CI image and default commands */
|
|
19
|
+
stack: Stack;
|
|
20
|
+
/** Working directory relative to the project root (default: ".") */
|
|
21
|
+
directory: string;
|
|
22
|
+
/** Explicit container image (mutually exclusive with `buildContext`) */
|
|
23
|
+
image?: string;
|
|
24
|
+
/** Docker build context directory (mutually exclusive with `image`) */
|
|
25
|
+
buildContext?: string;
|
|
26
|
+
/** Dependency setup commands, run before lint/build/test */
|
|
27
|
+
setup: string[];
|
|
28
|
+
lint: string[];
|
|
29
|
+
build: string[];
|
|
30
|
+
test: string[];
|
|
31
|
+
security: string[];
|
|
32
|
+
/** Tools that must exist in the runner environment (validated fail-closed) */
|
|
33
|
+
requires: string[];
|
|
34
|
+
}
|
|
35
|
+
export interface CIConfig {
|
|
36
|
+
version: number;
|
|
37
|
+
runners: CIRunnerConfig[];
|
|
38
|
+
}
|
|
39
|
+
export interface CIConfigValidationError {
|
|
40
|
+
path: string;
|
|
41
|
+
message: string;
|
|
42
|
+
}
|
|
43
|
+
export declare class CIConfigError extends Error {
|
|
44
|
+
readonly errors: CIConfigValidationError[];
|
|
45
|
+
constructor(errors: CIConfigValidationError[], source?: string);
|
|
46
|
+
}
|
|
47
|
+
/** Stacks accepted by the CI config schema and the --stack override. */
|
|
48
|
+
export declare const CI_STACKS: readonly string[];
|
|
49
|
+
/**
|
|
50
|
+
* Parse and validate CI config YAML text. Throws CIConfigError listing every
|
|
51
|
+
* validation problem; never returns a partially valid config.
|
|
52
|
+
*/
|
|
53
|
+
export declare function parseCIConfig(rawYaml: string, source?: string): CIConfig;
|
|
54
|
+
/**
|
|
55
|
+
* Load and validate a CI config file. Fails closed: a missing file or any
|
|
56
|
+
* validation error throws — no config is ever silently ignored.
|
|
57
|
+
*/
|
|
58
|
+
export declare function loadCIConfig(configPath: string): Promise<CIConfig>;
|
|
59
|
+
/**
|
|
60
|
+
* Discover the default CI config for a project directory.
|
|
61
|
+
* Returns the config path, or null when the project has no config
|
|
62
|
+
* (single-stack auto-detection stays the default).
|
|
63
|
+
*/
|
|
64
|
+
export declare function findCIConfig(projectDir: string): Promise<string | null>;
|
|
65
|
+
//# sourceMappingURL=ci-config.d.ts.map
|