pm-ops 2026.9.13 → 2026.9.23
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 +29 -17
- package/README.md +110 -6
- package/dist/attestation.d.ts.map +1 -1
- package/dist/attestation.js +13 -23
- package/dist/attestation.js.map +1 -1
- package/dist/docstrings.d.ts.map +1 -1
- package/dist/docstrings.js +59 -64
- package/dist/docstrings.js.map +1 -1
- package/dist/duplication.d.ts +118 -0
- package/dist/duplication.d.ts.map +1 -0
- package/dist/duplication.js +374 -0
- package/dist/duplication.js.map +1 -0
- package/dist/eslint.d.ts +41 -0
- package/dist/eslint.d.ts.map +1 -0
- package/dist/eslint.js +125 -0
- package/dist/eslint.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +92 -121
- package/dist/index.js.map +1 -1
- package/dist/invocation-audit.d.ts +33 -0
- package/dist/invocation-audit.d.ts.map +1 -0
- package/dist/invocation-audit.js +47 -0
- package/dist/invocation-audit.js.map +1 -0
- package/dist/merge-driver-prepare.d.ts +15 -0
- package/dist/merge-driver-prepare.d.ts.map +1 -0
- package/dist/merge-driver-prepare.js +16 -0
- package/dist/merge-driver-prepare.js.map +1 -0
- package/dist/merge-driver.d.ts +57 -0
- package/dist/merge-driver.d.ts.map +1 -0
- package/dist/merge-driver.js +122 -0
- package/dist/merge-driver.js.map +1 -0
- package/dist/shell-scan.d.ts.map +1 -1
- package/dist/shell-scan.js +52 -37
- package/dist/shell-scan.js.map +1 -1
- package/manifest.json +1 -1
- package/package.json +56 -5
- package/templates/prepare-merge-driver.ts +42 -0
package/dist/index.js
CHANGED
|
@@ -97,6 +97,16 @@ function reposFlag(description) {
|
|
|
97
97
|
list: true,
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
|
+
function opsExamples(command, examples) {
|
|
101
|
+
return [`pm ops ${command}`, ...examples];
|
|
102
|
+
}
|
|
103
|
+
/** Build the shared output-format and output-file flag definitions. */
|
|
104
|
+
function formatOutputFlags(outputDescription) {
|
|
105
|
+
return [
|
|
106
|
+
{ long: "--format", value_name: "toon|json|markdown", description: "Output format (default: toon)" },
|
|
107
|
+
{ long: "--output", value_name: "file", description: outputDescription },
|
|
108
|
+
];
|
|
109
|
+
}
|
|
100
110
|
/** Extract every --repos value that follows a command path in the raw argv array. */
|
|
101
111
|
function cliRepoFlagValues(commandPath, argv = process.argv.slice(2)) {
|
|
102
112
|
const commandTokens = commandPath.split(" ");
|
|
@@ -154,7 +164,7 @@ function expandHome(path) {
|
|
|
154
164
|
return path.startsWith("~/") || path.startsWith("~\\") ? join(homedir(), path.slice(2)) : path;
|
|
155
165
|
}
|
|
156
166
|
function hasGlob(path) {
|
|
157
|
-
return /[
|
|
167
|
+
return /[*?[]/.test(path);
|
|
158
168
|
}
|
|
159
169
|
function escapeRegexChar(char) {
|
|
160
170
|
return /[.+^${}()|[\]\\]/.test(char) ? `\\${char}` : char;
|
|
@@ -217,6 +227,16 @@ function expandSimpleGlob(pattern) {
|
|
|
217
227
|
// guaranteed — important for stable, diff-friendly agent output.
|
|
218
228
|
return candidates.length > 0 ? [...candidates].sort() : [absolute];
|
|
219
229
|
}
|
|
230
|
+
/** Normalize command context into the repository paths and output routing inputs. */
|
|
231
|
+
function resolveCommandInputs(ctx) {
|
|
232
|
+
const options = ctx.options;
|
|
233
|
+
return {
|
|
234
|
+
options,
|
|
235
|
+
repos: resolveRepos(options, ctx.args),
|
|
236
|
+
format: resolveFormat(options, ctx.global),
|
|
237
|
+
outputPath: readString(options, "output"),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
220
240
|
function resolveRepos(options, args = []) {
|
|
221
241
|
const repos = [...asArray(options["repos"]), ...asArray(args)];
|
|
222
242
|
if (repos.length > 0)
|
|
@@ -643,6 +663,21 @@ function ghOpenCount(repoPath, kind) {
|
|
|
643
663
|
const parsed = parseJsonSafe(r.stdout);
|
|
644
664
|
return Array.isArray(parsed) ? parsed.length : null;
|
|
645
665
|
}
|
|
666
|
+
function readRepoPackageInfo(repoPath) {
|
|
667
|
+
const pkg = readPackageJson(repoPath);
|
|
668
|
+
return { pkg, name: pkg?.name ?? null, version: pkg?.version ?? null };
|
|
669
|
+
}
|
|
670
|
+
/** Read npm audit severity counts and report unavailable audits to the caller. */
|
|
671
|
+
function readAuditCounts(repoPath, onError) {
|
|
672
|
+
try {
|
|
673
|
+
const audit = readAudit(repoPath);
|
|
674
|
+
return { critical: audit.critical, high: audit.high };
|
|
675
|
+
}
|
|
676
|
+
catch (error) {
|
|
677
|
+
onError(auditUnavailable(error));
|
|
678
|
+
return { critical: null, high: null };
|
|
679
|
+
}
|
|
680
|
+
}
|
|
646
681
|
/** Gather the full release-readiness snapshot for a single repository path. */
|
|
647
682
|
function scanRepo(repoPath) {
|
|
648
683
|
const errors = [];
|
|
@@ -670,9 +705,7 @@ function scanRepo(repoPath) {
|
|
|
670
705
|
errors,
|
|
671
706
|
};
|
|
672
707
|
}
|
|
673
|
-
const pkg =
|
|
674
|
-
const name = pkg?.name ?? null;
|
|
675
|
-
const version = pkg?.version ?? null;
|
|
708
|
+
const { pkg, name, version } = readRepoPackageInfo(repoPath);
|
|
676
709
|
const strict_ts = readTsConfigStrict(repoPath);
|
|
677
710
|
const has_changelog = existsSync(join(repoPath, "CHANGELOG.md"));
|
|
678
711
|
const has_release_workflow = existsSync(join(repoPath, ".github", "workflows", "release.yml"));
|
|
@@ -684,16 +717,9 @@ function scanRepo(repoPath) {
|
|
|
684
717
|
const pm_open_items = items ? items.filter((i) => (i.status ?? "").toLowerCase() === "open").length : null;
|
|
685
718
|
const pm_inprogress_items = items ? items.filter((i) => (i.status ?? "").toLowerCase() === "in_progress").length : null;
|
|
686
719
|
const outdated_count = countOutdated(repoPath);
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
const a = readAudit(repoPath);
|
|
691
|
-
audit_critical = a.critical;
|
|
692
|
-
audit_high = a.high;
|
|
693
|
-
}
|
|
694
|
-
catch (err) {
|
|
695
|
-
errors.push(auditUnavailable(err));
|
|
696
|
-
}
|
|
720
|
+
const audit = readAuditCounts(repoPath, (message) => errors.push(message));
|
|
721
|
+
const audit_critical = audit.critical;
|
|
722
|
+
const audit_high = audit.high;
|
|
697
723
|
const open_prs = ghOpenCount(repoPath, "pr");
|
|
698
724
|
const open_issues = ghOpenCount(repoPath, "issue");
|
|
699
725
|
const has_pkg = Boolean(pkg);
|
|
@@ -1065,6 +1091,10 @@ function verifyRelease(repos, progress) {
|
|
|
1065
1091
|
summary: { total: results.length, passed: results.filter((r) => r.failed === 0).length, failed: results.filter((r) => r.failed > 0).length },
|
|
1066
1092
|
};
|
|
1067
1093
|
}
|
|
1094
|
+
function throwVerifyReleaseFailure(result) {
|
|
1095
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
1096
|
+
throw new CommandError(`verify-release: ${result.summary.failed} repo(s) failed`, EXIT_CODE.GENERIC_FAILURE);
|
|
1097
|
+
}
|
|
1068
1098
|
/** Render the verify-release result as a markdown table of checks per repo. */
|
|
1069
1099
|
function renderVerifyReleaseMarkdown(result) {
|
|
1070
1100
|
const lines = [
|
|
@@ -1105,9 +1135,7 @@ async function collectStatus(repoPath) {
|
|
|
1105
1135
|
pending_receipts: null,
|
|
1106
1136
|
};
|
|
1107
1137
|
}
|
|
1108
|
-
const pkg =
|
|
1109
|
-
const name = pkg?.name ?? null;
|
|
1110
|
-
const version = pkg?.version ?? null;
|
|
1138
|
+
const { pkg, name, version } = readRepoPackageInfo(repoPath);
|
|
1111
1139
|
const issues = [];
|
|
1112
1140
|
const strict_ts = readTsConfigStrict(repoPath);
|
|
1113
1141
|
if (!strict_ts)
|
|
@@ -1126,16 +1154,9 @@ async function collectStatus(repoPath) {
|
|
|
1126
1154
|
if (!has_pm_changelog && !self_hosts_pm_changelog)
|
|
1127
1155
|
issues.push("pm-changelog not wired");
|
|
1128
1156
|
const outdated_count = countOutdated(repoPath);
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
const a = readAudit(repoPath);
|
|
1133
|
-
audit_critical = a.critical;
|
|
1134
|
-
audit_high = a.high;
|
|
1135
|
-
}
|
|
1136
|
-
catch (err) {
|
|
1137
|
-
issues.push(auditUnavailable(err));
|
|
1138
|
-
}
|
|
1157
|
+
const audit = readAuditCounts(repoPath, (message) => issues.push(message));
|
|
1158
|
+
const audit_critical = audit.critical;
|
|
1159
|
+
const audit_high = audit.high;
|
|
1139
1160
|
// Critical vulnerabilities gate readiness (matching scanRepo's
|
|
1140
1161
|
// audit gate). High-severity findings are still pushed to issues for
|
|
1141
1162
|
// textual visibility but do not block ready, so fleet-health reports
|
|
@@ -2061,7 +2082,7 @@ function renderDocstringsMarkdown(result) {
|
|
|
2061
2082
|
const defineExtension = (module) => module;
|
|
2062
2083
|
export default defineExtension({
|
|
2063
2084
|
name: "pm-ops",
|
|
2064
|
-
version: "2026.9.
|
|
2085
|
+
version: "2026.9.23",
|
|
2065
2086
|
activate(api) {
|
|
2066
2087
|
if (typeof api.registerRenderer === "function") {
|
|
2067
2088
|
// Derived from OPS_COMMAND_PATHS rather than restated. A literal copy is
|
|
@@ -2094,23 +2115,18 @@ export default defineExtension({
|
|
|
2094
2115
|
"(comma-separated or repeatable). --json emits clean JSON; --format markdown emits a table.",
|
|
2095
2116
|
intent: "audit release readiness across many pm repositories",
|
|
2096
2117
|
arguments: additionalRepoArguments(),
|
|
2097
|
-
examples: [
|
|
2098
|
-
"pm ops scan",
|
|
2118
|
+
examples: opsExamples("scan", [
|
|
2099
2119
|
"pm ops scan --repos ./pm-csv ./pm-github",
|
|
2100
2120
|
"pm ops scan --repos ./pm-csv,./pm-github --json",
|
|
2101
2121
|
"pm ops scan --format markdown",
|
|
2102
2122
|
"pm ops scan --repos ~/container/pm-* --format markdown --output FLEET.md",
|
|
2103
|
-
],
|
|
2123
|
+
]),
|
|
2104
2124
|
flags: [
|
|
2105
2125
|
reposFlag("Repo paths to scan (comma-separated or repeatable; default: current dir)"),
|
|
2106
|
-
|
|
2107
|
-
{ long: "--output", value_name: "file", description: "Write the rendered output to a file instead of stdout" },
|
|
2126
|
+
...formatOutputFlags("Write the rendered output to a file instead of stdout"),
|
|
2108
2127
|
],
|
|
2109
2128
|
async run(ctx) {
|
|
2110
|
-
const
|
|
2111
|
-
const repos = resolveRepos(options, ctx.args);
|
|
2112
|
-
const format = resolveFormat(options, ctx.global);
|
|
2113
|
-
const outputPath = readString(options, "output");
|
|
2129
|
+
const { repos, format, outputPath } = resolveCommandInputs(ctx);
|
|
2114
2130
|
console.error(`pm-ops scan: ${repos.length} repo(s)`);
|
|
2115
2131
|
const result = scanRepos(repos, (m) => console.error(` ${m}`));
|
|
2116
2132
|
console.error(`scan: ${result.summary.ready}/${result.summary.total} ready`);
|
|
@@ -2126,25 +2142,20 @@ export default defineExtension({
|
|
|
2126
2142
|
"({ checks: [{ id, severity, repo_filter?, params? }] }). --strict exits non-zero on any failure.",
|
|
2127
2143
|
intent: "enforce naming/workflow/pm policies across many pm repositories",
|
|
2128
2144
|
arguments: additionalRepoArguments(),
|
|
2129
|
-
examples: [
|
|
2130
|
-
"pm ops policy",
|
|
2145
|
+
examples: opsExamples("policy", [
|
|
2131
2146
|
"pm ops policy --repos ./pm-csv ./pm-github",
|
|
2132
2147
|
"pm ops policy --policy ./fleet-policy.json --strict",
|
|
2133
2148
|
"pm ops policy --format markdown",
|
|
2134
|
-
],
|
|
2149
|
+
]),
|
|
2135
2150
|
flags: [
|
|
2136
2151
|
reposFlag("Repo paths to check (comma-separated or repeatable; default: current dir)"),
|
|
2137
2152
|
{ long: "--policy", value_name: "file", description: "JSON policy bundle overriding the default checks" },
|
|
2138
|
-
|
|
2153
|
+
...formatOutputFlags("Write the rendered output to a file instead of stdout"),
|
|
2139
2154
|
{ long: "--strict", description: "Exit non-zero on any failed check (any severity)" },
|
|
2140
|
-
{ long: "--output", value_name: "file", description: "Write the rendered output to a file instead of stdout" },
|
|
2141
2155
|
],
|
|
2142
2156
|
async run(ctx) {
|
|
2143
|
-
const options = ctx
|
|
2144
|
-
const repos = resolveRepos(options, ctx.args);
|
|
2145
|
-
const format = resolveFormat(options, ctx.global);
|
|
2157
|
+
const { options, repos, format, outputPath } = resolveCommandInputs(ctx);
|
|
2146
2158
|
const strict = readBool(options, "strict");
|
|
2147
|
-
const outputPath = readString(options, "output");
|
|
2148
2159
|
let bundle = DEFAULT_POLICY;
|
|
2149
2160
|
const policyFile = readString(options, "policy");
|
|
2150
2161
|
if (policyFile) {
|
|
@@ -2181,22 +2192,17 @@ export default defineExtension({
|
|
|
2181
2192
|
"Exits non-zero if any repo fails. --output writes the report to a file.",
|
|
2182
2193
|
intent: "run a release gate matrix across many pm repositories",
|
|
2183
2194
|
arguments: additionalRepoArguments(),
|
|
2184
|
-
examples: [
|
|
2185
|
-
"pm ops verify-release",
|
|
2195
|
+
examples: opsExamples("verify-release", [
|
|
2186
2196
|
"pm ops verify-release --repos ./pm-csv ./pm-github",
|
|
2187
2197
|
"pm ops verify-release --json",
|
|
2188
2198
|
"pm ops verify-release --format markdown --output RELEASE.md",
|
|
2189
|
-
],
|
|
2199
|
+
]),
|
|
2190
2200
|
flags: [
|
|
2191
2201
|
reposFlag("Repo paths to verify (comma-separated or repeatable; default: current dir)"),
|
|
2192
|
-
|
|
2193
|
-
{ long: "--output", value_name: "file", description: "Write the rendered output to a file instead of stdout" },
|
|
2202
|
+
...formatOutputFlags("Write the rendered output to a file instead of stdout"),
|
|
2194
2203
|
],
|
|
2195
2204
|
async run(ctx) {
|
|
2196
|
-
const
|
|
2197
|
-
const repos = resolveRepos(options, ctx.args);
|
|
2198
|
-
const format = resolveFormat(options, ctx.global);
|
|
2199
|
-
const outputPath = readString(options, "output");
|
|
2205
|
+
const { repos, format, outputPath } = resolveCommandInputs(ctx);
|
|
2200
2206
|
console.error(`pm-ops verify-release: ${repos.length} repo(s)`);
|
|
2201
2207
|
const result = verifyRelease(repos, (m) => console.error(` ${m}`));
|
|
2202
2208
|
console.error(`verify-release: ${result.summary.passed}/${result.summary.total} repos passed`);
|
|
@@ -2220,10 +2226,8 @@ export default defineExtension({
|
|
|
2220
2226
|
return { written_to: outputPath, format };
|
|
2221
2227
|
}
|
|
2222
2228
|
if (format === "json") {
|
|
2223
|
-
if (failed)
|
|
2224
|
-
|
|
2225
|
-
throw new CommandError(`verify-release: ${result.summary.failed} repo(s) failed`, EXIT_CODE.GENERIC_FAILURE);
|
|
2226
|
-
}
|
|
2229
|
+
if (failed)
|
|
2230
|
+
throwVerifyReleaseFailure(result);
|
|
2227
2231
|
return renderedCommandResult(`${JSON.stringify(result, null, 2)}\n`);
|
|
2228
2232
|
}
|
|
2229
2233
|
if (format === "markdown") {
|
|
@@ -2234,10 +2238,8 @@ export default defineExtension({
|
|
|
2234
2238
|
}
|
|
2235
2239
|
return renderedCommandResult(md);
|
|
2236
2240
|
}
|
|
2237
|
-
if (failed)
|
|
2238
|
-
|
|
2239
|
-
throw new CommandError(`verify-release: ${result.summary.failed} repo(s) failed`, EXIT_CODE.GENERIC_FAILURE);
|
|
2240
|
-
}
|
|
2241
|
+
if (failed)
|
|
2242
|
+
throwVerifyReleaseFailure(result);
|
|
2241
2243
|
return result;
|
|
2242
2244
|
},
|
|
2243
2245
|
});
|
|
@@ -2249,25 +2251,20 @@ export default defineExtension({
|
|
|
2249
2251
|
"--output writes the report to a file. Default stdout TOON.",
|
|
2250
2252
|
intent: "produce a concise fleet report across many pm repositories",
|
|
2251
2253
|
arguments: additionalRepoArguments(),
|
|
2252
|
-
examples: [
|
|
2253
|
-
"pm ops report",
|
|
2254
|
+
examples: opsExamples("report", [
|
|
2254
2255
|
"pm ops report --repos ./pm-csv ./pm-github --format markdown",
|
|
2255
2256
|
"pm ops report --format markdown --output FLEET.md",
|
|
2256
2257
|
"pm ops report --format markdown --include-release --output FLEET.md",
|
|
2257
2258
|
"pm ops report --json",
|
|
2258
|
-
],
|
|
2259
|
+
]),
|
|
2259
2260
|
flags: [
|
|
2260
2261
|
reposFlag("Repo paths to report on (comma-separated or repeatable; default: current dir)"),
|
|
2261
|
-
|
|
2262
|
-
{ long: "--output", value_name: "file", description: "Write the rendered report to a file instead of stdout" },
|
|
2262
|
+
...formatOutputFlags("Write the rendered report to a file instead of stdout"),
|
|
2263
2263
|
{ long: "--include-release", description: "Also run verify-release and include results in the report" },
|
|
2264
2264
|
],
|
|
2265
2265
|
async run(ctx) {
|
|
2266
|
-
const
|
|
2267
|
-
const
|
|
2268
|
-
const format = resolveFormat(options, ctx.global);
|
|
2269
|
-
const outputPath = readString(options, "output");
|
|
2270
|
-
const includeRelease = readBool(options, "includeRelease", "include-release");
|
|
2266
|
+
const { repos, format, outputPath } = resolveCommandInputs(ctx);
|
|
2267
|
+
const includeRelease = readBool(ctx.options, "includeRelease", "include-release");
|
|
2271
2268
|
console.error(`pm-ops report: ${repos.length} repo(s)${includeRelease ? " (+release)" : ""}`);
|
|
2272
2269
|
const result = buildReport(repos, (m) => console.error(` ${m}`), includeRelease);
|
|
2273
2270
|
console.error(`report: scan ${result.scan.summary.ready}/${result.scan.summary.total} ready; policy ${result.policy.summary.failed} failed${result.release ? `; release ${result.release.summary.passed}/${result.release.summary.total} passed` : ""}`);
|
|
@@ -2283,21 +2280,16 @@ export default defineExtension({
|
|
|
2283
2280
|
"emits a compact table.",
|
|
2284
2281
|
intent: "get a quick fleet health overview across many pm repositories",
|
|
2285
2282
|
arguments: additionalRepoArguments(),
|
|
2286
|
-
examples: [
|
|
2287
|
-
"pm ops status",
|
|
2283
|
+
examples: opsExamples("status", [
|
|
2288
2284
|
"pm ops status --repos ./pm-csv ./pm-github",
|
|
2289
2285
|
"pm ops status --format markdown",
|
|
2290
|
-
],
|
|
2286
|
+
]),
|
|
2291
2287
|
flags: [
|
|
2292
2288
|
reposFlag("Repo paths (comma-separated or repeatable; default: current dir)"),
|
|
2293
|
-
|
|
2294
|
-
{ long: "--output", value_name: "file", description: "Write the rendered output to a file instead of stdout" },
|
|
2289
|
+
...formatOutputFlags("Write the rendered output to a file instead of stdout"),
|
|
2295
2290
|
],
|
|
2296
2291
|
async run(ctx) {
|
|
2297
|
-
const
|
|
2298
|
-
const repos = resolveRepos(options, ctx.args);
|
|
2299
|
-
const format = resolveFormat(options, ctx.global);
|
|
2300
|
-
const outputPath = readString(options, "output");
|
|
2292
|
+
const { repos, format, outputPath } = resolveCommandInputs(ctx);
|
|
2301
2293
|
console.error(`pm-ops status: ${repos.length} repo(s)`);
|
|
2302
2294
|
const result = await collectStatusAll(repos, (m) => console.error(` ${m}`));
|
|
2303
2295
|
console.error(`status: ${result.summary.ready}/${result.summary.total} ready, ${result.summary.total_issues} issue(s)`);
|
|
@@ -2311,21 +2303,16 @@ export default defineExtension({
|
|
|
2311
2303
|
"by repo with per-package current/wanted/latest columns.",
|
|
2312
2304
|
intent: "check dependency freshness across many pm repositories",
|
|
2313
2305
|
arguments: additionalRepoArguments(),
|
|
2314
|
-
examples: [
|
|
2315
|
-
"pm ops outdated",
|
|
2306
|
+
examples: opsExamples("outdated", [
|
|
2316
2307
|
"pm ops outdated --repos ./pm-csv ./pm-github",
|
|
2317
2308
|
"pm ops outdated --format markdown",
|
|
2318
|
-
],
|
|
2309
|
+
]),
|
|
2319
2310
|
flags: [
|
|
2320
2311
|
reposFlag("Repo paths (comma-separated or repeatable; default: current dir)"),
|
|
2321
|
-
|
|
2322
|
-
{ long: "--output", value_name: "file", description: "Write the rendered output to a file instead of stdout" },
|
|
2312
|
+
...formatOutputFlags("Write the rendered output to a file instead of stdout"),
|
|
2323
2313
|
],
|
|
2324
2314
|
async run(ctx) {
|
|
2325
|
-
const
|
|
2326
|
-
const repos = resolveRepos(options, ctx.args);
|
|
2327
|
-
const format = resolveFormat(options, ctx.global);
|
|
2328
|
-
const outputPath = readString(options, "output");
|
|
2315
|
+
const { repos, format, outputPath } = resolveCommandInputs(ctx);
|
|
2329
2316
|
console.error(`pm-ops outdated: ${repos.length} repo(s)`);
|
|
2330
2317
|
const result = collectOutdatedAll(repos, (m) => console.error(` ${m}`));
|
|
2331
2318
|
console.error(`outdated: ${result.summary.repos_with_outdated}/${result.summary.total} repos with outdated, ${result.summary.total_outdated} total`);
|
|
@@ -2339,21 +2326,16 @@ export default defineExtension({
|
|
|
2339
2326
|
"fleet-wide vulnerability table.",
|
|
2340
2327
|
intent: "audit security vulnerabilities across many pm repositories",
|
|
2341
2328
|
arguments: additionalRepoArguments(),
|
|
2342
|
-
examples: [
|
|
2343
|
-
"pm ops audit",
|
|
2329
|
+
examples: opsExamples("audit", [
|
|
2344
2330
|
"pm ops audit --repos ./pm-csv ./pm-github",
|
|
2345
2331
|
"pm ops audit --format markdown",
|
|
2346
|
-
],
|
|
2332
|
+
]),
|
|
2347
2333
|
flags: [
|
|
2348
2334
|
reposFlag("Repo paths (comma-separated or repeatable; default: current dir)"),
|
|
2349
|
-
|
|
2350
|
-
{ long: "--output", value_name: "file", description: "Write the rendered output to a file instead of stdout" },
|
|
2335
|
+
...formatOutputFlags("Write the rendered output to a file instead of stdout"),
|
|
2351
2336
|
],
|
|
2352
2337
|
async run(ctx) {
|
|
2353
|
-
const
|
|
2354
|
-
const repos = resolveRepos(options, ctx.args);
|
|
2355
|
-
const format = resolveFormat(options, ctx.global);
|
|
2356
|
-
const outputPath = readString(options, "output");
|
|
2338
|
+
const { repos, format, outputPath } = resolveCommandInputs(ctx);
|
|
2357
2339
|
console.error(`pm-ops audit: ${repos.length} repo(s)`);
|
|
2358
2340
|
const result = collectAuditAll(repos, (m) => console.error(` ${m}`));
|
|
2359
2341
|
console.error(`audit: ${result.summary.clean}/${result.summary.total} clean, ${result.summary.total_critical} critical, ${result.summary.total_high} high`);
|
|
@@ -2370,12 +2352,11 @@ export default defineExtension({
|
|
|
2370
2352
|
"exposition format; --output writes a .prom file for the node_exporter textfile collector.",
|
|
2371
2353
|
intent: "expose pm workspace metrics to Prometheus/Grafana across many pm repositories",
|
|
2372
2354
|
arguments: additionalRepoArguments(),
|
|
2373
|
-
examples: [
|
|
2374
|
-
"pm ops metrics",
|
|
2355
|
+
examples: opsExamples("metrics", [
|
|
2375
2356
|
"pm ops metrics --repos ./pm-csv ./pm-github",
|
|
2376
2357
|
"pm ops metrics --output /var/lib/node_exporter/pm.prom",
|
|
2377
2358
|
"pm ops metrics --stale-days 7 --format json",
|
|
2378
|
-
],
|
|
2359
|
+
]),
|
|
2379
2360
|
flags: [
|
|
2380
2361
|
reposFlag("Repo paths (comma-separated or repeatable; default: current dir)"),
|
|
2381
2362
|
{ long: "--stale-days", value_name: "days", description: "Age (days) after which an active item counts as stale (default: 14)" },
|
|
@@ -2446,26 +2427,21 @@ export default defineExtension({
|
|
|
2446
2427
|
"--warn-only reports identically but always exits 0.",
|
|
2447
2428
|
intent: "gate fleet merges on clone-local decision receipts and merge-driver safety",
|
|
2448
2429
|
arguments: additionalRepoArguments(),
|
|
2449
|
-
examples: [
|
|
2450
|
-
"pm ops merge-receipts",
|
|
2430
|
+
examples: opsExamples("merge-receipts", [
|
|
2451
2431
|
"pm ops merge-receipts --repos ./pm-csv ./pm-github",
|
|
2452
2432
|
"pm ops merge-receipts --json",
|
|
2453
2433
|
"pm ops merge-receipts --warn-only",
|
|
2454
2434
|
"pm ops merge-receipts --include-reconciled --format markdown",
|
|
2455
2435
|
"pm ops merge-receipts --repos ~/container/pm-* --format markdown --output MERGE.md",
|
|
2456
|
-
],
|
|
2436
|
+
]),
|
|
2457
2437
|
flags: [
|
|
2458
2438
|
reposFlag("Repo paths to audit (comma-separated or repeatable; default: current dir)"),
|
|
2459
|
-
|
|
2460
|
-
{ long: "--output", value_name: "file", description: "Write the rendered output to a file instead of stdout" },
|
|
2439
|
+
...formatOutputFlags("Write the rendered output to a file instead of stdout"),
|
|
2461
2440
|
{ long: "--warn-only", description: "Report identically but always exit 0 (never fail the gate)" },
|
|
2462
2441
|
{ long: "--include-reconciled", description: "Include receipts already represented in committed history (default: pending only)" },
|
|
2463
2442
|
],
|
|
2464
2443
|
async run(ctx) {
|
|
2465
|
-
const options = ctx
|
|
2466
|
-
const repos = resolveRepos(options, ctx.args);
|
|
2467
|
-
const format = resolveFormat(options, ctx.global);
|
|
2468
|
-
const outputPath = readString(options, "output");
|
|
2444
|
+
const { options, repos, format, outputPath } = resolveCommandInputs(ctx);
|
|
2469
2445
|
const warnOnly = readBool(options, "warnOnly", "warn-only");
|
|
2470
2446
|
const includeReconciled = readBool(options, "includeReconciled", "include-reconciled");
|
|
2471
2447
|
console.error(`pm-ops merge-receipts: ${repos.length} repo(s)${includeReconciled ? " (+reconciled)" : ""}${warnOnly ? " [warn-only]" : ""}`);
|
|
@@ -2520,22 +2496,17 @@ export default defineExtension({
|
|
|
2520
2496
|
"commented-out lines cannot satisfy it. Exits non-zero when any repo has violations.",
|
|
2521
2497
|
intent: "enforce docstring coverage across many pm repositories",
|
|
2522
2498
|
arguments: additionalRepoArguments(),
|
|
2523
|
-
examples: [
|
|
2524
|
-
"pm ops docstrings",
|
|
2499
|
+
examples: opsExamples("docstrings", [
|
|
2525
2500
|
"pm ops docstrings --repos ./pm-csv ./pm-github",
|
|
2526
2501
|
"pm ops docstrings --format markdown",
|
|
2527
2502
|
"pm ops docstrings --repos ./pm-csv --json",
|
|
2528
|
-
],
|
|
2503
|
+
]),
|
|
2529
2504
|
flags: [
|
|
2530
2505
|
reposFlag("Repo paths to audit (comma-separated or repeatable; default: current dir)"),
|
|
2531
|
-
|
|
2532
|
-
{ long: "--output", value_name: "file", description: "Write the rendered output to a file instead of stdout" },
|
|
2506
|
+
...formatOutputFlags("Write the rendered output to a file instead of stdout"),
|
|
2533
2507
|
],
|
|
2534
2508
|
async run(ctx) {
|
|
2535
|
-
const
|
|
2536
|
-
const repos = resolveRepos(options, ctx.args);
|
|
2537
|
-
const format = resolveFormat(options, ctx.global);
|
|
2538
|
-
const outputPath = readString(options, "output");
|
|
2509
|
+
const { repos, format, outputPath } = resolveCommandInputs(ctx);
|
|
2539
2510
|
console.error(`pm-ops docstrings: ${repos.length} repo(s)`);
|
|
2540
2511
|
const result = collectDocstringsAll(repos, (m) => console.error(` ${m}`));
|
|
2541
2512
|
console.error(`docstrings: ${result.summary.total_violations} violation(s) across ${result.summary.with_violations}/${result.summary.total} repo(s)`);
|