javi-forge 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -3
- package/ci-local/hooks/pre-push +17 -13
- package/dist/commands/analyze.d.ts +1 -1
- package/dist/commands/analyze.js +15 -15
- package/dist/commands/atlassian-mcp.d.ts +42 -0
- package/dist/commands/atlassian-mcp.js +98 -0
- package/dist/commands/ci.d.ts +3 -3
- package/dist/commands/ci.js +185 -147
- package/dist/commands/crash-recovery.d.ts +34 -0
- package/dist/commands/crash-recovery.js +123 -0
- package/dist/commands/doctor.d.ts +2 -2
- package/dist/commands/doctor.js +113 -61
- package/dist/commands/harness-audit.d.ts +35 -0
- package/dist/commands/harness-audit.js +277 -0
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +415 -118
- package/dist/commands/llmstxt.d.ts +1 -1
- package/dist/commands/llmstxt.js +36 -34
- package/dist/commands/parallel-batch.d.ts +42 -0
- package/dist/commands/parallel-batch.js +90 -0
- package/dist/commands/plugin.d.ts +26 -1
- package/dist/commands/plugin.js +138 -24
- package/dist/commands/secret-scanner.d.ts +30 -0
- package/dist/commands/secret-scanner.js +272 -0
- package/dist/commands/security-analysis.d.ts +74 -0
- package/dist/commands/security-analysis.js +487 -0
- package/dist/commands/security.d.ts +31 -0
- package/dist/commands/security.js +445 -0
- package/dist/commands/skill-scanner.d.ts +63 -0
- package/dist/commands/skill-scanner.js +383 -0
- package/dist/commands/skills.d.ts +139 -0
- package/dist/commands/skills.js +895 -0
- package/dist/commands/supply-chain.d.ts +23 -0
- package/dist/commands/supply-chain.js +126 -0
- package/dist/commands/tdd-pipeline.d.ts +17 -0
- package/dist/commands/tdd-pipeline.js +144 -0
- package/dist/commands/tdd.d.ts +21 -0
- package/dist/commands/tdd.js +120 -0
- package/dist/commands/team-presets.d.ts +53 -0
- package/dist/commands/team-presets.js +201 -0
- package/dist/commands/workflow.d.ts +23 -0
- package/dist/commands/workflow.js +114 -0
- package/dist/constants.d.ts +21 -0
- package/dist/constants.js +208 -37
- package/dist/index.js +400 -54
- package/dist/lib/agent-skills.d.ts +73 -0
- package/dist/lib/agent-skills.js +260 -0
- package/dist/lib/auto-skill-install.d.ts +37 -0
- package/dist/lib/auto-skill-install.js +92 -0
- package/dist/lib/auto-wire.d.ts +20 -0
- package/dist/lib/auto-wire.js +240 -0
- package/dist/lib/claudemd.d.ts +20 -0
- package/dist/lib/claudemd.js +222 -0
- package/dist/lib/codex-export.d.ts +16 -0
- package/dist/lib/codex-export.js +109 -0
- package/dist/lib/common.d.ts +1 -1
- package/dist/lib/common.js +52 -44
- package/dist/lib/context.d.ts +27 -0
- package/dist/lib/context.js +204 -0
- package/dist/lib/docker.d.ts +1 -1
- package/dist/lib/docker.js +141 -112
- package/dist/lib/frontmatter.d.ts +1 -1
- package/dist/lib/frontmatter.js +29 -15
- package/dist/lib/plugin.d.ts +19 -1
- package/dist/lib/plugin.js +174 -47
- package/dist/lib/skill-publish.d.ts +40 -0
- package/dist/lib/skill-publish.js +146 -0
- package/dist/lib/stack-detector.d.ts +38 -0
- package/dist/lib/stack-detector.js +207 -0
- package/dist/lib/template.d.ts +16 -1
- package/dist/lib/template.js +46 -17
- package/dist/lib/workflow/discovery.d.ts +19 -0
- package/dist/lib/workflow/discovery.js +68 -0
- package/dist/lib/workflow/index.d.ts +5 -0
- package/dist/lib/workflow/index.js +5 -0
- package/dist/lib/workflow/parser.d.ts +16 -0
- package/dist/lib/workflow/parser.js +198 -0
- package/dist/lib/workflow/renderer.d.ts +9 -0
- package/dist/lib/workflow/renderer.js +152 -0
- package/dist/lib/workflow/validator.d.ts +10 -0
- package/dist/lib/workflow/validator.js +189 -0
- package/dist/tasks/index.d.ts +4 -0
- package/dist/tasks/index.js +4 -0
- package/dist/tasks/scaffold-tasks.d.ts +3 -0
- package/dist/tasks/scaffold-tasks.js +14 -0
- package/dist/tasks/task-id.d.ts +30 -0
- package/dist/tasks/task-id.js +55 -0
- package/dist/tasks/task-tracker.d.ts +15 -0
- package/dist/tasks/task-tracker.js +81 -0
- package/dist/types/index.d.ts +252 -5
- 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 +92 -46
- package/dist/ui/AutoSkills.d.ts +9 -0
- package/dist/ui/AutoSkills.js +124 -0
- package/dist/ui/CI.d.ts +2 -2
- package/dist/ui/CI.js +24 -26
- package/dist/ui/CIContext.d.ts +1 -1
- package/dist/ui/CIContext.js +3 -2
- package/dist/ui/CISelector.d.ts +2 -2
- package/dist/ui/CISelector.js +23 -15
- package/dist/ui/Doctor.d.ts +1 -1
- package/dist/ui/Doctor.js +35 -29
- package/dist/ui/Header.d.ts +1 -1
- package/dist/ui/Header.js +14 -14
- package/dist/ui/HookProfileSelector.d.ts +9 -0
- package/dist/ui/HookProfileSelector.js +54 -0
- package/dist/ui/LlmsTxt.d.ts +1 -1
- package/dist/ui/LlmsTxt.js +31 -22
- package/dist/ui/MemorySelector.d.ts +2 -2
- package/dist/ui/MemorySelector.js +28 -16
- package/dist/ui/NameInput.d.ts +1 -1
- package/dist/ui/NameInput.js +21 -21
- package/dist/ui/OptionSelector.d.ts +8 -2
- package/dist/ui/OptionSelector.js +83 -26
- package/dist/ui/Plugin.d.ts +4 -3
- package/dist/ui/Plugin.js +89 -29
- package/dist/ui/Progress.d.ts +3 -3
- package/dist/ui/Progress.js +23 -22
- package/dist/ui/Skills.d.ts +11 -0
- package/dist/ui/Skills.js +148 -0
- package/dist/ui/StackSelector.d.ts +2 -2
- package/dist/ui/StackSelector.js +26 -16
- package/dist/ui/Summary.d.ts +3 -3
- package/dist/ui/Summary.js +60 -50
- package/dist/ui/Welcome.d.ts +1 -1
- package/dist/ui/Welcome.js +15 -16
- package/dist/ui/theme.d.ts +1 -1
- package/dist/ui/theme.js +6 -6
- package/package.json +9 -6
- package/templates/common/atlassian/mcp-atlassian-snippet.json +16 -0
- package/templates/common/repoforge/mcp-repoforge-snippet.json +11 -0
- package/templates/common/repoforge/repoforge.yaml +34 -0
- package/templates/github/deploy-docker-zero-downtime.yml +140 -0
- package/templates/github/repoforge-graph.yml +45 -0
- package/templates/gitlab/deploy-docker-zero-downtime.yml +57 -0
- package/templates/local-ai/.env.example +17 -0
- package/templates/local-ai/docker-compose.yml +95 -0
- package/templates/security-hooks/claude-settings-security.json +30 -0
- package/templates/security-hooks/commit-msg-signing +29 -0
- package/templates/security-hooks/pre-commit-permissions +74 -0
- package/templates/security-hooks/pre-commit-secrets +74 -0
- package/templates/security-hooks/pre-push-branch-protection +62 -0
- package/templates/security-hooks/pre-push-deps +83 -0
- package/templates/security-hooks/pre-push-signing +67 -0
- package/templates/woodpecker/deploy-docker-zero-downtime.yml +50 -0
- package/templates/workflows/ci-pipeline.dot +15 -0
- package/templates/workflows/feature-flow.dot +21 -0
- package/templates/workflows/release.dot +16 -0
- package/dist/__integration__/helpers.d.ts +0 -20
- package/dist/__integration__/helpers.d.ts.map +0 -1
- package/dist/__integration__/helpers.js +0 -31
- package/dist/__integration__/helpers.js.map +0 -1
- package/dist/commands/analyze.d.ts.map +0 -1
- package/dist/commands/analyze.js.map +0 -1
- package/dist/commands/ci.d.ts.map +0 -1
- package/dist/commands/ci.js.map +0 -1
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/llmstxt.d.ts.map +0 -1
- package/dist/commands/llmstxt.js.map +0 -1
- package/dist/commands/plugin.d.ts.map +0 -1
- package/dist/commands/plugin.js.map +0 -1
- package/dist/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/common.d.ts.map +0 -1
- package/dist/lib/common.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/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,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supply chain protection — configures Socket Firewall and enforces
|
|
3
|
+
* minimum package release age to protect against typosquatting,
|
|
4
|
+
* dependency confusion, and malicious package takeovers.
|
|
5
|
+
*/
|
|
6
|
+
import type { Stack } from "../types/index.js";
|
|
7
|
+
export type PackageManager = "npm" | "pnpm" | "yarn" | "pip" | "cargo" | "go";
|
|
8
|
+
export interface SupplyChainConfig {
|
|
9
|
+
packageManager: PackageManager;
|
|
10
|
+
minReleaseAgeHours: number;
|
|
11
|
+
socketEnabled: boolean;
|
|
12
|
+
enforceLockfile: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface SupplyChainResult {
|
|
15
|
+
configWritten: string[];
|
|
16
|
+
warnings: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare function detectPackageManager(projectDir: string): PackageManager;
|
|
19
|
+
export declare function stackForPM(pm: PackageManager): Stack;
|
|
20
|
+
export declare function buildSocketConfig(pm: PackageManager): Record<string, unknown>;
|
|
21
|
+
export declare function buildNpmrcLines(minAgeHours: number): string[];
|
|
22
|
+
export declare function configureSupplyChain(projectDir: string, options?: Partial<SupplyChainConfig>): Promise<SupplyChainResult>;
|
|
23
|
+
//# sourceMappingURL=supply-chain.d.ts.map
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supply chain protection — configures Socket Firewall and enforces
|
|
3
|
+
* minimum package release age to protect against typosquatting,
|
|
4
|
+
* dependency confusion, and malicious package takeovers.
|
|
5
|
+
*/
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
import path from "path";
|
|
8
|
+
// ── Detection ──
|
|
9
|
+
export function detectPackageManager(projectDir) {
|
|
10
|
+
if (fs.existsSync(path.join(projectDir, "pnpm-lock.yaml")))
|
|
11
|
+
return "pnpm";
|
|
12
|
+
if (fs.existsSync(path.join(projectDir, "yarn.lock")))
|
|
13
|
+
return "yarn";
|
|
14
|
+
if (fs.existsSync(path.join(projectDir, "package-lock.json")))
|
|
15
|
+
return "npm";
|
|
16
|
+
if (fs.existsSync(path.join(projectDir, "Pipfile.lock")))
|
|
17
|
+
return "pip";
|
|
18
|
+
if (fs.existsSync(path.join(projectDir, "Cargo.lock")))
|
|
19
|
+
return "cargo";
|
|
20
|
+
if (fs.existsSync(path.join(projectDir, "go.sum")))
|
|
21
|
+
return "go";
|
|
22
|
+
if (fs.existsSync(path.join(projectDir, "package.json")))
|
|
23
|
+
return "npm";
|
|
24
|
+
return "npm";
|
|
25
|
+
}
|
|
26
|
+
export function stackForPM(pm) {
|
|
27
|
+
switch (pm) {
|
|
28
|
+
case "npm":
|
|
29
|
+
case "pnpm":
|
|
30
|
+
case "yarn":
|
|
31
|
+
return "node";
|
|
32
|
+
case "pip":
|
|
33
|
+
return "python";
|
|
34
|
+
case "cargo":
|
|
35
|
+
return "rust";
|
|
36
|
+
case "go":
|
|
37
|
+
return "go";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// ── Socket Firewall config ──
|
|
41
|
+
export function buildSocketConfig(pm) {
|
|
42
|
+
return {
|
|
43
|
+
version: 2,
|
|
44
|
+
projectType: stackForPM(pm),
|
|
45
|
+
issueRules: {
|
|
46
|
+
"pkg:npm/*": {
|
|
47
|
+
installScripts: "error",
|
|
48
|
+
telemetry: "warn",
|
|
49
|
+
troll: "error",
|
|
50
|
+
unpublished: "error",
|
|
51
|
+
deprecated: "warn",
|
|
52
|
+
unmaintained: "warn",
|
|
53
|
+
"new-author": "warn",
|
|
54
|
+
shellAccess: "error",
|
|
55
|
+
filesystemAccess: "warn",
|
|
56
|
+
networkAccess: "warn",
|
|
57
|
+
envAccess: "warn",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// ── npmrc / lockfile enforcement ──
|
|
63
|
+
export function buildNpmrcLines(minAgeHours) {
|
|
64
|
+
const lines = [
|
|
65
|
+
"# Supply chain protection — generated by javi-forge",
|
|
66
|
+
"engine-strict=true",
|
|
67
|
+
"save-exact=true",
|
|
68
|
+
];
|
|
69
|
+
if (minAgeHours > 0) {
|
|
70
|
+
lines.push(`# Minimum package age: ${minAgeHours}h (enforced via CI/pre-install hook)`);
|
|
71
|
+
}
|
|
72
|
+
return lines;
|
|
73
|
+
}
|
|
74
|
+
// ── Orchestrator ──
|
|
75
|
+
export async function configureSupplyChain(projectDir, options = {}) {
|
|
76
|
+
const pm = options.packageManager ?? detectPackageManager(projectDir);
|
|
77
|
+
const minAge = options.minReleaseAgeHours ?? 48;
|
|
78
|
+
const socketEnabled = options.socketEnabled ?? true;
|
|
79
|
+
const enforceLockfile = options.enforceLockfile ?? true;
|
|
80
|
+
const configWritten = [];
|
|
81
|
+
const warnings = [];
|
|
82
|
+
// 1. Socket Firewall config
|
|
83
|
+
if (socketEnabled) {
|
|
84
|
+
const socketPath = path.join(projectDir, ".socketrc");
|
|
85
|
+
await fs.writeJson(socketPath, buildSocketConfig(pm), { spaces: 2 });
|
|
86
|
+
configWritten.push(".socketrc");
|
|
87
|
+
}
|
|
88
|
+
// 2. npmrc for node projects
|
|
89
|
+
if (stackForPM(pm) === "node") {
|
|
90
|
+
const npmrcPath = path.join(projectDir, ".npmrc");
|
|
91
|
+
const lines = buildNpmrcLines(minAge);
|
|
92
|
+
if (enforceLockfile) {
|
|
93
|
+
if (pm === "pnpm") {
|
|
94
|
+
lines.push("frozen-lockfile=true");
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
lines.push("package-lock=true");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Append to existing .npmrc if present
|
|
101
|
+
const existing = (await fs.pathExists(npmrcPath))
|
|
102
|
+
? await fs.readFile(npmrcPath, "utf-8")
|
|
103
|
+
: "";
|
|
104
|
+
const newContent = existing
|
|
105
|
+
? `${existing.trimEnd()}\n\n${lines.join("\n")}\n`
|
|
106
|
+
: `${lines.join("\n")}\n`;
|
|
107
|
+
await fs.writeFile(npmrcPath, newContent);
|
|
108
|
+
configWritten.push(".npmrc");
|
|
109
|
+
}
|
|
110
|
+
// 3. Supply chain metadata in baseline dir
|
|
111
|
+
const metaPath = path.join(projectDir, ".javi-forge", "supply-chain.json");
|
|
112
|
+
await fs.ensureDir(path.dirname(metaPath));
|
|
113
|
+
await fs.writeJson(metaPath, {
|
|
114
|
+
packageManager: pm,
|
|
115
|
+
minReleaseAgeHours: minAge,
|
|
116
|
+
socketEnabled,
|
|
117
|
+
enforceLockfile,
|
|
118
|
+
configuredAt: new Date().toISOString(),
|
|
119
|
+
}, { spaces: 2 });
|
|
120
|
+
configWritten.push(".javi-forge/supply-chain.json");
|
|
121
|
+
if (!socketEnabled) {
|
|
122
|
+
warnings.push("Socket Firewall disabled. Consider enabling it for supply chain protection.");
|
|
123
|
+
}
|
|
124
|
+
return { configWritten, warnings };
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=supply-chain.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Stack, TddPipelineMode, TddPipelineResult } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generate a TDD pipeline enforcement pre-push hook script.
|
|
4
|
+
*
|
|
5
|
+
* - strict: tests MUST pass or push is blocked (exit 1).
|
|
6
|
+
* - warn: tests are run and results shown, but push is never blocked.
|
|
7
|
+
*
|
|
8
|
+
* If testCmd is null, generates a skip-only hook regardless of mode.
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateTddPipelineHook(mode: TddPipelineMode, testCmd: string | null, stack: Stack): string;
|
|
11
|
+
/**
|
|
12
|
+
* Install TDD pipeline pre-push hook into .git/hooks/.
|
|
13
|
+
* Detects the project stack automatically and generates the appropriate hook.
|
|
14
|
+
* Backs up any existing pre-push hook to pre-push.bak.
|
|
15
|
+
*/
|
|
16
|
+
export declare function installTddPipelineHook(projectDir: string, mode: TddPipelineMode): Promise<TddPipelineResult>;
|
|
17
|
+
//# sourceMappingURL=tdd-pipeline.d.ts.map
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { detectCIStack } from "./ci.js";
|
|
4
|
+
import { getTddTestCommand } from "./tdd.js";
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// Hook generation
|
|
7
|
+
// =============================================================================
|
|
8
|
+
/**
|
|
9
|
+
* Generate a TDD pipeline enforcement pre-push hook script.
|
|
10
|
+
*
|
|
11
|
+
* - strict: tests MUST pass or push is blocked (exit 1).
|
|
12
|
+
* - warn: tests are run and results shown, but push is never blocked.
|
|
13
|
+
*
|
|
14
|
+
* If testCmd is null, generates a skip-only hook regardless of mode.
|
|
15
|
+
*/
|
|
16
|
+
export function generateTddPipelineHook(mode, testCmd, stack) {
|
|
17
|
+
if (!testCmd) {
|
|
18
|
+
return `#!/bin/bash
|
|
19
|
+
# =============================================================================
|
|
20
|
+
# TDD PIPELINE (pre-push): No test command detected for stack "${stack}"
|
|
21
|
+
# =============================================================================
|
|
22
|
+
# Install a test runner and re-run: javi-forge tdd pipeline --mode ${mode}
|
|
23
|
+
# =============================================================================
|
|
24
|
+
|
|
25
|
+
echo "TDD PIPELINE: No test command configured for stack '${stack}' — skipping."
|
|
26
|
+
exit 0
|
|
27
|
+
`;
|
|
28
|
+
}
|
|
29
|
+
if (mode === "warn") {
|
|
30
|
+
return `#!/bin/bash
|
|
31
|
+
# =============================================================================
|
|
32
|
+
# TDD PIPELINE (pre-push): WARN mode
|
|
33
|
+
# =============================================================================
|
|
34
|
+
# Flow: Spec → Tests → Fail → Implement → Pass
|
|
35
|
+
# Stack: ${stack} | Command: ${testCmd}
|
|
36
|
+
# Mode: warn — tests run but push is NEVER blocked
|
|
37
|
+
# To skip: git push --no-verify
|
|
38
|
+
# =============================================================================
|
|
39
|
+
|
|
40
|
+
echo "TDD PIPELINE [WARN]: Running tests before push..."
|
|
41
|
+
echo " Stack: ${stack}"
|
|
42
|
+
echo " Command: ${testCmd}"
|
|
43
|
+
echo " Mode: warn (push will proceed regardless)"
|
|
44
|
+
echo ""
|
|
45
|
+
|
|
46
|
+
${testCmd} && {
|
|
47
|
+
echo ""
|
|
48
|
+
echo "TDD PIPELINE [WARN]: All tests passed."
|
|
49
|
+
} || {
|
|
50
|
+
echo ""
|
|
51
|
+
echo "TDD PIPELINE [WARN]: Tests FAILED — but push will proceed (warn mode)."
|
|
52
|
+
echo " Consider fixing tests before merging."
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
exit 0
|
|
56
|
+
`;
|
|
57
|
+
}
|
|
58
|
+
// strict mode (default)
|
|
59
|
+
return `#!/bin/bash
|
|
60
|
+
# =============================================================================
|
|
61
|
+
# TDD PIPELINE (pre-push): STRICT mode
|
|
62
|
+
# =============================================================================
|
|
63
|
+
# Flow: Spec → Tests → Fail → Implement → Pass
|
|
64
|
+
# Stack: ${stack} | Command: ${testCmd}
|
|
65
|
+
# Mode: strict — push is BLOCKED if tests fail
|
|
66
|
+
# To skip: git push --no-verify
|
|
67
|
+
# =============================================================================
|
|
68
|
+
|
|
69
|
+
set -e
|
|
70
|
+
|
|
71
|
+
echo "TDD PIPELINE [STRICT]: Running tests before push..."
|
|
72
|
+
echo " Stack: ${stack}"
|
|
73
|
+
echo " Command: ${testCmd}"
|
|
74
|
+
echo " Mode: strict (push blocked on failure)"
|
|
75
|
+
echo ""
|
|
76
|
+
|
|
77
|
+
${testCmd} || {
|
|
78
|
+
echo ""
|
|
79
|
+
echo "TDD PIPELINE [STRICT]: FAILED — Tests did not pass."
|
|
80
|
+
echo " Fix failing tests before pushing."
|
|
81
|
+
echo " To skip: git push --no-verify"
|
|
82
|
+
exit 1
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
echo ""
|
|
86
|
+
echo "TDD PIPELINE [STRICT]: All tests passed. Push allowed."
|
|
87
|
+
`;
|
|
88
|
+
}
|
|
89
|
+
// =============================================================================
|
|
90
|
+
// Hook installation
|
|
91
|
+
// =============================================================================
|
|
92
|
+
/**
|
|
93
|
+
* Install TDD pipeline pre-push hook into .git/hooks/.
|
|
94
|
+
* Detects the project stack automatically and generates the appropriate hook.
|
|
95
|
+
* Backs up any existing pre-push hook to pre-push.bak.
|
|
96
|
+
*/
|
|
97
|
+
export async function installTddPipelineHook(projectDir, mode) {
|
|
98
|
+
const result = {
|
|
99
|
+
installed: [],
|
|
100
|
+
skipped: [],
|
|
101
|
+
errors: [],
|
|
102
|
+
mode,
|
|
103
|
+
};
|
|
104
|
+
const gitDir = path.join(projectDir, ".git");
|
|
105
|
+
if (!(await fs.pathExists(gitDir))) {
|
|
106
|
+
result.errors.push("Not a git repository. Run git init first.");
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
const hooksDir = path.join(gitDir, "hooks");
|
|
110
|
+
await fs.ensureDir(hooksDir);
|
|
111
|
+
// Detect stack
|
|
112
|
+
let stackInfo;
|
|
113
|
+
try {
|
|
114
|
+
stackInfo = await detectCIStack(projectDir);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
result.errors.push("Failed to detect project stack.");
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
const testCmd = await getTddTestCommand(stackInfo.stackType, stackInfo.buildTool, projectDir);
|
|
121
|
+
const hookContent = generateTddPipelineHook(mode, testCmd, stackInfo.stackType);
|
|
122
|
+
const hookPath = path.join(hooksDir, "pre-push");
|
|
123
|
+
// Backup existing hook
|
|
124
|
+
if (await fs.pathExists(hookPath)) {
|
|
125
|
+
const backupPath = path.join(hooksDir, "pre-push.bak");
|
|
126
|
+
try {
|
|
127
|
+
await fs.copy(hookPath, backupPath, { overwrite: true });
|
|
128
|
+
result.skipped.push("pre-push (backed up to pre-push.bak)");
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
result.errors.push(`backup: ${e instanceof Error ? e.message : String(e)}`);
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
await fs.writeFile(hookPath, hookContent, { mode: 0o755 });
|
|
137
|
+
result.installed.push("pre-push");
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
result.errors.push(`pre-push: ${e instanceof Error ? e.message : String(e)}`);
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=tdd-pipeline.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Stack } from "../types/index.js";
|
|
2
|
+
export interface TddHookResult {
|
|
3
|
+
installed: string[];
|
|
4
|
+
errors: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the correct test command for TDD hook based on stack and build tool.
|
|
8
|
+
* Returns null if no test command can be determined.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getTddTestCommand(stack: Stack, buildTool: string, projectDir: string): Promise<string | null>;
|
|
11
|
+
/**
|
|
12
|
+
* Generate a TDD-enforcing pre-commit hook script.
|
|
13
|
+
* If testCmd is null, generates a warning-only hook.
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateTddHook(testCmd: string | null, stack: Stack): string;
|
|
16
|
+
/**
|
|
17
|
+
* Install TDD pre-commit hook into .git/hooks/.
|
|
18
|
+
* Detects the project stack automatically and generates the appropriate hook.
|
|
19
|
+
*/
|
|
20
|
+
export declare function installTddHooks(projectDir: string): Promise<TddHookResult>;
|
|
21
|
+
//# sourceMappingURL=tdd.d.ts.map
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { detectCIStack } from "./ci.js";
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// Test command resolution
|
|
6
|
+
// =============================================================================
|
|
7
|
+
/**
|
|
8
|
+
* Resolve the correct test command for TDD hook based on stack and build tool.
|
|
9
|
+
* Returns null if no test command can be determined.
|
|
10
|
+
*/
|
|
11
|
+
export async function getTddTestCommand(stack, buildTool, projectDir) {
|
|
12
|
+
switch (stack) {
|
|
13
|
+
case "node": {
|
|
14
|
+
const pkgPath = path.join(projectDir, "package.json");
|
|
15
|
+
try {
|
|
16
|
+
const pkgContent = await fs.readFile(pkgPath, "utf-8");
|
|
17
|
+
if (!pkgContent.includes('"test"'))
|
|
18
|
+
return null;
|
|
19
|
+
return buildTool === "npm" ? "npm test" : `${buildTool} run test`;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
case "python":
|
|
26
|
+
return "pytest";
|
|
27
|
+
case "go":
|
|
28
|
+
return "go test ./...";
|
|
29
|
+
default:
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// Hook generation
|
|
35
|
+
// =============================================================================
|
|
36
|
+
/**
|
|
37
|
+
* Generate a TDD-enforcing pre-commit hook script.
|
|
38
|
+
* If testCmd is null, generates a warning-only hook.
|
|
39
|
+
*/
|
|
40
|
+
export function generateTddHook(testCmd, stack) {
|
|
41
|
+
if (!testCmd) {
|
|
42
|
+
return `#!/bin/bash
|
|
43
|
+
# =============================================================================
|
|
44
|
+
# TDD PRE-COMMIT: No test command detected for stack "${stack}"
|
|
45
|
+
# =============================================================================
|
|
46
|
+
# Install a test runner and re-run: javi-forge tdd init
|
|
47
|
+
# =============================================================================
|
|
48
|
+
|
|
49
|
+
echo "TDD HOOK: No test command configured for stack '${stack}' — skipping."
|
|
50
|
+
exit 0
|
|
51
|
+
`;
|
|
52
|
+
}
|
|
53
|
+
return `#!/bin/bash
|
|
54
|
+
# =============================================================================
|
|
55
|
+
# TDD PRE-COMMIT: Enforced test-driven development
|
|
56
|
+
# =============================================================================
|
|
57
|
+
# Flow: Tests MUST pass before commit is allowed.
|
|
58
|
+
# Stack: ${stack} | Command: ${testCmd}
|
|
59
|
+
# To skip: git commit --no-verify
|
|
60
|
+
# =============================================================================
|
|
61
|
+
|
|
62
|
+
set -e
|
|
63
|
+
|
|
64
|
+
echo "TDD PRE-COMMIT: Running tests..."
|
|
65
|
+
echo " Stack: ${stack}"
|
|
66
|
+
echo " Command: ${testCmd}"
|
|
67
|
+
echo ""
|
|
68
|
+
|
|
69
|
+
${testCmd} || {
|
|
70
|
+
echo ""
|
|
71
|
+
echo "TDD FAILED — Tests did not pass."
|
|
72
|
+
echo " Fix failing tests before committing."
|
|
73
|
+
echo " To skip: git commit --no-verify"
|
|
74
|
+
exit 1
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
echo ""
|
|
78
|
+
echo "TDD PASSED — All tests green. Commit allowed."
|
|
79
|
+
`;
|
|
80
|
+
}
|
|
81
|
+
// =============================================================================
|
|
82
|
+
// Hook installation
|
|
83
|
+
// =============================================================================
|
|
84
|
+
/**
|
|
85
|
+
* Install TDD pre-commit hook into .git/hooks/.
|
|
86
|
+
* Detects the project stack automatically and generates the appropriate hook.
|
|
87
|
+
*/
|
|
88
|
+
export async function installTddHooks(projectDir) {
|
|
89
|
+
const gitDir = path.join(projectDir, ".git");
|
|
90
|
+
if (!(await fs.pathExists(gitDir))) {
|
|
91
|
+
return {
|
|
92
|
+
installed: [],
|
|
93
|
+
errors: ["Not a git repository. Run git init first."],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const hooksDir = path.join(gitDir, "hooks");
|
|
97
|
+
await fs.ensureDir(hooksDir);
|
|
98
|
+
// Detect stack
|
|
99
|
+
let stackInfo;
|
|
100
|
+
try {
|
|
101
|
+
stackInfo = await detectCIStack(projectDir);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return { installed: [], errors: ["Failed to detect project stack."] };
|
|
105
|
+
}
|
|
106
|
+
const testCmd = await getTddTestCommand(stackInfo.stackType, stackInfo.buildTool, projectDir);
|
|
107
|
+
const hookContent = generateTddHook(testCmd, stackInfo.stackType);
|
|
108
|
+
const installed = [];
|
|
109
|
+
const errors = [];
|
|
110
|
+
const hookPath = path.join(hooksDir, "pre-commit");
|
|
111
|
+
try {
|
|
112
|
+
await fs.writeFile(hookPath, hookContent, { mode: 0o755 });
|
|
113
|
+
installed.push("pre-commit");
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
errors.push(`pre-commit: ${e instanceof Error ? e.message : String(e)}`);
|
|
117
|
+
}
|
|
118
|
+
return { installed, errors };
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=tdd.js.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Teams parallel dispatch presets — predefined team configurations
|
|
3
|
+
* for common workflows like review, debug, and security scanning.
|
|
4
|
+
*
|
|
5
|
+
* Each preset defines which sub-agents to spawn in parallel, their roles,
|
|
6
|
+
* and how to aggregate results.
|
|
7
|
+
*/
|
|
8
|
+
export interface AgentRole {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
skill: string;
|
|
12
|
+
perspective: string;
|
|
13
|
+
priority: "critical" | "high" | "medium" | "low";
|
|
14
|
+
}
|
|
15
|
+
export interface TeamPreset {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
roles: AgentRole[];
|
|
19
|
+
aggregation: "all-must-pass" | "majority" | "any-pass";
|
|
20
|
+
maxParallel: number;
|
|
21
|
+
}
|
|
22
|
+
export interface TeamDispatch {
|
|
23
|
+
preset: string;
|
|
24
|
+
roles: AgentRole[];
|
|
25
|
+
targetFiles: string[];
|
|
26
|
+
context: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
export interface AgentResult {
|
|
29
|
+
roleId: string;
|
|
30
|
+
roleName: string;
|
|
31
|
+
passed: boolean;
|
|
32
|
+
findings: string[];
|
|
33
|
+
severity: "critical" | "high" | "medium" | "low" | "info";
|
|
34
|
+
durationMs: number;
|
|
35
|
+
}
|
|
36
|
+
export interface TeamResult {
|
|
37
|
+
preset: string;
|
|
38
|
+
passed: boolean;
|
|
39
|
+
agents: AgentResult[];
|
|
40
|
+
totalDurationMs: number;
|
|
41
|
+
summary: string;
|
|
42
|
+
}
|
|
43
|
+
export declare const TEAM_PRESETS: Record<string, TeamPreset>;
|
|
44
|
+
export declare function getPreset(name: string): TeamPreset | null;
|
|
45
|
+
export declare function listPresets(): Array<{
|
|
46
|
+
name: string;
|
|
47
|
+
description: string;
|
|
48
|
+
roleCount: number;
|
|
49
|
+
}>;
|
|
50
|
+
export declare function createDispatch(presetName: string, targetFiles: string[], context?: Record<string, string>): TeamDispatch | null;
|
|
51
|
+
export declare function aggregateResults(preset: TeamPreset, results: AgentResult[]): TeamResult;
|
|
52
|
+
export declare function formatTeamResult(result: TeamResult): string;
|
|
53
|
+
//# sourceMappingURL=team-presets.d.ts.map
|