@praneeth_54/agentdoctor 2.0.0 → 2.1.0
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 +141 -4
- package/README.md +329 -153
- package/dist/agent/approvals.d.ts +24 -0
- package/dist/agent/approvals.js +64 -0
- package/dist/agent/chat/index.d.ts +7 -0
- package/dist/agent/chat/index.js +5 -0
- package/dist/agent/chat/memory.d.ts +44 -0
- package/dist/agent/chat/memory.js +103 -0
- package/dist/agent/chat/project-summary.d.ts +16 -0
- package/dist/agent/chat/project-summary.js +70 -0
- package/dist/agent/chat/prompts.d.ts +6 -0
- package/dist/agent/chat/prompts.js +39 -0
- package/dist/agent/chat/response.d.ts +19 -0
- package/dist/agent/chat/response.js +109 -0
- package/dist/agent/chat/service.d.ts +42 -0
- package/dist/agent/chat/service.js +252 -0
- package/dist/agent/chat/types.d.ts +48 -0
- package/dist/agent/chat/types.js +1 -0
- package/dist/agent/context/retrieve.d.ts +21 -0
- package/dist/agent/context/retrieve.js +117 -0
- package/dist/agent/context/truth.d.ts +6 -0
- package/dist/agent/context/truth.js +19 -0
- package/dist/agent/context/types.d.ts +23 -0
- package/dist/agent/context/types.js +4 -0
- package/dist/agent/index.d.ts +26 -0
- package/dist/agent/index.js +14 -0
- package/dist/agent/loop.d.ts +51 -0
- package/dist/agent/loop.js +222 -0
- package/dist/agent/modes.d.ts +18 -0
- package/dist/agent/modes.js +102 -0
- package/dist/agent/plan.d.ts +30 -0
- package/dist/agent/plan.js +121 -0
- package/dist/agent/runtime.d.ts +67 -0
- package/dist/agent/runtime.js +180 -0
- package/dist/agent/state.d.ts +30 -0
- package/dist/agent/state.js +95 -0
- package/dist/agent/student.d.ts +56 -0
- package/dist/agent/student.js +230 -0
- package/dist/agent/tools/execute.d.ts +18 -0
- package/dist/agent/tools/execute.js +355 -0
- package/dist/agent/tools/index.d.ts +6 -0
- package/dist/agent/tools/index.js +5 -0
- package/dist/agent/tools/registry.d.ts +7 -0
- package/dist/agent/tools/registry.js +212 -0
- package/dist/agent/tools/run.d.ts +24 -0
- package/dist/agent/tools/run.js +44 -0
- package/dist/agent/tools/types.d.ts +32 -0
- package/dist/agent/tools/types.js +10 -0
- package/dist/agent/tools/write.d.ts +24 -0
- package/dist/agent/tools/write.js +121 -0
- package/dist/agent/verify.d.ts +29 -0
- package/dist/agent/verify.js +210 -0
- package/dist/ai/config.d.ts +22 -0
- package/dist/ai/config.js +68 -0
- package/dist/ai/index.d.ts +17 -0
- package/dist/ai/index.js +52 -0
- package/dist/ai/providers/mock.d.ts +20 -0
- package/dist/ai/providers/mock.js +84 -0
- package/dist/ai/providers/none.d.ts +6 -0
- package/dist/ai/providers/none.js +23 -0
- package/dist/ai/providers/openai-compatible.d.ts +21 -0
- package/dist/ai/providers/openai-compatible.js +151 -0
- package/dist/ai/redact.d.ts +8 -0
- package/dist/ai/redact.js +21 -0
- package/dist/ai/types.d.ts +71 -0
- package/dist/ai/types.js +6 -0
- 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/agent.d.ts +27 -0
- package/dist/cli/commands/agent.js +153 -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/chat.d.ts +14 -0
- package/dist/cli/commands/chat.js +155 -0
- package/dist/cli/commands/complete.js +2 -2
- package/dist/cli/commands/learn.d.ts +12 -0
- package/dist/cli/commands/learn.js +107 -0
- 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 +627 -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 +7 -1
- package/dist/dashboard/server.js +110 -6
- package/dist/enforcement/runner.d.ts +52 -3
- package/dist/enforcement/runner.js +467 -16
- package/dist/index.d.ts +36 -2
- package/dist/index.js +23 -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 +50 -0
- package/dist/languages/index.d.ts +11 -0
- package/dist/languages/index.js +76 -0
- package/dist/languages/php.d.ts +8 -0
- package/dist/languages/php.js +202 -0
- package/dist/languages/python.d.ts +11 -0
- package/dist/languages/python.js +180 -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/agent/registry.d.ts +13 -0
- package/dist/mcp/agent/registry.js +234 -0
- package/dist/mcp/agentdoctor/server.js +8 -1
- 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 +133 -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,19 @@ 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";
|
|
20
|
+
import { runAskCommand, runChatCommand } from "./commands/chat.js";
|
|
21
|
+
import { runAgentCommand, runPlanCommand } from "./commands/agent.js";
|
|
22
|
+
import { runLearnCommand } from "./commands/learn.js";
|
|
16
23
|
import { collectOpsHealth } from "../ops/health.js";
|
|
17
24
|
import { listSessions, loadSession } from "../platform/sessions/store.js";
|
|
18
25
|
import { exportReports } from "../platform/reports/export.js";
|
|
19
26
|
import { runPlatformScan } from "../platform/index.js";
|
|
27
|
+
import { analyzeTestImpact, formatTestImpactHuman, persistTestImpactReport, } from "../platform/test-impact/analyze.js";
|
|
28
|
+
import { resolveRepoRoot } from "../utils/path.js";
|
|
20
29
|
function parseMinScore(value) {
|
|
21
30
|
const parsed = Number(value);
|
|
22
31
|
if (!Number.isFinite(parsed) || parsed < 0 || parsed > 100) {
|
|
@@ -89,7 +98,7 @@ export function createProgram() {
|
|
|
89
98
|
const program = new Command();
|
|
90
99
|
addScanOptions(program
|
|
91
100
|
.name("agentdoctor")
|
|
92
|
-
.description("
|
|
101
|
+
.description("Engineering intelligence and safety for AI coding agents — scan, knowledge, MCP, and verification (local, deterministic; no API key required for core flows).")
|
|
93
102
|
.version(PACKAGE_VERSION, "-V, --version", "Print AgentDoctor version")
|
|
94
103
|
.argument("[path]", "Repository path to scan (default: current directory)")).action(async (pathArg, _options, command) => {
|
|
95
104
|
await runScanFromCli(pathArg, command);
|
|
@@ -317,21 +326,76 @@ export function createProgram() {
|
|
|
317
326
|
...(options.domain ? { domain: options.domain } : {}),
|
|
318
327
|
});
|
|
319
328
|
});
|
|
320
|
-
program
|
|
329
|
+
const graph = program
|
|
321
330
|
.command("graph")
|
|
322
|
-
.description("Build intelligence graph (TypeScript AST when available; regex fallback)")
|
|
331
|
+
.description("Build / update intelligence graph (TypeScript AST when available; regex fallback). Bare `graph` aliases build.")
|
|
323
332
|
.argument("[path]", "Repository path")
|
|
324
333
|
.option("--mode <mode>", "auto|regex|typescript-ast", "auto")
|
|
325
334
|
.option("--json", "Emit JSON", false)
|
|
326
335
|
.action(async (pathArg, _options, command) => {
|
|
327
336
|
const options = command.optsWithGlobals();
|
|
328
|
-
|
|
329
|
-
|
|
337
|
+
// Backward compat: `agentdoctor graph --json` → build + persist
|
|
338
|
+
process.exitCode = await runGraphSurfaceCommand({
|
|
339
|
+
action: "build",
|
|
340
|
+
root: resolveTargetArgument(pathArg),
|
|
341
|
+
mode: options.mode ?? "auto",
|
|
342
|
+
json: Boolean(options.json),
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
graph
|
|
346
|
+
.command("build")
|
|
347
|
+
.description("Build graph and persist .agentdoctor/graph/index.json")
|
|
348
|
+
.argument("[path]", "Repository path")
|
|
349
|
+
.option("--mode <mode>", "auto|regex|typescript-ast", "auto")
|
|
350
|
+
.option("--json", "Emit JSON", false)
|
|
351
|
+
.action(async (pathArg, options) => {
|
|
352
|
+
process.exitCode = await runGraphSurfaceCommand({
|
|
353
|
+
action: "build",
|
|
354
|
+
root: resolveTargetArgument(pathArg),
|
|
355
|
+
mode: options.mode ?? "auto",
|
|
356
|
+
json: Boolean(options.json),
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
graph
|
|
360
|
+
.command("update")
|
|
361
|
+
.description("Incrementally update graph from git/hash changes (rebuilds on corruption)")
|
|
362
|
+
.argument("[path]", "Repository path")
|
|
363
|
+
.option("--mode <mode>", "auto|regex|typescript-ast", "auto")
|
|
364
|
+
.option("--json", "Emit JSON", false)
|
|
365
|
+
.action(async (pathArg, options) => {
|
|
366
|
+
process.exitCode = await runGraphSurfaceCommand({
|
|
367
|
+
action: "update",
|
|
368
|
+
root: resolveTargetArgument(pathArg),
|
|
369
|
+
mode: options.mode ?? "auto",
|
|
370
|
+
json: Boolean(options.json),
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
graph
|
|
374
|
+
.command("rebuild")
|
|
375
|
+
.description("Force full graph rebuild")
|
|
376
|
+
.argument("[path]", "Repository path")
|
|
377
|
+
.option("--mode <mode>", "auto|regex|typescript-ast", "auto")
|
|
378
|
+
.option("--json", "Emit JSON", false)
|
|
379
|
+
.action(async (pathArg, options) => {
|
|
380
|
+
process.exitCode = await runGraphSurfaceCommand({
|
|
381
|
+
action: "rebuild",
|
|
330
382
|
root: resolveTargetArgument(pathArg),
|
|
331
383
|
mode: options.mode ?? "auto",
|
|
332
384
|
json: Boolean(options.json),
|
|
333
385
|
});
|
|
334
386
|
});
|
|
387
|
+
graph
|
|
388
|
+
.command("status")
|
|
389
|
+
.description("Show persisted graph index status")
|
|
390
|
+
.argument("[path]", "Repository path")
|
|
391
|
+
.option("--json", "Emit JSON", false)
|
|
392
|
+
.action(async (pathArg, options) => {
|
|
393
|
+
process.exitCode = await runGraphSurfaceCommand({
|
|
394
|
+
action: "status",
|
|
395
|
+
root: resolveTargetArgument(pathArg),
|
|
396
|
+
json: Boolean(options.json),
|
|
397
|
+
});
|
|
398
|
+
});
|
|
335
399
|
program
|
|
336
400
|
.command("health")
|
|
337
401
|
.description("Git hotspot / engineering intelligence report")
|
|
@@ -347,29 +411,63 @@ export function createProgram() {
|
|
|
347
411
|
});
|
|
348
412
|
program
|
|
349
413
|
.command("impact")
|
|
350
|
-
.description("Change/test impact analysis")
|
|
414
|
+
.description("Change/test impact analysis (heuristic by default; coverage-backed with --coverage)")
|
|
351
415
|
.argument("[path]", "Repository path")
|
|
416
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
417
|
+
.option("--since <ref>", "Diff since git ref")
|
|
352
418
|
.option("--json", "Emit JSON", false)
|
|
353
419
|
.action(async (pathArg, _options, command) => {
|
|
354
420
|
const options = command.optsWithGlobals();
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
421
|
+
const root = resolveTargetArgument(pathArg);
|
|
422
|
+
try {
|
|
423
|
+
const impact = await analyzeTestImpact({
|
|
424
|
+
root,
|
|
425
|
+
...(options.coverage ? { coveragePath: options.coverage } : {}),
|
|
426
|
+
...(options.since ? { since: options.since } : {}),
|
|
427
|
+
});
|
|
428
|
+
if (options.json) {
|
|
429
|
+
process.stdout.write(`${JSON.stringify(impact, null, 2)}\n`);
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
process.stdout.write(formatTestImpactHuman(impact));
|
|
433
|
+
}
|
|
434
|
+
process.exitCode = EXIT_CODES.SUCCESS;
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
438
|
+
process.exitCode = EXIT_CODES.INTERNAL_ERROR;
|
|
439
|
+
}
|
|
360
440
|
});
|
|
361
441
|
program
|
|
362
442
|
.command("test-impact")
|
|
363
443
|
.description("Test-impact analysis (alias of impact)")
|
|
364
444
|
.argument("[path]", "Repository path")
|
|
445
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
446
|
+
.option("--since <ref>", "Diff since git ref")
|
|
365
447
|
.option("--json", "Emit JSON", false)
|
|
366
448
|
.action(async (pathArg, _options, command) => {
|
|
367
449
|
const options = command.optsWithGlobals();
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
450
|
+
const root = resolveTargetArgument(pathArg);
|
|
451
|
+
try {
|
|
452
|
+
const impact = await analyzeTestImpact({
|
|
453
|
+
root,
|
|
454
|
+
...(options.coverage ? { coveragePath: options.coverage } : {}),
|
|
455
|
+
...(options.since ? { since: options.since } : {}),
|
|
456
|
+
});
|
|
457
|
+
const out = await persistTestImpactReport(resolveRepoRoot(root), impact);
|
|
458
|
+
if (options.json) {
|
|
459
|
+
process.stdout.write(`${JSON.stringify({ ...impact, reportPath: out }, null, 2)}\n`);
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
process.stdout.write(formatTestImpactHuman(impact));
|
|
463
|
+
process.stdout.write(` wrote: ${out}\n`);
|
|
464
|
+
}
|
|
465
|
+
process.exitCode = EXIT_CODES.SUCCESS;
|
|
466
|
+
}
|
|
467
|
+
catch (error) {
|
|
468
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
469
|
+
process.exitCode = EXIT_CODES.INTERNAL_ERROR;
|
|
470
|
+
}
|
|
373
471
|
});
|
|
374
472
|
program
|
|
375
473
|
.command("refactor-impact")
|
|
@@ -458,6 +556,57 @@ export function createProgram() {
|
|
|
458
556
|
json: Boolean(options.json),
|
|
459
557
|
});
|
|
460
558
|
});
|
|
559
|
+
const architecture = program
|
|
560
|
+
.command("architecture")
|
|
561
|
+
.description("Architecture contract + C4 views (rules are advisory until you treat check as a gate)");
|
|
562
|
+
architecture
|
|
563
|
+
.command("init")
|
|
564
|
+
.description("Write default .agentdoctor/architecture.json if missing")
|
|
565
|
+
.argument("[path]", "Repository path")
|
|
566
|
+
.option("--json", "Emit JSON", false)
|
|
567
|
+
.action(async (pathArg, options) => {
|
|
568
|
+
process.exitCode = await runArchitectureCommand({
|
|
569
|
+
action: "init",
|
|
570
|
+
root: resolveTargetArgument(pathArg),
|
|
571
|
+
json: Boolean(options.json),
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
architecture
|
|
575
|
+
.command("analyze")
|
|
576
|
+
.description("C4 views + architecture contract summary")
|
|
577
|
+
.argument("[path]", "Repository path")
|
|
578
|
+
.option("--json", "Emit JSON", false)
|
|
579
|
+
.action(async (pathArg, options) => {
|
|
580
|
+
process.exitCode = await runArchitectureCommand({
|
|
581
|
+
action: "analyze",
|
|
582
|
+
root: resolveTargetArgument(pathArg),
|
|
583
|
+
json: Boolean(options.json),
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
architecture
|
|
587
|
+
.command("check")
|
|
588
|
+
.description("Check import edges against .agentdoctor/architecture.json|.yml")
|
|
589
|
+
.argument("[path]", "Repository path")
|
|
590
|
+
.option("--json", "Emit JSON", false)
|
|
591
|
+
.action(async (pathArg, options) => {
|
|
592
|
+
process.exitCode = await runArchitectureCommand({
|
|
593
|
+
action: "check",
|
|
594
|
+
root: resolveTargetArgument(pathArg),
|
|
595
|
+
json: Boolean(options.json),
|
|
596
|
+
});
|
|
597
|
+
});
|
|
598
|
+
architecture
|
|
599
|
+
.command("explain")
|
|
600
|
+
.description("Explain architecture layers, forbidden/allowed rules, and recent violations")
|
|
601
|
+
.argument("[path]", "Repository path")
|
|
602
|
+
.option("--json", "Emit JSON", false)
|
|
603
|
+
.action(async (pathArg, options) => {
|
|
604
|
+
process.exitCode = await runArchitectureCommand({
|
|
605
|
+
action: "explain",
|
|
606
|
+
root: resolveTargetArgument(pathArg),
|
|
607
|
+
json: Boolean(options.json),
|
|
608
|
+
});
|
|
609
|
+
});
|
|
461
610
|
program
|
|
462
611
|
.command("knowledge")
|
|
463
612
|
.description("List governed knowledge records")
|
|
@@ -554,6 +703,374 @@ export function createProgram() {
|
|
|
554
703
|
json: Boolean(options.json),
|
|
555
704
|
});
|
|
556
705
|
});
|
|
706
|
+
const change = program
|
|
707
|
+
.command("change")
|
|
708
|
+
.description("Change assurance — structured assessment and evidence (never claims verified without evidence)");
|
|
709
|
+
change
|
|
710
|
+
.command("analyze")
|
|
711
|
+
.description("Assemble a ChangeAssessment from git, graph, policy, knowledge, and test signals")
|
|
712
|
+
.argument("[path]", "Repository path")
|
|
713
|
+
.option("--since <ref>", "Diff since git ref (e.g. main)")
|
|
714
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
715
|
+
.option("--json", "Emit JSON", false)
|
|
716
|
+
.action(async (pathArg, options) => {
|
|
717
|
+
process.exitCode = await runChangeAnalyzeCommand({
|
|
718
|
+
root: resolveTargetArgument(pathArg),
|
|
719
|
+
...(options.since ? { since: options.since } : {}),
|
|
720
|
+
...(options.coverage ? { coverage: options.coverage } : {}),
|
|
721
|
+
json: Boolean(options.json),
|
|
722
|
+
});
|
|
723
|
+
});
|
|
724
|
+
change
|
|
725
|
+
.command("verify")
|
|
726
|
+
.description("Produce a durable evidence bundle under .agentdoctor/evidence/<id>/ (status: evidence-produced)")
|
|
727
|
+
.argument("[path]", "Repository path")
|
|
728
|
+
.option("--since <ref>", "Diff since git ref (e.g. main)")
|
|
729
|
+
.option("--change-id <id>", "Reuse a change id")
|
|
730
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
731
|
+
.option("--json", "Emit JSON", false)
|
|
732
|
+
.action(async (pathArg, options) => {
|
|
733
|
+
process.exitCode = await runChangeVerifyCommand({
|
|
734
|
+
root: resolveTargetArgument(pathArg),
|
|
735
|
+
...(options.since ? { since: options.since } : {}),
|
|
736
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
737
|
+
...(options.coverage ? { coverage: options.coverage } : {}),
|
|
738
|
+
json: Boolean(options.json),
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
change
|
|
742
|
+
.command("explain")
|
|
743
|
+
.description("Human explanation of a change assessment (does not claim correctness)")
|
|
744
|
+
.argument("[path]", "Repository path")
|
|
745
|
+
.option("--since <ref>", "Diff since git ref")
|
|
746
|
+
.option("--change-id <id>", "Change id")
|
|
747
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
748
|
+
.option("--json", "Emit JSON", false)
|
|
749
|
+
.action(async (pathArg, options) => {
|
|
750
|
+
process.exitCode = await runChangeExplainCommand({
|
|
751
|
+
root: resolveTargetArgument(pathArg),
|
|
752
|
+
...(options.since ? { since: options.since } : {}),
|
|
753
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
754
|
+
...(options.coverage ? { coverage: options.coverage } : {}),
|
|
755
|
+
json: Boolean(options.json),
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
change
|
|
759
|
+
.command("diff")
|
|
760
|
+
.description("Summarize base/target file diffs from git")
|
|
761
|
+
.argument("[path]", "Repository path")
|
|
762
|
+
.option("--since <ref>", "Diff since git ref")
|
|
763
|
+
.option("--change-id <id>", "Change id (label only)")
|
|
764
|
+
.option("--json", "Emit JSON", false)
|
|
765
|
+
.action(async (pathArg, options) => {
|
|
766
|
+
process.exitCode = await runChangeDiffCommand({
|
|
767
|
+
root: resolveTargetArgument(pathArg),
|
|
768
|
+
...(options.since ? { since: options.since } : {}),
|
|
769
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
770
|
+
json: Boolean(options.json),
|
|
771
|
+
});
|
|
772
|
+
});
|
|
773
|
+
change
|
|
774
|
+
.command("status")
|
|
775
|
+
.description("Verification / evidence status for latest or --change-id")
|
|
776
|
+
.argument("[path]", "Repository path")
|
|
777
|
+
.option("--change-id <id>", "Change id")
|
|
778
|
+
.option("--json", "Emit JSON", false)
|
|
779
|
+
.action(async (pathArg, options) => {
|
|
780
|
+
process.exitCode = await runChangeStatusCommand({
|
|
781
|
+
root: resolveTargetArgument(pathArg),
|
|
782
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
783
|
+
json: Boolean(options.json),
|
|
784
|
+
});
|
|
785
|
+
});
|
|
786
|
+
const evidence = program
|
|
787
|
+
.command("evidence")
|
|
788
|
+
.description("Inspect and hash-verify change evidence bundles");
|
|
789
|
+
evidence
|
|
790
|
+
.command("inspect")
|
|
791
|
+
.description("List evidence artifacts for a change id")
|
|
792
|
+
.argument("<changeId>", "Change id (chg_…)")
|
|
793
|
+
.argument("[path]", "Repository path")
|
|
794
|
+
.option("--json", "Emit JSON", false)
|
|
795
|
+
.action(async (changeId, pathArg, options) => {
|
|
796
|
+
process.exitCode = await runEvidenceInspectCommand({
|
|
797
|
+
root: resolveTargetArgument(pathArg),
|
|
798
|
+
changeId,
|
|
799
|
+
json: Boolean(options.json),
|
|
800
|
+
});
|
|
801
|
+
});
|
|
802
|
+
evidence
|
|
803
|
+
.command("verify")
|
|
804
|
+
.description("Hash-check evidence bundle; status verified only when all hashes match")
|
|
805
|
+
.argument("<changeId>", "Change id (chg_…)")
|
|
806
|
+
.argument("[path]", "Repository path")
|
|
807
|
+
.option("--json", "Emit JSON", false)
|
|
808
|
+
.action(async (changeId, pathArg, options) => {
|
|
809
|
+
process.exitCode = await runEvidenceVerifyCommand({
|
|
810
|
+
root: resolveTargetArgument(pathArg),
|
|
811
|
+
changeId,
|
|
812
|
+
json: Boolean(options.json),
|
|
813
|
+
});
|
|
814
|
+
});
|
|
815
|
+
const proof = program
|
|
816
|
+
.command("proof")
|
|
817
|
+
.description("ChangeProof — hash integrity over evidence (never claims engineering correctness)");
|
|
818
|
+
proof
|
|
819
|
+
.command("build")
|
|
820
|
+
.description("Build a ChangeProof from an evidence bundle")
|
|
821
|
+
.argument("<changeId>", "Change id (chg_…)")
|
|
822
|
+
.argument("[path]", "Repository path")
|
|
823
|
+
.option("--json", "Emit JSON", false)
|
|
824
|
+
.action(async (changeId, pathArg, options) => {
|
|
825
|
+
process.exitCode = await runProofBuildCommand({
|
|
826
|
+
root: resolveTargetArgument(pathArg),
|
|
827
|
+
changeId,
|
|
828
|
+
json: Boolean(options.json),
|
|
829
|
+
});
|
|
830
|
+
});
|
|
831
|
+
proof
|
|
832
|
+
.command("inspect")
|
|
833
|
+
.description("Inspect a proof by proofId or changeId")
|
|
834
|
+
.argument("<id>", "proofId or changeId")
|
|
835
|
+
.argument("[path]", "Repository path")
|
|
836
|
+
.option("--json", "Emit JSON", false)
|
|
837
|
+
.action(async (id, pathArg, options) => {
|
|
838
|
+
process.exitCode = await runProofInspectCommand({
|
|
839
|
+
root: resolveTargetArgument(pathArg),
|
|
840
|
+
id,
|
|
841
|
+
json: Boolean(options.json),
|
|
842
|
+
});
|
|
843
|
+
});
|
|
844
|
+
proof
|
|
845
|
+
.command("explain")
|
|
846
|
+
.description("Human explanation of a ChangeProof (does not claim correctness)")
|
|
847
|
+
.argument("<id>", "proofId or changeId")
|
|
848
|
+
.argument("[path]", "Repository path")
|
|
849
|
+
.option("--json", "Emit JSON", false)
|
|
850
|
+
.action(async (id, pathArg, options) => {
|
|
851
|
+
process.exitCode = await runProofExplainCommand({
|
|
852
|
+
root: resolveTargetArgument(pathArg),
|
|
853
|
+
id,
|
|
854
|
+
json: Boolean(options.json),
|
|
855
|
+
});
|
|
856
|
+
});
|
|
857
|
+
proof
|
|
858
|
+
.command("verify")
|
|
859
|
+
.description("Re-hash evidence and compare to proof (integrity only)")
|
|
860
|
+
.argument("<id>", "proofId or changeId")
|
|
861
|
+
.argument("[path]", "Repository path")
|
|
862
|
+
.option("--json", "Emit JSON", false)
|
|
863
|
+
.action(async (id, pathArg, options) => {
|
|
864
|
+
process.exitCode = await runProofVerifyCommand({
|
|
865
|
+
root: resolveTargetArgument(pathArg),
|
|
866
|
+
id,
|
|
867
|
+
json: Boolean(options.json),
|
|
868
|
+
});
|
|
869
|
+
});
|
|
870
|
+
proof
|
|
871
|
+
.command("export")
|
|
872
|
+
.description("Export a proof JSON file")
|
|
873
|
+
.argument("<id>", "proofId or changeId")
|
|
874
|
+
.requiredOption("--out <file>", "Output file path")
|
|
875
|
+
.argument("[path]", "Repository path")
|
|
876
|
+
.option("--json", "Emit JSON", false)
|
|
877
|
+
.action(async (id, pathArg, options) => {
|
|
878
|
+
process.exitCode = await runProofExportCommand({
|
|
879
|
+
root: resolveTargetArgument(pathArg),
|
|
880
|
+
id,
|
|
881
|
+
out: options.out,
|
|
882
|
+
json: Boolean(options.json),
|
|
883
|
+
});
|
|
884
|
+
});
|
|
885
|
+
const policy = program
|
|
886
|
+
.command("policy")
|
|
887
|
+
.description("Action policy check / explain / enforce (controlled runner)");
|
|
888
|
+
policy
|
|
889
|
+
.command("check")
|
|
890
|
+
.description("Evaluate a command against local policy (evaluate-only)")
|
|
891
|
+
.requiredOption("--command <cmd>", "Command string")
|
|
892
|
+
.argument("[path]", "Repository path")
|
|
893
|
+
.option("--fail-closed", "Deny on invalid local policy", false)
|
|
894
|
+
.option("--json", "Emit JSON", false)
|
|
895
|
+
.action(async (pathArg, options) => {
|
|
896
|
+
process.exitCode = await runPolicyCheckCommand({
|
|
897
|
+
root: resolveTargetArgument(pathArg),
|
|
898
|
+
command: options.command,
|
|
899
|
+
failClosed: Boolean(options.failClosed),
|
|
900
|
+
json: Boolean(options.json),
|
|
901
|
+
});
|
|
902
|
+
});
|
|
903
|
+
policy
|
|
904
|
+
.command("explain")
|
|
905
|
+
.description("Explain why a command receives its policy decision")
|
|
906
|
+
.requiredOption("--command <cmd>", "Command string")
|
|
907
|
+
.argument("[path]", "Repository path")
|
|
908
|
+
.option("--fail-closed", "Deny on invalid local policy", false)
|
|
909
|
+
.option("--json", "Emit JSON", false)
|
|
910
|
+
.action(async (pathArg, options) => {
|
|
911
|
+
process.exitCode = await runPolicyExplainCommand({
|
|
912
|
+
root: resolveTargetArgument(pathArg),
|
|
913
|
+
command: options.command,
|
|
914
|
+
failClosed: Boolean(options.failClosed),
|
|
915
|
+
json: Boolean(options.json),
|
|
916
|
+
});
|
|
917
|
+
});
|
|
918
|
+
policy
|
|
919
|
+
.command("enforce")
|
|
920
|
+
.description("Evaluate policy; optionally execute when --execute and decision=allow")
|
|
921
|
+
.requiredOption("--command <cmd>", "Command string")
|
|
922
|
+
.option("--execute", "Execute via controlled runner when allowed", false)
|
|
923
|
+
.argument("[path]", "Repository path")
|
|
924
|
+
.option("--fail-closed", "Deny on invalid local policy", false)
|
|
925
|
+
.option("--json", "Emit JSON", false)
|
|
926
|
+
.action(async (pathArg, options) => {
|
|
927
|
+
process.exitCode = await runPolicyEnforceCommand({
|
|
928
|
+
root: resolveTargetArgument(pathArg),
|
|
929
|
+
command: options.command,
|
|
930
|
+
execute: Boolean(options.execute),
|
|
931
|
+
failClosed: Boolean(options.failClosed),
|
|
932
|
+
json: Boolean(options.json),
|
|
933
|
+
});
|
|
934
|
+
});
|
|
935
|
+
const runCmd = program
|
|
936
|
+
.command("run")
|
|
937
|
+
.description("Controlled execution (shell=false by default). Prefer: agentdoctor run -- <cmd> <args...>");
|
|
938
|
+
runCmd
|
|
939
|
+
.command("explain")
|
|
940
|
+
.description("Explain controlled-runner decision for a command (evaluate-only, never executes)")
|
|
941
|
+
.requiredOption("--command <cmd>", "Command string")
|
|
942
|
+
.argument("[path]", "Repository path")
|
|
943
|
+
.option("--shell", "Explain as if shell=true were requested", false)
|
|
944
|
+
.option("--fail-closed", "Deny on invalid local policy", false)
|
|
945
|
+
.option("--json", "Emit JSON", false)
|
|
946
|
+
.action(async (pathArg, options) => {
|
|
947
|
+
process.exitCode = await runRunExplainCommand({
|
|
948
|
+
root: resolveTargetArgument(pathArg),
|
|
949
|
+
command: options.command,
|
|
950
|
+
shell: Boolean(options.shell),
|
|
951
|
+
failClosed: Boolean(options.failClosed),
|
|
952
|
+
json: Boolean(options.json),
|
|
953
|
+
});
|
|
954
|
+
});
|
|
955
|
+
runCmd
|
|
956
|
+
.option("--shell", "HIGH RISK: allow shell interpretation (still requires policy allow)", false)
|
|
957
|
+
.option("--timeout <ms>", "Kill after timeout milliseconds", "30000")
|
|
958
|
+
.option("--fail-closed", "Deny on invalid local policy", false)
|
|
959
|
+
.option("--json", "Emit JSON", false)
|
|
960
|
+
.argument("[path]", "Repository path (ignored when -- separates args; use cwd)")
|
|
961
|
+
.argument("[command...]", "Command argv after --")
|
|
962
|
+
.allowUnknownOption(false)
|
|
963
|
+
.action(async (pathArg, commandParts, cmd) => {
|
|
964
|
+
const options = cmd.opts();
|
|
965
|
+
// Commander may put path as first arg when no `--`; prefer argv after `--` via raw args.
|
|
966
|
+
const raw = cmd.args;
|
|
967
|
+
let root = process.cwd();
|
|
968
|
+
let argv = [];
|
|
969
|
+
// If first token looks like a path-only invocation without command, treat as root.
|
|
970
|
+
if (commandParts && commandParts.length > 0) {
|
|
971
|
+
argv = commandParts;
|
|
972
|
+
if (pathArg)
|
|
973
|
+
root = resolveTargetArgument(pathArg);
|
|
974
|
+
}
|
|
975
|
+
else if (pathArg && !pathArg.startsWith("-")) {
|
|
976
|
+
// `run npm --version` style: pathArg is actually first command token
|
|
977
|
+
argv = [pathArg, ...(raw.slice(1) ?? [])];
|
|
978
|
+
}
|
|
979
|
+
// Prefer explicit `--` remainder from process.argv
|
|
980
|
+
const dd = process.argv.indexOf("--");
|
|
981
|
+
if (dd >= 0) {
|
|
982
|
+
argv = process.argv.slice(dd + 1);
|
|
983
|
+
root = process.cwd();
|
|
984
|
+
}
|
|
985
|
+
const timeoutMs = Number(options.timeout ?? 30000);
|
|
986
|
+
process.exitCode = await runRunCommand({
|
|
987
|
+
root: resolveTargetArgument(root),
|
|
988
|
+
argv,
|
|
989
|
+
shell: Boolean(options.shell),
|
|
990
|
+
timeoutMs: Number.isFinite(timeoutMs) ? timeoutMs : 30000,
|
|
991
|
+
failClosed: Boolean(options.failClosed),
|
|
992
|
+
json: Boolean(options.json),
|
|
993
|
+
});
|
|
994
|
+
});
|
|
995
|
+
const workspace = program
|
|
996
|
+
.command("workspace")
|
|
997
|
+
.description("Multi-repo workspace model under .agentdoctor/workspaces/ (local isolation)");
|
|
998
|
+
workspace
|
|
999
|
+
.command("init")
|
|
1000
|
+
.description("Create a workspace JSON record")
|
|
1001
|
+
.requiredOption("--name <name>", "Workspace display name")
|
|
1002
|
+
.option("--id <id>", "Optional workspace id")
|
|
1003
|
+
.option("--repo <path>", "Initial repository root to add")
|
|
1004
|
+
.option("--allow-cross-read", "Allow reading other member repos (default false)", false)
|
|
1005
|
+
.argument("[path]", "Control root (stores .agentdoctor/workspaces)")
|
|
1006
|
+
.option("--json", "Emit JSON", false)
|
|
1007
|
+
.action(async (pathArg, options) => {
|
|
1008
|
+
process.exitCode = await runWorkspaceCommand({
|
|
1009
|
+
action: "init",
|
|
1010
|
+
root: resolveTargetArgument(pathArg),
|
|
1011
|
+
name: options.name,
|
|
1012
|
+
...(options.id ? { id: options.id } : {}),
|
|
1013
|
+
...(options.repo ? { repositoryRoot: resolveTargetArgument(options.repo) } : {}),
|
|
1014
|
+
allowCrossRead: Boolean(options.allowCrossRead),
|
|
1015
|
+
json: Boolean(options.json),
|
|
1016
|
+
});
|
|
1017
|
+
});
|
|
1018
|
+
workspace
|
|
1019
|
+
.command("add")
|
|
1020
|
+
.description("Add a repository root to a workspace")
|
|
1021
|
+
.requiredOption("--id <id>", "Workspace id")
|
|
1022
|
+
.requiredOption("--repo <path>", "Repository root to add")
|
|
1023
|
+
.argument("[path]", "Control root")
|
|
1024
|
+
.option("--json", "Emit JSON", false)
|
|
1025
|
+
.action(async (pathArg, options) => {
|
|
1026
|
+
process.exitCode = await runWorkspaceCommand({
|
|
1027
|
+
action: "add",
|
|
1028
|
+
root: resolveTargetArgument(pathArg),
|
|
1029
|
+
id: options.id,
|
|
1030
|
+
repositoryRoot: resolveTargetArgument(options.repo),
|
|
1031
|
+
json: Boolean(options.json),
|
|
1032
|
+
});
|
|
1033
|
+
});
|
|
1034
|
+
workspace
|
|
1035
|
+
.command("list")
|
|
1036
|
+
.description("List workspaces")
|
|
1037
|
+
.argument("[path]", "Control root")
|
|
1038
|
+
.option("--json", "Emit JSON", false)
|
|
1039
|
+
.action(async (pathArg, options) => {
|
|
1040
|
+
process.exitCode = await runWorkspaceCommand({
|
|
1041
|
+
action: "list",
|
|
1042
|
+
root: resolveTargetArgument(pathArg),
|
|
1043
|
+
json: Boolean(options.json),
|
|
1044
|
+
});
|
|
1045
|
+
});
|
|
1046
|
+
workspace
|
|
1047
|
+
.command("status")
|
|
1048
|
+
.description("Show workspace membership and missing roots")
|
|
1049
|
+
.requiredOption("--id <id>", "Workspace id")
|
|
1050
|
+
.argument("[path]", "Control root")
|
|
1051
|
+
.option("--json", "Emit JSON", false)
|
|
1052
|
+
.action(async (pathArg, options) => {
|
|
1053
|
+
process.exitCode = await runWorkspaceCommand({
|
|
1054
|
+
action: "status",
|
|
1055
|
+
root: resolveTargetArgument(pathArg),
|
|
1056
|
+
id: options.id,
|
|
1057
|
+
json: Boolean(options.json),
|
|
1058
|
+
});
|
|
1059
|
+
});
|
|
1060
|
+
workspace
|
|
1061
|
+
.command("remove")
|
|
1062
|
+
.description("Delete a workspace record")
|
|
1063
|
+
.requiredOption("--id <id>", "Workspace id")
|
|
1064
|
+
.argument("[path]", "Control root")
|
|
1065
|
+
.option("--json", "Emit JSON", false)
|
|
1066
|
+
.action(async (pathArg, options) => {
|
|
1067
|
+
process.exitCode = await runWorkspaceCommand({
|
|
1068
|
+
action: "remove",
|
|
1069
|
+
root: resolveTargetArgument(pathArg),
|
|
1070
|
+
id: options.id,
|
|
1071
|
+
json: Boolean(options.json),
|
|
1072
|
+
});
|
|
1073
|
+
});
|
|
557
1074
|
program
|
|
558
1075
|
.command("changes")
|
|
559
1076
|
.description("Analyze git working-tree / range changes")
|
|
@@ -721,6 +1238,95 @@ export function createProgram() {
|
|
|
721
1238
|
json: Boolean(options.json),
|
|
722
1239
|
});
|
|
723
1240
|
});
|
|
1241
|
+
program
|
|
1242
|
+
.command("chat")
|
|
1243
|
+
.description("Project Chat (2.1): evidence-backed conversation about this repository (requires AI provider)")
|
|
1244
|
+
.argument("[path]", "Repository path (default: current directory)")
|
|
1245
|
+
.action(async (pathArg) => {
|
|
1246
|
+
process.exitCode = await runChatCommand({
|
|
1247
|
+
root: resolveTargetArgument(pathArg),
|
|
1248
|
+
});
|
|
1249
|
+
});
|
|
1250
|
+
program
|
|
1251
|
+
.command("ask")
|
|
1252
|
+
.description("One-shot Project Chat question (same engine as chat)")
|
|
1253
|
+
.argument("<question>", "Question about the project")
|
|
1254
|
+
.argument("[path]", "Repository path (default: current directory)")
|
|
1255
|
+
.option("--json", "Emit JSON response", false)
|
|
1256
|
+
.action(async (question, pathArg, options) => {
|
|
1257
|
+
process.exitCode = await runAskCommand({
|
|
1258
|
+
question,
|
|
1259
|
+
root: resolveTargetArgument(pathArg),
|
|
1260
|
+
json: Boolean(options.json),
|
|
1261
|
+
});
|
|
1262
|
+
});
|
|
1263
|
+
program
|
|
1264
|
+
.command("plan")
|
|
1265
|
+
.description("Project Agent plan (2.1 M3): understand goal, list likely files, request approval — no file edits")
|
|
1266
|
+
.argument("<goal>", "What you want to build or change")
|
|
1267
|
+
.argument("[path]", "Repository path (default: current directory)")
|
|
1268
|
+
.option("--json", "Emit JSON plan", false)
|
|
1269
|
+
.option("--approve", "Record human approval (still no writes in M3)", false)
|
|
1270
|
+
.action(async (goal, pathArg, options) => {
|
|
1271
|
+
process.exitCode = await runPlanCommand({
|
|
1272
|
+
goal,
|
|
1273
|
+
root: resolveTargetArgument(pathArg),
|
|
1274
|
+
json: Boolean(options.json),
|
|
1275
|
+
approve: Boolean(options.approve),
|
|
1276
|
+
});
|
|
1277
|
+
});
|
|
1278
|
+
program
|
|
1279
|
+
.command("agent")
|
|
1280
|
+
.description("Project Agent (2.1): list tools, run tools, plan, or apply approved file/command changes")
|
|
1281
|
+
.argument("[path]", "Repository path (default: current directory)")
|
|
1282
|
+
.option("--list-tools", "List available agent tools", false)
|
|
1283
|
+
.option("--tool <name>", "Run a single tool by name")
|
|
1284
|
+
.option("--goal <text>", "Build a change plan for this goal")
|
|
1285
|
+
.option("--approve", "Record explicit human approval", false)
|
|
1286
|
+
.option("--apply", "Apply approved changes (requires --approve)", false)
|
|
1287
|
+
.option("--apply-ops <json>", "JSON array of {name, arguments} tool ops for --apply")
|
|
1288
|
+
.option("--skip-verify", "Skip post-change verification after apply", false)
|
|
1289
|
+
.option("--run-tests", "Run controlled tests during verification", false)
|
|
1290
|
+
.option("--json", "Emit JSON", false)
|
|
1291
|
+
.action(async (pathArg, options) => {
|
|
1292
|
+
process.exitCode = await runAgentCommand({
|
|
1293
|
+
root: resolveTargetArgument(pathArg),
|
|
1294
|
+
listTools: Boolean(options.listTools),
|
|
1295
|
+
...(options.tool !== undefined ? { tool: options.tool } : {}),
|
|
1296
|
+
...(options.goal !== undefined ? { goal: options.goal } : {}),
|
|
1297
|
+
approve: Boolean(options.approve),
|
|
1298
|
+
apply: Boolean(options.apply),
|
|
1299
|
+
...(options.applyOps !== undefined ? { applyOpsJson: options.applyOps } : {}),
|
|
1300
|
+
verify: !options.skipVerify,
|
|
1301
|
+
runTests: Boolean(options.runTests),
|
|
1302
|
+
json: Boolean(options.json),
|
|
1303
|
+
});
|
|
1304
|
+
});
|
|
1305
|
+
program
|
|
1306
|
+
.command("learn")
|
|
1307
|
+
.description("Student Learn mode (2.1 M6): explain project, viva questions, grounded documentation")
|
|
1308
|
+
.argument("[path]", "Repository path (default: current directory)")
|
|
1309
|
+
.option("--mode <mode>", "LEARN | BUILD_WITH_ME | BUILD_FOR_ME | DEVELOPER", "LEARN")
|
|
1310
|
+
.option("--viva", "Generate viva questions from detected stack", false)
|
|
1311
|
+
.option("--docs", "Generate project documentation sections", false)
|
|
1312
|
+
.option("--build <goal>", "BUILD_WITH_ME / BUILD_FOR_ME: explain, plan, then coding loop")
|
|
1313
|
+
.option("--approve", "Human approval required before BUILD writes", false)
|
|
1314
|
+
.option("--apply-ops <json>", "Deterministic tool ops JSON array for --build --approve")
|
|
1315
|
+
.option("--json", "Emit JSON", false)
|
|
1316
|
+
.option("--mock", "Use MockModelProvider", false)
|
|
1317
|
+
.action(async (pathArg, options) => {
|
|
1318
|
+
process.exitCode = await runLearnCommand({
|
|
1319
|
+
root: resolveTargetArgument(pathArg),
|
|
1320
|
+
...(options.mode !== undefined ? { mode: options.mode } : {}),
|
|
1321
|
+
viva: Boolean(options.viva),
|
|
1322
|
+
docs: Boolean(options.docs),
|
|
1323
|
+
...(options.build !== undefined ? { build: options.build } : {}),
|
|
1324
|
+
approve: Boolean(options.approve),
|
|
1325
|
+
...(options.applyOps !== undefined ? { applyOpsJson: options.applyOps } : {}),
|
|
1326
|
+
json: Boolean(options.json),
|
|
1327
|
+
useMock: Boolean(options.mock),
|
|
1328
|
+
});
|
|
1329
|
+
});
|
|
724
1330
|
const platform = program
|
|
725
1331
|
.command("platform")
|
|
726
1332
|
.description("AgentDoctor 2.0 local platform (intelligence, Action Policy Evaluator, sessions, reports)");
|
|
@@ -752,8 +1358,10 @@ export function createProgram() {
|
|
|
752
1358
|
});
|
|
753
1359
|
platform
|
|
754
1360
|
.command("test-impact")
|
|
755
|
-
.description("Analyze which tests
|
|
1361
|
+
.description("Analyze which tests relate to git changes (heuristic; coverage-backed with --coverage; does not run tests)")
|
|
756
1362
|
.argument("[path]", "Repository path")
|
|
1363
|
+
.option("--coverage <path>", "LCOV / Istanbul JSON / Cobertura XML coverage file")
|
|
1364
|
+
.option("--since <ref>", "Diff since git ref")
|
|
757
1365
|
.option("--json", "Emit JSON", false)
|
|
758
1366
|
.action(async (pathArg, _options, command) => {
|
|
759
1367
|
const options = command.optsWithGlobals();
|
|
@@ -761,6 +1369,8 @@ export function createProgram() {
|
|
|
761
1369
|
action: "test-impact",
|
|
762
1370
|
root: resolveTargetArgument(pathArg),
|
|
763
1371
|
json: Boolean(options.json),
|
|
1372
|
+
...(options.coverage ? { coverage: options.coverage } : {}),
|
|
1373
|
+
...(options.since ? { since: options.since } : {}),
|
|
764
1374
|
});
|
|
765
1375
|
});
|
|
766
1376
|
const registerPolicyCheck = (name, aliasNote) => {
|