@lousy-agents/cli 5.16.0 → 5.17.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.
Files changed (2) hide show
  1. package/dist/index.js +282 -35
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2990,7 +2990,7 @@ exports.basename = (path, { windows } = {}) => {
2990
2990
 
2991
2991
 
2992
2992
  },
2993
- 149(__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
2993
+ 889(__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
2994
2994
  // NAMESPACE OBJECT: ../../node_modules/micromark/lib/constructs.js
2995
2995
  var constructs_namespaceObject = {};
2996
2996
  __webpack_require__.r(constructs_namespaceObject);
@@ -11160,7 +11160,7 @@ function handleIntersectionResults(result, left, right) {
11160
11160
  result.value = merged.data;
11161
11161
  return result;
11162
11162
  }
11163
- const $ZodTuple = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodTuple", (inst, def) => {
11163
+ const $ZodTuple = /*@__PURE__*/ $constructor("$ZodTuple", (inst, def) => {
11164
11164
  $ZodType.init(inst, def);
11165
11165
  const items = def.items;
11166
11166
  inst._zod.parse = (payload, ctx) => {
@@ -11236,7 +11236,7 @@ const $ZodTuple = /*@__PURE__*/ (/* unused pure expression or super */ null && (
11236
11236
  }
11237
11237
  return handleTupleResults(itemResults, payload, items, input, optoutStart);
11238
11238
  };
11239
- })));
11239
+ });
11240
11240
  function getTupleOptStart(items, key) {
11241
11241
  for (let i = items.length - 1; i >= 0; i--) {
11242
11242
  if (items[i]._zod[key] !== "optional")
@@ -11246,7 +11246,7 @@ function getTupleOptStart(items, key) {
11246
11246
  }
11247
11247
  function handleTupleResult(result, final, index) {
11248
11248
  if (result.issues.length) {
11249
- final.issues.push(...util.prefixIssues(index, result.issues));
11249
+ final.issues.push(...prefixIssues(index, result.issues));
11250
11250
  }
11251
11251
  final.value[index] = result.value;
11252
11252
  }
@@ -11262,7 +11262,7 @@ function handleTupleResults(itemResults, final, items, input, optoutStart) {
11262
11262
  final.value.length = i;
11263
11263
  break;
11264
11264
  }
11265
- final.issues.push(...util.prefixIssues(i, r.issues));
11265
+ final.issues.push(...prefixIssues(i, r.issues));
11266
11266
  }
11267
11267
  final.value[i] = r.value;
11268
11268
  }
@@ -14046,12 +14046,12 @@ const tupleProcessor = (schema, ctx, _json, params) => {
14046
14046
  json.type = "array";
14047
14047
  const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
14048
14048
  const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
14049
- const prefixItems = def.items.map((x, i) => process(x, ctx, {
14049
+ const prefixItems = def.items.map((x, i) => to_json_schema_process(x, ctx, {
14050
14050
  ...params,
14051
14051
  path: [...params.path, prefixPath, i],
14052
14052
  }));
14053
14053
  const rest = def.rest
14054
- ? process(def.rest, ctx, {
14054
+ ? to_json_schema_process(def.rest, ctx, {
14055
14055
  ...params,
14056
14056
  path: [...params.path, restPath, ...(ctx.target === "openapi-3.0" ? [def.items.length] : [])],
14057
14057
  })
@@ -15257,24 +15257,24 @@ function intersection(left, right) {
15257
15257
  right: right,
15258
15258
  });
15259
15259
  }
15260
- const ZodTuple = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodTuple", (inst, def) => {
15261
- core.$ZodTuple.init(inst, def);
15260
+ const ZodTuple = /*@__PURE__*/ $constructor("ZodTuple", (inst, def) => {
15261
+ $ZodTuple.init(inst, def);
15262
15262
  ZodType.init(inst, def);
15263
- inst._zod.processJSONSchema = (ctx, json, params) => processors.tupleProcessor(inst, ctx, json, params);
15263
+ inst._zod.processJSONSchema = (ctx, json, params) => tupleProcessor(inst, ctx, json, params);
15264
15264
  inst.rest = (rest) => inst.clone({
15265
15265
  ...inst._zod.def,
15266
15266
  rest: rest,
15267
15267
  });
15268
- })));
15268
+ });
15269
15269
  function tuple(items, _paramsOrRest, _params) {
15270
- const hasRest = _paramsOrRest instanceof core.$ZodType;
15270
+ const hasRest = _paramsOrRest instanceof $ZodType;
15271
15271
  const params = hasRest ? _params : _paramsOrRest;
15272
15272
  const rest = hasRest ? _paramsOrRest : null;
15273
15273
  return new ZodTuple({
15274
15274
  type: "tuple",
15275
15275
  items: items,
15276
15276
  rest,
15277
- ...util.normalizeParams(params),
15277
+ ...normalizeParams(params),
15278
15278
  });
15279
15279
  }
