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/index.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;
|
|
@@ -15219,7 +15260,8 @@ init_dist5();
|
|
|
15219
15260
|
init_dist6();
|
|
15220
15261
|
init_dist();
|
|
15221
15262
|
init_dist();
|
|
15222
|
-
import { readFileSync as readFileSync6, existsSync as
|
|
15263
|
+
import { readFileSync as readFileSync6, existsSync as existsSync11, statSync, readdirSync } from "node:fs";
|
|
15264
|
+
import { join as joinPath } from "node:path";
|
|
15223
15265
|
function parseArgs(argv) {
|
|
15224
15266
|
const command = argv[0] ?? "";
|
|
15225
15267
|
let subcommand;
|
|
@@ -15279,7 +15321,7 @@ var COMMAND_HELP = {
|
|
|
15279
15321
|
description: "\u8A2D\u8A08\u751F\u6210"
|
|
15280
15322
|
},
|
|
15281
15323
|
codegen: {
|
|
15282
|
-
usage: "musubix codegen [
|
|
15324
|
+
usage: "musubix codegen [generate] <name> [--type class|interface|function|...]",
|
|
15283
15325
|
description: "\u30B3\u30FC\u30C9\u751F\u6210"
|
|
15284
15326
|
},
|
|
15285
15327
|
tasks: {
|
|
@@ -15315,8 +15357,8 @@ var COMMAND_HELP = {
|
|
|
15315
15357
|
description: "\u30B3\u30FC\u30C9\u30B0\u30E9\u30D5\u5206\u6790"
|
|
15316
15358
|
},
|
|
15317
15359
|
security: {
|
|
15318
|
-
usage: "musubix security <path>",
|
|
15319
|
-
description: "\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u30B9\u30AD\u30E3\u30F3"
|
|
15360
|
+
usage: "musubix security <path> [--fail-on critical|high|medium|low|info]",
|
|
15361
|
+
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"
|
|
15320
15362
|
},
|
|
15321
15363
|
skills: {
|
|
15322
15364
|
usage: "musubix skills <list|validate|create> [args]",
|
|
@@ -15411,7 +15453,7 @@ var CLIDispatcher = class {
|
|
|
15411
15453
|
if (!command) {
|
|
15412
15454
|
throw new Error(`Unknown command: ${commandName}. Available: ${[...this.commands.keys()].join(", ")}`);
|
|
15413
15455
|
}
|
|
15414
|
-
await command.action(args);
|
|
15456
|
+
return await command.action(args);
|
|
15415
15457
|
}
|
|
15416
15458
|
getHelp() {
|
|
15417
15459
|
const lines = [
|
|
@@ -15449,12 +15491,12 @@ var CLIDispatcher = class {
|
|
|
15449
15491
|
return ExitCode.SUCCESS;
|
|
15450
15492
|
}
|
|
15451
15493
|
try {
|
|
15452
|
-
await this.dispatch(parsed.command, {
|
|
15494
|
+
const result = await this.dispatch(parsed.command, {
|
|
15453
15495
|
subcommand: parsed.subcommand,
|
|
15454
15496
|
args: parsed.args,
|
|
15455
15497
|
...parsed.flags
|
|
15456
15498
|
});
|
|
15457
|
-
return ExitCode.SUCCESS;
|
|
15499
|
+
return result ?? ExitCode.SUCCESS;
|
|
15458
15500
|
} catch (err) {
|
|
15459
15501
|
const message = err instanceof Error ? err.message : String(err);
|
|
15460
15502
|
console.error(message);
|
|
@@ -15556,21 +15598,21 @@ async function handleInit(targetPath = ".", name, force) {
|
|
|
15556
15598
|
console.log(` ${f}`);
|
|
15557
15599
|
}
|
|
15558
15600
|
try {
|
|
15559
|
-
const { cpSync, existsSync:
|
|
15601
|
+
const { cpSync, existsSync: existsSync12, mkdirSync: mkdirSync3 } = await import("node:fs");
|
|
15560
15602
|
const { resolve: resolve9, dirname: dirname4 } = await import("node:path");
|
|
15561
15603
|
const { fileURLToPath: fileURLToPath2 } = await import("node:url");
|
|
15562
15604
|
const thisDir = typeof __dirname !== "undefined" ? __dirname : dirname4(fileURLToPath2(import.meta.url));
|
|
15563
15605
|
const pkgGithub = resolve9(thisDir, "..", ".github");
|
|
15564
15606
|
const destGithub = resolve9(targetPath, ".github");
|
|
15565
|
-
if (
|
|
15566
|
-
|
|
15607
|
+
if (existsSync12(pkgGithub)) {
|
|
15608
|
+
mkdirSync3(destGithub, { recursive: true });
|
|
15567
15609
|
const skillsSrc = resolve9(pkgGithub, "skills");
|
|
15568
|
-
if (
|
|
15610
|
+
if (existsSync12(skillsSrc)) {
|
|
15569
15611
|
cpSync(skillsSrc, resolve9(destGithub, "skills"), { recursive: true });
|
|
15570
15612
|
console.log(" .github/skills/ (SDD skills)");
|
|
15571
15613
|
}
|
|
15572
15614
|
const instrSrc = resolve9(pkgGithub, "copilot-instructions.md");
|
|
15573
|
-
if (
|
|
15615
|
+
if (existsSync12(instrSrc)) {
|
|
15574
15616
|
cpSync(instrSrc, resolve9(destGithub, "copilot-instructions.md"));
|
|
15575
15617
|
console.log(" .github/copilot-instructions.md");
|
|
15576
15618
|
}
|
|
@@ -15585,6 +15627,7 @@ async function handleTrace(sub, args) {
|
|
|
15585
15627
|
const generator = createMatrixGenerator();
|
|
15586
15628
|
const report = generator.generate([], [], []);
|
|
15587
15629
|
console.log(generator.toMarkdown(report));
|
|
15630
|
+
console.log("\n\u2139 No traceability data loaded \u2014 matrix is empty (completeness is N/A).");
|
|
15588
15631
|
return ExitCode.SUCCESS;
|
|
15589
15632
|
}
|
|
15590
15633
|
case "validate": {
|
|
@@ -15616,6 +15659,11 @@ async function handleTrace(sub, args) {
|
|
|
15616
15659
|
async function handleTraceVerify() {
|
|
15617
15660
|
const validator = createTraceabilityValidator();
|
|
15618
15661
|
const report = validator.validateCoverage([], [], [], []);
|
|
15662
|
+
if (report.totalRequirements === 0) {
|
|
15663
|
+
console.log("No traceability data loaded \u2014 nothing to verify.");
|
|
15664
|
+
console.log("\u2139 Coverage cannot be computed with 0 requirements (reported as N/A).");
|
|
15665
|
+
return ExitCode.SUCCESS;
|
|
15666
|
+
}
|
|
15619
15667
|
console.log(`Coverage: ${report.coveragePercent}%`);
|
|
15620
15668
|
console.log(`Requirements: ${report.coveredRequirements}/${report.totalRequirements}`);
|
|
15621
15669
|
if (report.gaps.length > 0) {
|
|
@@ -15715,6 +15763,31 @@ var EXT_TO_LANG = {
|
|
|
15715
15763
|
hs: "haskell",
|
|
15716
15764
|
lua: "lua"
|
|
15717
15765
|
};
|
|
15766
|
+
var WALK_IGNORE = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "coverage", ".next", "build"]);
|
|
15767
|
+
function collectFiles(target, extFilter) {
|
|
15768
|
+
const stat = statSync(target);
|
|
15769
|
+
if (stat.isFile())
|
|
15770
|
+
return [target];
|
|
15771
|
+
const out = [];
|
|
15772
|
+
const walk = (dir) => {
|
|
15773
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
15774
|
+
if (entry.name.startsWith(".") && entry.name !== ".")
|
|
15775
|
+
continue;
|
|
15776
|
+
if (WALK_IGNORE.has(entry.name))
|
|
15777
|
+
continue;
|
|
15778
|
+
const full = joinPath(dir, entry.name);
|
|
15779
|
+
if (entry.isDirectory()) {
|
|
15780
|
+
walk(full);
|
|
15781
|
+
} else if (entry.isFile()) {
|
|
15782
|
+
const ext = entry.name.split(".").pop() ?? "";
|
|
15783
|
+
if (!extFilter || extFilter(ext))
|
|
15784
|
+
out.push(full);
|
|
15785
|
+
}
|
|
15786
|
+
}
|
|
15787
|
+
};
|
|
15788
|
+
walk(target);
|
|
15789
|
+
return out;
|
|
15790
|
+
}
|
|
15718
15791
|
async function handleCodegraph(sub, args) {
|
|
15719
15792
|
switch (sub) {
|
|
15720
15793
|
case "index": {
|
|
@@ -15724,29 +15797,40 @@ async function handleCodegraph(sub, args) {
|
|
|
15724
15797
|
return ExitCode.GENERAL_ERROR;
|
|
15725
15798
|
}
|
|
15726
15799
|
try {
|
|
15727
|
-
|
|
15728
|
-
|
|
15729
|
-
const ext = targetPath.split(".").pop() ?? "";
|
|
15730
|
-
const lang = EXT_TO_LANG[ext];
|
|
15731
|
-
if (!lang) {
|
|
15732
|
-
console.error(`\u274C Unsupported file extension: .${ext}`);
|
|
15800
|
+
if (!existsSync11(targetPath)) {
|
|
15801
|
+
console.error(`\u274C Path not found: ${targetPath}`);
|
|
15733
15802
|
return ExitCode.GENERAL_ERROR;
|
|
15734
15803
|
}
|
|
15735
|
-
const
|
|
15804
|
+
const parser = createASTParser();
|
|
15736
15805
|
const engine = createGraphEngine();
|
|
15737
|
-
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15806
|
+
const files = collectFiles(targetPath, (ext) => ext in EXT_TO_LANG);
|
|
15807
|
+
if (files.length === 0) {
|
|
15808
|
+
console.error(`\u274C No indexable source files found under: ${targetPath}`);
|
|
15809
|
+
return ExitCode.GENERAL_ERROR;
|
|
15810
|
+
}
|
|
15811
|
+
let indexedFiles = 0;
|
|
15812
|
+
for (const file of files) {
|
|
15813
|
+
const ext = file.split(".").pop() ?? "";
|
|
15814
|
+
const lang = EXT_TO_LANG[ext];
|
|
15815
|
+
if (!lang)
|
|
15816
|
+
continue;
|
|
15817
|
+
const content = readFileSync6(file, "utf-8");
|
|
15818
|
+
const nodes = parser.parse(content, lang);
|
|
15819
|
+
for (const node of nodes) {
|
|
15820
|
+
engine.addNode({
|
|
15821
|
+
id: `${file}:${node.name}`,
|
|
15822
|
+
name: node.name,
|
|
15823
|
+
kind: node.kind,
|
|
15824
|
+
filePath: file,
|
|
15825
|
+
language: lang,
|
|
15826
|
+
startLine: 0,
|
|
15827
|
+
endLine: 0
|
|
15828
|
+
});
|
|
15829
|
+
}
|
|
15830
|
+
indexedFiles++;
|
|
15747
15831
|
}
|
|
15748
15832
|
const stats = engine.getStats();
|
|
15749
|
-
console.log(`\u2705 Indexed ${targetPath}: ${stats.nodeCount} nodes, ${stats.edgeCount} edges`);
|
|
15833
|
+
console.log(`\u2705 Indexed ${targetPath}: ${indexedFiles} file(s), ${stats.nodeCount} nodes, ${stats.edgeCount} edges`);
|
|
15750
15834
|
} catch (err) {
|
|
15751
15835
|
const msg = err instanceof Error ? err.message : String(err);
|
|
15752
15836
|
console.error(`\u274C ${msg}`);
|
|
@@ -15788,40 +15872,54 @@ async function handleCodegraph(sub, args) {
|
|
|
15788
15872
|
return ExitCode.SUCCESS;
|
|
15789
15873
|
}
|
|
15790
15874
|
}
|
|
15791
|
-
|
|
15875
|
+
var SEVERITY_ORDER = ["critical", "high", "medium", "low", "info"];
|
|
15876
|
+
async function handleSecurity(filePath, failOn) {
|
|
15792
15877
|
try {
|
|
15793
|
-
if (!
|
|
15794
|
-
console.error(`\u274C
|
|
15878
|
+
if (!existsSync11(filePath)) {
|
|
15879
|
+
console.error(`\u274C Path not found: ${filePath}`);
|
|
15795
15880
|
return ExitCode.GENERAL_ERROR;
|
|
15796
15881
|
}
|
|
15797
|
-
const code = readFileSync6(filePath, "utf-8");
|
|
15798
15882
|
const secrets = createSecretDetector();
|
|
15799
15883
|
const taint = new TaintAnalyzer();
|
|
15800
15884
|
const deps = new DependencyScanner();
|
|
15801
|
-
const
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
|
|
15805
|
-
|
|
15885
|
+
const files = collectFiles(filePath, (ext) => ext in EXT_TO_LANG);
|
|
15886
|
+
const findings = [];
|
|
15887
|
+
for (const file of files) {
|
|
15888
|
+
const code = readFileSync6(file, "utf-8");
|
|
15889
|
+
findings.push(...secrets.scan(code, file), ...taint.analyze(code, file), ...deps.scan(code, file));
|
|
15890
|
+
}
|
|
15806
15891
|
const bySeverity = /* @__PURE__ */ new Map();
|
|
15807
15892
|
for (const f of findings) {
|
|
15808
15893
|
const list = bySeverity.get(f.severity) ?? [];
|
|
15809
15894
|
list.push(f);
|
|
15810
15895
|
bySeverity.set(f.severity, list);
|
|
15811
15896
|
}
|
|
15812
|
-
console.log(`Security scan: ${filePath}`);
|
|
15897
|
+
console.log(`Security scan: ${filePath} (${files.length} file(s))`);
|
|
15813
15898
|
console.log(`Total findings: ${findings.length}`);
|
|
15814
|
-
const
|
|
15815
|
-
for (const sev of severityOrder) {
|
|
15899
|
+
for (const sev of SEVERITY_ORDER) {
|
|
15816
15900
|
const items = bySeverity.get(sev);
|
|
15817
15901
|
if (items && items.length > 0) {
|
|
15818
15902
|
console.log(`
|
|
15819
15903
|
${sev.toUpperCase()} (${items.length}):`);
|
|
15820
15904
|
for (const f of items) {
|
|
15821
|
-
console.log(` - ${f.description}`);
|
|
15905
|
+
console.log(` - ${f.description} (${f.location.file}:${f.location.line})`);
|
|
15822
15906
|
}
|
|
15823
15907
|
}
|
|
15824
15908
|
}
|
|
15909
|
+
if (failOn) {
|
|
15910
|
+
const threshold = failOn.toLowerCase();
|
|
15911
|
+
if (!SEVERITY_ORDER.includes(threshold)) {
|
|
15912
|
+
console.error(`\u274C Invalid --fail-on severity: ${failOn} (use critical|high|medium|low|info)`);
|
|
15913
|
+
return ExitCode.VALIDATION_ERROR;
|
|
15914
|
+
}
|
|
15915
|
+
const maxIdx = SEVERITY_ORDER.indexOf(threshold);
|
|
15916
|
+
const gating = findings.filter((f) => SEVERITY_ORDER.indexOf(f.severity) <= maxIdx);
|
|
15917
|
+
if (gating.length > 0) {
|
|
15918
|
+
console.error(`
|
|
15919
|
+
\u274C ${gating.length} finding(s) at or above "${threshold}" \u2014 failing.`);
|
|
15920
|
+
return ExitCode.VALIDATION_ERROR;
|
|
15921
|
+
}
|
|
15922
|
+
}
|
|
15825
15923
|
return ExitCode.SUCCESS;
|
|
15826
15924
|
} catch (err) {
|
|
15827
15925
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -15908,6 +16006,17 @@ async function handleReqValidate(filePath) {
|
|
|
15908
16006
|
}
|
|
15909
16007
|
if (requirements.length === 0) {
|
|
15910
16008
|
console.log("No requirements found in file");
|
|
16009
|
+
if (/REQ-/i.test(content)) {
|
|
16010
|
+
const headingLike = /^#{1,4}\s+REQ-[A-Z]{3}-\d{3}:/m.test(content);
|
|
16011
|
+
console.error('\u26A0 Found "REQ-" text but no parseable requirements. Requirements must be Markdown headings shaped like:');
|
|
16012
|
+
console.error(" ## REQ-XXX-000: <title> (XXX = 3-letter domain code)");
|
|
16013
|
+
console.error(" **\u8981\u4EF6**:");
|
|
16014
|
+
console.error(" THE \u30B7\u30B9\u30C6\u30E0 SHALL ...");
|
|
16015
|
+
if (!headingLike) {
|
|
16016
|
+
console.error('\u2139 Hint: list items (e.g. "- REQ-001: ...") and IDs without a 3-letter domain code are not recognized.');
|
|
16017
|
+
}
|
|
16018
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16019
|
+
}
|
|
15911
16020
|
}
|
|
15912
16021
|
return hasIssues ? ExitCode.VALIDATION_ERROR : ExitCode.SUCCESS;
|
|
15913
16022
|
} catch (err) {
|
|
@@ -16498,7 +16607,7 @@ async function handleExplain(input) {
|
|
|
16498
16607
|
const recorder = new ReasoningChainRecorder2();
|
|
16499
16608
|
const generator = new ExplanationGenerator2();
|
|
16500
16609
|
let code;
|
|
16501
|
-
if (
|
|
16610
|
+
if (existsSync11(input)) {
|
|
16502
16611
|
code = readFileSync6(input, "utf-8");
|
|
16503
16612
|
} else {
|
|
16504
16613
|
code = input;
|
|
@@ -16626,6 +16735,29 @@ async function handleWatch(pattern) {
|
|
|
16626
16735
|
});
|
|
16627
16736
|
return ExitCode.SUCCESS;
|
|
16628
16737
|
}
|
|
16738
|
+
function resolveTarget(args, verbs) {
|
|
16739
|
+
const positional = args["args"] ?? [];
|
|
16740
|
+
const sub = args["subcommand"];
|
|
16741
|
+
const explicitFile = args["file"];
|
|
16742
|
+
if (explicitFile)
|
|
16743
|
+
return explicitFile;
|
|
16744
|
+
if (sub && verbs.includes(sub.toLowerCase())) {
|
|
16745
|
+
return positional[0];
|
|
16746
|
+
}
|
|
16747
|
+
return sub ?? positional[0];
|
|
16748
|
+
}
|
|
16749
|
+
async function reqAction(args) {
|
|
16750
|
+
if (args["help"] === true || args["h"] === true) {
|
|
16751
|
+
console.log(showHelp("requirements"));
|
|
16752
|
+
return;
|
|
16753
|
+
}
|
|
16754
|
+
const filePath = resolveTarget(args, ["analyze", "validate"]);
|
|
16755
|
+
if (!filePath) {
|
|
16756
|
+
console.error("\u274C Usage: musubix requirements [analyze|validate] <file>");
|
|
16757
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16758
|
+
}
|
|
16759
|
+
return await handleReqValidate(filePath);
|
|
16760
|
+
}
|
|
16629
16761
|
function getDefaultCommands() {
|
|
16630
16762
|
return [
|
|
16631
16763
|
{
|
|
@@ -16675,7 +16807,7 @@ function getDefaultCommands() {
|
|
|
16675
16807
|
return;
|
|
16676
16808
|
}
|
|
16677
16809
|
const targetPath = args["subcommand"] ?? args["args"]?.[0] ?? ".";
|
|
16678
|
-
await handleInit(targetPath, args["name"], args["force"] === true);
|
|
16810
|
+
return await handleInit(targetPath, args["name"], args["force"] === true);
|
|
16679
16811
|
}
|
|
16680
16812
|
},
|
|
16681
16813
|
{
|
|
@@ -16693,37 +16825,32 @@ function getDefaultCommands() {
|
|
|
16693
16825
|
case "validate":
|
|
16694
16826
|
if (!filePath) {
|
|
16695
16827
|
console.error("\u274C Usage: musubix tasks validate <file>");
|
|
16696
|
-
return;
|
|
16828
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16697
16829
|
}
|
|
16698
|
-
await handleTasksValidate(filePath);
|
|
16830
|
+
return await handleTasksValidate(filePath);
|
|
16699
16831
|
break;
|
|
16700
16832
|
case "list":
|
|
16701
|
-
await handleTasksList(filePath);
|
|
16833
|
+
return await handleTasksList(filePath);
|
|
16702
16834
|
break;
|
|
16703
16835
|
case "stats":
|
|
16704
|
-
await handleTasksStats(filePath);
|
|
16836
|
+
return await handleTasksStats(filePath);
|
|
16705
16837
|
break;
|
|
16706
16838
|
default:
|
|
16707
16839
|
console.log(showHelp("tasks"));
|
|
16840
|
+
return;
|
|
16708
16841
|
}
|
|
16709
16842
|
}
|
|
16710
16843
|
},
|
|
16711
16844
|
{
|
|
16712
16845
|
name: "req",
|
|
16713
16846
|
description: "Analyze requirements (EARS validation)",
|
|
16714
|
-
action:
|
|
16715
|
-
|
|
16716
|
-
|
|
16717
|
-
|
|
16718
|
-
|
|
16719
|
-
|
|
16720
|
-
|
|
16721
|
-
if (!filePath) {
|
|
16722
|
-
console.error("\u274C Usage: musubix req <file>");
|
|
16723
|
-
return;
|
|
16724
|
-
}
|
|
16725
|
-
await handleReqValidate(filePath);
|
|
16726
|
-
}
|
|
16847
|
+
action: reqAction
|
|
16848
|
+
},
|
|
16849
|
+
{
|
|
16850
|
+
// Alias matching the documented `musubix requirements <analyze|validate> <file>` form.
|
|
16851
|
+
name: "requirements",
|
|
16852
|
+
description: "Analyze/validate requirements (EARS validation)",
|
|
16853
|
+
action: reqAction
|
|
16727
16854
|
},
|
|
16728
16855
|
{
|
|
16729
16856
|
name: "req:wizard",
|
|
@@ -16733,7 +16860,7 @@ function getDefaultCommands() {
|
|
|
16733
16860
|
console.log(showHelp("requirements"));
|
|
16734
16861
|
return;
|
|
16735
16862
|
}
|
|
16736
|
-
await handleReqWizard();
|
|
16863
|
+
return await handleReqWizard();
|
|
16737
16864
|
}
|
|
16738
16865
|
},
|
|
16739
16866
|
{
|
|
@@ -16744,7 +16871,7 @@ function getDefaultCommands() {
|
|
|
16744
16871
|
console.log(showHelp("requirements"));
|
|
16745
16872
|
return;
|
|
16746
16873
|
}
|
|
16747
|
-
await handleReqInterview(args);
|
|
16874
|
+
return await handleReqInterview(args);
|
|
16748
16875
|
}
|
|
16749
16876
|
},
|
|
16750
16877
|
{
|
|
@@ -16755,13 +16882,20 @@ function getDefaultCommands() {
|
|
|
16755
16882
|
console.log(showHelp("design"));
|
|
16756
16883
|
return;
|
|
16757
16884
|
}
|
|
16758
|
-
|
|
16759
|
-
|
|
16885
|
+
if (args["subcommand"]?.toLowerCase() === "verify") {
|
|
16886
|
+
const vf = resolveTarget(args, ["verify"]);
|
|
16887
|
+
if (!vf) {
|
|
16888
|
+
console.error("\u274C Usage: musubix design verify <design-file>");
|
|
16889
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16890
|
+
}
|
|
16891
|
+
return await handleDesignVerify(vf);
|
|
16892
|
+
}
|
|
16893
|
+
const filePath = resolveTarget(args, ["generate"]);
|
|
16760
16894
|
if (!filePath) {
|
|
16761
|
-
console.error("\u274C Usage: musubix design <requirements-file>");
|
|
16762
|
-
return;
|
|
16895
|
+
console.error("\u274C Usage: musubix design [generate] <requirements-file>");
|
|
16896
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16763
16897
|
}
|
|
16764
|
-
await handleDesignGenerate(filePath);
|
|
16898
|
+
return await handleDesignGenerate(filePath);
|
|
16765
16899
|
}
|
|
16766
16900
|
},
|
|
16767
16901
|
{
|
|
@@ -16776,10 +16910,10 @@ function getDefaultCommands() {
|
|
|
16776
16910
|
const filePath = args["file"] ?? args["subcommand"] ?? positionalArgs[0];
|
|
16777
16911
|
if (!filePath) {
|
|
16778
16912
|
console.error("\u274C Usage: musubix design:c4 <file> [--level context|container|component]");
|
|
16779
|
-
return;
|
|
16913
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16780
16914
|
}
|
|
16781
16915
|
const level = args["level"] ?? "context";
|
|
16782
|
-
await handleDesignC4(filePath, level);
|
|
16916
|
+
return await handleDesignC4(filePath, level);
|
|
16783
16917
|
}
|
|
16784
16918
|
},
|
|
16785
16919
|
{
|
|
@@ -16794,9 +16928,9 @@ function getDefaultCommands() {
|
|
|
16794
16928
|
const filePath = args["file"] ?? args["subcommand"] ?? positionalArgs[0];
|
|
16795
16929
|
if (!filePath) {
|
|
16796
16930
|
console.error("\u274C Usage: musubix design:verify <design-file>");
|
|
16797
|
-
return;
|
|
16931
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16798
16932
|
}
|
|
16799
|
-
await handleDesignVerify(filePath);
|
|
16933
|
+
return await handleDesignVerify(filePath);
|
|
16800
16934
|
}
|
|
16801
16935
|
},
|
|
16802
16936
|
{
|
|
@@ -16807,14 +16941,13 @@ function getDefaultCommands() {
|
|
|
16807
16941
|
console.log(showHelp("codegen"));
|
|
16808
16942
|
return;
|
|
16809
16943
|
}
|
|
16810
|
-
const
|
|
16811
|
-
const name = args["subcommand"] ?? positionalArgs[0];
|
|
16944
|
+
const name = resolveTarget(args, ["generate"]);
|
|
16812
16945
|
if (!name) {
|
|
16813
|
-
console.error("\u274C Usage: musubix codegen <name> [--type class|interface|function|...]");
|
|
16814
|
-
return;
|
|
16946
|
+
console.error("\u274C Usage: musubix codegen [generate] <name> [--type class|interface|function|...]");
|
|
16947
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16815
16948
|
}
|
|
16816
16949
|
const type = args["type"] ?? "class";
|
|
16817
|
-
await handleCodegen(name, type);
|
|
16950
|
+
return await handleCodegen(name, type);
|
|
16818
16951
|
}
|
|
16819
16952
|
},
|
|
16820
16953
|
{
|
|
@@ -16829,9 +16962,9 @@ function getDefaultCommands() {
|
|
|
16829
16962
|
const filePath = args["file"] ?? args["subcommand"] ?? positionalArgs[0];
|
|
16830
16963
|
if (!filePath) {
|
|
16831
16964
|
console.error("\u274C Usage: musubix test:gen <source-file>");
|
|
16832
|
-
return;
|
|
16965
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16833
16966
|
}
|
|
16834
|
-
await handleTestGen(filePath);
|
|
16967
|
+
return await handleTestGen(filePath);
|
|
16835
16968
|
}
|
|
16836
16969
|
},
|
|
16837
16970
|
{
|
|
@@ -16844,7 +16977,7 @@ function getDefaultCommands() {
|
|
|
16844
16977
|
}
|
|
16845
16978
|
const sub = args["subcommand"];
|
|
16846
16979
|
const positionalArgs = args["args"] ?? [];
|
|
16847
|
-
await handleTrace(sub, positionalArgs);
|
|
16980
|
+
return await handleTrace(sub, positionalArgs);
|
|
16848
16981
|
}
|
|
16849
16982
|
},
|
|
16850
16983
|
{
|
|
@@ -16855,7 +16988,7 @@ function getDefaultCommands() {
|
|
|
16855
16988
|
console.log(showHelp("trace:verify"));
|
|
16856
16989
|
return;
|
|
16857
16990
|
}
|
|
16858
|
-
await handleTraceVerify();
|
|
16991
|
+
return await handleTraceVerify();
|
|
16859
16992
|
}
|
|
16860
16993
|
},
|
|
16861
16994
|
{
|
|
@@ -16868,7 +17001,7 @@ function getDefaultCommands() {
|
|
|
16868
17001
|
}
|
|
16869
17002
|
const sub = args["subcommand"];
|
|
16870
17003
|
const positionalArgs = args["args"] ?? [];
|
|
16871
|
-
await handlePolicy(sub, positionalArgs);
|
|
17004
|
+
return await handlePolicy(sub, positionalArgs);
|
|
16872
17005
|
}
|
|
16873
17006
|
},
|
|
16874
17007
|
{
|
|
@@ -16880,7 +17013,7 @@ function getDefaultCommands() {
|
|
|
16880
17013
|
return;
|
|
16881
17014
|
}
|
|
16882
17015
|
const sub = args["subcommand"];
|
|
16883
|
-
await handleOntology(sub);
|
|
17016
|
+
return await handleOntology(sub);
|
|
16884
17017
|
}
|
|
16885
17018
|
},
|
|
16886
17019
|
{
|
|
@@ -16893,7 +17026,7 @@ function getDefaultCommands() {
|
|
|
16893
17026
|
}
|
|
16894
17027
|
const sub = args["subcommand"];
|
|
16895
17028
|
const positionalArgs = args["args"] ?? [];
|
|
16896
|
-
await handleCodegraph(sub, positionalArgs);
|
|
17029
|
+
return await handleCodegraph(sub, positionalArgs);
|
|
16897
17030
|
}
|
|
16898
17031
|
},
|
|
16899
17032
|
{
|
|
@@ -16907,10 +17040,10 @@ function getDefaultCommands() {
|
|
|
16907
17040
|
const positionalArgs = args["args"] ?? [];
|
|
16908
17041
|
const filePath = args["subcommand"] ?? positionalArgs[0];
|
|
16909
17042
|
if (!filePath) {
|
|
16910
|
-
console.error("\u274C Usage: musubix security <path>");
|
|
16911
|
-
return;
|
|
17043
|
+
console.error("\u274C Usage: musubix security <path> [--fail-on critical|high|medium|low|info]");
|
|
17044
|
+
return ExitCode.VALIDATION_ERROR;
|
|
16912
17045
|
}
|
|
16913
|
-
await handleSecurity(filePath);
|
|
17046
|
+
return await handleSecurity(filePath, args["fail-on"]);
|
|
16914
17047
|
}
|
|
16915
17048
|
},
|
|
16916
17049
|
{
|
|
@@ -16923,7 +17056,7 @@ function getDefaultCommands() {
|
|
|
16923
17056
|
}
|
|
16924
17057
|
const sub = args["subcommand"];
|
|
16925
17058
|
const positionalArgs = args["args"] ?? [];
|
|
16926
|
-
await handleWorkflow(sub, positionalArgs);
|
|
17059
|
+
return await handleWorkflow(sub, positionalArgs);
|
|
16927
17060
|
}
|
|
16928
17061
|
},
|
|
16929
17062
|
{
|
|
@@ -16934,7 +17067,7 @@ function getDefaultCommands() {
|
|
|
16934
17067
|
console.log(showHelp("status"));
|
|
16935
17068
|
return;
|
|
16936
17069
|
}
|
|
16937
|
-
await handleStatus();
|
|
17070
|
+
return await handleStatus();
|
|
16938
17071
|
}
|
|
16939
17072
|
},
|
|
16940
17073
|
{
|
|
@@ -16947,7 +17080,7 @@ function getDefaultCommands() {
|
|
|
16947
17080
|
}
|
|
16948
17081
|
const sub = args["subcommand"];
|
|
16949
17082
|
const positionalArgs = args["args"] ?? [];
|
|
16950
|
-
await handleSkills(sub, positionalArgs);
|
|
17083
|
+
return await handleSkills(sub, positionalArgs);
|
|
16951
17084
|
}
|
|
16952
17085
|
},
|
|
16953
17086
|
{
|
|
@@ -16960,7 +17093,7 @@ function getDefaultCommands() {
|
|
|
16960
17093
|
}
|
|
16961
17094
|
const sub = args["subcommand"];
|
|
16962
17095
|
const positionalArgs = args["args"] ?? [];
|
|
16963
|
-
await handleKnowledge(sub, positionalArgs, args);
|
|
17096
|
+
return await handleKnowledge(sub, positionalArgs, args);
|
|
16964
17097
|
}
|
|
16965
17098
|
},
|
|
16966
17099
|
{
|
|
@@ -16973,7 +17106,7 @@ function getDefaultCommands() {
|
|
|
16973
17106
|
}
|
|
16974
17107
|
const sub = args["subcommand"];
|
|
16975
17108
|
const positionalArgs = args["args"] ?? [];
|
|
16976
|
-
await handleDecision(sub, positionalArgs, args);
|
|
17109
|
+
return await handleDecision(sub, positionalArgs, args);
|
|
16977
17110
|
}
|
|
16978
17111
|
},
|
|
16979
17112
|
{
|
|
@@ -16986,7 +17119,7 @@ function getDefaultCommands() {
|
|
|
16986
17119
|
}
|
|
16987
17120
|
const sub = args["subcommand"];
|
|
16988
17121
|
const positionalArgs = args["args"] ?? [];
|
|
16989
|
-
await handleDeepResearch(sub, positionalArgs);
|
|
17122
|
+
return await handleDeepResearch(sub, positionalArgs);
|
|
16990
17123
|
}
|
|
16991
17124
|
},
|
|
16992
17125
|
{
|
|
@@ -16997,7 +17130,7 @@ function getDefaultCommands() {
|
|
|
16997
17130
|
console.log(showHelp("repl"));
|
|
16998
17131
|
return;
|
|
16999
17132
|
}
|
|
17000
|
-
await handleRepl();
|
|
17133
|
+
return await handleRepl();
|
|
17001
17134
|
}
|
|
17002
17135
|
},
|
|
17003
17136
|
{
|
|
@@ -17010,7 +17143,7 @@ function getDefaultCommands() {
|
|
|
17010
17143
|
}
|
|
17011
17144
|
const sub = args["subcommand"];
|
|
17012
17145
|
const positionalArgs = args["args"] ?? [];
|
|
17013
|
-
await handleScaffold(sub, positionalArgs);
|
|
17146
|
+
return await handleScaffold(sub, positionalArgs);
|
|
17014
17147
|
}
|
|
17015
17148
|
},
|
|
17016
17149
|
{
|
|
@@ -17023,7 +17156,7 @@ function getDefaultCommands() {
|
|
|
17023
17156
|
}
|
|
17024
17157
|
const positionalArgs = args["args"] ?? [];
|
|
17025
17158
|
const input = args["subcommand"] ?? positionalArgs[0];
|
|
17026
|
-
await handleExplain(input);
|
|
17159
|
+
return await handleExplain(input);
|
|
17027
17160
|
}
|
|
17028
17161
|
},
|
|
17029
17162
|
{
|
|
@@ -17036,7 +17169,7 @@ function getDefaultCommands() {
|
|
|
17036
17169
|
}
|
|
17037
17170
|
const sub = args["subcommand"];
|
|
17038
17171
|
const positionalArgs = args["args"] ?? [];
|
|
17039
|
-
await handleLearn(sub, positionalArgs);
|
|
17172
|
+
return await handleLearn(sub, positionalArgs);
|
|
17040
17173
|
}
|
|
17041
17174
|
},
|
|
17042
17175
|
{
|
|
@@ -17049,7 +17182,7 @@ function getDefaultCommands() {
|
|
|
17049
17182
|
}
|
|
17050
17183
|
const sub = args["subcommand"];
|
|
17051
17184
|
const positionalArgs = args["args"] ?? [];
|
|
17052
|
-
await handleSynthesis(sub, positionalArgs);
|
|
17185
|
+
return await handleSynthesis(sub, positionalArgs);
|
|
17053
17186
|
}
|
|
17054
17187
|
},
|
|
17055
17188
|
{
|
|
@@ -17062,7 +17195,7 @@ function getDefaultCommands() {
|
|
|
17062
17195
|
}
|
|
17063
17196
|
const positionalArgs = args["args"] ?? [];
|
|
17064
17197
|
const pattern = args["subcommand"] ?? positionalArgs[0];
|
|
17065
|
-
await handleWatch(pattern);
|
|
17198
|
+
return await handleWatch(pattern);
|
|
17066
17199
|
}
|
|
17067
17200
|
},
|
|
17068
17201
|
// P3-07: MCP server launcher
|