@fro.bot/systematic 3.15.0 → 3.16.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/dist/cli.js +350 -128
- package/dist/index-ae6mhwth.js +9014 -0
- package/dist/index.js +167 -151
- package/dist/lib/agent-resolver.d.ts +7 -1
- package/dist/lib/capability-snapshot.d.ts +1 -1
- package/dist/lib/config-schema.d.ts +63 -1
- package/dist/lib/config.d.ts +59 -1
- package/dist/lib/pi-delegate-session.d.ts +2 -0
- package/dist/lib/pi-delegate-tool.d.ts +33 -1
- package/dist/lib/routing-resolver.d.ts +151 -0
- package/dist/pi.js +7495 -235
- package/dist/schemas/systematic-config.schema.json +1027 -185
- package/package.json +7 -7
- package/skills/ce-review/references/review-summary-schema.json +1 -1
- package/dist/index-0stf3ag0.js +0 -17100
package/dist/cli.js
CHANGED
|
@@ -1,20 +1,53 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @bun
|
|
3
3
|
import {
|
|
4
|
+
parseFrontmatter,
|
|
5
|
+
parse,
|
|
6
|
+
parseTree,
|
|
7
|
+
modify,
|
|
4
8
|
applyEdits,
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
_isoDateTime,
|
|
10
|
+
_isoDate,
|
|
11
|
+
_isoTime,
|
|
12
|
+
_isoDuration,
|
|
13
|
+
string,
|
|
14
|
+
ZodISODateTime,
|
|
15
|
+
ZodISODate,
|
|
16
|
+
ZodISOTime,
|
|
17
|
+
ZodISODuration,
|
|
18
|
+
number,
|
|
19
|
+
boolean,
|
|
20
|
+
array,
|
|
21
|
+
object,
|
|
22
|
+
union,
|
|
23
|
+
discriminatedUnion,
|
|
24
|
+
_enum,
|
|
25
|
+
literal,
|
|
7
26
|
extractString,
|
|
27
|
+
toSourcedPiSubagentsOverlays,
|
|
28
|
+
resolveRouting,
|
|
29
|
+
loadConfigWithSources,
|
|
30
|
+
collectRoutingTargets,
|
|
31
|
+
getConfigPaths,
|
|
8
32
|
findAgentsInDir,
|
|
9
33
|
findCommandsInDir,
|
|
10
34
|
findSkillsInDir,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
35
|
+
discoverSkills
|
|
36
|
+
} from "./index-ae6mhwth.js";
|
|
37
|
+
var __defProp = Object.defineProperty;
|
|
38
|
+
var __returnValue = (v) => v;
|
|
39
|
+
function __exportSetter(name, newValue) {
|
|
40
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
41
|
+
}
|
|
42
|
+
var __export = (target, all) => {
|
|
43
|
+
for (var name in all)
|
|
44
|
+
__defProp(target, name, {
|
|
45
|
+
get: all[name],
|
|
46
|
+
enumerable: true,
|
|
47
|
+
configurable: true,
|
|
48
|
+
set: __exportSetter.bind(all, name)
|
|
49
|
+
});
|
|
50
|
+
};
|
|
18
51
|
|
|
19
52
|
// src/cli.ts
|
|
20
53
|
import fs6 from "fs";
|
|
@@ -29,7 +62,15 @@ function buildAgentCatalog(agentsDir) {
|
|
|
29
62
|
const entries = [];
|
|
30
63
|
for (const info of infos) {
|
|
31
64
|
const content = fs.readFileSync(info.file, "utf8");
|
|
32
|
-
const
|
|
65
|
+
const parsed = parseValidatedAgentEntry(content, info.file);
|
|
66
|
+
const category = info.category ?? "";
|
|
67
|
+
const key = info.name;
|
|
68
|
+
const entry = {
|
|
69
|
+
...parsed,
|
|
70
|
+
key,
|
|
71
|
+
category,
|
|
72
|
+
id: category ? `${category}/${key}` : key
|
|
73
|
+
};
|
|
33
74
|
try {
|
|
34
75
|
resolveToolAllowlist(entry.toolsSource);
|
|
35
76
|
} catch (error) {
|
|
@@ -38,9 +79,9 @@ function buildAgentCatalog(agentsDir) {
|
|
|
38
79
|
}
|
|
39
80
|
const existing = byName.get(entry.name);
|
|
40
81
|
if (existing) {
|
|
41
|
-
existing.push(
|
|
82
|
+
existing.push(category);
|
|
42
83
|
} else {
|
|
43
|
-
byName.set(entry.name, [
|
|
84
|
+
byName.set(entry.name, [category]);
|
|
44
85
|
}
|
|
45
86
|
entries.push(entry);
|
|
46
87
|
}
|
|
@@ -144,14 +185,19 @@ var CONFIG_AUTHORITY_FIELD_PATHS = [
|
|
|
144
185
|
];
|
|
145
186
|
var CONFIG_PROTECTED_FIELD_PATHS = [
|
|
146
187
|
"workflow_guard",
|
|
188
|
+
"profiles",
|
|
147
189
|
"agents.*.model",
|
|
148
190
|
"agents.*.permission",
|
|
149
191
|
"agents.*.skills",
|
|
150
192
|
"agents.*.variant",
|
|
193
|
+
"agents.*.opencode",
|
|
194
|
+
"agents.*.pi",
|
|
151
195
|
"categories.*.model",
|
|
152
196
|
"categories.*.permission",
|
|
153
197
|
"categories.*.skills",
|
|
154
|
-
"categories.*.variant"
|
|
198
|
+
"categories.*.variant",
|
|
199
|
+
"categories.*.opencode",
|
|
200
|
+
"categories.*.pi"
|
|
155
201
|
];
|
|
156
202
|
var CONFIG_SOURCE_ERROR_CODES = [
|
|
157
203
|
"parse-failed",
|
|
@@ -409,7 +455,14 @@ function configErrorCode(errorCode) {
|
|
|
409
455
|
}
|
|
410
456
|
function normalizeConfigObservation(config) {
|
|
411
457
|
assertRecord(config, "config");
|
|
412
|
-
assertAllowedKeys(config, [
|
|
458
|
+
assertAllowedKeys(config, [
|
|
459
|
+
"authorities",
|
|
460
|
+
"protectedFields",
|
|
461
|
+
"sources",
|
|
462
|
+
"activeProfile",
|
|
463
|
+
"profileSelectorSource",
|
|
464
|
+
"profileFallback"
|
|
465
|
+
], "config");
|
|
413
466
|
if (!Array.isArray(config.sources)) {
|
|
414
467
|
throw new TypeError("config.sources must be an array");
|
|
415
468
|
}
|
|
@@ -778,7 +831,30 @@ function buildCapabilitySnapshot(options) {
|
|
|
778
831
|
options.outputSink?.(serialized);
|
|
779
832
|
return snapshot;
|
|
780
833
|
}
|
|
781
|
-
|
|
834
|
+
// node_modules/.bun/zod@4.5.4/node_modules/zod/v4/classic/iso.js
|
|
835
|
+
var exports_iso = {};
|
|
836
|
+
__export(exports_iso, {
|
|
837
|
+
ZodISODate: () => ZodISODate,
|
|
838
|
+
ZodISODateTime: () => ZodISODateTime,
|
|
839
|
+
ZodISODuration: () => ZodISODuration,
|
|
840
|
+
ZodISOTime: () => ZodISOTime,
|
|
841
|
+
date: () => date,
|
|
842
|
+
datetime: () => datetime,
|
|
843
|
+
duration: () => duration,
|
|
844
|
+
time: () => time
|
|
845
|
+
});
|
|
846
|
+
function datetime(params) {
|
|
847
|
+
return _isoDateTime(ZodISODateTime, params);
|
|
848
|
+
}
|
|
849
|
+
function date(params) {
|
|
850
|
+
return _isoDate(ZodISODate, params);
|
|
851
|
+
}
|
|
852
|
+
function time(params) {
|
|
853
|
+
return _isoTime(ZodISOTime, params);
|
|
854
|
+
}
|
|
855
|
+
function duration(params) {
|
|
856
|
+
return _isoDuration(ZodISODuration, params);
|
|
857
|
+
}
|
|
782
858
|
// src/lib/pi-subagents-export.ts
|
|
783
859
|
import * as crypto2 from "crypto";
|
|
784
860
|
import * as fs3 from "fs";
|
|
@@ -1424,10 +1500,10 @@ function ownedFilenames(manifest) {
|
|
|
1424
1500
|
function parseSourceCategoryAndKey(sourceRelPath) {
|
|
1425
1501
|
const parts = sourceRelPath.split("/");
|
|
1426
1502
|
if (parts.length >= 3 && parts[0] === "agents") {
|
|
1427
|
-
const
|
|
1503
|
+
const fileName = parts.at(-1) ?? "";
|
|
1428
1504
|
return {
|
|
1429
1505
|
category: parts[1],
|
|
1430
|
-
agentKey:
|
|
1506
|
+
agentKey: fileName.replace(/\.md$/, "")
|
|
1431
1507
|
};
|
|
1432
1508
|
}
|
|
1433
1509
|
const fileName = parts.at(-1) ?? sourceRelPath;
|
|
@@ -1443,21 +1519,19 @@ function lookupOverlay(map, category, agentKey) {
|
|
|
1443
1519
|
}
|
|
1444
1520
|
return map[agentKey];
|
|
1445
1521
|
}
|
|
1446
|
-
function
|
|
1447
|
-
const
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
}
|
|
1457
|
-
return;
|
|
1522
|
+
function resolveRoutedFields(overlays, piSubagentsOverlays, category, agentKey) {
|
|
1523
|
+
const resolution = resolveRouting({
|
|
1524
|
+
overlays,
|
|
1525
|
+
piSubagentsOverlays,
|
|
1526
|
+
target: { agentKey, category: category ?? "" },
|
|
1527
|
+
harness: "pi"
|
|
1528
|
+
});
|
|
1529
|
+
return {
|
|
1530
|
+
model: typeof resolution.model === "string" ? resolution.model : undefined,
|
|
1531
|
+
thinking: resolution.qualifier
|
|
1532
|
+
};
|
|
1458
1533
|
}
|
|
1459
|
-
var
|
|
1460
|
-
"thinking",
|
|
1534
|
+
var OTHER_PI_SUBAGENTS_FRONTMATTER_FIELDS = [
|
|
1461
1535
|
"max_turns",
|
|
1462
1536
|
"tools",
|
|
1463
1537
|
"skills"
|
|
@@ -1466,7 +1540,7 @@ function resolvePiSubagentsFields(config, category, agentKey) {
|
|
|
1466
1540
|
const categoryOverlay = category ? config.pi_subagents?.categories?.[category] : undefined;
|
|
1467
1541
|
const agentOverlay = lookupOverlay(config.pi_subagents?.agents, category, agentKey);
|
|
1468
1542
|
const result = {};
|
|
1469
|
-
for (const field of
|
|
1543
|
+
for (const field of OTHER_PI_SUBAGENTS_FRONTMATTER_FIELDS) {
|
|
1470
1544
|
if (agentOverlay && Object.hasOwn(agentOverlay, field)) {
|
|
1471
1545
|
result[field] = agentOverlay[field];
|
|
1472
1546
|
} else if (categoryOverlay && Object.hasOwn(categoryOverlay, field)) {
|
|
@@ -1475,19 +1549,21 @@ function resolvePiSubagentsFields(config, category, agentKey) {
|
|
|
1475
1549
|
}
|
|
1476
1550
|
return result;
|
|
1477
1551
|
}
|
|
1478
|
-
function applyConfigToContent(content, config, category, agentKey) {
|
|
1552
|
+
function applyConfigToContent(content, config, overlays, piSubagentsOverlays, category, agentKey) {
|
|
1479
1553
|
const { data, body } = parseFrontmatter(content);
|
|
1480
|
-
const model =
|
|
1481
|
-
const
|
|
1554
|
+
const { model, thinking } = resolveRoutedFields(overlays, piSubagentsOverlays, category, agentKey);
|
|
1555
|
+
const otherFields = resolvePiSubagentsFields(config, category, agentKey);
|
|
1482
1556
|
const frontmatter = {};
|
|
1483
1557
|
if (typeof data.description === "string") {
|
|
1484
1558
|
frontmatter.description = data.description;
|
|
1485
1559
|
}
|
|
1486
1560
|
if (model !== undefined)
|
|
1487
1561
|
frontmatter.model = model;
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1562
|
+
if (thinking !== undefined)
|
|
1563
|
+
frontmatter.thinking = thinking;
|
|
1564
|
+
for (const field of OTHER_PI_SUBAGENTS_FRONTMATTER_FIELDS) {
|
|
1565
|
+
if (Object.hasOwn(otherFields, field)) {
|
|
1566
|
+
frontmatter[field] = otherFields[field];
|
|
1491
1567
|
}
|
|
1492
1568
|
}
|
|
1493
1569
|
let frontmatterBlock;
|
|
@@ -1506,12 +1582,12 @@ ${lines}
|
|
|
1506
1582
|
|
|
1507
1583
|
${trimmedBody}`;
|
|
1508
1584
|
}
|
|
1509
|
-
function applyConfigToEntries(entries, config) {
|
|
1585
|
+
function applyConfigToEntries(entries, config, overlays, piSubagentsOverlays) {
|
|
1510
1586
|
return entries.map((entry) => {
|
|
1511
1587
|
if (entry.status === "excluded-critical" || !entry.content)
|
|
1512
1588
|
return entry;
|
|
1513
1589
|
const { category, agentKey } = parseSourceCategoryAndKey(entry.sourceRelPath);
|
|
1514
|
-
const content = applyConfigToContent(entry.content, config, category, agentKey);
|
|
1590
|
+
const content = applyConfigToContent(entry.content, config, overlays, piSubagentsOverlays, category, agentKey);
|
|
1515
1591
|
const hash = crypto2.createHash("sha256").update(content).digest("hex");
|
|
1516
1592
|
return { ...entry, content, hash };
|
|
1517
1593
|
});
|
|
@@ -1520,10 +1596,11 @@ function generateEntries(repoRoot, configOptions) {
|
|
|
1520
1596
|
const entries = generateAll(repoRoot);
|
|
1521
1597
|
if (!configOptions)
|
|
1522
1598
|
return entries;
|
|
1523
|
-
const config = loadConfigWithSources(configOptions.cwd, {
|
|
1599
|
+
const { config, overlays } = loadConfigWithSources(configOptions.cwd, {
|
|
1524
1600
|
includeProject: configOptions.scope === "project"
|
|
1525
|
-
})
|
|
1526
|
-
|
|
1601
|
+
});
|
|
1602
|
+
const piSubagentsOverlays = toSourcedPiSubagentsOverlays(config.pi_subagents);
|
|
1603
|
+
return applyConfigToEntries(entries, config, overlays, piSubagentsOverlays);
|
|
1527
1604
|
}
|
|
1528
1605
|
function findPackageRoot() {
|
|
1529
1606
|
const thisFile = fileURLToPath(import.meta.url);
|
|
@@ -1949,7 +2026,7 @@ function cleanup(agentsRoot, configOptions) {
|
|
|
1949
2026
|
...targets.map((t) => t.path),
|
|
1950
2027
|
...manifestPath ? [manifestPath] : []
|
|
1951
2028
|
];
|
|
1952
|
-
const
|
|
2029
|
+
const tx = runWithRollback(pathsToWatch, [
|
|
1953
2030
|
...targets.map(({ path: p, filename, hash }) => () => {
|
|
1954
2031
|
if (fs3.existsSync(p)) {
|
|
1955
2032
|
assertHashMatchesOrThrow(p, hash, filename, "delete");
|
|
@@ -1963,7 +2040,7 @@ function cleanup(agentsRoot, configOptions) {
|
|
|
1963
2040
|
}
|
|
1964
2041
|
] : []
|
|
1965
2042
|
]);
|
|
1966
|
-
return { kind: "tx", tx
|
|
2043
|
+
return { kind: "tx", tx };
|
|
1967
2044
|
});
|
|
1968
2045
|
if (!lockResult.locked) {
|
|
1969
2046
|
if (lockResult.isContention)
|
|
@@ -2010,8 +2087,8 @@ function hasParentDirectoryTraversal(input) {
|
|
|
2010
2087
|
}
|
|
2011
2088
|
function pathContainsSymlink(candidate) {
|
|
2012
2089
|
let current = path3.parse(candidate).root;
|
|
2013
|
-
const
|
|
2014
|
-
for (const segment of
|
|
2090
|
+
const relative = path3.relative(current, candidate);
|
|
2091
|
+
for (const segment of relative.split(path3.sep)) {
|
|
2015
2092
|
if (!segment)
|
|
2016
2093
|
continue;
|
|
2017
2094
|
current = path3.join(current, segment);
|
|
@@ -2025,8 +2102,8 @@ function pathContainsSymlink(candidate) {
|
|
|
2025
2102
|
return false;
|
|
2026
2103
|
}
|
|
2027
2104
|
function isWithinDirectory(candidate, directory) {
|
|
2028
|
-
const
|
|
2029
|
-
return
|
|
2105
|
+
const relative = path3.relative(directory, candidate);
|
|
2106
|
+
return relative !== "" && relative !== ".." && !relative.startsWith(`..${path3.sep}`) && !path3.isAbsolute(relative);
|
|
2030
2107
|
}
|
|
2031
2108
|
function resolveReviewArtifactPath(input, cwd) {
|
|
2032
2109
|
if (hasParentDirectoryTraversal(input)) {
|
|
@@ -2096,14 +2173,14 @@ var REVIEW_ARTIFACT_CUSTOM_MESSAGES = [
|
|
|
2096
2173
|
"unsatisfied risk coverage must not cite an input finding ID",
|
|
2097
2174
|
"passed validation must not include a reason; non-passed validation requires a reason"
|
|
2098
2175
|
];
|
|
2099
|
-
var boundedText = (maxLength) =>
|
|
2100
|
-
var DispatchOutcomeSchema =
|
|
2176
|
+
var boundedText = (maxLength) => string().min(1).max(maxLength).regex(/\S/);
|
|
2177
|
+
var DispatchOutcomeSchema = _enum([
|
|
2101
2178
|
"findings",
|
|
2102
2179
|
"empty",
|
|
2103
2180
|
"malformed",
|
|
2104
2181
|
"never_returned"
|
|
2105
2182
|
]);
|
|
2106
|
-
var DispositionSchema =
|
|
2183
|
+
var DispositionSchema = _enum([
|
|
2107
2184
|
"surviving",
|
|
2108
2185
|
"merged",
|
|
2109
2186
|
"suppressed",
|
|
@@ -2111,12 +2188,12 @@ var DispositionSchema = exports_external.enum([
|
|
|
2111
2188
|
"rejected"
|
|
2112
2189
|
]);
|
|
2113
2190
|
var AdmittedDispositionSchema = DispositionSchema.exclude(["rejected"]);
|
|
2114
|
-
var HarnessSchema =
|
|
2191
|
+
var HarnessSchema = _enum(["opencode", "pi", "claude-code"]);
|
|
2115
2192
|
var RepoRelativePathSchema = boundedText(256).regex(/^(?!\/)(?![A-Za-z]:[\\/])(?!\\).+/);
|
|
2116
2193
|
var ReviewerSchema = boundedText(MAX_REVIEWER_LENGTH);
|
|
2117
|
-
var BranchSchema =
|
|
2118
|
-
var HeadShaSchema =
|
|
2119
|
-
var CompletedAtSchema =
|
|
2194
|
+
var BranchSchema = string().max(MAX_BRANCH_LENGTH);
|
|
2195
|
+
var HeadShaSchema = string().regex(/^[0-9a-f]{40}$/);
|
|
2196
|
+
var CompletedAtSchema = exports_iso.datetime({ offset: false });
|
|
2120
2197
|
var ReasonSchema = boundedText(MAX_REASON_LENGTH);
|
|
2121
2198
|
var RISK_CRITICAL_PERSONAS = [
|
|
2122
2199
|
"security",
|
|
@@ -2125,42 +2202,42 @@ var RISK_CRITICAL_PERSONAS = [
|
|
|
2125
2202
|
"reliability",
|
|
2126
2203
|
"performance"
|
|
2127
2204
|
];
|
|
2128
|
-
var RiskCriticalPersonaSchema =
|
|
2205
|
+
var RiskCriticalPersonaSchema = _enum(RISK_CRITICAL_PERSONAS);
|
|
2129
2206
|
var FindingTitleSchema = boundedText(256);
|
|
2130
|
-
var SeveritySchema =
|
|
2207
|
+
var SeveritySchema = _enum(["P0", "P1", "P2", "P3", "unknown"]);
|
|
2131
2208
|
var FindingSeveritySchema = SeveritySchema.exclude(["unknown"]);
|
|
2132
|
-
var AutofixClassSchema =
|
|
2209
|
+
var AutofixClassSchema = _enum([
|
|
2133
2210
|
"safe_auto",
|
|
2134
2211
|
"gated_auto",
|
|
2135
2212
|
"manual",
|
|
2136
2213
|
"advisory"
|
|
2137
2214
|
]);
|
|
2138
|
-
var OwnerSchema =
|
|
2215
|
+
var OwnerSchema = _enum([
|
|
2139
2216
|
"review-fixer",
|
|
2140
2217
|
"downstream-resolver",
|
|
2141
2218
|
"human",
|
|
2142
2219
|
"release"
|
|
2143
2220
|
]);
|
|
2144
2221
|
var BoundedEvidenceStringSchema = boundedText(500).regex(/^(?!\/)(?![A-Za-z]:[\\/])(?!\\).+/);
|
|
2145
|
-
var OverflowEvidenceSchema =
|
|
2146
|
-
overflow:
|
|
2222
|
+
var OverflowEvidenceSchema = object({
|
|
2223
|
+
overflow: literal(true),
|
|
2147
2224
|
excerpt: BoundedEvidenceStringSchema
|
|
2148
2225
|
}).strict();
|
|
2149
|
-
var EvidenceSchema =
|
|
2150
|
-
var AdmittedInputFindingSchema =
|
|
2151
|
-
record_type:
|
|
2226
|
+
var EvidenceSchema = array(union([BoundedEvidenceStringSchema, OverflowEvidenceSchema])).min(1).max(5);
|
|
2227
|
+
var AdmittedInputFindingSchema = object({
|
|
2228
|
+
record_type: literal("admitted"),
|
|
2152
2229
|
input_id: boundedText(MAX_INPUT_ID_LENGTH),
|
|
2153
2230
|
reviewer: ReviewerSchema,
|
|
2154
|
-
confidence:
|
|
2231
|
+
confidence: number().min(0).max(1),
|
|
2155
2232
|
disposition: AdmittedDispositionSchema,
|
|
2156
2233
|
reason: ReasonSchema
|
|
2157
2234
|
}).strict();
|
|
2158
|
-
var RejectedInputFindingSchema =
|
|
2159
|
-
record_type:
|
|
2235
|
+
var RejectedInputFindingSchema = object({
|
|
2236
|
+
record_type: literal("rejected_summary"),
|
|
2160
2237
|
reviewer: ReviewerSchema,
|
|
2161
2238
|
dispatch_outcome: DispatchOutcomeSchema,
|
|
2162
|
-
rejected_finding_count:
|
|
2163
|
-
rejected_severities:
|
|
2239
|
+
rejected_finding_count: number().int().positive().max(MAX_FINDINGS),
|
|
2240
|
+
rejected_severities: array(SeveritySchema).max(MAX_FINDINGS),
|
|
2164
2241
|
disposition: DispositionSchema.extract(["rejected"]),
|
|
2165
2242
|
reason: ReasonSchema
|
|
2166
2243
|
}).strict().superRefine((row, ctx) => {
|
|
@@ -2172,31 +2249,31 @@ var RejectedInputFindingSchema = exports_external.object({
|
|
|
2172
2249
|
});
|
|
2173
2250
|
}
|
|
2174
2251
|
});
|
|
2175
|
-
var InputFindingSchema =
|
|
2252
|
+
var InputFindingSchema = discriminatedUnion("record_type", [
|
|
2176
2253
|
AdmittedInputFindingSchema,
|
|
2177
2254
|
RejectedInputFindingSchema
|
|
2178
2255
|
]);
|
|
2179
|
-
var ProvenanceSchema =
|
|
2256
|
+
var ProvenanceSchema = object({
|
|
2180
2257
|
fingerprint: boundedText(512),
|
|
2181
|
-
submitters:
|
|
2182
|
-
agreement_credit:
|
|
2258
|
+
submitters: array(ReviewerSchema).max(MAX_PERSONAS),
|
|
2259
|
+
agreement_credit: array(ReviewerSchema).max(MAX_PERSONAS)
|
|
2183
2260
|
}).strict();
|
|
2184
|
-
var SynthesizedFindingFieldsSchema =
|
|
2261
|
+
var SynthesizedFindingFieldsSchema = object({
|
|
2185
2262
|
title: FindingTitleSchema,
|
|
2186
2263
|
severity: FindingSeveritySchema,
|
|
2187
2264
|
file: RepoRelativePathSchema,
|
|
2188
|
-
line:
|
|
2265
|
+
line: number().int().positive(),
|
|
2189
2266
|
why_it_matters: boundedText(2048),
|
|
2190
2267
|
autofix_class: AutofixClassSchema,
|
|
2191
2268
|
owner: OwnerSchema,
|
|
2192
|
-
requires_verification:
|
|
2193
|
-
confidence:
|
|
2269
|
+
requires_verification: boolean(),
|
|
2270
|
+
confidence: number().min(0).max(1),
|
|
2194
2271
|
evidence: EvidenceSchema,
|
|
2195
|
-
pre_existing:
|
|
2196
|
-
suggested_fix:
|
|
2197
|
-
validated:
|
|
2272
|
+
pre_existing: boolean(),
|
|
2273
|
+
suggested_fix: string().max(2048).nullable().optional(),
|
|
2274
|
+
validated: boolean().optional(),
|
|
2198
2275
|
validation_reason: ReasonSchema.optional(),
|
|
2199
|
-
input_finding_ids:
|
|
2276
|
+
input_finding_ids: array(boundedText(MAX_INPUT_ID_LENGTH)).min(1).max(MAX_FINDINGS),
|
|
2200
2277
|
provenance: ProvenanceSchema
|
|
2201
2278
|
}).strict();
|
|
2202
2279
|
var SynthesizedFindingSchema = SynthesizedFindingFieldsSchema.superRefine((finding, ctx) => {
|
|
@@ -2208,12 +2285,12 @@ var SynthesizedFindingSchema = SynthesizedFindingFieldsSchema.superRefine((findi
|
|
|
2208
2285
|
});
|
|
2209
2286
|
}
|
|
2210
2287
|
});
|
|
2211
|
-
var DispatchSchema =
|
|
2288
|
+
var DispatchSchema = object({
|
|
2212
2289
|
persona: ReviewerSchema,
|
|
2213
2290
|
dispatch_outcome: DispatchOutcomeSchema,
|
|
2214
|
-
input_finding_count:
|
|
2291
|
+
input_finding_count: number().int().nonnegative().max(MAX_FINDINGS),
|
|
2215
2292
|
rejection_reason: ReasonSchema.optional(),
|
|
2216
|
-
selection_surface:
|
|
2293
|
+
selection_surface: array(RepoRelativePathSchema).max(MAX_FINDINGS).optional(),
|
|
2217
2294
|
selection_reason: ReasonSchema.optional()
|
|
2218
2295
|
}).strict().superRefine((dispatch, ctx) => {
|
|
2219
2296
|
if (RISK_CRITICAL_PERSONAS.includes(dispatch.persona) && (!dispatch.selection_surface || dispatch.selection_surface.length === 0)) {
|
|
@@ -2224,29 +2301,29 @@ var DispatchSchema = exports_external.object({
|
|
|
2224
2301
|
});
|
|
2225
2302
|
}
|
|
2226
2303
|
});
|
|
2227
|
-
var DispositionCountsSchema =
|
|
2228
|
-
surviving:
|
|
2229
|
-
merged:
|
|
2230
|
-
suppressed:
|
|
2231
|
-
filtered:
|
|
2232
|
-
rejected:
|
|
2304
|
+
var DispositionCountsSchema = object({
|
|
2305
|
+
surviving: number().int().nonnegative().max(MAX_FINDINGS * MAX_PERSONAS),
|
|
2306
|
+
merged: number().int().nonnegative().max(MAX_FINDINGS * MAX_PERSONAS),
|
|
2307
|
+
suppressed: number().int().nonnegative().max(MAX_FINDINGS * MAX_PERSONAS),
|
|
2308
|
+
filtered: number().int().nonnegative().max(MAX_FINDINGS * MAX_PERSONAS),
|
|
2309
|
+
rejected: number().int().nonnegative().max(MAX_FINDINGS * MAX_PERSONAS)
|
|
2233
2310
|
}).strict();
|
|
2234
|
-
var CoverageSchema =
|
|
2235
|
-
reviewers:
|
|
2236
|
-
validators:
|
|
2237
|
-
residual_risks:
|
|
2238
|
-
testing_gaps:
|
|
2239
|
-
failed_reviewers:
|
|
2240
|
-
validator_failures:
|
|
2241
|
-
intent_uncertainty:
|
|
2311
|
+
var CoverageSchema = object({
|
|
2312
|
+
reviewers: number().int().nonnegative().max(MAX_PERSONAS).optional(),
|
|
2313
|
+
validators: number().int().nonnegative().max(MAX_PERSONAS).optional(),
|
|
2314
|
+
residual_risks: array(ReasonSchema).max(MAX_PERSONAS),
|
|
2315
|
+
testing_gaps: array(ReasonSchema).max(MAX_PERSONAS),
|
|
2316
|
+
failed_reviewers: array(ReviewerSchema).max(MAX_PERSONAS),
|
|
2317
|
+
validator_failures: array(ReasonSchema).max(MAX_PERSONAS),
|
|
2318
|
+
intent_uncertainty: array(ReasonSchema).max(MAX_PERSONAS)
|
|
2242
2319
|
}).strict();
|
|
2243
|
-
var DeclinedMergeSchema =
|
|
2320
|
+
var DeclinedMergeSchema = object({
|
|
2244
2321
|
file: RepoRelativePathSchema,
|
|
2245
|
-
input_finding_ids:
|
|
2322
|
+
input_finding_ids: array(boundedText(MAX_INPUT_ID_LENGTH)).min(2).max(MAX_FINDINGS),
|
|
2246
2323
|
reason: ReasonSchema
|
|
2247
2324
|
}).strict();
|
|
2248
|
-
var ValidationSchema =
|
|
2249
|
-
status:
|
|
2325
|
+
var ValidationSchema = object({
|
|
2326
|
+
status: _enum([
|
|
2250
2327
|
"passed",
|
|
2251
2328
|
"failed",
|
|
2252
2329
|
"unavailable",
|
|
@@ -2269,9 +2346,9 @@ var ValidationSchema = exports_external.object({
|
|
|
2269
2346
|
});
|
|
2270
2347
|
}
|
|
2271
2348
|
});
|
|
2272
|
-
var RiskCoverageSchema =
|
|
2349
|
+
var RiskCoverageSchema = object({
|
|
2273
2350
|
persona: RiskCriticalPersonaSchema,
|
|
2274
|
-
satisfied:
|
|
2351
|
+
satisfied: boolean(),
|
|
2275
2352
|
input_finding_id: boundedText(MAX_INPUT_ID_LENGTH).optional()
|
|
2276
2353
|
}).strict().superRefine((coverage, ctx) => {
|
|
2277
2354
|
if (coverage.satisfied && coverage.input_finding_id === undefined) {
|
|
@@ -2289,14 +2366,14 @@ var RiskCoverageSchema = exports_external.object({
|
|
|
2289
2366
|
});
|
|
2290
2367
|
}
|
|
2291
2368
|
});
|
|
2292
|
-
var ReviewArtifactSchema =
|
|
2293
|
-
schema_version:
|
|
2369
|
+
var ReviewArtifactSchema = object({
|
|
2370
|
+
schema_version: literal(1),
|
|
2294
2371
|
run_id: boundedText(MAX_RUN_ID_LENGTH),
|
|
2295
2372
|
branch: BranchSchema,
|
|
2296
2373
|
head_sha: HeadShaSchema,
|
|
2297
|
-
mode:
|
|
2374
|
+
mode: _enum(["interactive", "autofix", "headless"]),
|
|
2298
2375
|
harness: HarnessSchema,
|
|
2299
|
-
run_status:
|
|
2376
|
+
run_status: _enum([
|
|
2300
2377
|
"in_progress",
|
|
2301
2378
|
"completed",
|
|
2302
2379
|
"degraded",
|
|
@@ -2304,15 +2381,15 @@ var ReviewArtifactSchema = exports_external.object({
|
|
|
2304
2381
|
]),
|
|
2305
2382
|
verdict: boundedText(256),
|
|
2306
2383
|
completed_at: CompletedAtSchema,
|
|
2307
|
-
dispatches:
|
|
2308
|
-
input_findings:
|
|
2309
|
-
findings:
|
|
2310
|
-
declined_merges:
|
|
2311
|
-
risk_coverage:
|
|
2384
|
+
dispatches: array(DispatchSchema).max(MAX_PERSONAS),
|
|
2385
|
+
input_findings: array(InputFindingSchema).max(MAX_FINDINGS * MAX_PERSONAS),
|
|
2386
|
+
findings: array(SynthesizedFindingSchema).max(MAX_FINDINGS),
|
|
2387
|
+
declined_merges: array(DeclinedMergeSchema).max(MAX_FINDINGS).optional(),
|
|
2388
|
+
risk_coverage: array(RiskCoverageSchema).max(MAX_PERSONAS).optional(),
|
|
2312
2389
|
disposition_counts: DispositionCountsSchema,
|
|
2313
|
-
applied_fixes:
|
|
2314
|
-
residual_actionable_work:
|
|
2315
|
-
advisory_outputs:
|
|
2390
|
+
applied_fixes: array(ReasonSchema).max(MAX_FINDINGS),
|
|
2391
|
+
residual_actionable_work: array(ReasonSchema).max(MAX_FINDINGS),
|
|
2392
|
+
advisory_outputs: array(ReasonSchema).max(MAX_FINDINGS),
|
|
2316
2393
|
coverage: CoverageSchema,
|
|
2317
2394
|
validation: ValidationSchema.optional()
|
|
2318
2395
|
}).strict();
|
|
@@ -2365,8 +2442,8 @@ function lstatOrNull(targetPath) {
|
|
|
2365
2442
|
function assertRealpathUnderCwd(dir, cwd) {
|
|
2366
2443
|
const realDir = fs5.realpathSync(dir);
|
|
2367
2444
|
const realCwd = fs5.realpathSync(cwd);
|
|
2368
|
-
const
|
|
2369
|
-
if (
|
|
2445
|
+
const relative = path4.relative(realCwd, realDir);
|
|
2446
|
+
if (relative.startsWith("..") || path4.isAbsolute(relative)) {
|
|
2370
2447
|
throw createSetupError(`Refusing to write under ${dir}: resolved directory escapes the project root`);
|
|
2371
2448
|
}
|
|
2372
2449
|
}
|
|
@@ -2459,8 +2536,8 @@ function writeTempAndRename(destPath, content, mode, preserveExactMode, ops) {
|
|
|
2459
2536
|
throw error;
|
|
2460
2537
|
}
|
|
2461
2538
|
}
|
|
2462
|
-
function makeTempPath(parentDir,
|
|
2463
|
-
return path4.join(parentDir, `.${
|
|
2539
|
+
function makeTempPath(parentDir, basename) {
|
|
2540
|
+
return path4.join(parentDir, `.${basename}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
2464
2541
|
}
|
|
2465
2542
|
function cleanupTemp(tempPath, ops) {
|
|
2466
2543
|
if (!fs5.existsSync(tempPath))
|
|
@@ -2515,8 +2592,8 @@ function setupOpenCode(cwd, ops) {
|
|
|
2515
2592
|
throw createSetupError(`Invalid OpenCode config in ${targetPath}: \`plugins\` (plural) is not supported by OpenCode's schema; use singular \`plugin\``);
|
|
2516
2593
|
}
|
|
2517
2594
|
if (!Object.hasOwn(parsed, "plugin")) {
|
|
2518
|
-
const
|
|
2519
|
-
atomicWrite(targetPath, applyEdits(rawText,
|
|
2595
|
+
const edits = modify(rawText, ["plugin"], [SYSTEMATIC_PACKAGE_NAME], {});
|
|
2596
|
+
atomicWrite(targetPath, applyEdits(rawText, edits), existing.bytes, existing.mode, ops);
|
|
2520
2597
|
return { status: "configured", targetPath };
|
|
2521
2598
|
}
|
|
2522
2599
|
const existingValue = parsed.plugin;
|
|
@@ -2577,8 +2654,8 @@ function setupPi(cwd, ops) {
|
|
|
2577
2654
|
}
|
|
2578
2655
|
const existingPackages = parsed.packages;
|
|
2579
2656
|
if (existingPackages === undefined) {
|
|
2580
|
-
const
|
|
2581
|
-
atomicWrite(targetPath, applyEdits(rawText,
|
|
2657
|
+
const edits = modify(rawText, ["packages"], [PI_PACKAGE_IDENTIFIER], {});
|
|
2658
|
+
atomicWrite(targetPath, applyEdits(rawText, edits), existing.bytes, existing.mode, ops);
|
|
2582
2659
|
return { status: "configured", targetPath };
|
|
2583
2660
|
}
|
|
2584
2661
|
if (!Array.isArray(existingPackages)) {
|
|
@@ -2650,7 +2727,7 @@ Commands:
|
|
|
2650
2727
|
Exit statuses: 0 valid artifact, 1 validation failure,
|
|
2651
2728
|
2 operational failure, 3 legacy artifact with no schema_version
|
|
2652
2729
|
config [subcommand] Configuration management
|
|
2653
|
-
show
|
|
2730
|
+
show [--json] Show configuration (--json for a machine-readable resolved view)
|
|
2654
2731
|
path Print config file locations
|
|
2655
2732
|
setup --harness opencode|pi Configure a harness to load Systematic (project-local only)
|
|
2656
2733
|
pi-subagents <subcommand> Manage Systematic persona export for pi-subagents
|
|
@@ -2669,6 +2746,7 @@ Examples:
|
|
|
2669
2746
|
systematic validate-review-artifact .context/systematic/ce-review/review-summary.json
|
|
2670
2747
|
systematic list agents
|
|
2671
2748
|
systematic config show
|
|
2749
|
+
systematic config show --json
|
|
2672
2750
|
systematic setup --harness opencode
|
|
2673
2751
|
systematic setup --harness pi
|
|
2674
2752
|
systematic pi-subagents preview
|
|
@@ -2677,6 +2755,13 @@ Examples:
|
|
|
2677
2755
|
systematic pi-subagents refresh
|
|
2678
2756
|
systematic pi-subagents cleanup
|
|
2679
2757
|
`;
|
|
2758
|
+
var CONFIG_SHOW_USAGE = `Usage: systematic config show [--json]
|
|
2759
|
+
|
|
2760
|
+
Options:
|
|
2761
|
+
--json Print a machine-readable resolved view (active profile, fallback,
|
|
2762
|
+
and per-agent/harness routing) instead of prose. No raw file
|
|
2763
|
+
contents in JSON mode.
|
|
2764
|
+
`;
|
|
2680
2765
|
var PI_SUBAGENTS_USAGE = `Usage: systematic pi-subagents <subcommand> [--scope project|global]
|
|
2681
2766
|
|
|
2682
2767
|
Subcommands:
|
|
@@ -2952,7 +3037,130 @@ function listItems(type) {
|
|
|
2952
3037
|
console.log(` ${item.name}`);
|
|
2953
3038
|
}
|
|
2954
3039
|
}
|
|
2955
|
-
function
|
|
3040
|
+
function formatRoutingModel(model) {
|
|
3041
|
+
if (model === undefined)
|
|
3042
|
+
return "(unset)";
|
|
3043
|
+
if (model === null)
|
|
3044
|
+
return "null (inherit)";
|
|
3045
|
+
return model;
|
|
3046
|
+
}
|
|
3047
|
+
function formatRoutingQualifier(qualifier) {
|
|
3048
|
+
return qualifier === undefined ? "(none)" : qualifier;
|
|
3049
|
+
}
|
|
3050
|
+
function formatRoutingSource(source) {
|
|
3051
|
+
return source === undefined ? "(n/a)" : `${source.level}/${source.form}`;
|
|
3052
|
+
}
|
|
3053
|
+
function printProfileSummary(metadata) {
|
|
3054
|
+
const activeLabel = metadata.activeProfile ?? "none";
|
|
3055
|
+
const selectedByLabel = metadata.profileSelectorSource ?? "(none)";
|
|
3056
|
+
console.log(` Active profile: ${activeLabel}`);
|
|
3057
|
+
console.log(` Selected by: ${selectedByLabel}`);
|
|
3058
|
+
if (metadata.profileFallback) {
|
|
3059
|
+
const usedLabel = metadata.profileFallback.usedDefault ? `your default profile "${metadata.profileFallback.usedDefault}"` : "base configuration (no default profile is set)";
|
|
3060
|
+
console.log(` Fallback: requested "${metadata.profileFallback.requested}" is not defined; used ${usedLabel}`);
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
function disabledAgentsSet(loaded) {
|
|
3064
|
+
return new Set(loaded.config.disabled_agents ?? []);
|
|
3065
|
+
}
|
|
3066
|
+
function printRoutingTable(loaded) {
|
|
3067
|
+
const targets = collectRoutingTargets(loaded.overlays, disabledAgentsSet(loaded)).sort((left, right) => `${left.category}/${left.agentKey}`.localeCompare(`${right.category}/${right.agentKey}`));
|
|
3068
|
+
if (targets.length === 0) {
|
|
3069
|
+
console.log(" No per-agent or per-category overlays are defined.");
|
|
3070
|
+
return;
|
|
3071
|
+
}
|
|
3072
|
+
for (const target of targets) {
|
|
3073
|
+
console.log(` ${target.agentKey} (${target.category}):`);
|
|
3074
|
+
for (const harness of ["opencode", "pi"]) {
|
|
3075
|
+
const resolution = resolveRouting({
|
|
3076
|
+
harness,
|
|
3077
|
+
overlays: loaded.overlays,
|
|
3078
|
+
piSubagentsOverlays: loaded.piSubagentsOverlays,
|
|
3079
|
+
target
|
|
3080
|
+
});
|
|
3081
|
+
const qualifierName = harness === "opencode" ? "variant" : "thinking";
|
|
3082
|
+
console.log(` ${harness}: model=${formatRoutingModel(resolution.model)} (${formatRoutingSource(resolution.source.model)}), ` + `${qualifierName}=${formatRoutingQualifier(resolution.qualifier)} (${formatRoutingSource(resolution.source.qualifier)})`);
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
function printResolvedSection() {
|
|
3087
|
+
let loaded;
|
|
3088
|
+
try {
|
|
3089
|
+
loaded = loadConfigWithSources(process.cwd());
|
|
3090
|
+
} catch {
|
|
3091
|
+
console.log(`
|
|
3092
|
+
Resolved configuration: unavailable (the configuration failed to load).`);
|
|
3093
|
+
return;
|
|
3094
|
+
}
|
|
3095
|
+
const { metadata, overlays } = loaded;
|
|
3096
|
+
const hasProfileSelection = metadata.activeProfile !== null || metadata.profileSelectorSource !== null;
|
|
3097
|
+
const hasOverlays = Object.keys(overlays.agents).length > 0 || Object.keys(overlays.categories).length > 0;
|
|
3098
|
+
console.log(`
|
|
3099
|
+
Resolved configuration:`);
|
|
3100
|
+
if (!hasProfileSelection && !hasOverlays) {
|
|
3101
|
+
console.log(" No profiles are selected and no per-agent/category overlays are defined.");
|
|
3102
|
+
return;
|
|
3103
|
+
}
|
|
3104
|
+
printProfileSummary(metadata);
|
|
3105
|
+
console.log("");
|
|
3106
|
+
console.log(" Routing:");
|
|
3107
|
+
printRoutingTable(loaded);
|
|
3108
|
+
}
|
|
3109
|
+
function toJsonRoutingResolution(resolution) {
|
|
3110
|
+
return {
|
|
3111
|
+
model: resolution.model,
|
|
3112
|
+
qualifier: resolution.qualifier,
|
|
3113
|
+
source: resolution.source
|
|
3114
|
+
};
|
|
3115
|
+
}
|
|
3116
|
+
function buildConfigShowJson() {
|
|
3117
|
+
const paths = getConfigPaths(process.cwd());
|
|
3118
|
+
const locations = {
|
|
3119
|
+
user: paths.userConfig,
|
|
3120
|
+
project: paths.projectConfig,
|
|
3121
|
+
custom: paths.customConfig ?? null
|
|
3122
|
+
};
|
|
3123
|
+
let loaded;
|
|
3124
|
+
try {
|
|
3125
|
+
loaded = loadConfigWithSources(process.cwd());
|
|
3126
|
+
} catch (error) {
|
|
3127
|
+
return {
|
|
3128
|
+
locations,
|
|
3129
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3130
|
+
};
|
|
3131
|
+
}
|
|
3132
|
+
const targets = collectRoutingTargets(loaded.overlays, disabledAgentsSet(loaded)).sort((left, right) => `${left.category}/${left.agentKey}`.localeCompare(`${right.category}/${right.agentKey}`));
|
|
3133
|
+
const routing = targets.map((target) => ({
|
|
3134
|
+
target,
|
|
3135
|
+
opencode: toJsonRoutingResolution(resolveRouting({
|
|
3136
|
+
harness: "opencode",
|
|
3137
|
+
overlays: loaded.overlays,
|
|
3138
|
+
piSubagentsOverlays: loaded.piSubagentsOverlays,
|
|
3139
|
+
target
|
|
3140
|
+
})),
|
|
3141
|
+
pi: toJsonRoutingResolution(resolveRouting({
|
|
3142
|
+
harness: "pi",
|
|
3143
|
+
overlays: loaded.overlays,
|
|
3144
|
+
piSubagentsOverlays: loaded.piSubagentsOverlays,
|
|
3145
|
+
target
|
|
3146
|
+
}))
|
|
3147
|
+
}));
|
|
3148
|
+
return {
|
|
3149
|
+
locations,
|
|
3150
|
+
activeProfile: loaded.metadata.activeProfile,
|
|
3151
|
+
profileSelectorSource: loaded.metadata.profileSelectorSource,
|
|
3152
|
+
profileFallback: loaded.metadata.profileFallback,
|
|
3153
|
+
routing
|
|
3154
|
+
};
|
|
3155
|
+
}
|
|
3156
|
+
function configShow(options) {
|
|
3157
|
+
if (options.json) {
|
|
3158
|
+
const output = buildConfigShowJson();
|
|
3159
|
+
console.log(JSON.stringify(output, null, 2));
|
|
3160
|
+
if ("error" in output)
|
|
3161
|
+
process.exit(1);
|
|
3162
|
+
return;
|
|
3163
|
+
}
|
|
2956
3164
|
const paths = getConfigPaths(process.cwd());
|
|
2957
3165
|
console.log(`Configuration locations:
|
|
2958
3166
|
`);
|
|
@@ -2968,6 +3176,20 @@ Project configuration:`);
|
|
|
2968
3176
|
User configuration:`);
|
|
2969
3177
|
console.log(fs6.readFileSync(paths.userConfig, "utf-8"));
|
|
2970
3178
|
}
|
|
3179
|
+
printResolvedSection();
|
|
3180
|
+
}
|
|
3181
|
+
function parseConfigShowArgs(rest) {
|
|
3182
|
+
let json = false;
|
|
3183
|
+
for (const arg of rest) {
|
|
3184
|
+
if (arg === "--json") {
|
|
3185
|
+
json = true;
|
|
3186
|
+
} else {
|
|
3187
|
+
console.error(`Unknown argument: ${arg}`);
|
|
3188
|
+
console.error(CONFIG_SHOW_USAGE);
|
|
3189
|
+
process.exit(1);
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
return { json };
|
|
2971
3193
|
}
|
|
2972
3194
|
function configPath() {
|
|
2973
3195
|
const paths = getConfigPaths(process.cwd());
|
|
@@ -3166,7 +3388,7 @@ function runLegacyCli(args) {
|
|
|
3166
3388
|
switch (args[1]) {
|
|
3167
3389
|
case "show":
|
|
3168
3390
|
case undefined:
|
|
3169
|
-
configShow();
|
|
3391
|
+
configShow(parseConfigShowArgs(args.slice(2)));
|
|
3170
3392
|
break;
|
|
3171
3393
|
case "path":
|
|
3172
3394
|
configPath();
|