15280
15280
  const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => {
@@ -28402,22 +28402,206 @@ function hasBlockingFindings(findings) {
28402
28402
  return findings.some((f)=>(f.severity === "critical" || f.severity === "high") && f.classification === "defect");
28403
28403
  }
28404
28404
 
28405
+ ;// CONCATENATED MODULE: ../doctor/src/lib/cross-harness-edges.ts
28406
+ function resolveEdgeTargets(edge) {
28407
+ return Array.isArray(edge.direction.to) ? edge.direction.to : [
28408
+ edge.direction.to
28409
+ ];
28410
+ }
28411
+ function buildHarnessByPath(records) {
28412
+ const harnessByPath = new Map();
28413
+ for (const record of records){
28414
+ harnessByPath.set(record.path, record.harness);
28415
+ }
28416
+ return harnessByPath;
28417
+ }
28418
+ function isCrossHarnessTarget(edge, targetPath, sourceHarness, harnessByPath) {
28419
+ if (edge.malformed || edge.type === "glob-binding") return false;
28420
+ const targetHarness = harnessByPath.get(targetPath);
28421
+ return targetHarness !== undefined && targetHarness !== sourceHarness;
28422
+ }
28423
+ function countCrossHarnessEdges(records) {
28424
+ const harnessByPath = buildHarnessByPath(records);
28425
+ let count = 0;
28426
+ for (const record of records){
28427
+ for (const edge of record.edges){
28428
+ for (const target of resolveEdgeTargets(edge)){
28429
+ if (isCrossHarnessTarget(edge, target, record.harness, harnessByPath)) {
28430
+ count++;
28431
+ }
28432
+ }
28433
+ }
28434
+ }
28435
+ return count;
28436
+ }
28437
+
28405
28438
  ;// CONCATENATED MODULE: ../doctor/src/formatters/json-formatter.ts
28406
- function toJson(summary, findings, snapshotRef) {
28407
- return {
28439
+
28440
+
28441
+ const HarnessNameSchema = schemas_enum([
28442
+ "claude",
28443
+ "copilot",
28444
+ "codex",
28445
+ "antigravity",
28446
+ "hermes",
28447
+ "crush",
28448
+ "pi",
28449
+ "shared"
28450
+ ]);
28451
+ const ConstructTypeSchema = schemas_enum([
28452
+ "instruction",
28453
+ "skill",
28454
+ "agent",
28455
+ "subagent",
28456
+ "mcp-server",
28457
+ "plugin",
28458
+ "hook"
28459
+ ]);
28460
+ const EdgeTypeSchema = schemas_enum([
28461
+ "hard-import",
28462
+ "soft-reference",
28463
+ "glob-binding"
28464
+ ]);
28465
+ const ArchetypeSchema = schemas_enum([
28466
+ "pure",
28467
+ "intentional-hybrid",
28468
+ "canonical-contract",
28469
+ "accidental-sprawl",
28470
+ "none",
28471
+ "ambiguous"
28472
+ ]);
28473
+ const CitationHandleSchema = schemas_object({
28474
+ nodeId: schemas_string(),
28475
+ sourceFile: schemas_string(),
28476
+ lineRange: tuple([
28477
+ schemas_number(),
28478
+ schemas_number()
28479
+ ]).optional(),
28480
+ snapshotRef: schemas_string().optional()
28481
+ });
28482
+ const FindingSchema = schemas_object({
28483
+ id: schemas_string(),
28484
+ criterionId: schemas_string(),
28485
+ targetId: schemas_string(),
28486
+ severity: schemas_enum([
28487
+ "critical",
28488
+ "high",
28489
+ "medium",
28490
+ "low",
28491
+ "info"
28492
+ ]),
28493
+ category: schemas_enum([
28494
+ "missing-required",
28495
+ "malformed-reference",
28496
+ "wrong-direction",
28497
+ "drift",
28498
+ "governance",
28499
+ "composition-style"
28500
+ ]),
28501
+ classification: schemas_enum([
28502
+ "defect",
28503
+ "advisory",
28504
+ "info"
28505
+ ]),
28506
+ intentGated: schemas_boolean(),
28507
+ assumedIntent: schemas_boolean(),
28508
+ description: schemas_string(),
28509
+ evidenceCitation: CitationHandleSchema.optional(),
28510
+ snapshotRef: schemas_string().optional()
28511
+ });
28512
+ const ReportInventoryItemSchema = schemas_object({
28513
+ id: schemas_string(),
28514
+ path: schemas_string(),
28515
+ harness: HarnessNameSchema,
28516
+ constructType: ConstructTypeSchema,
28517
+ loadMechanism: schemas_enum([
28518
+ "referenced",
28519
+ "convention-loaded"
28520
+ ]),
28521
+ serverName: schemas_string().optional(),
28522
+ transport: schemas_string().optional()
28523
+ });
28524
+ const ReportEdgeSchema = schemas_object({
28525
+ from: schemas_string(),
28526
+ to: schemas_string(),
28527
+ type: EdgeTypeSchema,
28528
+ malformed: schemas_boolean(),
28529
+ reason: schemas_enum([
28530
+ "missing-target",
28531
+ "path-traversal"
28532
+ ]).optional(),
28533
+ crossHarness: schemas_boolean()
28534
+ });
28535
+ const ReportJsonSchema = schemas_object({
28536
+ archetype: ArchetypeSchema,
28537
+ dominanceScore: schemas_number(),
28538
+ totalRecords: schemas_number(),
28539
+ harnessBreakdown: schemas_array(schemas_object({
28540
+ harness: schemas_string(),
28541
+ count: schemas_number()
28542
+ })),
28543
+ crossHarnessEdges: schemas_number(),
28544
+ inventory: schemas_array(ReportInventoryItemSchema),
28545
+ edges: schemas_array(ReportEdgeSchema),
28546
+ findings: schemas_array(FindingSchema),
28547
+ snapshotRef: schemas_string().optional()
28548
+ });
28549
+ function toInventoryItems(records) {
28550
+ return records.map((record)=>({
28551
+ id: record.id,
28552
+ path: record.path,
28553
+ harness: record.harness,
28554
+ constructType: record.constructType,
28555
+ loadMechanism: record.loadMechanism,
28556
+ ...record.serverName !== undefined ? {
28557
+ serverName: record.serverName
28558
+ } : {},
28559
+ ...record.transport !== undefined ? {
28560
+ transport: record.transport
28561
+ } : {}
28562
+ })).sort((a, b)=>a.path.localeCompare(b.path) || a.id.localeCompare(b.id));
28563
+ }
28564
+ function toReportEdges(records) {
28565
+ const harnessByPath = buildHarnessByPath(records);
28566
+ const result = [];
28567
+ for (const record of records){
28568
+ for (const edge of record.edges){
28569
+ for (const target of resolveEdgeTargets(edge)){
28570
+ result.push({
28571
+ from: edge.direction.from,
28572
+ to: target,
28573
+ type: edge.type,
28574
+ malformed: edge.malformed,
28575
+ ...edge.reason !== undefined ? {
28576
+ reason: edge.reason
28577
+ } : {},
28578
+ crossHarness: isCrossHarnessTarget(edge, target, record.harness, harnessByPath)
28579
+ });
28580
+ }
28581
+ }
28582
+ }
28583
+ return result;
28584
+ }
28585
+ function toJson(summary, findings, records, snapshotRef) {
28586
+ const edges = toReportEdges(records);
28587
+ const report = {
28408
28588
  archetype: summary.archetype,
28409
28589
  dominanceScore: summary.dominanceScore,
28410
28590
  totalRecords: summary.totalRecords,
28411
28591
  harnessBreakdown: summary.harnessBreakdown,
28412
- crossHarnessEdges: summary.crossHarnessEdges,
28592
+ crossHarnessEdges: edges.filter((edge)=>edge.crossHarness).length,
28593
+ inventory: toInventoryItems(records),
28594
+ edges,
28413
28595
  findings,
28414
28596
  ...snapshotRef !== undefined ? {
28415
28597
  snapshotRef
28416
28598
  } : {}
28417
28599
  };
28600
+ return ReportJsonSchema.parse(report);
28418
28601
  }
28419
28602
 
28420
28603
  ;// CONCATENATED MODULE: ../doctor/src/formatters/summary-formatter.ts
28604
+
28421
28605
  const ARCHETYPE_DESCRIPTIONS = {
28422
28606
  pure: "Single-harness configuration. One AI coding assistant dominates the repository.",
28423
28607
  "intentional-hybrid": "Multi-harness configuration with cross-harness references. Harnesses deliberately share context.",
@@ -28435,21 +28619,7 @@ function formatSummary(records, classification) {
28435
28619
  harness,
28436
28620
  count
28437
28621
  })).sort((a, b)=>a.harness.localeCompare(b.harness));
28438
- let crossHarnessEdges = 0;
28439
- const harnessByPath = new Map();
28440
- for (const r of records){
28441
- harnessByPath.set(r.path, r.harness);
28442
- }
28443
- for (const r of records){
28444
- for (const edge of r.edges){
28445
- if (!edge.malformed && edge.type !== "glob-binding" && typeof edge.direction.to === "string") {
28446
- const targetHarness = harnessByPath.get(edge.direction.to);
28447
- if (targetHarness && targetHarness !== r.harness) {
28448
- crossHarnessEdges++;
28449
- }
28450
- }
28451
- }
28452
- }
28622
+ const crossHarnessEdges = countCrossHarnessEdges(records);
28453
28623
  return {
28454
28624
  archetype: classification.archetype,
28455
28625
  archetypeDescription: ARCHETYPE_DESCRIPTIONS[classification.archetype],
@@ -28841,11 +29011,69 @@ function parseRawEdges(content) {
28841
29011
  return edges;
28842
29012
  }
28843
29013
 
29014
+ ;// CONCATENATED MODULE: ../doctor/src/gateways/mcp-config.ts
29015
+
29016
+
29017
+ const MAX_MCP_CONFIG_BYTES = 1_048_576;
29018
+ const MCP_CONFIG_SOURCES = [
29019
+ {
29020
+ relPath: ".mcp.json",
29021
+ harness: "shared"
29022
+ },
29023
+ {
29024
+ relPath: ".vscode/mcp.json",
29025
+ harness: "copilot"
29026
+ }
29027
+ ];
29028
+ const McpServerEntrySchema = schemas_object({
29029
+ type: schemas_string().optional(),
29030
+ transport: schemas_string().optional()
29031
+ }).passthrough();
29032
+ const McpConfigSchema = schemas_object({
29033
+ mcpServers: schemas_record(schemas_string(), McpServerEntrySchema).optional()
29034
+ }).passthrough();
29035
+ async function readMcpServersFromSource(repoRoot, source) {
29036
+ let content;
29037
+ try {
29038
+ content = await file_system_utils_readTextWithinRoot(repoRoot, source.relPath, MAX_MCP_CONFIG_BYTES);
29039
+ } catch {
29040
+ return [];
29041
+ }
29042
+ let raw;
29043
+ try {
29044
+ raw = JSON.parse(content);
29045
+ } catch {
29046
+ return [];
29047
+ }
29048
+ const result = McpConfigSchema.safeParse(raw);
29049
+ if (!result.success || result.data.mcpServers === undefined) {
29050
+ return [];
29051
+ }
29052
+ return Object.entries(result.data.mcpServers).map(([serverName, entry])=>({
29053
+ serverName,
29054
+ harness: source.harness,
29055
+ path: source.relPath,
29056
+ ...entry.transport !== undefined ? {
29057
+ transport: entry.transport
29058
+ } : entry.type !== undefined ? {
29059
+ transport: entry.type
29060
+ } : {}
29061
+ }));
29062
+ }
29063
+ async function enumerateMcpServers(repoRoot) {
29064
+ const records = [];
29065
+ for (const source of MCP_CONFIG_SOURCES){
29066
+ records.push(...await readMcpServersFromSource(repoRoot, source));
29067
+ }
29068
+ return records;
29069
+ }
29070
+
28844
29071
  ;// CONCATENATED MODULE: ../doctor/src/gateways/scanner.ts
28845
29072
 
28846
29073
 
28847
29074
 
28848
29075
 
29076
+
28849
29077
  const MAX_FILE_BYTES = 1_048_576;
28850
29078
  const SCANNABLE_EXTENSIONS = new Set([
28851
29079
  ".md",
@@ -28882,6 +29110,9 @@ function determineConstructType(relPath) {
28882
29110
  if (relPath.startsWith(".claude/hooks/")) {
28883
29111
  return "hook";
28884
29112
  }
29113
+ if (relPath.startsWith(".claude/agents/")) {
29114
+ return "subagent";
29115
+ }
28885
29116
  if (relPath.startsWith(".claude/commands/")) {
28886
29117
  return "agent";
28887
29118
  }
@@ -29025,6 +29256,21 @@ async function scanRepository(repoRoot) {
29025
29256
  record.loadMechanism = "referenced";
29026
29257
  }
29027
29258
  }
29259
+ const mcpServers = await enumerateMcpServers(absRoot);
29260
+ for (const server of mcpServers){
29261
+ records.push({
29262
+ id: `mcp-server:${server.path}#${server.serverName}`,
29263
+ path: server.path,
29264
+ harness: server.harness,
29265
+ constructType: "mcp-server",
29266
+ loadMechanism: "convention-loaded",
29267
+ edges: [],
29268
+ serverName: server.serverName,
29269
+ ...server.transport !== undefined ? {
29270
+ transport: server.transport
29271
+ } : {}
29272
+ });
29273
+ }
29028
29274
  return records;
29029
29275
  }
29030
29276
 
@@ -29619,7 +29865,8 @@ const doctorCommand = defineCommand({
29619
29865
  dominanceScore: summary.dominanceScore,
29620
29866
  totalRecords: summary.totalRecords,
29621
29867
  harnessBreakdown: summary.harnessBreakdown,
29622
- crossHarnessEdges: summary.crossHarnessEdges
29868
+ crossHarnessEdges: summary.crossHarnessEdges,
29869
+ inventory: toInventoryItems(records)
29623
29870
  }, null, 2)}\n`);
29624
29871
  } else {
29625
29872
  renderHuman(summary, [], logger, snapshotRef);
@@ -29628,7 +29875,7 @@ const doctorCommand = defineCommand({
29628
29875
  }
29629
29876
  if (classification.archetype === "none") {
29630
29877
  if (format === "json") {
29631
- process.stdout.write(`${JSON.stringify(toJson(summary, [], snapshotRef), null, 2)}\n`);
29878
+ process.stdout.write(`${JSON.stringify(toJson(summary, [], records, snapshotRef), null, 2)}\n`);
29632
29879
  } else {
29633
29880
  logger.info("No agentic constructs found in the repository.");
29634
29881
  }
@@ -29660,7 +29907,7 @@ const doctorCommand = defineCommand({
29660
29907
  intent
29661
29908
  });
29662
29909
  if (format === "json") {
29663
- const report = toJson(summary, findings, snapshotRef);
29910
+ const report = toJson(summary, findings, records, snapshotRef);
29664
29911
  process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
29665
29912
  } else {
29666
29913
  renderHuman(summary, findings, logger, snapshotRef);
@@ -61374,4 +61621,4 @@ if (installedChunkData !== 0) { // 0 means "already installed".'
61374
61621
  // module factories are used so entry inlining is disabled
61375
61622
  // startup
61376
61623
  // Load entry module and return exports
61377
- var __webpack_exports__ = __webpack_require__(149);
61624
+ var __webpack_exports__ = __webpack_require__(889);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lousy-agents/cli",
3
- "version": "5.16.0",
3
+ "version": "5.17.0",
4
4
  "description": "CLI scaffolding tool that sets up projects with structure, instructions, and feedback loops for AI coding assistants",
5
5
  "type": "module",
6
6
  "repository": {