@ipation/specbridge 1.0.4 → 1.0.5
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/dist/cli.js +117 -113
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2762,38 +2762,22 @@ npx specbridge hook run --level commit --files "$STAGED_FILES"
|
|
|
2762
2762
|
|
|
2763
2763
|
exit $?
|
|
2764
2764
|
`;
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
hookContent = HOOK_SCRIPT;
|
|
2778
|
-
spinner.text = "Installing husky pre-commit hook...";
|
|
2779
|
-
} else if (options.lefthook) {
|
|
2780
|
-
spinner.succeed("Lefthook detected");
|
|
2781
|
-
console.log("");
|
|
2782
|
-
console.log(chalk8.cyan("Add this to your lefthook.yml:"));
|
|
2783
|
-
console.log("");
|
|
2784
|
-
console.log(chalk8.dim(`pre-commit:
|
|
2785
|
-
commands:
|
|
2786
|
-
specbridge:
|
|
2787
|
-
glob: "*.{ts,tsx}"
|
|
2788
|
-
run: npx specbridge hook run --level commit --files {staged_files}
|
|
2789
|
-
`));
|
|
2790
|
-
return;
|
|
2791
|
-
} else {
|
|
2792
|
-
if (await pathExists(join7(cwd, ".husky"))) {
|
|
2765
|
+
function createHookCommand() {
|
|
2766
|
+
const hookCommand2 = new Command9("hook").description("Manage Git hooks for verification");
|
|
2767
|
+
hookCommand2.command("install").description("Install Git pre-commit hook").option("-f, --force", "Overwrite existing hook").option("--husky", "Install for husky").option("--lefthook", "Install for lefthook").action(async (options) => {
|
|
2768
|
+
const cwd = process.cwd();
|
|
2769
|
+
if (!await pathExists(getSpecBridgeDir(cwd))) {
|
|
2770
|
+
throw new NotInitializedError();
|
|
2771
|
+
}
|
|
2772
|
+
const spinner = ora5("Detecting hook system...").start();
|
|
2773
|
+
try {
|
|
2774
|
+
let hookPath;
|
|
2775
|
+
let hookContent;
|
|
2776
|
+
if (options.husky) {
|
|
2793
2777
|
hookPath = join7(cwd, ".husky", "pre-commit");
|
|
2794
2778
|
hookContent = HOOK_SCRIPT;
|
|
2795
2779
|
spinner.text = "Installing husky pre-commit hook...";
|
|
2796
|
-
} else if (
|
|
2780
|
+
} else if (options.lefthook) {
|
|
2797
2781
|
spinner.succeed("Lefthook detected");
|
|
2798
2782
|
console.log("");
|
|
2799
2783
|
console.log(chalk8.cyan("Add this to your lefthook.yml:"));
|
|
@@ -2806,97 +2790,117 @@ hookCommand.command("install").description("Install Git pre-commit hook").option
|
|
|
2806
2790
|
`));
|
|
2807
2791
|
return;
|
|
2808
2792
|
} else {
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2793
|
+
if (await pathExists(join7(cwd, ".husky"))) {
|
|
2794
|
+
hookPath = join7(cwd, ".husky", "pre-commit");
|
|
2795
|
+
hookContent = HOOK_SCRIPT;
|
|
2796
|
+
spinner.text = "Installing husky pre-commit hook...";
|
|
2797
|
+
} else if (await pathExists(join7(cwd, "lefthook.yml"))) {
|
|
2798
|
+
spinner.succeed("Lefthook detected");
|
|
2799
|
+
console.log("");
|
|
2800
|
+
console.log(chalk8.cyan("Add this to your lefthook.yml:"));
|
|
2801
|
+
console.log("");
|
|
2802
|
+
console.log(chalk8.dim(`pre-commit:
|
|
2803
|
+
commands:
|
|
2804
|
+
specbridge:
|
|
2805
|
+
glob: "*.{ts,tsx}"
|
|
2806
|
+
run: npx specbridge hook run --level commit --files {staged_files}
|
|
2807
|
+
`));
|
|
2808
|
+
return;
|
|
2809
|
+
} else {
|
|
2810
|
+
hookPath = join7(cwd, ".git", "hooks", "pre-commit");
|
|
2811
|
+
hookContent = HOOK_SCRIPT;
|
|
2812
|
+
spinner.text = "Installing Git pre-commit hook...";
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
if (await pathExists(hookPath) && !options.force) {
|
|
2816
|
+
spinner.fail("Hook already exists");
|
|
2817
|
+
console.log(chalk8.yellow(`Use --force to overwrite: ${hookPath}`));
|
|
2818
|
+
return;
|
|
2812
2819
|
}
|
|
2820
|
+
await writeTextFile(hookPath, hookContent);
|
|
2821
|
+
const { execSync } = await import("child_process");
|
|
2822
|
+
try {
|
|
2823
|
+
execSync(`chmod +x "${hookPath}"`, { stdio: "ignore" });
|
|
2824
|
+
} catch {
|
|
2825
|
+
}
|
|
2826
|
+
spinner.succeed("Pre-commit hook installed");
|
|
2827
|
+
console.log(chalk8.dim(` Path: ${hookPath}`));
|
|
2828
|
+
console.log("");
|
|
2829
|
+
console.log(chalk8.cyan("The hook will run on each commit and verify staged files."));
|
|
2830
|
+
} catch (error) {
|
|
2831
|
+
spinner.fail("Failed to install hook");
|
|
2832
|
+
throw error;
|
|
2813
2833
|
}
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2834
|
+
});
|
|
2835
|
+
hookCommand2.command("run").description("Run verification (called by hook)").option("-l, --level <level>", "Verification level", "commit").option("-f, --files <files>", "Space or comma-separated file list").action(async (options) => {
|
|
2836
|
+
const cwd = process.cwd();
|
|
2837
|
+
if (!await pathExists(getSpecBridgeDir(cwd))) {
|
|
2838
|
+
throw new NotInitializedError();
|
|
2818
2839
|
}
|
|
2819
|
-
await writeTextFile(hookPath, hookContent);
|
|
2820
|
-
const { execSync } = await import("child_process");
|
|
2821
2840
|
try {
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
});
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
if (result.violations.length === 0) {
|
|
2853
|
-
console.log(chalk8.green("\u2713 SpecBridge: All checks passed"));
|
|
2854
|
-
process.exit(0);
|
|
2855
|
-
}
|
|
2856
|
-
console.log(chalk8.red(`\u2717 SpecBridge: ${result.violations.length} violation(s) found`));
|
|
2857
|
-
console.log("");
|
|
2858
|
-
for (const v of result.violations) {
|
|
2859
|
-
const location = v.line ? `:${v.line}` : "";
|
|
2860
|
-
console.log(` ${v.file}${location}: ${v.message}`);
|
|
2861
|
-
console.log(chalk8.dim(` [${v.severity}] ${v.decisionId}/${v.constraintId}`));
|
|
2841
|
+
const config = await loadConfig(cwd);
|
|
2842
|
+
const level = options.level || "commit";
|
|
2843
|
+
const files = options.files ? options.files.split(/[\s,]+/).filter((f) => f.length > 0) : void 0;
|
|
2844
|
+
if (!files || files.length === 0) {
|
|
2845
|
+
process.exit(0);
|
|
2846
|
+
}
|
|
2847
|
+
const engine = createVerificationEngine();
|
|
2848
|
+
const result = await engine.verify(config, {
|
|
2849
|
+
level,
|
|
2850
|
+
files,
|
|
2851
|
+
cwd
|
|
2852
|
+
});
|
|
2853
|
+
if (result.violations.length === 0) {
|
|
2854
|
+
console.log(chalk8.green("\u2713 SpecBridge: All checks passed"));
|
|
2855
|
+
process.exit(0);
|
|
2856
|
+
}
|
|
2857
|
+
console.log(chalk8.red(`\u2717 SpecBridge: ${result.violations.length} violation(s) found`));
|
|
2858
|
+
console.log("");
|
|
2859
|
+
for (const v of result.violations) {
|
|
2860
|
+
const location = v.line ? `:${v.line}` : "";
|
|
2861
|
+
console.log(` ${v.file}${location}: ${v.message}`);
|
|
2862
|
+
console.log(chalk8.dim(` [${v.severity}] ${v.decisionId}/${v.constraintId}`));
|
|
2863
|
+
}
|
|
2864
|
+
console.log("");
|
|
2865
|
+
console.log(chalk8.yellow("Run `specbridge verify` for full details."));
|
|
2866
|
+
process.exit(result.success ? 0 : 1);
|
|
2867
|
+
} catch (error) {
|
|
2868
|
+
console.error(chalk8.red("SpecBridge verification failed"));
|
|
2869
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
2870
|
+
process.exit(1);
|
|
2862
2871
|
}
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
process.
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
if (await pathExists(hookPath)) {
|
|
2883
|
-
const content = await readTextFile(hookPath);
|
|
2884
|
-
if (content.includes("SpecBridge")) {
|
|
2885
|
-
const { unlink } = await import("fs/promises");
|
|
2886
|
-
await unlink(hookPath);
|
|
2887
|
-
spinner.succeed(`Removed hook: ${hookPath}`);
|
|
2888
|
-
removed = true;
|
|
2872
|
+
});
|
|
2873
|
+
hookCommand2.command("uninstall").description("Remove Git pre-commit hook").action(async () => {
|
|
2874
|
+
const cwd = process.cwd();
|
|
2875
|
+
const spinner = ora5("Removing hook...").start();
|
|
2876
|
+
try {
|
|
2877
|
+
const hookPaths = [
|
|
2878
|
+
join7(cwd, ".husky", "pre-commit"),
|
|
2879
|
+
join7(cwd, ".git", "hooks", "pre-commit")
|
|
2880
|
+
];
|
|
2881
|
+
let removed = false;
|
|
2882
|
+
for (const hookPath of hookPaths) {
|
|
2883
|
+
if (await pathExists(hookPath)) {
|
|
2884
|
+
const content = await readTextFile(hookPath);
|
|
2885
|
+
if (content.includes("SpecBridge")) {
|
|
2886
|
+
const { unlink } = await import("fs/promises");
|
|
2887
|
+
await unlink(hookPath);
|
|
2888
|
+
spinner.succeed(`Removed hook: ${hookPath}`);
|
|
2889
|
+
removed = true;
|
|
2890
|
+
}
|
|
2889
2891
|
}
|
|
2890
2892
|
}
|
|
2893
|
+
if (!removed) {
|
|
2894
|
+
spinner.info("No SpecBridge hooks found");
|
|
2895
|
+
}
|
|
2896
|
+
} catch (error) {
|
|
2897
|
+
spinner.fail("Failed to remove hook");
|
|
2898
|
+
throw error;
|
|
2891
2899
|
}
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
spinner.fail("Failed to remove hook");
|
|
2897
|
-
throw error;
|
|
2898
|
-
}
|
|
2899
|
-
});
|
|
2900
|
+
});
|
|
2901
|
+
return hookCommand2;
|
|
2902
|
+
}
|
|
2903
|
+
var hookCommand = createHookCommand();
|
|
2900
2904
|
|
|
2901
2905
|
// src/cli/commands/report.ts
|
|
2902
2906
|
import { Command as Command10 } from "commander";
|
|
@@ -3303,7 +3307,7 @@ var contextCommand = new Command11("context").description("Generate architectura
|
|
|
3303
3307
|
const config = await loadConfig(cwd);
|
|
3304
3308
|
const output = await generateFormattedContext(file, config, {
|
|
3305
3309
|
format: options.format,
|
|
3306
|
-
includeRationale: options.
|
|
3310
|
+
includeRationale: options.rationale !== false,
|
|
3307
3311
|
cwd
|
|
3308
3312
|
});
|
|
3309
3313
|
if (options.output) {
|