@praneeth_54/agentdoctor 2.0.0 → 2.0.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/CHANGELOG.md +73 -4
- package/README.md +283 -158
- package/dist/architecture/contract.d.ts +64 -0
- package/dist/architecture/contract.js +373 -0
- package/dist/assurance/change.d.ts +211 -0
- package/dist/assurance/change.js +624 -0
- package/dist/assurance/proof.d.ts +136 -0
- package/dist/assurance/proof.js +338 -0
- package/dist/auth/index.d.ts +81 -0
- package/dist/auth/index.js +130 -0
- package/dist/auth/rbac.d.ts +9 -0
- package/dist/auth/rbac.js +26 -0
- package/dist/cli/commands/architecture.d.ts +6 -0
- package/dist/cli/commands/architecture.js +109 -0
- package/dist/cli/commands/assurance.d.ts +67 -0
- package/dist/cli/commands/assurance.js +210 -0
- package/dist/cli/commands/complete.js +2 -2
- package/dist/cli/commands/platform.d.ts +2 -0
- package/dist/cli/commands/platform.js +5 -1
- package/dist/cli/commands/policy-graph-run.d.ts +40 -0
- package/dist/cli/commands/policy-graph-run.js +200 -0
- package/dist/cli/commands/workspace.d.ts +9 -0
- package/dist/cli/commands/workspace.js +82 -0
- package/dist/cli/program.js +535 -17
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/index.js +2 -2
- package/dist/core/brain-product/init.js +5 -2
- package/dist/core/secrets/scan.d.ts +7 -1
- package/dist/core/secrets/scan.js +9 -9
- package/dist/coverage/cobertura.d.ts +6 -0
- package/dist/coverage/cobertura.js +52 -0
- package/dist/coverage/istanbul.d.ts +7 -0
- package/dist/coverage/istanbul.js +134 -0
- package/dist/coverage/lcov.d.ts +7 -0
- package/dist/coverage/lcov.js +59 -0
- package/dist/coverage/load.d.ts +9 -0
- package/dist/coverage/load.js +39 -0
- package/dist/coverage/types.d.ts +23 -0
- package/dist/coverage/types.js +5 -0
- package/dist/dashboard/server.d.ts +1 -1
- package/dist/dashboard/server.js +21 -5
- package/dist/enforcement/runner.d.ts +47 -3
- package/dist/enforcement/runner.js +420 -16
- package/dist/index.d.ts +23 -2
- package/dist/index.js +15 -2
- package/dist/intelligence/graph/build.d.ts +2 -0
- package/dist/intelligence/graph/build.js +49 -5
- package/dist/intelligence/graph/incremental.d.ts +68 -0
- package/dist/intelligence/graph/incremental.js +234 -0
- package/dist/intelligence/resolve/imports.d.ts +36 -0
- package/dist/intelligence/resolve/imports.js +245 -0
- package/dist/languages/go.d.ts +9 -0
- package/dist/languages/go.js +45 -0
- package/dist/languages/index.d.ts +11 -0
- package/dist/languages/index.js +76 -0
- package/dist/languages/php.d.ts +7 -0
- package/dist/languages/php.js +193 -0
- package/dist/languages/python.d.ts +7 -0
- package/dist/languages/python.js +150 -0
- package/dist/languages/types.d.ts +42 -0
- package/dist/languages/types.js +26 -0
- package/dist/languages/typescript.d.ts +3 -0
- package/dist/languages/typescript.js +95 -0
- package/dist/mcp/intelligence/handlers.d.ts +5 -0
- package/dist/mcp/intelligence/handlers.js +229 -40
- package/dist/mcp/intelligence/path-safety.d.ts +2 -4
- package/dist/mcp/intelligence/path-safety.js +25 -44
- package/dist/mcp/intelligence/registry.d.ts +1 -1
- package/dist/mcp/intelligence/registry.js +69 -1
- package/dist/platform/firewall/evaluate.d.ts +6 -3
- package/dist/platform/firewall/evaluate.js +66 -15
- package/dist/platform/graph/build.js +19 -23
- package/dist/platform/health/analyze.js +23 -17
- package/dist/platform/index.js +2 -0
- package/dist/platform/test-impact/analyze.d.ts +21 -3
- package/dist/platform/test-impact/analyze.js +214 -28
- package/dist/platform/tokens/plan.js +39 -20
- package/dist/platform/types.d.ts +9 -0
- package/dist/policy/compose.d.ts +34 -0
- package/dist/policy/compose.js +118 -0
- package/dist/policy/packs.js +33 -1
- package/dist/security/paths.d.ts +21 -0
- package/dist/security/paths.js +105 -0
- package/dist/storage/postgres.d.ts +26 -0
- package/dist/storage/postgres.js +90 -0
- package/dist/storage/provider.d.ts +2 -7
- package/dist/storage/provider.js +22 -16
- package/dist/storage/sqlite.d.ts +33 -0
- package/dist/storage/sqlite.js +77 -0
- package/dist/team/auth.js +1 -1
- package/dist/workspace/index.d.ts +69 -0
- package/dist/workspace/index.js +220 -0
- package/package.json +9 -3
package/dist/cli/program.js
CHANGED
|
@@ -13,10 +13,16 @@ import { runBaselineCommand, runChangesCommand, runContextHealthCommand, runDash
|
|
|
13
13
|
import { runPlatformCommand } from "./commands/platform.js";
|
|
14
14
|
import { runInitCommand, runV2SurfaceCommand } from "./commands/complete.js";
|
|
15
15
|
import { runMcpCommand } from "./commands/mcp.js";
|
|
16
|
+
import { runChangeAnalyzeCommand, runChangeDiffCommand, runChangeExplainCommand, runChangeStatusCommand, runChangeVerifyCommand, runEvidenceInspectCommand, runEvidenceVerifyCommand, runProofBuildCommand, runProofExplainCommand, runProofExportCommand, runProofInspectCommand, runProofVerifyCommand, } from "./commands/assurance.js";
|
|
17
|
+
import { runGraphSurfaceCommand, runPolicyCheckCommand, runPolicyEnforceCommand, runPolicyExplainCommand, runRunCommand, runRunExplainCommand, } from "./commands/policy-graph-run.js";
|
|
18
|
+
import { runArchitectureCommand } from "./commands/architecture.js";
|
|
19
|
+
import { runWorkspaceCommand } from "./commands/workspace.js";
|
|
16
20
|
import { collectOpsHealth } from "../ops/health.js";
|
|
17
21
|
import { listSessions, loadSession } from "../platform/sessions/store.js";
|
|
18
22
|
import { exportReports } from "../platform/reports/export.js";
|
|
19
23
|
import { runPlatformScan } from "../platform/index.js";
|
|
24
|
+
import { analyzeTestImpact, formatTestImpactHuman, persistTestImpactReport, } from "../platform/test-impact/analyze.js";
|
|
25
|
+
import { resolveRepoRoot } from "../utils/path.js";
|
|
20
26
|
function parseMinScore(value) {
|
|
21
27
|
const parsed = Number(value);
|
|
22
28
|
if (!Number.isFinite(parsed) || parsed < 0 || parsed > 100) {
|
|
@@ -89,7 +95,7 @@ export function createProgram() {
|
|
|
89
95
|
const program = new Command();
|
|
90
96
|
addScanOptions(program
|
|
91
97
|
.name("agentdoctor")
|
|
92
|
-
.description("
|
|
98
|
+
.description("Engineering intelligence and safety for AI coding agents — scan, knowledge, MCP, and verification (local, deterministic; no API key required for core flows).")
|
|
93
99
|
.version(PACKAGE_VERSION, "-V, --version", "Print AgentDoctor version")
|
|
94
100
|
.argument("[path]", "Repository path to scan (default: current directory)")).action(async (pathArg, _options, command) => {
|
|
95
101
|
await runScanFromCli(pathArg, command);
|
|
@@ -317,21 +323,76 @@ export function createProgram() {
|
|
|
317
323
|
...(options.domain ? { domain: options.domain } : {}),
|
|
318
324
|
});
|
|
319
325
|
});
|
|
320
|
-
program
|
|
326
|
+
const graph = program
|
|
321
327
|
.command("graph")
|
|
322
|
-
.description("Build intelligence graph (TypeScript AST when available; regex fallback)")
|
|
328
|
+
.description("Build / update intelligence graph (TypeScript AST when available; regex fallback). Bare `graph` aliases build.")
|
|
323
329
|
.argument("[path]", "Repository path")
|
|
324
330
|
.option("--mode <mode>", "auto|regex|typescript-ast", "auto")
|
|
325
331
|
.option("--json", "Emit JSON", false)
|
|
326
332
|
.action(async (pathArg, _options, command) => {
|
|
327
333
|
const options = command.optsWithGlobals();
|
|
328
|
-
|
|
329
|
-
|
|
334
|
+
// Backward compat: `agentdoctor graph --json` → build + persist
|
|
335
|
+
process.exitCode = await runGraphSurfaceCommand({
|
|
336
|
+
action: "build",
|
|
337
|
+
root: resolveTargetArgument(pathArg),
|
|
338
|
+
mode: options.mode ?? "auto",
|
|
339
|
+
json: Boolean(options.json),
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
graph
|
|
343
|
+
.command("build")
|
|
344
|
+
.description("Build graph and persist .agentdoctor/graph/index.json")
|
|
345
|
+
.argument("[path]", "Repository path")
|
|
346
|
+
.option("--mode <mode>", "auto|regex|typescript-ast", "auto")
|
|
347
|
+
.option("--json", "Emit JSON", false)
|
|
348
|
+
.action(async (pathArg, options) => {
|
|
349
|
+
process.exitCode = await runGraphSurfaceCommand({
|
|
350
|
+
action: "build",
|
|
351
|
+
root: resolveTargetArgument(pathArg),
|
|
352
|
+
mode: options.mode ?? "auto",
|
|
353
|
+
json: Boolean(options.json),
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
graph
|
|
357
|
+
.command("update")
|
|
358
|
+
.description("Incrementally update graph from git/hash changes (rebuilds on corruption)")
|
|
359
|
+
.argument("[path]", "Repository path")
|
|
360
|
+
.option("--mode <mode>", "auto|regex|typescript-ast", "auto")
|
|
361
|
+
.option("--json", "Emit JSON", false)
|
|
362
|
+
.action(async (pathArg, options) => {
|
|
363
|
+
process.exitCode = await runGraphSurfaceCommand({
|
|
364
|
+
action: "update",
|
|
365
|
+
root: resolveTargetArgument(pathArg),
|
|
366
|
+
mode: options.mode ?? "auto",
|
|
367
|
+
json: Boolean(options.json),
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
graph
|
|
371
|
+
.command("rebuild")
|
|
372
|
+
.description("Force full graph rebuild")
|
|
373
|
+
.argument("[path]", "Repository path")
|
|
374
|
+
.option("--mode <mode>", "auto|regex|typescript-ast", "auto")
|
|
375
|
+
.option("--json", "Emit JSON", false)
|
|
376
|
+
.action(async (pathArg, options) => {
|
|
377
|
+
process.exitCode = await runGraphSurfaceCommand({
|
|
378
|
+
action: "rebuild",
|
|
330
379
|
root: resolveTargetArgument(pathArg),
|
|
331
380
|
mode: options.mode ?? "auto",
|
|
332
381
|
json: Boolean(options.json),
|
|
333
382
|
});
|
|
334
383
|
});
|
|
384
|
+
graph
|
|
385
|
+
.command("status")
|
|
386
|
+
.description("Show persisted graph index status")
|
|
387
|
+
.argument("[path]", "Repository path")
|
|
388
|
+
.option("--json", "Emit JSON", false)
|
|
389
|
+
.action(async (pathArg, options) => {
|
|
390
|
+
process.exitCode = await runGraphSurfaceCommand({
|
|
391
|
+
action: "status",
|
|
392
|
+
root: resolveTargetArgument(pathArg),
|
|
393
|
+
json: Boolean(options.json),
|
|
394
|
+
});
|
|
395
|
+
});
|
|
335
396
|
program
|
|
336
397
|
.command("health")
|
|
337
398
|
.description("Git hotspot / engineering intelligence report")
|
|
@@ -347,29 +408,63 @@ export function createProgram() {
|
|
|
347
408
|
});
|
|
348
409
|
program
|
|
349
410
|
.command("impact")
|
|
350
|
-
.description("Change/test impact analysis")
|
|
411
|
+
.description("Change/test impact analysis (heuristic by default; coverage-backed with --coverage)")
|
|
351
412
|
.argument("[path]", "Repository path")
|
|
413
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
414
|
+
.option("--since <ref>", "Diff since git ref")
|
|
352
415
|
.option("--json", "Emit JSON", false)
|
|
353
416
|
.action(async (pathArg, _options, command) => {
|
|
354
417
|
const options = command.optsWithGlobals();
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
418
|
+
const root = resolveTargetArgument(pathArg);
|
|
419
|
+
try {
|
|
420
|
+
const impact = await analyzeTestImpact({
|
|
421
|
+
root,
|
|
422
|
+
...(options.coverage ? { coveragePath: options.coverage } : {}),
|
|
423
|
+
...(options.since ? { since: options.since } : {}),
|
|
424
|
+
});
|
|
425
|
+
if (options.json) {
|
|
426
|
+
process.stdout.write(`${JSON.stringify(impact, null, 2)}\n`);
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
process.stdout.write(formatTestImpactHuman(impact));
|
|
430
|
+
}
|
|
431
|
+
process.exitCode = EXIT_CODES.SUCCESS;
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
435
|
+
process.exitCode = EXIT_CODES.INTERNAL_ERROR;
|
|
436
|
+
}
|
|
360
437
|
});
|
|
361
438
|
program
|
|
362
439
|
.command("test-impact")
|
|
363
440
|
.description("Test-impact analysis (alias of impact)")
|
|
364
441
|
.argument("[path]", "Repository path")
|
|
442
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
443
|
+
.option("--since <ref>", "Diff since git ref")
|
|
365
444
|
.option("--json", "Emit JSON", false)
|
|
366
445
|
.action(async (pathArg, _options, command) => {
|
|
367
446
|
const options = command.optsWithGlobals();
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
447
|
+
const root = resolveTargetArgument(pathArg);
|
|
448
|
+
try {
|
|
449
|
+
const impact = await analyzeTestImpact({
|
|
450
|
+
root,
|
|
451
|
+
...(options.coverage ? { coveragePath: options.coverage } : {}),
|
|
452
|
+
...(options.since ? { since: options.since } : {}),
|
|
453
|
+
});
|
|
454
|
+
const out = await persistTestImpactReport(resolveRepoRoot(root), impact);
|
|
455
|
+
if (options.json) {
|
|
456
|
+
process.stdout.write(`${JSON.stringify({ ...impact, reportPath: out }, null, 2)}\n`);
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
process.stdout.write(formatTestImpactHuman(impact));
|
|
460
|
+
process.stdout.write(` wrote: ${out}\n`);
|
|
461
|
+
}
|
|
462
|
+
process.exitCode = EXIT_CODES.SUCCESS;
|
|
463
|
+
}
|
|
464
|
+
catch (error) {
|
|
465
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
466
|
+
process.exitCode = EXIT_CODES.INTERNAL_ERROR;
|
|
467
|
+
}
|
|
373
468
|
});
|
|
374
469
|
program
|
|
375
470
|
.command("refactor-impact")
|
|
@@ -458,6 +553,57 @@ export function createProgram() {
|
|
|
458
553
|
json: Boolean(options.json),
|
|
459
554
|
});
|
|
460
555
|
});
|
|
556
|
+
const architecture = program
|
|
557
|
+
.command("architecture")
|
|
558
|
+
.description("Architecture contract + C4 views (rules are advisory until you treat check as a gate)");
|
|
559
|
+
architecture
|
|
560
|
+
.command("init")
|
|
561
|
+
.description("Write default .agentdoctor/architecture.json if missing")
|
|
562
|
+
.argument("[path]", "Repository path")
|
|
563
|
+
.option("--json", "Emit JSON", false)
|
|
564
|
+
.action(async (pathArg, options) => {
|
|
565
|
+
process.exitCode = await runArchitectureCommand({
|
|
566
|
+
action: "init",
|
|
567
|
+
root: resolveTargetArgument(pathArg),
|
|
568
|
+
json: Boolean(options.json),
|
|
569
|
+
});
|
|
570
|
+
});
|
|
571
|
+
architecture
|
|
572
|
+
.command("analyze")
|
|
573
|
+
.description("C4 views + architecture contract summary")
|
|
574
|
+
.argument("[path]", "Repository path")
|
|
575
|
+
.option("--json", "Emit JSON", false)
|
|
576
|
+
.action(async (pathArg, options) => {
|
|
577
|
+
process.exitCode = await runArchitectureCommand({
|
|
578
|
+
action: "analyze",
|
|
579
|
+
root: resolveTargetArgument(pathArg),
|
|
580
|
+
json: Boolean(options.json),
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
architecture
|
|
584
|
+
.command("check")
|
|
585
|
+
.description("Check import edges against .agentdoctor/architecture.json|.yml")
|
|
586
|
+
.argument("[path]", "Repository path")
|
|
587
|
+
.option("--json", "Emit JSON", false)
|
|
588
|
+
.action(async (pathArg, options) => {
|
|
589
|
+
process.exitCode = await runArchitectureCommand({
|
|
590
|
+
action: "check",
|
|
591
|
+
root: resolveTargetArgument(pathArg),
|
|
592
|
+
json: Boolean(options.json),
|
|
593
|
+
});
|
|
594
|
+
});
|
|
595
|
+
architecture
|
|
596
|
+
.command("explain")
|
|
597
|
+
.description("Explain architecture layers, forbidden/allowed rules, and recent violations")
|
|
598
|
+
.argument("[path]", "Repository path")
|
|
599
|
+
.option("--json", "Emit JSON", false)
|
|
600
|
+
.action(async (pathArg, options) => {
|
|
601
|
+
process.exitCode = await runArchitectureCommand({
|
|
602
|
+
action: "explain",
|
|
603
|
+
root: resolveTargetArgument(pathArg),
|
|
604
|
+
json: Boolean(options.json),
|
|
605
|
+
});
|
|
606
|
+
});
|
|
461
607
|
program
|
|
462
608
|
.command("knowledge")
|
|
463
609
|
.description("List governed knowledge records")
|
|
@@ -554,6 +700,374 @@ export function createProgram() {
|
|
|
554
700
|
json: Boolean(options.json),
|
|
555
701
|
});
|
|
556
702
|
});
|
|
703
|
+
const change = program
|
|
704
|
+
.command("change")
|
|
705
|
+
.description("Change assurance — structured assessment and evidence (never claims verified without evidence)");
|
|
706
|
+
change
|
|
707
|
+
.command("analyze")
|
|
708
|
+
.description("Assemble a ChangeAssessment from git, graph, policy, knowledge, and test signals")
|
|
709
|
+
.argument("[path]", "Repository path")
|
|
710
|
+
.option("--since <ref>", "Diff since git ref (e.g. main)")
|
|
711
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
712
|
+
.option("--json", "Emit JSON", false)
|
|
713
|
+
.action(async (pathArg, options) => {
|
|
714
|
+
process.exitCode = await runChangeAnalyzeCommand({
|
|
715
|
+
root: resolveTargetArgument(pathArg),
|
|
716
|
+
...(options.since ? { since: options.since } : {}),
|
|
717
|
+
...(options.coverage ? { coverage: options.coverage } : {}),
|
|
718
|
+
json: Boolean(options.json),
|
|
719
|
+
});
|
|
720
|
+
});
|
|
721
|
+
change
|
|
722
|
+
.command("verify")
|
|
723
|
+
.description("Produce a durable evidence bundle under .agentdoctor/evidence/<id>/ (status: evidence-produced)")
|
|
724
|
+
.argument("[path]", "Repository path")
|
|
725
|
+
.option("--since <ref>", "Diff since git ref (e.g. main)")
|
|
726
|
+
.option("--change-id <id>", "Reuse a change id")
|
|
727
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
728
|
+
.option("--json", "Emit JSON", false)
|
|
729
|
+
.action(async (pathArg, options) => {
|
|
730
|
+
process.exitCode = await runChangeVerifyCommand({
|
|
731
|
+
root: resolveTargetArgument(pathArg),
|
|
732
|
+
...(options.since ? { since: options.since } : {}),
|
|
733
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
734
|
+
...(options.coverage ? { coverage: options.coverage } : {}),
|
|
735
|
+
json: Boolean(options.json),
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
change
|
|
739
|
+
.command("explain")
|
|
740
|
+
.description("Human explanation of a change assessment (does not claim correctness)")
|
|
741
|
+
.argument("[path]", "Repository path")
|
|
742
|
+
.option("--since <ref>", "Diff since git ref")
|
|
743
|
+
.option("--change-id <id>", "Change id")
|
|
744
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
745
|
+
.option("--json", "Emit JSON", false)
|
|
746
|
+
.action(async (pathArg, options) => {
|
|
747
|
+
process.exitCode = await runChangeExplainCommand({
|
|
748
|
+
root: resolveTargetArgument(pathArg),
|
|
749
|
+
...(options.since ? { since: options.since } : {}),
|
|
750
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
751
|
+
...(options.coverage ? { coverage: options.coverage } : {}),
|
|
752
|
+
json: Boolean(options.json),
|
|
753
|
+
});
|
|
754
|
+
});
|
|
755
|
+
change
|
|
756
|
+
.command("diff")
|
|
757
|
+
.description("Summarize base/target file diffs from git")
|
|
758
|
+
.argument("[path]", "Repository path")
|
|
759
|
+
.option("--since <ref>", "Diff since git ref")
|
|
760
|
+
.option("--change-id <id>", "Change id (label only)")
|
|
761
|
+
.option("--json", "Emit JSON", false)
|
|
762
|
+
.action(async (pathArg, options) => {
|
|
763
|
+
process.exitCode = await runChangeDiffCommand({
|
|
764
|
+
root: resolveTargetArgument(pathArg),
|
|
765
|
+
...(options.since ? { since: options.since } : {}),
|
|
766
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
767
|
+
json: Boolean(options.json),
|
|
768
|
+
});
|
|
769
|
+
});
|
|
770
|
+
change
|
|
771
|
+
.command("status")
|
|
772
|
+
.description("Verification / evidence status for latest or --change-id")
|
|
773
|
+
.argument("[path]", "Repository path")
|
|
774
|
+
.option("--change-id <id>", "Change id")
|
|
775
|
+
.option("--json", "Emit JSON", false)
|
|
776
|
+
.action(async (pathArg, options) => {
|
|
777
|
+
process.exitCode = await runChangeStatusCommand({
|
|
778
|
+
root: resolveTargetArgument(pathArg),
|
|
779
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
780
|
+
json: Boolean(options.json),
|
|
781
|
+
});
|
|
782
|
+
});
|
|
783
|
+
const evidence = program
|
|
784
|
+
.command("evidence")
|
|
785
|
+
.description("Inspect and hash-verify change evidence bundles");
|
|
786
|
+
evidence
|
|
787
|
+
.command("inspect")
|
|
788
|
+
.description("List evidence artifacts for a change id")
|
|
789
|
+
.argument("<changeId>", "Change id (chg_…)")
|
|
790
|
+
.argument("[path]", "Repository path")
|
|
791
|
+
.option("--json", "Emit JSON", false)
|
|
792
|
+
.action(async (changeId, pathArg, options) => {
|
|
793
|
+
process.exitCode = await runEvidenceInspectCommand({
|
|
794
|
+
root: resolveTargetArgument(pathArg),
|
|
795
|
+
changeId,
|
|
796
|
+
json: Boolean(options.json),
|
|
797
|
+
});
|
|
798
|
+
});
|
|
799
|
+
evidence
|
|
800
|
+
.command("verify")
|
|
801
|
+
.description("Hash-check evidence bundle; status verified only when all hashes match")
|
|
802
|
+
.argument("<changeId>", "Change id (chg_…)")
|
|
803
|
+
.argument("[path]", "Repository path")
|
|
804
|
+
.option("--json", "Emit JSON", false)
|
|
805
|
+
.action(async (changeId, pathArg, options) => {
|
|
806
|
+
process.exitCode = await runEvidenceVerifyCommand({
|
|
807
|
+
root: resolveTargetArgument(pathArg),
|
|
808
|
+
changeId,
|
|
809
|
+
json: Boolean(options.json),
|
|
810
|
+
});
|
|
811
|
+
});
|
|
812
|
+
const proof = program
|
|
813
|
+
.command("proof")
|
|
814
|
+
.description("ChangeProof — hash integrity over evidence (never claims engineering correctness)");
|
|
815
|
+
proof
|
|
816
|
+
.command("build")
|
|
817
|
+
.description("Build a ChangeProof from an evidence bundle")
|
|
818
|
+
.argument("<changeId>", "Change id (chg_…)")
|
|
819
|
+
.argument("[path]", "Repository path")
|
|
820
|
+
.option("--json", "Emit JSON", false)
|
|
821
|
+
.action(async (changeId, pathArg, options) => {
|
|
822
|
+
process.exitCode = await runProofBuildCommand({
|
|
823
|
+
root: resolveTargetArgument(pathArg),
|
|
824
|
+
changeId,
|
|
825
|
+
json: Boolean(options.json),
|
|
826
|
+
});
|
|
827
|
+
});
|
|
828
|
+
proof
|
|
829
|
+
.command("inspect")
|
|
830
|
+
.description("Inspect a proof by proofId or changeId")
|
|
831
|
+
.argument("<id>", "proofId or changeId")
|
|
832
|
+
.argument("[path]", "Repository path")
|
|
833
|
+
.option("--json", "Emit JSON", false)
|
|
834
|
+
.action(async (id, pathArg, options) => {
|
|
835
|
+
process.exitCode = await runProofInspectCommand({
|
|
836
|
+
root: resolveTargetArgument(pathArg),
|
|
837
|
+
id,
|
|
838
|
+
json: Boolean(options.json),
|
|
839
|
+
});
|
|
840
|
+
});
|
|
841
|
+
proof
|
|
842
|
+
.command("explain")
|
|
843
|
+
.description("Human explanation of a ChangeProof (does not claim correctness)")
|
|
844
|
+
.argument("<id>", "proofId or changeId")
|
|
845
|
+
.argument("[path]", "Repository path")
|
|
846
|
+
.option("--json", "Emit JSON", false)
|
|
847
|
+
.action(async (id, pathArg, options) => {
|
|
848
|
+
process.exitCode = await runProofExplainCommand({
|
|
849
|
+
root: resolveTargetArgument(pathArg),
|
|
850
|
+
id,
|
|
851
|
+
json: Boolean(options.json),
|
|
852
|
+
});
|
|
853
|
+
});
|
|
854
|
+
proof
|
|
855
|
+
.command("verify")
|
|
856
|
+
.description("Re-hash evidence and compare to proof (integrity only)")
|
|
857
|
+
.argument("<id>", "proofId or changeId")
|
|
858
|
+
.argument("[path]", "Repository path")
|
|
859
|
+
.option("--json", "Emit JSON", false)
|
|
860
|
+
.action(async (id, pathArg, options) => {
|
|
861
|
+
process.exitCode = await runProofVerifyCommand({
|
|
862
|
+
root: resolveTargetArgument(pathArg),
|
|
863
|
+
id,
|
|
864
|
+
json: Boolean(options.json),
|
|
865
|
+
});
|
|
866
|
+
});
|
|
867
|
+
proof
|
|
868
|
+
.command("export")
|
|
869
|
+
.description("Export a proof JSON file")
|
|
870
|
+
.argument("<id>", "proofId or changeId")
|
|
871
|
+
.requiredOption("--out <file>", "Output file path")
|
|
872
|
+
.argument("[path]", "Repository path")
|
|
873
|
+
.option("--json", "Emit JSON", false)
|
|
874
|
+
.action(async (id, pathArg, options) => {
|
|
875
|
+
process.exitCode = await runProofExportCommand({
|
|
876
|
+
root: resolveTargetArgument(pathArg),
|
|
877
|
+
id,
|
|
878
|
+
out: options.out,
|
|
879
|
+
json: Boolean(options.json),
|
|
880
|
+
});
|
|
881
|
+
});
|
|
882
|
+
const policy = program
|
|
883
|
+
.command("policy")
|
|
884
|
+
.description("Action policy check / explain / enforce (controlled runner)");
|
|
885
|
+
policy
|
|
886
|
+
.command("check")
|
|
887
|
+
.description("Evaluate a command against local policy (evaluate-only)")
|
|
888
|
+
.requiredOption("--command <cmd>", "Command string")
|
|
889
|
+
.argument("[path]", "Repository path")
|
|
890
|
+
.option("--fail-closed", "Deny on invalid local policy", false)
|
|
891
|
+
.option("--json", "Emit JSON", false)
|
|
892
|
+
.action(async (pathArg, options) => {
|
|
893
|
+
process.exitCode = await runPolicyCheckCommand({
|
|
894
|
+
root: resolveTargetArgument(pathArg),
|
|
895
|
+
command: options.command,
|
|
896
|
+
failClosed: Boolean(options.failClosed),
|
|
897
|
+
json: Boolean(options.json),
|
|
898
|
+
});
|
|
899
|
+
});
|
|
900
|
+
policy
|
|
901
|
+
.command("explain")
|
|
902
|
+
.description("Explain why a command receives its policy decision")
|
|
903
|
+
.requiredOption("--command <cmd>", "Command string")
|
|
904
|
+
.argument("[path]", "Repository path")
|
|
905
|
+
.option("--fail-closed", "Deny on invalid local policy", false)
|
|
906
|
+
.option("--json", "Emit JSON", false)
|
|
907
|
+
.action(async (pathArg, options) => {
|
|
908
|
+
process.exitCode = await runPolicyExplainCommand({
|
|
909
|
+
root: resolveTargetArgument(pathArg),
|
|
910
|
+
command: options.command,
|
|
911
|
+
failClosed: Boolean(options.failClosed),
|
|
912
|
+
json: Boolean(options.json),
|
|
913
|
+
});
|
|
914
|
+
});
|
|
915
|
+
policy
|
|
916
|
+
.command("enforce")
|
|
917
|
+
.description("Evaluate policy; optionally execute when --execute and decision=allow")
|
|
918
|
+
.requiredOption("--command <cmd>", "Command string")
|
|
919
|
+
.option("--execute", "Execute via controlled runner when allowed", false)
|
|
920
|
+
.argument("[path]", "Repository path")
|
|
921
|
+
.option("--fail-closed", "Deny on invalid local policy", false)
|
|
922
|
+
.option("--json", "Emit JSON", false)
|
|
923
|
+
.action(async (pathArg, options) => {
|
|
924
|
+
process.exitCode = await runPolicyEnforceCommand({
|
|
925
|
+
root: resolveTargetArgument(pathArg),
|
|
926
|
+
command: options.command,
|
|
927
|
+
execute: Boolean(options.execute),
|
|
928
|
+
failClosed: Boolean(options.failClosed),
|
|
929
|
+
json: Boolean(options.json),
|
|
930
|
+
});
|
|
931
|
+
});
|
|
932
|
+
const runCmd = program
|
|
933
|
+
.command("run")
|
|
934
|
+
.description("Controlled execution (shell=false by default). Prefer: agentdoctor run -- <cmd> <args...>");
|
|
935
|
+
runCmd
|
|
936
|
+
.command("explain")
|
|
937
|
+
.description("Explain controlled-runner decision for a command (evaluate-only, never executes)")
|
|
938
|
+
.requiredOption("--command <cmd>", "Command string")
|
|
939
|
+
.argument("[path]", "Repository path")
|
|
940
|
+
.option("--shell", "Explain as if shell=true were requested", false)
|
|
941
|
+
.option("--fail-closed", "Deny on invalid local policy", false)
|
|
942
|
+
.option("--json", "Emit JSON", false)
|
|
943
|
+
.action(async (pathArg, options) => {
|
|
944
|
+
process.exitCode = await runRunExplainCommand({
|
|
945
|
+
root: resolveTargetArgument(pathArg),
|
|
946
|
+
command: options.command,
|
|
947
|
+
shell: Boolean(options.shell),
|
|
948
|
+
failClosed: Boolean(options.failClosed),
|
|
949
|
+
json: Boolean(options.json),
|
|
950
|
+
});
|
|
951
|
+
});
|
|
952
|
+
runCmd
|
|
953
|
+
.option("--shell", "HIGH RISK: allow shell interpretation (still requires policy allow)", false)
|
|
954
|
+
.option("--timeout <ms>", "Kill after timeout milliseconds", "30000")
|
|
955
|
+
.option("--fail-closed", "Deny on invalid local policy", false)
|
|
956
|
+
.option("--json", "Emit JSON", false)
|
|
957
|
+
.argument("[path]", "Repository path (ignored when -- separates args; use cwd)")
|
|
958
|
+
.argument("[command...]", "Command argv after --")
|
|
959
|
+
.allowUnknownOption(false)
|
|
960
|
+
.action(async (pathArg, commandParts, cmd) => {
|
|
961
|
+
const options = cmd.opts();
|
|
962
|
+
// Commander may put path as first arg when no `--`; prefer argv after `--` via raw args.
|
|
963
|
+
const raw = cmd.args;
|
|
964
|
+
let root = process.cwd();
|
|
965
|
+
let argv = [];
|
|
966
|
+
// If first token looks like a path-only invocation without command, treat as root.
|
|
967
|
+
if (commandParts && commandParts.length > 0) {
|
|
968
|
+
argv = commandParts;
|
|
969
|
+
if (pathArg)
|
|
970
|
+
root = resolveTargetArgument(pathArg);
|
|
971
|
+
}
|
|
972
|
+
else if (pathArg && !pathArg.startsWith("-")) {
|
|
973
|
+
// `run npm --version` style: pathArg is actually first command token
|
|
974
|
+
argv = [pathArg, ...(raw.slice(1) ?? [])];
|
|
975
|
+
}
|
|
976
|
+
// Prefer explicit `--` remainder from process.argv
|
|
977
|
+
const dd = process.argv.indexOf("--");
|
|
978
|
+
if (dd >= 0) {
|
|
979
|
+
argv = process.argv.slice(dd + 1);
|
|
980
|
+
root = process.cwd();
|
|
981
|
+
}
|
|
982
|
+
const timeoutMs = Number(options.timeout ?? 30000);
|
|
983
|
+
process.exitCode = await runRunCommand({
|
|
984
|
+
root: resolveTargetArgument(root),
|
|
985
|
+
argv,
|
|
986
|
+
shell: Boolean(options.shell),
|
|
987
|
+
timeoutMs: Number.isFinite(timeoutMs) ? timeoutMs : 30000,
|
|
988
|
+
failClosed: Boolean(options.failClosed),
|
|
989
|
+
json: Boolean(options.json),
|
|
990
|
+
});
|
|
991
|
+
});
|
|
992
|
+
const workspace = program
|
|
993
|
+
.command("workspace")
|
|
994
|
+
.description("Multi-repo workspace model under .agentdoctor/workspaces/ (local isolation)");
|
|
995
|
+
workspace
|
|
996
|
+
.command("init")
|
|
997
|
+
.description("Create a workspace JSON record")
|
|
998
|
+
.requiredOption("--name <name>", "Workspace display name")
|
|
999
|
+
.option("--id <id>", "Optional workspace id")
|
|
1000
|
+
.option("--repo <path>", "Initial repository root to add")
|
|
1001
|
+
.option("--allow-cross-read", "Allow reading other member repos (default false)", false)
|
|
1002
|
+
.argument("[path]", "Control root (stores .agentdoctor/workspaces)")
|
|
1003
|
+
.option("--json", "Emit JSON", false)
|
|
1004
|
+
.action(async (pathArg, options) => {
|
|
1005
|
+
process.exitCode = await runWorkspaceCommand({
|
|
1006
|
+
action: "init",
|
|
1007
|
+
root: resolveTargetArgument(pathArg),
|
|
1008
|
+
name: options.name,
|
|
1009
|
+
...(options.id ? { id: options.id } : {}),
|
|
1010
|
+
...(options.repo ? { repositoryRoot: resolveTargetArgument(options.repo) } : {}),
|
|
1011
|
+
allowCrossRead: Boolean(options.allowCrossRead),
|
|
1012
|
+
json: Boolean(options.json),
|
|
1013
|
+
});
|
|
1014
|
+
});
|
|
1015
|
+
workspace
|
|
1016
|
+
.command("add")
|
|
1017
|
+
.description("Add a repository root to a workspace")
|
|
1018
|
+
.requiredOption("--id <id>", "Workspace id")
|
|
1019
|
+
.requiredOption("--repo <path>", "Repository root to add")
|
|
1020
|
+
.argument("[path]", "Control root")
|
|
1021
|
+
.option("--json", "Emit JSON", false)
|
|
1022
|
+
.action(async (pathArg, options) => {
|
|
1023
|
+
process.exitCode = await runWorkspaceCommand({
|
|
1024
|
+
action: "add",
|
|
1025
|
+
root: resolveTargetArgument(pathArg),
|
|
1026
|
+
id: options.id,
|
|
1027
|
+
repositoryRoot: resolveTargetArgument(options.repo),
|
|
1028
|
+
json: Boolean(options.json),
|
|
1029
|
+
});
|
|
1030
|
+
});
|
|
1031
|
+
workspace
|
|
1032
|
+
.command("list")
|
|
1033
|
+
.description("List workspaces")
|
|
1034
|
+
.argument("[path]", "Control root")
|
|
1035
|
+
.option("--json", "Emit JSON", false)
|
|
1036
|
+
.action(async (pathArg, options) => {
|
|
1037
|
+
process.exitCode = await runWorkspaceCommand({
|
|
1038
|
+
action: "list",
|
|
1039
|
+
root: resolveTargetArgument(pathArg),
|
|
1040
|
+
json: Boolean(options.json),
|
|
1041
|
+
});
|
|
1042
|
+
});
|
|
1043
|
+
workspace
|
|
1044
|
+
.command("status")
|
|
1045
|
+
.description("Show workspace membership and missing roots")
|
|
1046
|
+
.requiredOption("--id <id>", "Workspace id")
|
|
1047
|
+
.argument("[path]", "Control root")
|
|
1048
|
+
.option("--json", "Emit JSON", false)
|
|
1049
|
+
.action(async (pathArg, options) => {
|
|
1050
|
+
process.exitCode = await runWorkspaceCommand({
|
|
1051
|
+
action: "status",
|
|
1052
|
+
root: resolveTargetArgument(pathArg),
|
|
1053
|
+
id: options.id,
|
|
1054
|
+
json: Boolean(options.json),
|
|
1055
|
+
});
|
|
1056
|
+
});
|
|
1057
|
+
workspace
|
|
1058
|
+
.command("remove")
|
|
1059
|
+
.description("Delete a workspace record")
|
|
1060
|
+
.requiredOption("--id <id>", "Workspace id")
|
|
1061
|
+
.argument("[path]", "Control root")
|
|
1062
|
+
.option("--json", "Emit JSON", false)
|
|
1063
|
+
.action(async (pathArg, options) => {
|
|
1064
|
+
process.exitCode = await runWorkspaceCommand({
|
|
1065
|
+
action: "remove",
|
|
1066
|
+
root: resolveTargetArgument(pathArg),
|
|
1067
|
+
id: options.id,
|
|
1068
|
+
json: Boolean(options.json),
|
|
1069
|
+
});
|
|
1070
|
+
});
|
|
557
1071
|
program
|
|
558
1072
|
.command("changes")
|
|
559
1073
|
.description("Analyze git working-tree / range changes")
|
|
@@ -752,8 +1266,10 @@ export function createProgram() {
|
|
|
752
1266
|
});
|
|
753
1267
|
platform
|
|
754
1268
|
.command("test-impact")
|
|
755
|
-
.description("Analyze which tests
|
|
1269
|
+
.description("Analyze which tests relate to git changes (heuristic; coverage-backed with --coverage; does not run tests)")
|
|
756
1270
|
.argument("[path]", "Repository path")
|
|
1271
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
1272
|
+
.option("--since <ref>", "Diff since git ref")
|
|
757
1273
|
.option("--json", "Emit JSON", false)
|
|
758
1274
|
.action(async (pathArg, _options, command) => {
|
|
759
1275
|
const options = command.optsWithGlobals();
|
|
@@ -761,6 +1277,8 @@ export function createProgram() {
|
|
|
761
1277
|
action: "test-impact",
|
|
762
1278
|
root: resolveTargetArgument(pathArg),
|
|
763
1279
|
json: Boolean(options.json),
|
|
1280
|
+
...(options.coverage ? { coverage: options.coverage } : {}),
|
|
1281
|
+
...(options.since ? { since: options.since } : {}),
|
|
764
1282
|
});
|
|
765
1283
|
});
|
|
766
1284
|
const registerPolicyCheck = (name, aliasNote) => {
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentId } from "./types/index.js";
|
|
2
|
-
export declare const PACKAGE_VERSION = "2.0.
|
|
2
|
+
export declare const PACKAGE_VERSION = "2.0.1";
|
|
3
3
|
export declare const DEFAULT_MAX_FILE_SIZE_BYTES: number;
|
|
4
4
|
/** Directories skipped during normal discovery (unless a rule needs them later). */
|
|
5
5
|
export declare const DEFAULT_IGNORE_DIRECTORIES: Set<string>;
|
package/dist/constants.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = "2.0.
|
|
1
|
+
export const PACKAGE_VERSION = "2.0.1";
|
|
2
2
|
export const DEFAULT_MAX_FILE_SIZE_BYTES = 2 * 1024 * 1024; // 2 MiB
|
|
3
3
|
/** Directories skipped during normal discovery (unless a rule needs them later). */
|
|
4
4
|
export const DEFAULT_IGNORE_DIRECTORIES = new Set([
|
|
@@ -105,7 +105,7 @@ export interface PolicyDecisionContract {
|
|
|
105
105
|
inputClassification: string;
|
|
106
106
|
evidence: EvidenceRef[];
|
|
107
107
|
riskLevel: Severity;
|
|
108
|
-
executionStatus: "not-executed" | "executed" | "blocked-by-enforcement";
|
|
108
|
+
executionStatus: "not-executed" | "executed" | "blocked-by-enforcement" | "execution-failed";
|
|
109
109
|
approvalStatus: "not-required" | "pending" | "approved" | "denied";
|
|
110
110
|
timestamp: string;
|
|
111
111
|
}
|
package/dist/contracts/index.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
export const CONTRACTS_VERSION = "2.0.0-contracts";
|
|
6
6
|
export const DEFAULT_FEATURE_FLAGS = {
|
|
7
7
|
typescriptAst: true,
|
|
8
|
-
sqliteStorage:
|
|
8
|
+
sqliteStorage: true,
|
|
9
9
|
teamMode: false,
|
|
10
|
-
enforcementRunner:
|
|
10
|
+
enforcementRunner: true,
|
|
11
11
|
vectorSearch: false,
|
|
12
12
|
architectureC4: true,
|
|
13
13
|
};
|