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,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crash recovery — reconstruct pipeline state from git commit history
|
|
3
|
+
* when checkpoint files are corrupted or lost. Git is the single
|
|
4
|
+
* source of truth for what was actually done.
|
|
5
|
+
*/
|
|
6
|
+
import { execFileAsync } from "./exec.js";
|
|
7
|
+
// ── Git operations ──
|
|
8
|
+
export async function getGitLog(projectDir, options = {}) {
|
|
9
|
+
const args = [
|
|
10
|
+
"log",
|
|
11
|
+
`--max-count=${options.maxCommits ?? 50}`,
|
|
12
|
+
"--pretty=format:%H|%s|%aI",
|
|
13
|
+
"--name-only",
|
|
14
|
+
];
|
|
15
|
+
if (options.since)
|
|
16
|
+
args.push(`--since=${options.since}`);
|
|
17
|
+
try {
|
|
18
|
+
const { stdout } = await execFileAsync("git", args, {
|
|
19
|
+
cwd: projectDir,
|
|
20
|
+
timeout: 10_000,
|
|
21
|
+
});
|
|
22
|
+
return stdout;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function getCurrentBranch(projectDir) {
|
|
29
|
+
try {
|
|
30
|
+
const { stdout } = await execFileAsync("git", ["branch", "--show-current"], { cwd: projectDir, timeout: 5_000 });
|
|
31
|
+
return stdout.trim();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return "unknown";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// ── Parsing ──
|
|
38
|
+
const CONVENTIONAL_RE = /^(feat|fix|test|refactor|docs|chore|ci|perf|style|build)(?:\(([^)]*)\))?:\s*(.+)/;
|
|
39
|
+
const TASK_ID_RE = /#(\d+)|task[- ](\d+[.\d]*)/i;
|
|
40
|
+
export function parseCommitPhase(message) {
|
|
41
|
+
const match = CONVENTIONAL_RE.exec(message);
|
|
42
|
+
return match ? (match[1] ?? null) : null;
|
|
43
|
+
}
|
|
44
|
+
export function extractTaskId(message) {
|
|
45
|
+
const match = TASK_ID_RE.exec(message);
|
|
46
|
+
if (match)
|
|
47
|
+
return match[1] ?? match[2] ?? null;
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
export function parseGitLog(raw) {
|
|
51
|
+
if (!raw.trim())
|
|
52
|
+
return [];
|
|
53
|
+
const tasks = [];
|
|
54
|
+
const blocks = raw.split("\n\n").filter((b) => b.trim());
|
|
55
|
+
for (const block of blocks) {
|
|
56
|
+
const lines = block.split("\n").filter((l) => l.trim());
|
|
57
|
+
if (lines.length === 0)
|
|
58
|
+
continue;
|
|
59
|
+
const headerLine = lines[0];
|
|
60
|
+
if (!headerLine)
|
|
61
|
+
continue;
|
|
62
|
+
const parts = headerLine.split("|");
|
|
63
|
+
if (parts.length < 3)
|
|
64
|
+
continue;
|
|
65
|
+
const [hash, message, timestamp] = parts;
|
|
66
|
+
const filesChanged = lines.slice(1).filter((l) => !l.includes("|"));
|
|
67
|
+
tasks.push({
|
|
68
|
+
commitHash: hash.slice(0, 7),
|
|
69
|
+
message,
|
|
70
|
+
timestamp,
|
|
71
|
+
filesChanged,
|
|
72
|
+
taskId: extractTaskId(message),
|
|
73
|
+
phase: parseCommitPhase(message),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return tasks;
|
|
77
|
+
}
|
|
78
|
+
// ── Recovery ──
|
|
79
|
+
export async function recoverFromGit(projectDir, options = {}) {
|
|
80
|
+
const branch = await getCurrentBranch(projectDir);
|
|
81
|
+
const raw = await getGitLog(projectDir, options);
|
|
82
|
+
const tasks = parseGitLog(raw);
|
|
83
|
+
const phases = {};
|
|
84
|
+
for (const task of tasks) {
|
|
85
|
+
if (task.phase) {
|
|
86
|
+
phases[task.phase] = (phases[task.phase] ?? 0) + 1;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
branch,
|
|
91
|
+
totalCommits: tasks.length,
|
|
92
|
+
tasks,
|
|
93
|
+
phases,
|
|
94
|
+
lastActivity: tasks[0]?.timestamp ?? null,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// ── Formatting ──
|
|
98
|
+
export function formatRecovery(report) {
|
|
99
|
+
const lines = [];
|
|
100
|
+
lines.push(`## Crash Recovery Report`);
|
|
101
|
+
lines.push(`**Branch**: ${report.branch} | **Commits**: ${report.totalCommits}`);
|
|
102
|
+
if (report.lastActivity) {
|
|
103
|
+
lines.push(`**Last activity**: ${report.lastActivity}`);
|
|
104
|
+
}
|
|
105
|
+
lines.push("");
|
|
106
|
+
if (Object.keys(report.phases).length > 0) {
|
|
107
|
+
const phaseStr = Object.entries(report.phases)
|
|
108
|
+
.map(([p, c]) => `${p}: ${c}`)
|
|
109
|
+
.join(", ");
|
|
110
|
+
lines.push(`**Phases**: ${phaseStr}`);
|
|
111
|
+
lines.push("");
|
|
112
|
+
}
|
|
113
|
+
for (const task of report.tasks.slice(0, 10)) {
|
|
114
|
+
const tag = task.phase ? `[${task.phase}]` : "";
|
|
115
|
+
const id = task.taskId ? ` #${task.taskId}` : "";
|
|
116
|
+
lines.push(`- \`${task.commitHash}\` ${tag}${id} ${task.message} (${task.filesChanged.length} files)`);
|
|
117
|
+
}
|
|
118
|
+
if (report.totalCommits > 10) {
|
|
119
|
+
lines.push(`\n... and ${report.totalCommits - 10} more commits`);
|
|
120
|
+
}
|
|
121
|
+
return lines.join("\n");
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=crash-recovery.js.map
|
package/dist/lib/docker.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import type { Stack } from
|
|
1
|
+
import type { Stack } from "../types/index.js";
|
|
2
2
|
export interface DockerRunOptions {
|
|
3
3
|
/** Absolute path to mount as /home/runner/work */
|
|
4
4
|
projectDir: string;
|
|
5
|
+
/**
|
|
6
|
+
* Pre-resolved image from the CI runner (required). Passed through
|
|
7
|
+
* verbatim, including digest pins (`name@sha256:...`). runInContainer
|
|
8
|
+
* never performs marker detection — resolution happens once, upstream.
|
|
9
|
+
*/
|
|
10
|
+
image: string;
|
|
5
11
|
/** Command to run inside the container */
|
|
6
12
|
command: string;
|
|
7
13
|
/** Timeout in seconds (default: 600) */
|
|
@@ -22,6 +28,14 @@ export interface DockerImageOptions {
|
|
|
22
28
|
javaVersion?: string;
|
|
23
29
|
/** Directory where Dockerfiles are stored (defaults to package-bundled dir) */
|
|
24
30
|
dockerfilesDir?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Custom build context directory (must contain a Dockerfile, which is
|
|
33
|
+
* the source of truth and is never overwritten). Mutually exclusive
|
|
34
|
+
* with dockerfilesDir.
|
|
35
|
+
*/
|
|
36
|
+
buildContext?: string;
|
|
37
|
+
/** Image tag for build-context builds (default: derived from the stack) */
|
|
38
|
+
imageTag?: string;
|
|
25
39
|
}
|
|
26
40
|
export declare function getImageName(stack: Stack): string;
|
|
27
41
|
export declare function getDockerfileContent(stack: Stack): string;
|
|
@@ -30,6 +44,12 @@ export declare function isDockerAvailable(): Promise<boolean>;
|
|
|
30
44
|
* Ensure a CI Docker image exists and is up-to-date.
|
|
31
45
|
* Rebuilds only if the Dockerfile content has changed (hash-based staleness check).
|
|
32
46
|
* Returns the image name.
|
|
47
|
+
*
|
|
48
|
+
* Two modes:
|
|
49
|
+
* - per-stack (default): the Dockerfile is generated/managed by javi-forge
|
|
50
|
+
* - build-context: the configured context directory provides its own
|
|
51
|
+
* Dockerfile (source of truth, never overwritten); fails closed if
|
|
52
|
+
* the Dockerfile is missing.
|
|
33
53
|
*/
|
|
34
54
|
export declare function ensureImage(options: DockerImageOptions): Promise<string>;
|
|
35
55
|
/**
|
|
@@ -40,6 +60,7 @@ export declare function ensureImage(options: DockerImageOptions): Promise<string
|
|
|
40
60
|
export declare function runInContainer(options: DockerRunOptions): Promise<DockerRunResult>;
|
|
41
61
|
/**
|
|
42
62
|
* Open an interactive shell inside the CI container.
|
|
63
|
+
* The image must be pre-resolved by the caller (no marker detection here).
|
|
43
64
|
*/
|
|
44
|
-
export declare function openShell(projectDir: string): Promise<void>;
|
|
65
|
+
export declare function openShell(projectDir: string, image: string): Promise<void>;
|
|
45
66
|
//# sourceMappingURL=docker.d.ts.map
|
package/dist/lib/docker.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import fs from
|
|
5
|
-
import
|
|
6
|
-
const execFileAsync = promisify(execFile);
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import fs from "fs-extra";
|
|
5
|
+
import { execFileAsync } from "./exec.js";
|
|
7
6
|
// =============================================================================
|
|
8
7
|
// Image name
|
|
9
8
|
// =============================================================================
|
|
@@ -15,66 +14,66 @@ export function getImageName(stack) {
|
|
|
15
14
|
// =============================================================================
|
|
16
15
|
export function getDockerfileContent(stack) {
|
|
17
16
|
switch (stack) {
|
|
18
|
-
case
|
|
19
|
-
case
|
|
17
|
+
case "java-gradle":
|
|
18
|
+
case "java-maven":
|
|
20
19
|
return [
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
"ARG JAVA_VERSION=21",
|
|
21
|
+
"FROM eclipse-temurin:${JAVA_VERSION}-jdk-noble",
|
|
22
|
+
"RUN apt-get update && apt-get install -y git curl unzip && rm -rf /var/lib/apt/lists/*",
|
|
23
|
+
"RUN useradd -m -s /bin/bash runner",
|
|
24
|
+
"USER runner",
|
|
25
|
+
"WORKDIR /home/runner/work",
|
|
27
26
|
'ENTRYPOINT ["/bin/bash", "-c"]',
|
|
28
|
-
].join(
|
|
29
|
-
case
|
|
27
|
+
].join("\n");
|
|
28
|
+
case "node":
|
|
30
29
|
return [
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
"FROM node:22-slim",
|
|
31
|
+
"RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*",
|
|
32
|
+
"RUN npm install -g pnpm",
|
|
33
|
+
"RUN useradd -m -s /bin/bash runner",
|
|
34
|
+
"USER runner",
|
|
35
|
+
"WORKDIR /home/runner/work",
|
|
37
36
|
'ENTRYPOINT ["/bin/bash", "-c"]',
|
|
38
|
-
].join(
|
|
39
|
-
case
|
|
37
|
+
].join("\n");
|
|
38
|
+
case "python":
|
|
40
39
|
return [
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
"FROM python:3.12-slim",
|
|
41
|
+
"RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*",
|
|
42
|
+
"RUN pip install --no-cache-dir pytest ruff pylint poetry",
|
|
43
|
+
"RUN useradd -m -s /bin/bash runner",
|
|
44
|
+
"USER runner",
|
|
45
|
+
"WORKDIR /home/runner/work",
|
|
47
46
|
'ENTRYPOINT ["/bin/bash", "-c"]',
|
|
48
|
-
].join(
|
|
49
|
-
case
|
|
47
|
+
].join("\n");
|
|
48
|
+
case "go":
|
|
50
49
|
return [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
"FROM golang:1.23-bookworm",
|
|
51
|
+
"RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*",
|
|
52
|
+
"RUN go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.0 && mv /root/go/bin/golangci-lint /usr/local/bin/",
|
|
53
|
+
"RUN useradd -m -s /bin/bash runner",
|
|
54
|
+
"USER runner",
|
|
55
|
+
"WORKDIR /home/runner/work",
|
|
57
56
|
'ENTRYPOINT ["/bin/bash", "-c"]',
|
|
58
|
-
].join(
|
|
59
|
-
case
|
|
57
|
+
].join("\n");
|
|
58
|
+
case "rust":
|
|
60
59
|
return [
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
"FROM rust:1.83-slim",
|
|
61
|
+
"RUN apt-get update && apt-get install -y git pkg-config libssl-dev && rm -rf /var/lib/apt/lists/*",
|
|
62
|
+
"RUN rustup component add clippy rustfmt",
|
|
63
|
+
"RUN useradd -m -s /bin/bash runner",
|
|
64
|
+
"USER runner",
|
|
65
|
+
"WORKDIR /home/runner/work",
|
|
67
66
|
'ENTRYPOINT ["/bin/bash", "-c"]',
|
|
68
|
-
].join(
|
|
67
|
+
].join("\n");
|
|
69
68
|
default:
|
|
70
69
|
return [
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
"FROM ubuntu:24.04",
|
|
71
|
+
"RUN apt-get update && apt-get install -y git curl && rm -rf /var/lib/apt/lists/*",
|
|
72
|
+
"RUN useradd -m -s /bin/bash runner",
|
|
73
|
+
"USER runner",
|
|
74
|
+
"WORKDIR /home/runner/work",
|
|
76
75
|
'ENTRYPOINT ["/bin/bash", "-c"]',
|
|
77
|
-
].join(
|
|
76
|
+
].join("\n");
|
|
78
77
|
}
|
|
79
78
|
}
|
|
80
79
|
// =============================================================================
|
|
@@ -82,7 +81,7 @@ export function getDockerfileContent(stack) {
|
|
|
82
81
|
// =============================================================================
|
|
83
82
|
export async function isDockerAvailable() {
|
|
84
83
|
try {
|
|
85
|
-
await execFileAsync(
|
|
84
|
+
await execFileAsync("docker", ["info"], { timeout: 5000 });
|
|
86
85
|
return true;
|
|
87
86
|
}
|
|
88
87
|
catch {
|
|
@@ -96,25 +95,51 @@ export async function isDockerAvailable() {
|
|
|
96
95
|
* Ensure a CI Docker image exists and is up-to-date.
|
|
97
96
|
* Rebuilds only if the Dockerfile content has changed (hash-based staleness check).
|
|
98
97
|
* Returns the image name.
|
|
98
|
+
*
|
|
99
|
+
* Two modes:
|
|
100
|
+
* - per-stack (default): the Dockerfile is generated/managed by javi-forge
|
|
101
|
+
* - build-context: the configured context directory provides its own
|
|
102
|
+
* Dockerfile (source of truth, never overwritten); fails closed if
|
|
103
|
+
* the Dockerfile is missing.
|
|
99
104
|
*/
|
|
100
105
|
export async function ensureImage(options) {
|
|
101
|
-
const { stack, javaVersion, dockerfilesDir } = options;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
const { stack, javaVersion, dockerfilesDir, buildContext, imageTag } = options;
|
|
107
|
+
let imageName;
|
|
108
|
+
let dockerfilePath;
|
|
109
|
+
let contextDir;
|
|
110
|
+
if (buildContext) {
|
|
111
|
+
imageName = imageTag ?? getImageName(stack);
|
|
112
|
+
dockerfilePath = path.join(buildContext, "Dockerfile");
|
|
113
|
+
contextDir = buildContext;
|
|
114
|
+
// Fail closed: a build context without a Dockerfile is a config error,
|
|
115
|
+
// never something to silently work around.
|
|
116
|
+
if (!(await fs.pathExists(dockerfilePath))) {
|
|
117
|
+
throw new Error(`build-context "${buildContext}" has no Dockerfile — ` +
|
|
118
|
+
"add one or use image/stack defaults instead");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
imageName = getImageName(stack);
|
|
123
|
+
const dockerDir = dockerfilesDir ??
|
|
124
|
+
path.join(path.dirname(new URL(import.meta.url).pathname), "../../ci-local/docker");
|
|
125
|
+
dockerfilePath = path.join(dockerDir, `${stack}.Dockerfile`);
|
|
126
|
+
contextDir = dockerDir;
|
|
127
|
+
// Write Dockerfile if it doesn't exist yet (first run)
|
|
128
|
+
if (!(await fs.pathExists(dockerfilePath))) {
|
|
129
|
+
await fs.ensureDir(dockerDir);
|
|
130
|
+
await fs.writeFile(dockerfilePath, getDockerfileContent(stack), "utf-8");
|
|
131
|
+
}
|
|
110
132
|
}
|
|
111
133
|
// Staleness check: compare Dockerfile hash with the one embedded in the image label
|
|
112
|
-
const content = await fs.readFile(dockerfilePath,
|
|
113
|
-
const currentHash = crypto.createHash(
|
|
114
|
-
let imageHash =
|
|
134
|
+
const content = await fs.readFile(dockerfilePath, "utf-8");
|
|
135
|
+
const currentHash = crypto.createHash("sha256").update(content).digest("hex");
|
|
136
|
+
let imageHash = "";
|
|
115
137
|
try {
|
|
116
|
-
const { stdout } = await execFileAsync(
|
|
117
|
-
|
|
138
|
+
const { stdout } = await execFileAsync("docker", [
|
|
139
|
+
"inspect",
|
|
140
|
+
"--format",
|
|
141
|
+
'{{index .Config.Labels "dockerfile-hash"}}',
|
|
142
|
+
imageName,
|
|
118
143
|
]);
|
|
119
144
|
imageHash = stdout.trim();
|
|
120
145
|
}
|
|
@@ -126,19 +151,26 @@ export async function ensureImage(options) {
|
|
|
126
151
|
}
|
|
127
152
|
// Build image
|
|
128
153
|
const buildArgs = [
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
154
|
+
"build",
|
|
155
|
+
"--label",
|
|
156
|
+
`dockerfile-hash=${currentHash}`,
|
|
157
|
+
"-f",
|
|
158
|
+
dockerfilePath,
|
|
159
|
+
"-t",
|
|
160
|
+
imageName,
|
|
133
161
|
];
|
|
134
|
-
if (
|
|
135
|
-
|
|
162
|
+
if (!buildContext &&
|
|
163
|
+
javaVersion &&
|
|
164
|
+
(stack === "java-gradle" || stack === "java-maven")) {
|
|
165
|
+
buildArgs.push("--build-arg", `JAVA_VERSION=${javaVersion}`);
|
|
136
166
|
}
|
|
137
|
-
buildArgs.push(
|
|
167
|
+
buildArgs.push(contextDir);
|
|
138
168
|
await new Promise((resolve, reject) => {
|
|
139
|
-
const proc = spawn(
|
|
140
|
-
proc.on(
|
|
141
|
-
|
|
169
|
+
const proc = spawn("docker", buildArgs, { stdio: "inherit" });
|
|
170
|
+
proc.on("close", (code) => code === 0
|
|
171
|
+
? resolve()
|
|
172
|
+
: reject(new Error(`docker build exited with code ${code}`)));
|
|
173
|
+
proc.on("error", reject);
|
|
142
174
|
});
|
|
143
175
|
return imageName;
|
|
144
176
|
}
|
|
@@ -151,74 +183,79 @@ export async function ensureImage(options) {
|
|
|
151
183
|
* Streams output to process.stdout/stderr by default.
|
|
152
184
|
*/
|
|
153
185
|
export async function runInContainer(options) {
|
|
154
|
-
const { projectDir, command, timeout = 600, stream = true, user } = options;
|
|
155
|
-
|
|
156
|
-
|
|
186
|
+
const { projectDir, image, command, timeout = 600, stream = true, user, } = options;
|
|
187
|
+
// The image is always pre-resolved by the caller (resolveCIRunners →
|
|
188
|
+
// ensureImage or an explicit/digest-pinned config image). No marker
|
|
189
|
+
// detection happens on this path — ever.
|
|
190
|
+
const imageName = image;
|
|
157
191
|
const isInteractive = process.stdin.isTTY && stream;
|
|
192
|
+
// Use --mount instead of -v: the -v form parses the value as a single
|
|
193
|
+
// "src:dst[:opt]" colon-separated string, which breaks (and could be
|
|
194
|
+
// hijacked) when projectDir itself contains a colon. --mount takes
|
|
195
|
+
// comma-separated key=value pairs and is colon-safe.
|
|
158
196
|
const dockerArgs = [
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
197
|
+
"run",
|
|
198
|
+
"--rm",
|
|
199
|
+
...(isInteractive ? ["-it"] : []),
|
|
200
|
+
"--stop-timeout",
|
|
201
|
+
"30",
|
|
202
|
+
"--entrypoint",
|
|
203
|
+
"",
|
|
204
|
+
...(user ? ["--user", user] : []),
|
|
205
|
+
"--mount",
|
|
206
|
+
`type=bind,source=${projectDir},target=/home/runner/work`,
|
|
207
|
+
"-e",
|
|
208
|
+
"CI=true",
|
|
166
209
|
imageName,
|
|
167
|
-
|
|
210
|
+
"timeout",
|
|
211
|
+
String(timeout),
|
|
212
|
+
"bash",
|
|
213
|
+
"-c",
|
|
214
|
+
command,
|
|
168
215
|
];
|
|
169
216
|
return new Promise((resolve, reject) => {
|
|
170
|
-
const proc = spawn(
|
|
171
|
-
stdio: stream ?
|
|
217
|
+
const proc = spawn("docker", dockerArgs, {
|
|
218
|
+
stdio: stream ? "inherit" : "pipe",
|
|
172
219
|
});
|
|
173
|
-
let stdout =
|
|
174
|
-
let stderr =
|
|
220
|
+
let stdout = "";
|
|
221
|
+
let stderr = "";
|
|
175
222
|
if (!stream) {
|
|
176
|
-
proc.stdout?.on(
|
|
177
|
-
|
|
223
|
+
proc.stdout?.on("data", (d) => {
|
|
224
|
+
stdout += d.toString();
|
|
225
|
+
});
|
|
226
|
+
proc.stderr?.on("data", (d) => {
|
|
227
|
+
stderr += d.toString();
|
|
228
|
+
});
|
|
178
229
|
}
|
|
179
|
-
proc.on(
|
|
180
|
-
proc.on(
|
|
230
|
+
proc.on("close", (code) => resolve({ exitCode: code ?? 1, stdout, stderr }));
|
|
231
|
+
proc.on("error", reject);
|
|
181
232
|
});
|
|
182
233
|
}
|
|
183
234
|
/**
|
|
184
235
|
* Open an interactive shell inside the CI container.
|
|
236
|
+
* The image must be pre-resolved by the caller (no marker detection here).
|
|
185
237
|
*/
|
|
186
|
-
export async function openShell(projectDir) {
|
|
187
|
-
const
|
|
188
|
-
const imageName = getImageName(stack);
|
|
238
|
+
export async function openShell(projectDir, image) {
|
|
239
|
+
const imageName = image;
|
|
189
240
|
await new Promise((resolve, reject) => {
|
|
190
|
-
const proc = spawn(
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
241
|
+
const proc = spawn("docker", [
|
|
242
|
+
"run",
|
|
243
|
+
"--rm",
|
|
244
|
+
"-it",
|
|
245
|
+
"--entrypoint",
|
|
246
|
+
"",
|
|
247
|
+
// --mount is colon-safe; see runInContainer for the rationale.
|
|
248
|
+
"--mount",
|
|
249
|
+
`type=bind,source=${projectDir},target=/home/runner/work`,
|
|
250
|
+
"-e",
|
|
251
|
+
"CI=true",
|
|
195
252
|
imageName,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
253
|
+
"bash",
|
|
254
|
+
"-c",
|
|
255
|
+
"cd /home/runner/work && exec bash",
|
|
256
|
+
], { stdio: "inherit" });
|
|
257
|
+
proc.on("close", () => resolve());
|
|
258
|
+
proc.on("error", reject);
|
|
200
259
|
});
|
|
201
260
|
}
|
|
202
|
-
// =============================================================================
|
|
203
|
-
// Internal helpers
|
|
204
|
-
// =============================================================================
|
|
205
|
-
async function detectStackFromDir(projectDir) {
|
|
206
|
-
if (await fs.pathExists(path.join(projectDir, 'build.gradle.kts')))
|
|
207
|
-
return 'java-gradle';
|
|
208
|
-
if (await fs.pathExists(path.join(projectDir, 'build.gradle')))
|
|
209
|
-
return 'java-gradle';
|
|
210
|
-
if (await fs.pathExists(path.join(projectDir, 'pom.xml')))
|
|
211
|
-
return 'java-maven';
|
|
212
|
-
if (await fs.pathExists(path.join(projectDir, 'package.json')))
|
|
213
|
-
return 'node';
|
|
214
|
-
if (await fs.pathExists(path.join(projectDir, 'go.mod')))
|
|
215
|
-
return 'go';
|
|
216
|
-
if (await fs.pathExists(path.join(projectDir, 'Cargo.toml')))
|
|
217
|
-
return 'rust';
|
|
218
|
-
if (await fs.pathExists(path.join(projectDir, 'pyproject.toml')) ||
|
|
219
|
-
await fs.pathExists(path.join(projectDir, 'requirements.txt')) ||
|
|
220
|
-
await fs.pathExists(path.join(projectDir, 'setup.py')))
|
|
221
|
-
return 'python';
|
|
222
|
-
return 'node'; // fallback
|
|
223
|
-
}
|
|
224
261
|
//# sourceMappingURL=docker.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
/**
|
|
3
|
+
* Promisified `execFile` for shelling out to subprocesses with arguments
|
|
4
|
+
* (safer than `exec` because arguments are NOT shell-interpreted).
|
|
5
|
+
*
|
|
6
|
+
* Centralized helper used across the codebase by command modules and
|
|
7
|
+
* init steps that invoke external CLIs (git, javi-ai, etc.).
|
|
8
|
+
*/
|
|
9
|
+
export declare const execFileAsync: typeof execFile.__promisify__;
|
|
10
|
+
//# sourceMappingURL=exec.d.ts.map
|
package/dist/lib/exec.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
/**
|
|
4
|
+
* Promisified `execFile` for shelling out to subprocesses with arguments
|
|
5
|
+
* (safer than `exec` because arguments are NOT shell-interpreted).
|
|
6
|
+
*
|
|
7
|
+
* Centralized helper used across the codebase by command modules and
|
|
8
|
+
* init steps that invoke external CLIs (git, javi-ai, etc.).
|
|
9
|
+
*/
|
|
10
|
+
export const execFileAsync = promisify(execFile);
|
|
11
|
+
//# sourceMappingURL=exec.js.map
|
|
@@ -14,5 +14,5 @@ export interface ValidationError {
|
|
|
14
14
|
/**
|
|
15
15
|
* Validate frontmatter against schema rules for agent or skill definitions.
|
|
16
16
|
*/
|
|
17
|
-
export declare function validateFrontmatter(frontmatter: Record<string, unknown>, type:
|
|
17
|
+
export declare function validateFrontmatter(frontmatter: Record<string, unknown>, type: "agent" | "skill"): ValidationError[];
|
|
18
18
|
//# sourceMappingURL=frontmatter.d.ts.map
|