musubix2 0.5.0 → 0.5.2
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/.claude/.musubix-managed +1 -1
- package/dist/assets/skills-manifest.json +1 -1
- package/dist/cli.d.ts +17 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +247 -112
- package/dist/cli.js.map +1 -1
- package/dist/index.js +245 -112
- package/dist/interface/cli/init-command-handler.d.ts +6 -0
- package/dist/interface/cli/init-command-handler.d.ts.map +1 -1
- package/dist/interface/cli/init-command-handler.js +61 -10
- package/dist/interface/cli/init-command-handler.js.map +1 -1
- package/dist/templates/claude-md.md +21 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -11780,8 +11780,8 @@ __export(init_command_handler_exports, {
|
|
|
11780
11780
|
InitCommandHandler: () => InitCommandHandler,
|
|
11781
11781
|
createInitCommandHandler: () => createInitCommandHandler
|
|
11782
11782
|
});
|
|
11783
|
-
import {
|
|
11784
|
-
import { basename } from "node:path";
|
|
11783
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, existsSync as existsSync10 } from "node:fs";
|
|
11784
|
+
import { basename, join as join5 } from "node:path";
|
|
11785
11785
|
function createInitCommandHandler() {
|
|
11786
11786
|
const locator = new PackageRootLocator();
|
|
11787
11787
|
const catalog = new PackageAssetCatalog(locator);
|
|
@@ -11800,7 +11800,7 @@ function createInitCommandHandler() {
|
|
|
11800
11800
|
const dryRunReporter = new DryRunReporter();
|
|
11801
11801
|
return new InitCommandHandler(detector, confirmation, planner, copilotSetup, claudeSetup, merger, writer, updateService, dryRunReporter);
|
|
11802
11802
|
}
|
|
11803
|
-
var InitCommandHandler;
|
|
11803
|
+
var STARTER_REQUIREMENTS, InitCommandHandler;
|
|
11804
11804
|
var init_init_command_handler = __esm({
|
|
11805
11805
|
"dist/interface/cli/init-command-handler.js"() {
|
|
11806
11806
|
"use strict";
|
|
@@ -11819,6 +11819,20 @@ var init_init_command_handler = __esm({
|
|
|
11819
11819
|
init_workspace_writer();
|
|
11820
11820
|
init_confirmation_resolver();
|
|
11821
11821
|
init_dry_run_reporter();
|
|
11822
|
+
STARTER_REQUIREMENTS = `# \u8981\u4EF6\u5B9A\u7FA9\u66F8
|
|
11823
|
+
|
|
11824
|
+
> \`musubix requirements analyze storage/specs/requirements.md\` \u3067\u89E3\u6790\u3067\u304D\u307E\u3059\u3002
|
|
11825
|
+
> \u8981\u4EF6\u306F\u898B\u51FA\u3057\u5F62\u5F0F\u30FBID \u306F \`REQ-<3\u6587\u5B57\u30C9\u30E1\u30A4\u30F3>-<3\u6841\u9023\u756A>\` \u3067\u8A18\u8FF0\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
11826
|
+
|
|
11827
|
+
## REQ-SMP-001: \u30B5\u30F3\u30D7\u30EB\u8981\u4EF6
|
|
11828
|
+
**\u7A2E\u5225**: UBIQUITOUS
|
|
11829
|
+
**\u512A\u5148\u5EA6**: P1
|
|
11830
|
+
**\u8981\u4EF6**:
|
|
11831
|
+
THE \u30B7\u30B9\u30C6\u30E0 SHALL \u30E6\u30FC\u30B6\u30FC\u306B\u30B5\u30F3\u30D7\u30EB\u6A5F\u80FD\u3092\u63D0\u4F9B\u3059\u308B\u3002
|
|
11832
|
+
|
|
11833
|
+
**\u53D7\u5165\u57FA\u6E96**:
|
|
11834
|
+
- [ ] \u30B5\u30F3\u30D7\u30EB\u6A5F\u80FD\u304C\u52D5\u4F5C\u3059\u308B
|
|
11835
|
+
`;
|
|
11822
11836
|
InitCommandHandler = class {
|
|
11823
11837
|
detector;
|
|
11824
11838
|
confirmation;
|
|
@@ -11886,22 +11900,49 @@ var init_init_command_handler = __esm({
|
|
|
11886
11900
|
await this.writer.execute(copilotOps, false);
|
|
11887
11901
|
}
|
|
11888
11902
|
const summary = await this.writer.execute([], true);
|
|
11903
|
+
const scaffolded = options.dryRun ? [] : this.scaffoldSddWorkspace(options.projectPath);
|
|
11889
11904
|
return {
|
|
11890
11905
|
detectedPlatforms: selection,
|
|
11891
|
-
created: summary.created,
|
|
11906
|
+
created: [...summary.created, ...scaffolded],
|
|
11892
11907
|
updated: summary.updated,
|
|
11893
11908
|
skipped: summary.skipped,
|
|
11894
11909
|
warnings,
|
|
11895
11910
|
durationMs: Date.now() - start
|
|
11896
11911
|
};
|
|
11897
11912
|
}
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11913
|
+
/**
|
|
11914
|
+
* Create the SDD directory skeleton and a parseable starter requirements
|
|
11915
|
+
* document. Idempotent and non-destructive — existing files are left as-is.
|
|
11916
|
+
* Returns the relative paths of files/dirs actually created.
|
|
11917
|
+
*/
|
|
11918
|
+
scaffoldSddWorkspace(projectPath) {
|
|
11919
|
+
const created = [];
|
|
11901
11920
|
try {
|
|
11902
|
-
|
|
11921
|
+
for (const dir of ["steering", "storage/specs"]) {
|
|
11922
|
+
const abs = join5(projectPath, dir);
|
|
11923
|
+
if (!existsSync10(abs)) {
|
|
11924
|
+
mkdirSync2(abs, { recursive: true });
|
|
11925
|
+
created.push(`${dir}/`);
|
|
11926
|
+
}
|
|
11927
|
+
}
|
|
11928
|
+
const reqPath = join5(projectPath, "storage/specs/requirements.md");
|
|
11929
|
+
if (!existsSync10(reqPath)) {
|
|
11930
|
+
writeFileSync2(reqPath, STARTER_REQUIREMENTS, "utf-8");
|
|
11931
|
+
created.push("storage/specs/requirements.md");
|
|
11932
|
+
}
|
|
11903
11933
|
} catch {
|
|
11904
11934
|
}
|
|
11935
|
+
return created;
|
|
11936
|
+
}
|
|
11937
|
+
buildProjectContext(projectPath) {
|
|
11938
|
+
const name = basename(projectPath);
|
|
11939
|
+
const rootStructure = [
|
|
11940
|
+
"steering/ # \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30E1\u30E2\u30EA\uFF08\u6C7A\u5B9A\u524D\u306B\u53C2\u7167\uFF09",
|
|
11941
|
+
"storage/specs/ # requirements / design / tasks \u4ED5\u69D8",
|
|
11942
|
+
".claude/skills/ # SDD Agent Skills",
|
|
11943
|
+
"src/ # \u5B9F\u88C5\u30B3\u30FC\u30C9",
|
|
11944
|
+
"tests/ # \u30C6\u30B9\u30C8\u30B3\u30FC\u30C9"
|
|
11945
|
+
];
|
|
11905
11946
|
return {
|
|
11906
11947
|
projectName: name,
|
|
11907
11948
|
packageManager: "npm",
|
|
@@ -12903,7 +12944,7 @@ __export(dist_exports16, {
|
|
|
12903
12944
|
import { execFile } from "node:child_process";
|
|
12904
12945
|
import { writeFile as writeFile3, unlink } from "node:fs/promises";
|
|
12905
12946
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
12906
|
-
import { join as
|
|
12947
|
+
import { join as join6 } from "node:path";
|
|
12907
12948
|
import { promisify } from "node:util";
|
|
12908
12949
|
import { randomBytes } from "node:crypto";
|
|
12909
12950
|
function sanitizeName(raw) {
|
|
@@ -13106,7 +13147,7 @@ var init_dist16 = __esm({
|
|
|
13106
13147
|
}
|
|
13107
13148
|
async realSolve(smtScript) {
|
|
13108
13149
|
const start = Date.now();
|
|
13109
|
-
const tmpFile =
|
|
13150
|
+
const tmpFile = join6(tmpdir2(), `musubix2-z3-${randomBytes(8).toString("hex")}.smt2`);
|
|
13110
13151
|
try {
|
|
13111
13152
|
await writeFile3(tmpFile, smtScript, "utf-8");
|
|
13112
13153
|
const { stdout, stderr } = await execFileAsync(this.z3Path, ["-smt2", tmpFile], {
|
|
@@ -13330,7 +13371,7 @@ __export(dist_exports17, {
|
|
|
13330
13371
|
import { execFile as execFile2 } from "node:child_process";
|
|
13331
13372
|
import { writeFile as writeFile4, unlink as unlink2 } from "node:fs/promises";
|
|
13332
13373
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
13333
|
-
import { join as
|
|
13374
|
+
import { join as join7 } from "node:path";
|
|
13334
13375
|
import { promisify as promisify2 } from "node:util";
|
|
13335
13376
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
13336
13377
|
function createLeanIntegration() {
|
|
@@ -13454,7 +13495,7 @@ var init_dist17 = __esm({
|
|
|
13454
13495
|
time: Date.now() - start
|
|
13455
13496
|
};
|
|
13456
13497
|
}
|
|
13457
|
-
const tmpFile =
|
|
13498
|
+
const tmpFile = join7(tmpdir3(), `musubix2-lean-${randomBytes2(8).toString("hex")}.lean`);
|
|
13458
13499
|
try {
|
|
13459
13500
|
await writeFile4(tmpFile, leanCode, "utf-8");
|
|
13460
13501
|
const timeout = timeoutMs ?? this.defaultTimeoutMs;
|
|
@@ -15215,7 +15256,8 @@ init_dist5();
|
|
|
15215
15256
|
init_dist6();
|
|
15216
15257
|
init_dist();
|
|
15217
15258
|
init_dist();
|
|
15218
|
-
import { readFileSync as readFileSync6, existsSync as
|
|
15259
|
+
import { readFileSync as readFileSync6, existsSync as existsSync11, statSync, readdirSync } from "node:fs";
|
|
15260
|
+
import { join as joinPath } from "node:path";
|
|
15219
15261
|
function parseArgs(argv) {
|
|
15220
15262
|
const command = argv[0] ?? "";
|
|
15221
15263
|
let subcommand;
|
|
@@ -15275,7 +15317,7 @@ var COMMAND_HELP = {
|
|
|
15275
15317
|
description: "\u8A2D\u8A08\u751F\u6210"
|
|
15276
15318
|
},
|
|
15277
15319
|
codegen: {
|
|
15278
|
-
usage: "musubix codegen [
|
|
15320
|
+
usage: "musubix codegen [generate] <name> [--type class|interface|function|...]",
|
|
15279
15321
|
description: "\u30B3\u30FC\u30C9\u751F\u6210"
|
|
15280
15322
|
},
|
|
15281
15323
|
tasks: {
|
|
@@ -15311,8 +15353,8 @@ var COMMAND_HELP = {
|
|
|
15311
15353
|
description: "\u30B3\u30FC\u30C9\u30B0\u30E9\u30D5\u5206\u6790"
|
|
15312
15354
|
},
|
|
15313
15355
|
security: {
|
|
15314
|
-
usage: "musubix security <path>",
|
|
15315
|
-
description: "\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u30B9\u30AD\u30E3\u30F3"
|
|
15356
|
+
usage: "musubix security <path> [--fail-on critical|high|medium|low|info]",
|
|
15357
|
+
description: "\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u30B9\u30AD\u30E3\u30F3\uFF08\u30D5\u30A1\u30A4\u30EB/\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u5BFE\u5FDC\uFF09"
|
|
15316
15358
|
},
|
|
15317
15359
|
skills: {
|
|
15318
15360
|
usage: "musubix skills <list|validate|create> [args]",
|
|
@@ -15407,7 +15449,7 @@ var CLIDispatcher = class {
|
|
|
15407
15449
|
if (!command) {
|
|
15408
15450
|
throw new Error(`Unknown command: ${commandName}. Available: ${[...this.commands.keys()].join(", ")}`);
|
|
15409
15451
|
}
|
|
15410
|
-
await command.action(args);
|
|
15452
|
+
return await command.action(args);
|
|
15411
15453
|
}
|
|
15412
15454
|
getHelp() {
|
|
15413
15455
|
const lines = [
|
|
@@ -15445,12 +15487,12 @@ var CLIDispatcher = class {
|
|
|
15445
15487
|
return ExitCode.SUCCESS;
|
|
15446
15488
|
}
|
|
15447
15489
|
try {
|
|
15448
|
-
await this.dispatch(parsed.command, {
|
|
15490
|
+
const result = await this.dispatch(parsed.command, {
|
|
15449
15491
|
subcommand: parsed.subcommand,
|
|
15450
15492
|
args: parsed.args,
|
|
15451
15493
|
...parsed.flags
|
|
15452
15494
|
});
|
|
15453
|
-
return ExitCode.SUCCESS;
|
|
15495
|
+
return result ?? ExitCode.SUCCESS;
|
|
15454
15496
|
} catch (err) {
|
|
15455
15497
|
const message = err instanceof Error ? err.message : String(err);
|
|
15456
15498
|
console.error(message);
|
|
@@ -15552,21 +15594,21 @@ async function handleInit(targetPath = ".", name, force) {
|
|
|
15552
15594
|
console.log(` ${f}`);
|
|
15553
15595
|
}
|
|
15554
15596
|
try {
|
|
15555
|
-
const { cpSync, existsSync:
|
|
15597
|
+
const { cpSync, existsSync: existsSync12, mkdirSync: mkdirSync3 } = await import("node:fs");
|
|
15556
15598
|
const { resolve: resolve9, dirname: dirname4 } = await import("node:path");
|
|
15557
15599
|
const { fileURLToPath: fileURLToPath2 } = await import("node:url");
|
|
15558
15600
|
const thisDir = typeof __dirname !== "undefined" ? __dirname : dirname4(fileURLToPath2(import.meta.url));
|
|
15559
15601
|
const pkgGithub = resolve9(thisDir, "..", ".github");
|
|
15560
15602
|
const destGithub = resolve9(targetPath, ".github");
|
|
15561
|
-
if (
|
|
15562
|
-
|
|
15603
|
+
if (existsSync12(pkgGithub)) {
|
|
15604
|
+
mkdirSync3(destGithub, { recursive: true });
|
|
15563
15605
|
const skillsSrc = resolve9(pkgGithub, "skills");
|
|
15564
|
-
if (
|
|
15606
|
+
if (existsSync12(skillsSrc)) {
|
|
15565
15607
|
cpSync(skillsSrc, resolve9(destGithub, "skills"), { recursive: true });
|
|
15566
15608
|
console.log(" .github/skills/ (SDD skills)");
|
|
15567
15609
|
}
|
|
15568
15610
|
const instrSrc = resolve9(pkgGithub, "copilot-instructions.md");
|
|
15569
|
-
if (
|
|
15611
|
+
if (existsSync12(instrSrc)) {
|
|
15570
15612
|
cpSync(instrSrc, resolve9(destGithub, "copilot-instructions.md"));
|
|
15571
15613
|
console.log(" .github/copilot-instructions.md");
|
|
15572
15614
|
}
|
|
@@ -15581,6 +15623,7 @@ async function handleTrace(sub, args) {
|
|
|
15581
15623
|
const generator = createMatrixGenerator();
|
|
15582
15624
|
const report = generator.generate([], [], []);
|
|
15583
15625
|
console.log(generator.toMarkdown(report));
|
|
15626
|
+
console.log("\n\u2139 No traceability data loaded \u2014 matrix is empty (completeness is N/A).");
|
|
15584
15627
|
return ExitCode.SUCCESS;
|
|
15585
15628
|
}
|
|
15586
15629
|
case "validate": {
|
|
@@ -15612,6 +15655,11 @@ async function handleTrace(sub, args) {
|
|
|
15612
15655
|
async function handleTraceVerify() {
|
|
15613
15656
|
const validator = createTraceabilityValidator();
|
|
15614
15657
|
const report = validator.validateCoverage([], [], [], []);
|
|
15658
|
+
if (report.totalRequirements === 0) {
|
|
15659
|
+
console.log("No traceability data loaded \u2014 nothing to verify.");
|
|
15660
|
+
console.log("\u2139 Coverage cannot be computed with 0 requirements (reported as N/A).");
|
|
15661
|
+
return ExitCode.SUCCESS;
|
|
15662
|
+
}
|
|
15615
15663
|
console.log(`Coverage: ${report.coveragePercent}%`);
|
|
15616
15664
|
console.log(`Requirements: ${report.coveredRequirements}/${report.totalRequirements}`);
|
|
15617
15665
|
if (report.gaps.length > 0) {
|
|
@@ -15711,6 +15759,31 @@ var EXT_TO_LANG = {
|
|
|
15711
15759
|
hs: "haskell",
|
|
15712
15760
|
lua: "lua"
|
|
15713
15761
|
};
|
|
15762
|
+
var WALK_IGNORE = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "coverage", ".next", "build"]);
|
|
15763
|
+
function collectFiles(target, extFilter) {
|
|
15764
|
+
const stat = statSync(target);
|
|
15765
|
+
if (stat.isFile())
|
|
15766
|
+
return [target];
|
|
15767
|
+
const out = [];
|
|
15768
|
+
const walk = (dir) => {
|
|
15769
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
15770
|
+
if (entry.name.startsWith(".") && entry.name !== ".")
|
|
15771
|
+
continue;
|
|
15772
|
+
if (WALK_IGNORE.has(entry.name))
|
|
15773
|
+
continue;
|
|
15774
|
+
const full = joinPath(dir, entry.name);
|
|
15775
|
+
if (entry.isDirectory()) {
|
|
15776
|
+
walk(full);
|
|
15777
|
+
} else if (entry.isFile()) {
|
|
15778
|
+
const ext = entry.name.split(".").pop() ?? "";
|
|
15779
|
+
if (!extFilter || extFilter(ext))
|
|
15780
|
+
out.push(full);
|
|
15781
|
+
}
|
|
15782
|
+
}
|
|
15783
|
+
};
|
|
15784
|
+
walk(target);
|
|
15785
|
+
return out;
|
|
15786
|
+
}
|
|
15714
15787
|
async function handleCodegraph(sub, args) {
|
|
15715
15788
|
switch (sub) {
|
|
15716
15789
|
case "index": {
|
|
@@ -15720,29 +15793,40 @@ async function handleCodegraph(sub, args) {
|
|
|
15720
15793
|
return ExitCode.GENERAL_ERROR;
|
|
15721
15794
|
}
|
|
15722
15795
|
try {
|
|
15723
|
-
|
|
15724
|
-
|
|
15725
|
-
const ext = targetPath.split(".").pop() ?? "";
|
|
15726
|
-
const lang = EXT_TO_LANG[ext];
|
|
15727
|
-
if (!lang) {
|
|
15728
|
-
console.error(`\u274C Unsupported file extension: .${ext}`);
|
|
15796
|
+
if (!existsSync11(targetPath)) {
|
|
15797
|
+
console.error(`\u274C Path not found: ${targetPath}`);
|
|
15729
15798
|
return ExitCode.GENERAL_ERROR;
|
|
15730
15799
|
}
|
|
15731
|
-
const
|
|
15800
|
+
const parser = createASTParser();
|
|
15732
15801
|
const engine = createGraphEngine();
|
|
15733
|
-
|
|
15734
|
-
|
|
15735
|
-
|
|
15736
|
-
|
|
15737
|
-
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
|
|
15802
|
+
const files = collectFiles(targetPath, (ext) => ext in EXT_TO_LANG);
|
|
15803
|
+
if (files.length === 0) {
|
|
15804
|
+
console.error(`\u274C No indexable source files found under: ${targetPath}`);
|
|
15805
|
+
return ExitCode.GENERAL_ERROR;
|
|
15806
|
+
}
|
|
15807
|
+
let indexedFiles = 0;
|
|
15808
|
+
for (const file of files) {
|
|
15809
|
+
const ext = file.split(".").pop() ?? "";
|
|
15810
|
+
const lang = EXT_TO_LANG[ext];
|
|
15811
|
+
if (!lang)
|
|
15812
|
+
continue;
|
|
15813
|
+
const content = readFileSync6(file, "utf-8");
|
|
15814
|
+
const nodes = parser.parse(content, lang);
|
|
15815
|
+
for (const node of nodes) {
|
|
15816
|
+
engine.addNode({
|
|
15817
|
+
id: `${file}:${node.name}`,
|
|
15818
|
+
name: node.name,
|
|
15819
|
+
kind: node.kind,
|
|
15820
|
+
filePath: file,
|
|
15821
|
+
language: lang,
|
|
15822
|
+
startLine: 0,
|
|
15823
|
+
endLine: 0
|
|
15824
|
+
});
|
|
15825
|
+
}
|
|
15826
|
+
indexedFiles++;
|
|
15743
15827
|
}
|
|
15744
15828
|
const stats = engine.getStats();
|
|
15745
|
-
console.log(`\u2705 Indexed ${targetPath}: ${stats.nodeCount} nodes, ${stats.edgeCount} edges`);
|
|
15829
|
+
console.log(`\u2705 Indexed ${targetPath}: ${indexedFiles} file(s), ${stats.nodeCount} nodes, ${stats.edgeCount} edges`);
|
|
15746
15830
|
} catch (err) {
|
|
15747
15831
|
const msg = err instanceof Error ? err.message : String(err);
|
|
15748
15832
|
console.error(`\u274C ${msg}`);
|
|
@@ -15784,40 +15868,54 @@ async function handleCodegraph(sub, args) {
|
|
|
15784
15868
|
return ExitCode.SUCCESS;
|
|
15785
15869
|
}
|
|
15786
15870
|
}
|
|
15787
|
-
|
|
15871
|
+
var SEVERITY_ORDER = ["critical", "high", "medium", "low", "info"];
|
|
15872
|
+
async function handleSecurity(filePath, failOn) {
|
|
15788
15873
|
try {
|
|
15789
|
-
if (!
|
|
15790
|
-
console.error(`\u274C
|
|
15874
|
+
if (!existsSync11(filePath)) {
|
|
15875
|
+
console.error(`\u274C Path not found: ${filePath}`);
|
|
15791
15876
|
return ExitCode.GENERAL_ERROR;
|
|
15792
15877
|
}
|
|
15793
|
-
const code = readFileSync6(filePath, "utf-8");
|
|
15794
15878
|
const secrets = createSecretDetector();
|
|
15795
15879
|
const taint = new TaintAnalyzer();
|
|
15796
15880
|
const deps = new DependencyScanner();
|
|
15797
|
-
const
|
|
15798
|
-
|
|
15799
|
-
|
|
15800
|
-
|
|
15801
|
-
|
|
15881
|
+
const files = collectFiles(filePath, (ext) => ext in EXT_TO_LANG);
|
|
15882
|
+
const findings = [];
|
|
15883
|
+
for (const file of files) {
|
|
15884
|
+
const code = readFileSync6(file, "utf-8");
|
|
15885
|
+
findings.push(...secrets.scan(code, file), ...taint.analyze(code, file), ...deps.scan(code, file));
|
|
15886
|
+
}
|
|
15802
15887
|
const bySeverity = /* @__PURE__ */ new Map();
|
|
15803
15888
|
for (const f of findings) {
|
|
15804
15889
|
const list = bySeverity.get(f.severity) ?? [];
|
|
15805
15890
|
list.push(f);
|
|
15806
15891
|
bySeverity.set(f.severity, list);
|
|
15807
15892
|
}
|
|
15808
|
-
console.log(`Security scan: ${filePath}`);
|
|
15893
|
+
console.log(`Security scan: ${filePath} (${files.length} file(s))`);
|
|
15809
15894
|
console.log(`Total findings: ${findings.length}`);
|
|
15810
|
-
const
|
|
15811
|
-
for (const sev of severityOrder) {
|
|
15895
|
+
for (const sev of SEVERITY_ORDER) {
|
|
15812
15896
|
const items = bySeverity.get(sev);
|
|
15813
15897
|
if (items && items.length > 0) {
|
|
15814
15898
|
console.log(`
|
|
15815
15899
|
${sev.toUpperCase()} (${items.length}):`);
|
|
15816
15900
|
for (const f of items) {
|
|
15817
|
-
console.log(` - ${f.description}`);
|
|
15901
|
+
console.log(` - ${f.description} (${f.location.file}:${f.location.line})`);
|
|
15818
15902
|
}
|
|
15819
15903
|
}
|
|
15820
15904
|
}
|
|
15905
|
+
if (failOn) {
|
|
15906
|
+
const threshold = failOn.toLowerCase();
|
|
15907
|
+
if (!SEVERITY_ORDER.includes(threshold)) {
|
|
15908
|
+
console.error(`\u274C Invalid --fail-on severity: ${failOn} (use critical|high|medium|low|info)`);
|
|
15909
|
+
return ExitCode.VALIDATION_ERROR;
|
|
15910
|
+
}
|
|
15911
|
+
const maxIdx = SEVERITY_ORDER.indexOf(threshold);
|
|
15912
|
+
const gating = findings.filter((f) => SEVERITY_ORDER.indexOf(f.severity) <= maxIdx);
|
|
15913
|
+
if (gating.length > 0) {
|
|
15914
|
+
console.error(`
|
|
15915
|
+
\u274C ${gating.length} finding(s) at or above "${threshold}" \u2014 failing.`);
|
|
15916
|
+
return ExitCode.VALIDATION_ERROR;
|
|
15917
|
+
}
|
|
15918
|
+
}
|
|
15821
15919
|
return ExitCode.SUCCESS;
|
|
15822
15920
|
} catch (err) {
|
|
15823
15921
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -15904,6 +16002,17 @@ async function handleReqValidate(filePath) {
|
|
|
15904
16002
|
}
|
|
15905
16003
|
if (requirements.length === 0) {
|
|
15906
16004
|
console.log("No requirements found in file");
|
|
16005
|
+
if (/REQ-/i.test(content)) {
|
|
16006
|
+
const headingLike = /^#{1,4}\s+REQ-[A-Z]{3}-\d{3}:/m.test(content);
|
|
16007
|
+
console.error('\u26A0 Found "REQ-" text but no parseable requirements. Requirements must be Markdown headings shaped like:');
|
|
16008
|
+
console.error(" ## REQ-XXX-000: <title> (XXX = 3-letter domain code)");
|
|
16009
|
+
console.error(" **\u8981\u4EF6**:");
|
|
16010
|
+
console.error(" THE \u30B7\u30B9\u30C6\u30E0 SHALL ...");
|
|
16011
|
+
if (!headingLike) {
|
|
16012
|
+
console.error('\u2139 Hint: list items (e.g. "- REQ-001: ...") and IDs without a 3-letter domain code are not recognized.');
|
|
16013
|
+
}
|
|
16014
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16015
|
+
}
|
|
15907
16016
|
}
|
|
15908
16017
|
return hasIssues ? ExitCode.VALIDATION_ERROR : ExitCode.SUCCESS;
|
|
15909
16018
|
} catch (err) {
|
|
@@ -16494,7 +16603,7 @@ async function handleExplain(input) {
|
|
|
16494
16603
|
const recorder = new ReasoningChainRecorder2();
|
|
16495
16604
|
const generator = new ExplanationGenerator2();
|
|
16496
16605
|
let code;
|
|
16497
|
-
if (
|
|
16606
|
+
if (existsSync11(input)) {
|
|
16498
16607
|
code = readFileSync6(input, "utf-8");
|
|
16499
16608
|
} else {
|
|
16500
16609
|
code = input;
|
|
@@ -16622,6 +16731,29 @@ async function handleWatch(pattern) {
|
|
|
16622
16731
|
});
|
|
16623
16732
|
return ExitCode.SUCCESS;
|
|
16624
16733
|
}
|
|
16734
|
+
function resolveTarget(args, verbs) {
|
|
16735
|
+
const positional = args["args"] ?? [];
|
|
16736
|
+
const sub = args["subcommand"];
|
|
16737
|
+
const explicitFile = args["file"];
|
|
16738
|
+
if (explicitFile)
|
|
16739
|
+
return explicitFile;
|
|
16740
|
+
if (sub && verbs.includes(sub.toLowerCase())) {
|
|
16741
|
+
return positional[0];
|
|
16742
|
+
}
|
|
16743
|
+
return sub ?? positional[0];
|
|
16744
|
+
}
|
|
16745
|
+
async function reqAction(args) {
|
|
16746
|
+
if (args["help"] === true || args["h"] === true) {
|
|
16747
|
+
console.log(showHelp("requirements"));
|
|
16748
|
+
return;
|
|
16749
|
+
}
|
|
16750
|
+
const filePath = resolveTarget(args, ["analyze", "validate"]);
|
|
16751
|
+
if (!filePath) {
|
|
16752
|
+
console.error("\u274C Usage: musubix requirements [analyze|validate] <file>");
|
|
16753
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16754
|
+
}
|
|
16755
|
+
return await handleReqValidate(filePath);
|
|
16756
|
+
}
|
|
16625
16757
|
function getDefaultCommands() {
|
|
16626
16758
|
return [
|
|
16627
16759
|
{
|
|
@@ -16671,7 +16803,7 @@ function getDefaultCommands() {
|
|
|
16671
16803
|
return;
|
|
16672
16804
|
}
|
|
16673
16805
|
const targetPath = args["subcommand"] ?? args["args"]?.[0] ?? ".";
|
|
16674
|
-
await handleInit(targetPath, args["name"], args["force"] === true);
|
|
16806
|
+
return await handleInit(targetPath, args["name"], args["force"] === true);
|
|
16675
16807
|
}
|
|
16676
16808
|
},
|
|
16677
16809
|
{
|
|
@@ -16689,37 +16821,32 @@ function getDefaultCommands() {
|
|
|
16689
16821
|
case "validate":
|
|
16690
16822
|
if (!filePath) {
|
|
16691
16823
|
console.error("\u274C Usage: musubix tasks validate <file>");
|
|
16692
|
-
return;
|
|
16824
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16693
16825
|
}
|
|
16694
|
-
await handleTasksValidate(filePath);
|
|
16826
|
+
return await handleTasksValidate(filePath);
|
|
16695
16827
|
break;
|
|
16696
16828
|
case "list":
|
|
16697
|
-
await handleTasksList(filePath);
|
|
16829
|
+
return await handleTasksList(filePath);
|
|
16698
16830
|
break;
|
|
16699
16831
|
case "stats":
|
|
16700
|
-
await handleTasksStats(filePath);
|
|
16832
|
+
return await handleTasksStats(filePath);
|
|
16701
16833
|
break;
|
|
16702
16834
|
default:
|
|
16703
16835
|
console.log(showHelp("tasks"));
|
|
16836
|
+
return;
|
|
16704
16837
|
}
|
|
16705
16838
|
}
|
|
16706
16839
|
},
|
|
16707
16840
|
{
|
|
16708
16841
|
name: "req",
|
|
16709
16842
|
description: "Analyze requirements (EARS validation)",
|
|
16710
|
-
action:
|
|
16711
|
-
|
|
16712
|
-
|
|
16713
|
-
|
|
16714
|
-
|
|
16715
|
-
|
|
16716
|
-
|
|
16717
|
-
if (!filePath) {
|
|
16718
|
-
console.error("\u274C Usage: musubix req <file>");
|
|
16719
|
-
return;
|
|
16720
|
-
}
|
|
16721
|
-
await handleReqValidate(filePath);
|
|
16722
|
-
}
|
|
16843
|
+
action: reqAction
|
|
16844
|
+
},
|
|
16845
|
+
{
|
|
16846
|
+
// Alias matching the documented `musubix requirements <analyze|validate> <file>` form.
|
|
16847
|
+
name: "requirements",
|
|
16848
|
+
description: "Analyze/validate requirements (EARS validation)",
|
|
16849
|
+
action: reqAction
|
|
16723
16850
|
},
|
|
16724
16851
|
{
|
|
16725
16852
|
name: "req:wizard",
|
|
@@ -16729,7 +16856,7 @@ function getDefaultCommands() {
|
|
|
16729
16856
|
console.log(showHelp("requirements"));
|
|
16730
16857
|
return;
|
|
16731
16858
|
}
|
|
16732
|
-
await handleReqWizard();
|
|
16859
|
+
return await handleReqWizard();
|
|
16733
16860
|
}
|
|
16734
16861
|
},
|
|
16735
16862
|
{
|
|
@@ -16740,7 +16867,7 @@ function getDefaultCommands() {
|
|
|
16740
16867
|
console.log(showHelp("requirements"));
|
|
16741
16868
|
return;
|
|
16742
16869
|
}
|
|
16743
|
-
await handleReqInterview(args);
|
|
16870
|
+
return await handleReqInterview(args);
|
|
16744
16871
|
}
|
|
16745
16872
|
},
|
|
16746
16873
|
{
|
|
@@ -16751,13 +16878,20 @@ function getDefaultCommands() {
|
|
|
16751
16878
|
console.log(showHelp("design"));
|
|
16752
16879
|
return;
|
|
16753
16880
|
}
|
|
16754
|
-
|
|
16755
|
-
|
|
16881
|
+
if (args["subcommand"]?.toLowerCase() === "verify") {
|
|
16882
|
+
const vf = resolveTarget(args, ["verify"]);
|
|
16883
|
+
if (!vf) {
|
|
16884
|
+
console.error("\u274C Usage: musubix design verify <design-file>");
|
|
16885
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16886
|
+
}
|
|
16887
|
+
return await handleDesignVerify(vf);
|
|
16888
|
+
}
|
|
16889
|
+
const filePath = resolveTarget(args, ["generate"]);
|
|
16756
16890
|
if (!filePath) {
|
|
16757
|
-
console.error("\u274C Usage: musubix design <requirements-file>");
|
|
16758
|
-
return;
|
|
16891
|
+
console.error("\u274C Usage: musubix design [generate] <requirements-file>");
|
|
16892
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16759
16893
|
}
|
|
16760
|
-
await handleDesignGenerate(filePath);
|
|
16894
|
+
return await handleDesignGenerate(filePath);
|
|
16761
16895
|
}
|
|
16762
16896
|
},
|
|
16763
16897
|
{
|
|
@@ -16772,10 +16906,10 @@ function getDefaultCommands() {
|
|
|
16772
16906
|
const filePath = args["file"] ?? args["subcommand"] ?? positionalArgs[0];
|
|
16773
16907
|
if (!filePath) {
|
|
16774
16908
|
console.error("\u274C Usage: musubix design:c4 <file> [--level context|container|component]");
|
|
16775
|
-
return;
|
|
16909
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16776
16910
|
}
|
|
16777
16911
|
const level = args["level"] ?? "context";
|
|
16778
|
-
await handleDesignC4(filePath, level);
|
|
16912
|
+
return await handleDesignC4(filePath, level);
|
|
16779
16913
|
}
|
|
16780
16914
|
},
|
|
16781
16915
|
{
|
|
@@ -16790,9 +16924,9 @@ function getDefaultCommands() {
|
|
|
16790
16924
|
const filePath = args["file"] ?? args["subcommand"] ?? positionalArgs[0];
|
|
16791
16925
|
if (!filePath) {
|
|
16792
16926
|
console.error("\u274C Usage: musubix design:verify <design-file>");
|
|
16793
|
-
return;
|
|
16927
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16794
16928
|
}
|
|
16795
|
-
await handleDesignVerify(filePath);
|
|
16929
|
+
return await handleDesignVerify(filePath);
|
|
16796
16930
|
}
|
|
16797
16931
|
},
|
|
16798
16932
|
{
|
|
@@ -16803,14 +16937,13 @@ function getDefaultCommands() {
|
|
|
16803
16937
|
console.log(showHelp("codegen"));
|
|
16804
16938
|
return;
|
|
16805
16939
|
}
|
|
16806
|
-
const
|
|
16807
|
-
const name = args["subcommand"] ?? positionalArgs[0];
|
|
16940
|
+
const name = resolveTarget(args, ["generate"]);
|
|
16808
16941
|
if (!name) {
|
|
16809
|
-
console.error("\u274C Usage: musubix codegen <name> [--type class|interface|function|...]");
|
|
16810
|
-
return;
|
|
16942
|
+
console.error("\u274C Usage: musubix codegen [generate] <name> [--type class|interface|function|...]");
|
|
16943
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16811
16944
|
}
|
|
16812
16945
|
const type = args["type"] ?? "class";
|
|
16813
|
-
await handleCodegen(name, type);
|
|
16946
|
+
return await handleCodegen(name, type);
|
|
16814
16947
|
}
|
|
16815
16948
|
},
|
|
16816
16949
|
{
|
|
@@ -16825,9 +16958,9 @@ function getDefaultCommands() {
|
|
|
16825
16958
|
const filePath = args["file"] ?? args["subcommand"] ?? positionalArgs[0];
|
|
16826
16959
|
if (!filePath) {
|
|
16827
16960
|
console.error("\u274C Usage: musubix test:gen <source-file>");
|
|
16828
|
-
return;
|
|
16961
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16829
16962
|
}
|
|
16830
|
-
await handleTestGen(filePath);
|
|
16963
|
+
return await handleTestGen(filePath);
|
|
16831
16964
|
}
|
|
16832
16965
|
},
|
|
16833
16966
|
{
|
|
@@ -16840,7 +16973,7 @@ function getDefaultCommands() {
|
|
|
16840
16973
|
}
|
|
16841
16974
|
const sub = args["subcommand"];
|
|
16842
16975
|
const positionalArgs = args["args"] ?? [];
|
|
16843
|
-
await handleTrace(sub, positionalArgs);
|
|
16976
|
+
return await handleTrace(sub, positionalArgs);
|
|
16844
16977
|
}
|
|
16845
16978
|
},
|
|
16846
16979
|
{
|
|
@@ -16851,7 +16984,7 @@ function getDefaultCommands() {
|
|
|
16851
16984
|
console.log(showHelp("trace:verify"));
|
|
16852
16985
|
return;
|
|
16853
16986
|
}
|
|
16854
|
-
await handleTraceVerify();
|
|
16987
|
+
return await handleTraceVerify();
|
|
16855
16988
|
}
|
|
16856
16989
|
},
|
|
16857
16990
|
{
|
|
@@ -16864,7 +16997,7 @@ function getDefaultCommands() {
|
|
|
16864
16997
|
}
|
|
16865
16998
|
const sub = args["subcommand"];
|
|
16866
16999
|
const positionalArgs = args["args"] ?? [];
|
|
16867
|
-
await handlePolicy(sub, positionalArgs);
|
|
17000
|
+
return await handlePolicy(sub, positionalArgs);
|
|
16868
17001
|
}
|
|
16869
17002
|
},
|
|
16870
17003
|
{
|
|
@@ -16876,7 +17009,7 @@ function getDefaultCommands() {
|
|
|
16876
17009
|
return;
|
|
16877
17010
|
}
|
|
16878
17011
|
const sub = args["subcommand"];
|
|
16879
|
-
await handleOntology(sub);
|
|
17012
|
+
return await handleOntology(sub);
|
|
16880
17013
|
}
|
|
16881
17014
|
},
|
|
16882
17015
|
{
|
|
@@ -16889,7 +17022,7 @@ function getDefaultCommands() {
|
|
|
16889
17022
|
}
|
|
16890
17023
|
const sub = args["subcommand"];
|
|
16891
17024
|
const positionalArgs = args["args"] ?? [];
|
|
16892
|
-
await handleCodegraph(sub, positionalArgs);
|
|
17025
|
+
return await handleCodegraph(sub, positionalArgs);
|
|
16893
17026
|
}
|
|
16894
17027
|
},
|
|
16895
17028
|
{
|
|
@@ -16903,10 +17036,10 @@ function getDefaultCommands() {
|
|
|
16903
17036
|
const positionalArgs = args["args"] ?? [];
|
|
16904
17037
|
const filePath = args["subcommand"] ?? positionalArgs[0];
|
|
16905
17038
|
if (!filePath) {
|
|
16906
|
-
console.error("\u274C Usage: musubix security <path>");
|
|
16907
|
-
return;
|
|
17039
|
+
console.error("\u274C Usage: musubix security <path> [--fail-on critical|high|medium|low|info]");
|
|
17040
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16908
17041
|
}
|
|
16909
|
-
await handleSecurity(filePath);
|
|
17042
|
+
return await handleSecurity(filePath, args["fail-on"]);
|
|
16910
17043
|
}
|
|
16911
17044
|
},
|
|
16912
17045
|
{
|
|
@@ -16919,7 +17052,7 @@ function getDefaultCommands() {
|
|
|
16919
17052
|
}
|
|
16920
17053
|
const sub = args["subcommand"];
|
|
16921
17054
|
const positionalArgs = args["args"] ?? [];
|
|
16922
|
-
await handleWorkflow(sub, positionalArgs);
|
|
17055
|
+
return await handleWorkflow(sub, positionalArgs);
|
|
16923
17056
|
}
|
|
16924
17057
|
},
|
|
16925
17058
|
{
|
|
@@ -16930,7 +17063,7 @@ function getDefaultCommands() {
|
|
|
16930
17063
|
console.log(showHelp("status"));
|
|
16931
17064
|
return;
|
|
16932
17065
|
}
|
|
16933
|
-
await handleStatus();
|
|
17066
|
+
return await handleStatus();
|
|
16934
17067
|
}
|
|
16935
17068
|
},
|
|
16936
17069
|
{
|
|
@@ -16943,7 +17076,7 @@ function getDefaultCommands() {
|
|
|
16943
17076
|
}
|
|
16944
17077
|
const sub = args["subcommand"];
|
|
16945
17078
|
const positionalArgs = args["args"] ?? [];
|
|
16946
|
-
await handleSkills(sub, positionalArgs);
|
|
17079
|
+
return await handleSkills(sub, positionalArgs);
|
|
16947
17080
|
}
|
|
16948
17081
|
},
|
|
16949
17082
|
{
|
|
@@ -16956,7 +17089,7 @@ function getDefaultCommands() {
|
|
|
16956
17089
|
}
|
|
16957
17090
|
const sub = args["subcommand"];
|
|
16958
17091
|
const positionalArgs = args["args"] ?? [];
|
|
16959
|
-
await handleKnowledge(sub, positionalArgs, args);
|
|
17092
|
+
return await handleKnowledge(sub, positionalArgs, args);
|
|
16960
17093
|
}
|
|
16961
17094
|
},
|
|
16962
17095
|
{
|
|
@@ -16969,7 +17102,7 @@ function getDefaultCommands() {
|
|
|
16969
17102
|
}
|
|
16970
17103
|
const sub = args["subcommand"];
|
|
16971
17104
|
const positionalArgs = args["args"] ?? [];
|
|
16972
|
-
await handleDecision(sub, positionalArgs, args);
|
|
17105
|
+
return await handleDecision(sub, positionalArgs, args);
|
|
16973
17106
|
}
|
|
16974
17107
|
},
|
|
16975
17108
|
{
|
|
@@ -16982,7 +17115,7 @@ function getDefaultCommands() {
|
|
|
16982
17115
|
}
|
|
16983
17116
|
const sub = args["subcommand"];
|
|
16984
17117
|
const positionalArgs = args["args"] ?? [];
|
|
16985
|
-
await handleDeepResearch(sub, positionalArgs);
|
|
17118
|
+
return await handleDeepResearch(sub, positionalArgs);
|
|
16986
17119
|
}
|
|
16987
17120
|
},
|
|
16988
17121
|
{
|
|
@@ -16993,7 +17126,7 @@ function getDefaultCommands() {
|
|
|
16993
17126
|
console.log(showHelp("repl"));
|
|
16994
17127
|
return;
|
|
16995
17128
|
}
|
|
16996
|
-
await handleRepl();
|
|
17129
|
+
return await handleRepl();
|
|
16997
17130
|
}
|
|
16998
17131
|
},
|
|
16999
17132
|
{
|
|
@@ -17006,7 +17139,7 @@ function getDefaultCommands() {
|
|
|
17006
17139
|
}
|
|
17007
17140
|
const sub = args["subcommand"];
|
|
17008
17141
|
const positionalArgs = args["args"] ?? [];
|
|
17009
|
-
await handleScaffold(sub, positionalArgs);
|
|
17142
|
+
return await handleScaffold(sub, positionalArgs);
|
|
17010
17143
|
}
|
|
17011
17144
|
},
|
|
17012
17145
|
{
|
|
@@ -17019,7 +17152,7 @@ function getDefaultCommands() {
|
|
|
17019
17152
|
}
|
|
17020
17153
|
const positionalArgs = args["args"] ?? [];
|
|
17021
17154
|
const input = args["subcommand"] ?? positionalArgs[0];
|
|
17022
|
-
await handleExplain(input);
|
|
17155
|
+
return await handleExplain(input);
|
|
17023
17156
|
}
|
|
17024
17157
|
},
|
|
17025
17158
|
{
|
|
@@ -17032,7 +17165,7 @@ function getDefaultCommands() {
|
|
|
17032
17165
|
}
|
|
17033
17166
|
const sub = args["subcommand"];
|
|
17034
17167
|
const positionalArgs = args["args"] ?? [];
|
|
17035
|
-
await handleLearn(sub, positionalArgs);
|
|
17168
|
+
return await handleLearn(sub, positionalArgs);
|
|
17036
17169
|
}
|
|
17037
17170
|
},
|
|
17038
17171
|
{
|
|
@@ -17045,7 +17178,7 @@ function getDefaultCommands() {
|
|
|
17045
17178
|
}
|
|
17046
17179
|
const sub = args["subcommand"];
|
|
17047
17180
|
const positionalArgs = args["args"] ?? [];
|
|
17048
|
-
await handleSynthesis(sub, positionalArgs);
|
|
17181
|
+
return await handleSynthesis(sub, positionalArgs);
|
|
17049
17182
|
}
|
|
17050
17183
|
},
|
|
17051
17184
|
{
|
|
@@ -17058,7 +17191,7 @@ function getDefaultCommands() {
|
|
|
17058
17191
|
}
|
|
17059
17192
|
const positionalArgs = args["args"] ?? [];
|
|
17060
17193
|
const pattern = args["subcommand"] ?? positionalArgs[0];
|
|
17061
|
-
await handleWatch(pattern);
|
|
17194
|
+
return await handleWatch(pattern);
|
|
17062
17195
|
}
|
|
17063
17196
|
},
|
|
17064
17197
|
// P3-07: MCP server launcher
|
|
@@ -17095,6 +17228,7 @@ function createCLIDispatcher() {
|
|
|
17095
17228
|
}
|
|
17096
17229
|
export {
|
|
17097
17230
|
CLIDispatcher,
|
|
17231
|
+
collectFiles,
|
|
17098
17232
|
createCLIDispatcher,
|
|
17099
17233
|
getDefaultCommands,
|
|
17100
17234
|
handleCodegen,
|
|
@@ -17129,5 +17263,6 @@ export {
|
|
|
17129
17263
|
handleWorkflow,
|
|
17130
17264
|
parseArgs,
|
|
17131
17265
|
parseTaskFile,
|
|
17266
|
+
resolveTarget,
|
|
17132
17267
|
showHelp
|
|
17133
17268
|
};
|