@kolatts/pncli 1.14.1 → 1.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/copilot-instructions.md +212 -19
- package/dist/{chunk-CFUUOW7B.js → chunk-P5NWDQ2B.js} +12 -1
- package/dist/chunk-P5NWDQ2B.js.map +1 -0
- package/dist/{chunk-BNMFIGXF.js → chunk-XPPEXJBP.js} +114 -4
- package/dist/chunk-XPPEXJBP.js.map +1 -0
- package/dist/cli.js +725 -109
- package/dist/cli.js.map +1 -1
- package/dist/{config-TL5X47RY.js → config-3QD5Y2O5.js} +2 -2
- package/dist/{http-UN6N4WIB.js → http-5WRBWEM6.js} +2 -2
- package/package.json +1 -1
- package/skills/pncli/SKILL.md +2 -1
- package/skills/pncli/github.md +38 -0
- package/dist/chunk-BNMFIGXF.js.map +0 -1
- package/dist/chunk-CFUUOW7B.js.map +0 -1
- /package/dist/{config-TL5X47RY.js.map → config-3QD5Y2O5.js.map} +0 -0
- /package/dist/{http-UN6N4WIB.js.map → http-5WRBWEM6.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
setRepoConfigValue,
|
|
9
9
|
writeGlobalConfig,
|
|
10
10
|
writeRepoConfig
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-P5NWDQ2B.js";
|
|
12
12
|
import {
|
|
13
13
|
ExitCode,
|
|
14
14
|
PncliError,
|
|
@@ -20,13 +20,13 @@ import {
|
|
|
20
20
|
success,
|
|
21
21
|
warn,
|
|
22
22
|
writeRawOutput
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-XPPEXJBP.js";
|
|
24
24
|
import {
|
|
25
25
|
AdoCoreClient
|
|
26
26
|
} from "./chunk-VDL32PSG.js";
|
|
27
27
|
|
|
28
28
|
// src/cli.ts
|
|
29
|
-
import { Command as
|
|
29
|
+
import { Command as Command3 } from "commander";
|
|
30
30
|
import { createRequire } from "module";
|
|
31
31
|
|
|
32
32
|
// src/services/git/client.ts
|
|
@@ -306,7 +306,7 @@ function parseBranchReportOutput(raw, branchName, opts) {
|
|
|
306
306
|
}
|
|
307
307
|
function normalizeGitDate(dateStr) {
|
|
308
308
|
if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
|
|
309
|
-
return `${dateStr}T00:00:00`;
|
|
309
|
+
return `${dateStr}T00:00:00+00:00`;
|
|
310
310
|
}
|
|
311
311
|
return dateStr;
|
|
312
312
|
}
|
|
@@ -328,7 +328,7 @@ function getBranchReport(root, opts) {
|
|
|
328
328
|
const args = buildReportArgs(opts);
|
|
329
329
|
let raw = "";
|
|
330
330
|
try {
|
|
331
|
-
raw = execFileSync("git", args, { encoding: "utf8", cwd: root }).trim();
|
|
331
|
+
raw = execFileSync("git", args, { encoding: "utf8", cwd: root, maxBuffer: 200 * 1024 * 1024 }).trim();
|
|
332
332
|
} catch {
|
|
333
333
|
}
|
|
334
334
|
let branchName = opts.branch ?? "";
|
|
@@ -455,6 +455,42 @@ function parseAdoRemote(remoteUrl, adoBaseUrl) {
|
|
|
455
455
|
const collection = decodeURIComponent(parts[parts.length - 2]);
|
|
456
456
|
return { collection, project, repo };
|
|
457
457
|
}
|
|
458
|
+
function parseGitHubRemote(remoteUrl, baseUrl) {
|
|
459
|
+
let targetHost;
|
|
460
|
+
if (baseUrl) {
|
|
461
|
+
try {
|
|
462
|
+
const normalizedBase = /^https?:\/\//i.test(baseUrl) ? baseUrl : `https://${baseUrl}`;
|
|
463
|
+
const hostname = new URL(normalizedBase).hostname.toLowerCase();
|
|
464
|
+
targetHost = hostname === "api.github.com" ? "github.com" : hostname;
|
|
465
|
+
} catch {
|
|
466
|
+
targetHost = baseUrl.replace(/\/$/, "").replace(/^https?:\/\//i, "").split(/[:/]/)[0].toLowerCase();
|
|
467
|
+
}
|
|
468
|
+
} else {
|
|
469
|
+
targetHost = "github.com";
|
|
470
|
+
}
|
|
471
|
+
const sshMatch = remoteUrl.match(/^git@([^:]+):([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
472
|
+
if (sshMatch) {
|
|
473
|
+
const [, host, owner, repo] = sshMatch;
|
|
474
|
+
if (host.toLowerCase() === targetHost) {
|
|
475
|
+
return { owner, repo };
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
const sshProtoMatch = remoteUrl.match(/^ssh:\/\/git@([^/:]+)(?::\d+)?\/([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
479
|
+
if (sshProtoMatch) {
|
|
480
|
+
const [, host, owner, repo] = sshProtoMatch;
|
|
481
|
+
if (host.toLowerCase() === targetHost) {
|
|
482
|
+
return { owner, repo };
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
const httpsMatch = remoteUrl.match(/^https?:\/\/([^/:]+)(?::\d+)?\/([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
486
|
+
if (httpsMatch) {
|
|
487
|
+
const [, host, owner, repo] = httpsMatch;
|
|
488
|
+
if (host.toLowerCase() === targetHost) {
|
|
489
|
+
return { owner, repo };
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
458
494
|
function getRemoteUrls(repoRoot) {
|
|
459
495
|
try {
|
|
460
496
|
const output = execSync2("git remote -v", { encoding: "utf8", cwd: repoRoot });
|
|
@@ -486,7 +522,15 @@ function getGitContext(config) {
|
|
|
486
522
|
break;
|
|
487
523
|
}
|
|
488
524
|
}
|
|
489
|
-
|
|
525
|
+
let githubContext = null;
|
|
526
|
+
for (const url of remoteUrls) {
|
|
527
|
+
const parsed = parseGitHubRemote(url, config.github.baseUrl);
|
|
528
|
+
if (parsed) {
|
|
529
|
+
githubContext = parsed;
|
|
530
|
+
break;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return { root, branch, project, repo, ado: adoContext, github: githubContext };
|
|
490
534
|
}
|
|
491
535
|
|
|
492
536
|
// src/services/bitbucket/client.ts
|
|
@@ -1675,6 +1719,466 @@ function registerBitbucketCommands(program2) {
|
|
|
1675
1719
|
});
|
|
1676
1720
|
}
|
|
1677
1721
|
|
|
1722
|
+
// src/services/github/commands.ts
|
|
1723
|
+
import { Option } from "commander";
|
|
1724
|
+
|
|
1725
|
+
// src/services/github/client.ts
|
|
1726
|
+
var GitHubClient = class {
|
|
1727
|
+
constructor(http) {
|
|
1728
|
+
this.http = http;
|
|
1729
|
+
}
|
|
1730
|
+
http;
|
|
1731
|
+
async listPRs(opts) {
|
|
1732
|
+
return this.http.githubPaginate(
|
|
1733
|
+
(page, perPage) => this.http.github(
|
|
1734
|
+
`/repos/${opts.owner}/${opts.repo}/pulls`,
|
|
1735
|
+
{
|
|
1736
|
+
params: {
|
|
1737
|
+
state: opts.state ?? "open",
|
|
1738
|
+
...opts.head ? { head: opts.head } : {},
|
|
1739
|
+
...opts.base ? { base: opts.base } : {},
|
|
1740
|
+
per_page: perPage,
|
|
1741
|
+
page
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
)
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1747
|
+
async getPR(owner, repo, pullNumber) {
|
|
1748
|
+
return this.http.github(`/repos/${owner}/${repo}/pulls/${pullNumber}`);
|
|
1749
|
+
}
|
|
1750
|
+
async createPR(opts) {
|
|
1751
|
+
return this.http.github(
|
|
1752
|
+
`/repos/${opts.owner}/${opts.repo}/pulls`,
|
|
1753
|
+
{
|
|
1754
|
+
method: "POST",
|
|
1755
|
+
body: {
|
|
1756
|
+
title: opts.title,
|
|
1757
|
+
head: opts.head,
|
|
1758
|
+
base: opts.base,
|
|
1759
|
+
...opts.body !== void 0 ? { body: opts.body } : {},
|
|
1760
|
+
...opts.draft !== void 0 ? { draft: opts.draft } : {}
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
);
|
|
1764
|
+
}
|
|
1765
|
+
async updatePR(opts) {
|
|
1766
|
+
const body = {};
|
|
1767
|
+
if (opts.title !== void 0) body.title = opts.title;
|
|
1768
|
+
if (opts.body !== void 0) body.body = opts.body;
|
|
1769
|
+
if (opts.state !== void 0) body.state = opts.state;
|
|
1770
|
+
if (opts.base !== void 0) body.base = opts.base;
|
|
1771
|
+
return this.http.github(
|
|
1772
|
+
`/repos/${opts.owner}/${opts.repo}/pulls/${opts.pullNumber}`,
|
|
1773
|
+
{ method: "PATCH", body }
|
|
1774
|
+
);
|
|
1775
|
+
}
|
|
1776
|
+
async mergePR(opts) {
|
|
1777
|
+
const body = {};
|
|
1778
|
+
if (opts.commitTitle) body.commit_title = opts.commitTitle;
|
|
1779
|
+
if (opts.commitMessage) body.commit_message = opts.commitMessage;
|
|
1780
|
+
if (opts.mergeMethod) body.merge_method = opts.mergeMethod;
|
|
1781
|
+
return this.http.github(
|
|
1782
|
+
`/repos/${opts.owner}/${opts.repo}/pulls/${opts.pullNumber}/merge`,
|
|
1783
|
+
{ method: "PUT", body }
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
async closePR(owner, repo, pullNumber) {
|
|
1787
|
+
return this.updatePR({ owner, repo, pullNumber, state: "closed" });
|
|
1788
|
+
}
|
|
1789
|
+
async listComments(owner, repo, pullNumber) {
|
|
1790
|
+
return this.http.githubPaginate(
|
|
1791
|
+
(page, perPage) => this.http.github(
|
|
1792
|
+
`/repos/${owner}/${repo}/issues/${pullNumber}/comments`,
|
|
1793
|
+
{ params: { per_page: perPage, page } }
|
|
1794
|
+
)
|
|
1795
|
+
);
|
|
1796
|
+
}
|
|
1797
|
+
async addComment(owner, repo, pullNumber, body) {
|
|
1798
|
+
return this.http.github(
|
|
1799
|
+
`/repos/${owner}/${repo}/issues/${pullNumber}/comments`,
|
|
1800
|
+
{ method: "POST", body: { body } }
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1803
|
+
async listReviewComments(owner, repo, pullNumber) {
|
|
1804
|
+
return this.http.githubPaginate(
|
|
1805
|
+
(page, perPage) => this.http.github(
|
|
1806
|
+
`/repos/${owner}/${repo}/pulls/${pullNumber}/comments`,
|
|
1807
|
+
{ params: { per_page: perPage, page } }
|
|
1808
|
+
)
|
|
1809
|
+
);
|
|
1810
|
+
}
|
|
1811
|
+
async addInlineComment(opts) {
|
|
1812
|
+
return this.http.github(
|
|
1813
|
+
`/repos/${opts.owner}/${opts.repo}/pulls/${opts.pullNumber}/comments`,
|
|
1814
|
+
{
|
|
1815
|
+
method: "POST",
|
|
1816
|
+
body: {
|
|
1817
|
+
body: opts.body,
|
|
1818
|
+
commit_id: opts.commitId,
|
|
1819
|
+
path: opts.path,
|
|
1820
|
+
line: opts.line,
|
|
1821
|
+
side: opts.side ?? "RIGHT"
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
async replyComment(owner, repo, pullNumber, commentId, body) {
|
|
1827
|
+
return this.http.github(
|
|
1828
|
+
`/repos/${owner}/${repo}/pulls/${pullNumber}/comments/${commentId}/replies`,
|
|
1829
|
+
{ method: "POST", body: { body } }
|
|
1830
|
+
);
|
|
1831
|
+
}
|
|
1832
|
+
async deleteComment(owner, repo, commentId) {
|
|
1833
|
+
await this.http.github(
|
|
1834
|
+
`/repos/${owner}/${repo}/issues/comments/${commentId}`,
|
|
1835
|
+
{ method: "DELETE" }
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
async deleteReviewComment(owner, repo, commentId) {
|
|
1839
|
+
await this.http.github(
|
|
1840
|
+
`/repos/${owner}/${repo}/pulls/comments/${commentId}`,
|
|
1841
|
+
{ method: "DELETE" }
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
async getDiff(owner, repo, pullNumber) {
|
|
1845
|
+
return this.http.githubText(`/repos/${owner}/${repo}/pulls/${pullNumber}`);
|
|
1846
|
+
}
|
|
1847
|
+
async listFiles(owner, repo, pullNumber) {
|
|
1848
|
+
return this.http.githubPaginate(
|
|
1849
|
+
(page, perPage) => this.http.github(
|
|
1850
|
+
`/repos/${owner}/${repo}/pulls/${pullNumber}/files`,
|
|
1851
|
+
{ params: { per_page: perPage, page } }
|
|
1852
|
+
)
|
|
1853
|
+
);
|
|
1854
|
+
}
|
|
1855
|
+
async listReviews(owner, repo, pullNumber) {
|
|
1856
|
+
return this.http.githubPaginate(
|
|
1857
|
+
(page, perPage) => this.http.github(
|
|
1858
|
+
`/repos/${owner}/${repo}/pulls/${pullNumber}/reviews`,
|
|
1859
|
+
{ params: { per_page: perPage, page } }
|
|
1860
|
+
)
|
|
1861
|
+
);
|
|
1862
|
+
}
|
|
1863
|
+
async submitReview(opts) {
|
|
1864
|
+
return this.http.github(
|
|
1865
|
+
`/repos/${opts.owner}/${opts.repo}/pulls/${opts.pullNumber}/reviews`,
|
|
1866
|
+
{
|
|
1867
|
+
method: "POST",
|
|
1868
|
+
body: {
|
|
1869
|
+
event: opts.event,
|
|
1870
|
+
...opts.body !== void 0 ? { body: opts.body } : {}
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
);
|
|
1874
|
+
}
|
|
1875
|
+
async listRequestedReviewers(owner, repo, pullNumber) {
|
|
1876
|
+
return this.http.github(
|
|
1877
|
+
`/repos/${owner}/${repo}/pulls/${pullNumber}/requested_reviewers`
|
|
1878
|
+
);
|
|
1879
|
+
}
|
|
1880
|
+
async getCommitStatuses(owner, repo, ref) {
|
|
1881
|
+
return this.http.github(`/repos/${owner}/${repo}/commits/${ref}/status`);
|
|
1882
|
+
}
|
|
1883
|
+
async listCheckRuns(owner, repo, ref) {
|
|
1884
|
+
const results = [];
|
|
1885
|
+
let page = 1;
|
|
1886
|
+
const perPage = 100;
|
|
1887
|
+
while (true) {
|
|
1888
|
+
const result = await this.http.github(
|
|
1889
|
+
`/repos/${owner}/${repo}/commits/${ref}/check-runs`,
|
|
1890
|
+
{ params: { per_page: perPage, page } }
|
|
1891
|
+
);
|
|
1892
|
+
const runs = result.check_runs ?? [];
|
|
1893
|
+
results.push(...runs);
|
|
1894
|
+
if (runs.length < perPage) break;
|
|
1895
|
+
page++;
|
|
1896
|
+
}
|
|
1897
|
+
return results;
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
|
|
1901
|
+
// src/services/github/commands.ts
|
|
1902
|
+
function getClient3(program2, overrides) {
|
|
1903
|
+
const opts = program2.optsWithGlobals();
|
|
1904
|
+
const config = loadConfig({ configPath: opts.config });
|
|
1905
|
+
const http = createHttpClient(config, Boolean(opts.dryRun));
|
|
1906
|
+
const client = new GitHubClient(http);
|
|
1907
|
+
const ctx = getGitContext(config);
|
|
1908
|
+
const owner = overrides?.owner ?? opts.owner ?? ctx?.github?.owner ?? config.defaults.github?.owner ?? "";
|
|
1909
|
+
const repo = overrides?.repo ?? opts.repo ?? ctx?.github?.repo ?? config.defaults.github?.repo ?? "";
|
|
1910
|
+
if (!owner || !repo) {
|
|
1911
|
+
throw new PncliError(
|
|
1912
|
+
"Could not determine GitHub owner/repo. Pass --owner and --repo, or run pncli config init.",
|
|
1913
|
+
1
|
|
1914
|
+
);
|
|
1915
|
+
}
|
|
1916
|
+
return { client, owner, repo, config };
|
|
1917
|
+
}
|
|
1918
|
+
function registerGitHubCommands(program2) {
|
|
1919
|
+
const gh = program2.command("github").description("GitHub repository operations").option("--owner <owner>", "GitHub owner (user or org)").option("--repo <repo>", "GitHub repository name");
|
|
1920
|
+
gh.command("list-prs").description("List pull requests").addOption(new Option("--state <state>", "PR state").choices(["open", "closed", "all"]).default("open")).option("--head <branch>", "Filter by head branch (user:branch)").option("--base <branch>", "Filter by base branch").action(async (opts) => {
|
|
1921
|
+
const start = Date.now();
|
|
1922
|
+
try {
|
|
1923
|
+
const { client, owner, repo } = getClient3(gh);
|
|
1924
|
+
const data = await client.listPRs({
|
|
1925
|
+
owner,
|
|
1926
|
+
repo,
|
|
1927
|
+
state: opts.state,
|
|
1928
|
+
head: opts.head,
|
|
1929
|
+
base: opts.base
|
|
1930
|
+
});
|
|
1931
|
+
success(data, "github", "list-prs", start);
|
|
1932
|
+
} catch (err) {
|
|
1933
|
+
fail(err, "github", "list-prs", start);
|
|
1934
|
+
}
|
|
1935
|
+
});
|
|
1936
|
+
gh.command("get-pr").description("Get a pull request by number").requiredOption("--number <n>", "Pull request number").action(async (opts) => {
|
|
1937
|
+
const start = Date.now();
|
|
1938
|
+
try {
|
|
1939
|
+
const { client, owner, repo } = getClient3(gh);
|
|
1940
|
+
const data = await client.getPR(owner, repo, parseInt(opts.number, 10));
|
|
1941
|
+
success(data, "github", "get-pr", start);
|
|
1942
|
+
} catch (err) {
|
|
1943
|
+
fail(err, "github", "get-pr", start);
|
|
1944
|
+
}
|
|
1945
|
+
});
|
|
1946
|
+
gh.command("create-pr").description("Create a pull request").requiredOption("--title <title>", "PR title").requiredOption("--head <branch>", "Source branch (or user:branch for forks)").option("--base <branch>", "Target branch (defaults to config or main)").option("--body <body>", "PR description").option("--draft", "Create as draft PR").option("--owner <owner>", "GitHub owner (overrides parent --owner)").option("--repo <repo>", "GitHub repository name (overrides parent --repo)").action(async (opts) => {
|
|
1947
|
+
const start = Date.now();
|
|
1948
|
+
try {
|
|
1949
|
+
const { client, owner, repo, config } = getClient3(gh, { owner: opts.owner, repo: opts.repo });
|
|
1950
|
+
const base = opts.base ?? config.defaults.github?.targetBranch ?? "main";
|
|
1951
|
+
const data = await client.createPR({
|
|
1952
|
+
owner,
|
|
1953
|
+
repo,
|
|
1954
|
+
title: opts.title,
|
|
1955
|
+
head: opts.head,
|
|
1956
|
+
base,
|
|
1957
|
+
body: opts.body,
|
|
1958
|
+
draft: opts.draft
|
|
1959
|
+
});
|
|
1960
|
+
success(data, "github", "create-pr", start);
|
|
1961
|
+
} catch (err) {
|
|
1962
|
+
fail(err, "github", "create-pr", start);
|
|
1963
|
+
}
|
|
1964
|
+
});
|
|
1965
|
+
gh.command("update-pr").description("Update a pull request").requiredOption("--number <n>", "Pull request number").option("--title <title>", "New title").option("--body <body>", "New description").option("--base <branch>", "New base branch").action(async (opts) => {
|
|
1966
|
+
const start = Date.now();
|
|
1967
|
+
try {
|
|
1968
|
+
const { client, owner, repo } = getClient3(gh);
|
|
1969
|
+
const data = await client.updatePR({
|
|
1970
|
+
owner,
|
|
1971
|
+
repo,
|
|
1972
|
+
pullNumber: parseInt(opts.number, 10),
|
|
1973
|
+
title: opts.title,
|
|
1974
|
+
body: opts.body,
|
|
1975
|
+
base: opts.base
|
|
1976
|
+
});
|
|
1977
|
+
success(data, "github", "update-pr", start);
|
|
1978
|
+
} catch (err) {
|
|
1979
|
+
fail(err, "github", "update-pr", start);
|
|
1980
|
+
}
|
|
1981
|
+
});
|
|
1982
|
+
gh.command("merge-pr").description("Merge a pull request").requiredOption("--number <n>", "Pull request number").addOption(new Option("--method <method>", "Merge method").choices(["merge", "squash", "rebase"]).default("merge")).option("--commit-title <title>", "Commit title for merge/squash").option("--commit-message <msg>", "Commit message for merge/squash").action(async (opts) => {
|
|
1983
|
+
const start = Date.now();
|
|
1984
|
+
try {
|
|
1985
|
+
const { client, owner, repo } = getClient3(gh);
|
|
1986
|
+
const data = await client.mergePR({
|
|
1987
|
+
owner,
|
|
1988
|
+
repo,
|
|
1989
|
+
pullNumber: parseInt(opts.number, 10),
|
|
1990
|
+
mergeMethod: opts.method,
|
|
1991
|
+
commitTitle: opts.commitTitle,
|
|
1992
|
+
commitMessage: opts.commitMessage
|
|
1993
|
+
});
|
|
1994
|
+
success(data, "github", "merge-pr", start);
|
|
1995
|
+
} catch (err) {
|
|
1996
|
+
fail(err, "github", "merge-pr", start);
|
|
1997
|
+
}
|
|
1998
|
+
});
|
|
1999
|
+
gh.command("close-pr").description("Close a pull request").requiredOption("--number <n>", "Pull request number").action(async (opts) => {
|
|
2000
|
+
const start = Date.now();
|
|
2001
|
+
try {
|
|
2002
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2003
|
+
const data = await client.closePR(owner, repo, parseInt(opts.number, 10));
|
|
2004
|
+
success(data, "github", "close-pr", start);
|
|
2005
|
+
} catch (err) {
|
|
2006
|
+
fail(err, "github", "close-pr", start);
|
|
2007
|
+
}
|
|
2008
|
+
});
|
|
2009
|
+
gh.command("list-comments").description("List general comments on a pull request").requiredOption("--number <n>", "Pull request number").action(async (opts) => {
|
|
2010
|
+
const start = Date.now();
|
|
2011
|
+
try {
|
|
2012
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2013
|
+
const data = await client.listComments(owner, repo, parseInt(opts.number, 10));
|
|
2014
|
+
success(data, "github", "list-comments", start);
|
|
2015
|
+
} catch (err) {
|
|
2016
|
+
fail(err, "github", "list-comments", start);
|
|
2017
|
+
}
|
|
2018
|
+
});
|
|
2019
|
+
gh.command("add-comment").description("Add a general comment to a pull request").requiredOption("--number <n>", "Pull request number").requiredOption("--body <text>", "Comment text").action(async (opts) => {
|
|
2020
|
+
const start = Date.now();
|
|
2021
|
+
try {
|
|
2022
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2023
|
+
const data = await client.addComment(owner, repo, parseInt(opts.number, 10), opts.body);
|
|
2024
|
+
success(data, "github", "add-comment", start);
|
|
2025
|
+
} catch (err) {
|
|
2026
|
+
fail(err, "github", "add-comment", start);
|
|
2027
|
+
}
|
|
2028
|
+
});
|
|
2029
|
+
gh.command("list-review-comments").description("List inline review comments on a pull request").requiredOption("--number <n>", "Pull request number").action(async (opts) => {
|
|
2030
|
+
const start = Date.now();
|
|
2031
|
+
try {
|
|
2032
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2033
|
+
const data = await client.listReviewComments(owner, repo, parseInt(opts.number, 10));
|
|
2034
|
+
success(data, "github", "list-review-comments", start);
|
|
2035
|
+
} catch (err) {
|
|
2036
|
+
fail(err, "github", "list-review-comments", start);
|
|
2037
|
+
}
|
|
2038
|
+
});
|
|
2039
|
+
gh.command("add-inline-comment").description("Add an inline review comment to a file in a pull request").requiredOption("--number <n>", "Pull request number").requiredOption("--commit <sha>", "Commit SHA the comment is on").requiredOption("--file <path>", "File path").requiredOption("--line <n>", "Line number").requiredOption("--body <text>", "Comment text").addOption(new Option("--side <side>", "Comment side").choices(["LEFT", "RIGHT"]).default("RIGHT")).action(async (opts) => {
|
|
2040
|
+
const start = Date.now();
|
|
2041
|
+
try {
|
|
2042
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2043
|
+
const data = await client.addInlineComment({
|
|
2044
|
+
owner,
|
|
2045
|
+
repo,
|
|
2046
|
+
pullNumber: parseInt(opts.number, 10),
|
|
2047
|
+
body: opts.body,
|
|
2048
|
+
commitId: opts.commit,
|
|
2049
|
+
path: opts.file,
|
|
2050
|
+
line: parseInt(opts.line, 10),
|
|
2051
|
+
side: opts.side
|
|
2052
|
+
});
|
|
2053
|
+
success(data, "github", "add-inline-comment", start);
|
|
2054
|
+
} catch (err) {
|
|
2055
|
+
fail(err, "github", "add-inline-comment", start);
|
|
2056
|
+
}
|
|
2057
|
+
});
|
|
2058
|
+
gh.command("reply-comment").description("Reply to a review comment on a pull request").requiredOption("--number <n>", "Pull request number").requiredOption("--comment-id <id>", "Review comment ID to reply to").requiredOption("--body <text>", "Reply text").action(async (opts) => {
|
|
2059
|
+
const start = Date.now();
|
|
2060
|
+
try {
|
|
2061
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2062
|
+
const data = await client.replyComment(owner, repo, parseInt(opts.number, 10), parseInt(opts.commentId, 10), opts.body);
|
|
2063
|
+
success(data, "github", "reply-comment", start);
|
|
2064
|
+
} catch (err) {
|
|
2065
|
+
fail(err, "github", "reply-comment", start);
|
|
2066
|
+
}
|
|
2067
|
+
});
|
|
2068
|
+
gh.command("delete-comment").description("Delete a general issue comment").requiredOption("--comment-id <id>", "Comment ID").action(async (opts) => {
|
|
2069
|
+
const start = Date.now();
|
|
2070
|
+
try {
|
|
2071
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2072
|
+
await client.deleteComment(owner, repo, parseInt(opts.commentId, 10));
|
|
2073
|
+
success({ deleted: true }, "github", "delete-comment", start);
|
|
2074
|
+
} catch (err) {
|
|
2075
|
+
fail(err, "github", "delete-comment", start);
|
|
2076
|
+
}
|
|
2077
|
+
});
|
|
2078
|
+
gh.command("delete-review-comment").description("Delete an inline review comment").requiredOption("--comment-id <id>", "Review comment ID").action(async (opts) => {
|
|
2079
|
+
const start = Date.now();
|
|
2080
|
+
try {
|
|
2081
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2082
|
+
await client.deleteReviewComment(owner, repo, parseInt(opts.commentId, 10));
|
|
2083
|
+
success({ deleted: true }, "github", "delete-review-comment", start);
|
|
2084
|
+
} catch (err) {
|
|
2085
|
+
fail(err, "github", "delete-review-comment", start);
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
2088
|
+
gh.command("diff").description("Get unified diff for a pull request").requiredOption("--number <n>", "Pull request number").action(async (opts) => {
|
|
2089
|
+
const start = Date.now();
|
|
2090
|
+
try {
|
|
2091
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2092
|
+
const diff = await client.getDiff(owner, repo, parseInt(opts.number, 10));
|
|
2093
|
+
success({ diff }, "github", "diff", start);
|
|
2094
|
+
} catch (err) {
|
|
2095
|
+
fail(err, "github", "diff", start);
|
|
2096
|
+
}
|
|
2097
|
+
});
|
|
2098
|
+
gh.command("list-files").description("List files changed in a pull request").requiredOption("--number <n>", "Pull request number").action(async (opts) => {
|
|
2099
|
+
const start = Date.now();
|
|
2100
|
+
try {
|
|
2101
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2102
|
+
const data = await client.listFiles(owner, repo, parseInt(opts.number, 10));
|
|
2103
|
+
success(data, "github", "list-files", start);
|
|
2104
|
+
} catch (err) {
|
|
2105
|
+
fail(err, "github", "list-files", start);
|
|
2106
|
+
}
|
|
2107
|
+
});
|
|
2108
|
+
gh.command("list-reviews").description("List reviews on a pull request").requiredOption("--number <n>", "Pull request number").action(async (opts) => {
|
|
2109
|
+
const start = Date.now();
|
|
2110
|
+
try {
|
|
2111
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2112
|
+
const data = await client.listReviews(owner, repo, parseInt(opts.number, 10));
|
|
2113
|
+
success(data, "github", "list-reviews", start);
|
|
2114
|
+
} catch (err) {
|
|
2115
|
+
fail(err, "github", "list-reviews", start);
|
|
2116
|
+
}
|
|
2117
|
+
});
|
|
2118
|
+
gh.command("approve").description("Approve a pull request").requiredOption("--number <n>", "Pull request number").option("--body <text>", "Review body text").action(async (opts) => {
|
|
2119
|
+
const start = Date.now();
|
|
2120
|
+
try {
|
|
2121
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2122
|
+
const data = await client.submitReview({
|
|
2123
|
+
owner,
|
|
2124
|
+
repo,
|
|
2125
|
+
pullNumber: parseInt(opts.number, 10),
|
|
2126
|
+
event: "APPROVE",
|
|
2127
|
+
body: opts.body
|
|
2128
|
+
});
|
|
2129
|
+
success(data, "github", "approve", start);
|
|
2130
|
+
} catch (err) {
|
|
2131
|
+
fail(err, "github", "approve", start);
|
|
2132
|
+
}
|
|
2133
|
+
});
|
|
2134
|
+
gh.command("request-changes").description("Request changes on a pull request").requiredOption("--number <n>", "Pull request number").requiredOption("--body <text>", "Review feedback text").action(async (opts) => {
|
|
2135
|
+
const start = Date.now();
|
|
2136
|
+
try {
|
|
2137
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2138
|
+
const data = await client.submitReview({
|
|
2139
|
+
owner,
|
|
2140
|
+
repo,
|
|
2141
|
+
pullNumber: parseInt(opts.number, 10),
|
|
2142
|
+
event: "REQUEST_CHANGES",
|
|
2143
|
+
body: opts.body
|
|
2144
|
+
});
|
|
2145
|
+
success(data, "github", "request-changes", start);
|
|
2146
|
+
} catch (err) {
|
|
2147
|
+
fail(err, "github", "request-changes", start);
|
|
2148
|
+
}
|
|
2149
|
+
});
|
|
2150
|
+
gh.command("list-reviewers").description("List requested reviewers for a pull request").requiredOption("--number <n>", "Pull request number").action(async (opts) => {
|
|
2151
|
+
const start = Date.now();
|
|
2152
|
+
try {
|
|
2153
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2154
|
+
const data = await client.listRequestedReviewers(owner, repo, parseInt(opts.number, 10));
|
|
2155
|
+
success(data, "github", "list-reviewers", start);
|
|
2156
|
+
} catch (err) {
|
|
2157
|
+
fail(err, "github", "list-reviewers", start);
|
|
2158
|
+
}
|
|
2159
|
+
});
|
|
2160
|
+
gh.command("get-status").description("Get combined commit status for a ref (branch, tag, or SHA)").requiredOption("--ref <ref>", "Git ref (branch, tag, or commit SHA)").action(async (opts) => {
|
|
2161
|
+
const start = Date.now();
|
|
2162
|
+
try {
|
|
2163
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2164
|
+
const data = await client.getCommitStatuses(owner, repo, opts.ref);
|
|
2165
|
+
success(data, "github", "get-status", start);
|
|
2166
|
+
} catch (err) {
|
|
2167
|
+
fail(err, "github", "get-status", start);
|
|
2168
|
+
}
|
|
2169
|
+
});
|
|
2170
|
+
gh.command("list-checks").description("List check runs for a ref (branch, tag, or SHA)").requiredOption("--ref <ref>", "Git ref (branch, tag, or commit SHA)").action(async (opts) => {
|
|
2171
|
+
const start = Date.now();
|
|
2172
|
+
try {
|
|
2173
|
+
const { client, owner, repo } = getClient3(gh);
|
|
2174
|
+
const data = await client.listCheckRuns(owner, repo, opts.ref);
|
|
2175
|
+
success(data, "github", "list-checks", start);
|
|
2176
|
+
} catch (err) {
|
|
2177
|
+
fail(err, "github", "list-checks", start);
|
|
2178
|
+
}
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
|
|
1678
2182
|
// src/services/confluence/client.ts
|
|
1679
2183
|
var API3 = "/rest/api";
|
|
1680
2184
|
var ConfluenceClient = class {
|
|
@@ -1823,7 +2327,7 @@ var ConfluenceClient = class {
|
|
|
1823
2327
|
};
|
|
1824
2328
|
|
|
1825
2329
|
// src/services/confluence/commands.ts
|
|
1826
|
-
function
|
|
2330
|
+
function getClient4(program2) {
|
|
1827
2331
|
const opts = program2.optsWithGlobals();
|
|
1828
2332
|
const config = loadConfig({ configPath: opts.config });
|
|
1829
2333
|
if (!config.confluence.baseUrl) throw new PncliError("Confluence not configured. Run: pncli config init");
|
|
@@ -1835,7 +2339,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1835
2339
|
confluence.command("get-page").description("Get a Confluence page by ID").requiredOption("--id <page-id>", "Page ID").option("--expand <fields>", "Comma-separated fields to expand", "body.storage,version,space,ancestors").action(async (opts) => {
|
|
1836
2340
|
const start = Date.now();
|
|
1837
2341
|
try {
|
|
1838
|
-
const client =
|
|
2342
|
+
const client = getClient4(program2);
|
|
1839
2343
|
const data = await client.getPage(opts.id, opts.expand);
|
|
1840
2344
|
success(data, "confluence", "get-page", start);
|
|
1841
2345
|
} catch (err) {
|
|
@@ -1845,7 +2349,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1845
2349
|
confluence.command("get-page-by-title").description("Find a Confluence page by space key and title").requiredOption("--space <key>", "Space key").requiredOption("--title <title>", "Page title").action(async (opts) => {
|
|
1846
2350
|
const start = Date.now();
|
|
1847
2351
|
try {
|
|
1848
|
-
const client =
|
|
2352
|
+
const client = getClient4(program2);
|
|
1849
2353
|
const data = await client.getPageByTitle(opts.space, opts.title);
|
|
1850
2354
|
if (!data) throw new PncliError(`Page not found: "${opts.title}" in space ${opts.space}`, 1);
|
|
1851
2355
|
success(data, "confluence", "get-page-by-title", start);
|
|
@@ -1856,7 +2360,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1856
2360
|
confluence.command("list-pages").description("List pages in a Confluence space (consider --output-file for large results)").requiredOption("--space <key>", "Space key").option("--limit <n>", "Max total pages to return (default: all)").option("--start <n>", "Offset for first result").action(async (opts) => {
|
|
1857
2361
|
const start = Date.now();
|
|
1858
2362
|
try {
|
|
1859
|
-
const client =
|
|
2363
|
+
const client = getClient4(program2);
|
|
1860
2364
|
const data = await client.listPages(opts.space, {
|
|
1861
2365
|
limit: opts.limit ? parseInt(opts.limit, 10) : void 0,
|
|
1862
2366
|
start: opts.start ? parseInt(opts.start, 10) : void 0
|
|
@@ -1869,7 +2373,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1869
2373
|
confluence.command("get-page-children").description("Get child pages of a Confluence page").requiredOption("--id <page-id>", "Parent page ID").action(async (opts) => {
|
|
1870
2374
|
const start = Date.now();
|
|
1871
2375
|
try {
|
|
1872
|
-
const client =
|
|
2376
|
+
const client = getClient4(program2);
|
|
1873
2377
|
const data = await client.getPageChildren(opts.id);
|
|
1874
2378
|
success(data, "confluence", "get-page-children", start);
|
|
1875
2379
|
} catch (err) {
|
|
@@ -1879,7 +2383,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1879
2383
|
confluence.command("get-labels").description("Get labels on a Confluence page").requiredOption("--id <page-id>", "Page ID").action(async (opts) => {
|
|
1880
2384
|
const start = Date.now();
|
|
1881
2385
|
try {
|
|
1882
|
-
const client =
|
|
2386
|
+
const client = getClient4(program2);
|
|
1883
2387
|
const data = await client.getLabels(opts.id);
|
|
1884
2388
|
success(data, "confluence", "get-labels", start);
|
|
1885
2389
|
} catch (err) {
|
|
@@ -1889,7 +2393,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1889
2393
|
confluence.command("search").description("Search Confluence with CQL").requiredOption("--cql <query>", 'CQL query string (e.g. "space=PROJ AND type=page")').option("--limit <n>", "Maximum number of results", "25").option("--start <n>", "Offset for first result", "0").option("--expand <fields>", "Comma-separated fields to expand").action(async (opts) => {
|
|
1890
2394
|
const start = Date.now();
|
|
1891
2395
|
try {
|
|
1892
|
-
const client =
|
|
2396
|
+
const client = getClient4(program2);
|
|
1893
2397
|
const data = await client.search(opts.cql, {
|
|
1894
2398
|
limit: parseInt(opts.limit, 10),
|
|
1895
2399
|
start: parseInt(opts.start, 10),
|
|
@@ -1903,7 +2407,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1903
2407
|
confluence.command("create-page").description("Create a new Confluence page").requiredOption("--space <key>", "Space key").requiredOption("--title <title>", "Page title").requiredOption("--body <html>", "Page body (storage format HTML)").option("--parent-id <id>", "Parent page ID (to nest under a page)").option("--representation <format>", "Body format: storage (default) or wiki", "storage").action(async (opts) => {
|
|
1904
2408
|
const start = Date.now();
|
|
1905
2409
|
try {
|
|
1906
|
-
const client =
|
|
2410
|
+
const client = getClient4(program2);
|
|
1907
2411
|
const data = await client.createPage({
|
|
1908
2412
|
spaceKey: opts.space,
|
|
1909
2413
|
title: opts.title,
|
|
@@ -1919,7 +2423,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1919
2423
|
confluence.command("update-page").description("Update a Confluence page (fetches current version automatically)").requiredOption("--id <page-id>", "Page ID").option("--title <title>", "New page title").option("--body <html>", "New page body (storage format HTML)").option("--status <status>", "Page status: current (default) or draft", "current").option("--representation <format>", "Body format: storage (default) or wiki", "storage").action(async (opts) => {
|
|
1920
2424
|
const start = Date.now();
|
|
1921
2425
|
try {
|
|
1922
|
-
const client =
|
|
2426
|
+
const client = getClient4(program2);
|
|
1923
2427
|
const current = await client.getPage(opts.id, "version");
|
|
1924
2428
|
const nextVersion = current.version.number + 1;
|
|
1925
2429
|
const data = await client.updatePage(opts.id, {
|
|
@@ -1937,7 +2441,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1937
2441
|
confluence.command("delete-page").description("Delete a Confluence page").requiredOption("--id <page-id>", "Page ID").action(async (opts) => {
|
|
1938
2442
|
const start = Date.now();
|
|
1939
2443
|
try {
|
|
1940
|
-
const client =
|
|
2444
|
+
const client = getClient4(program2);
|
|
1941
2445
|
await client.deletePage(opts.id);
|
|
1942
2446
|
success({ deleted: opts.id }, "confluence", "delete-page", start);
|
|
1943
2447
|
} catch (err) {
|
|
@@ -1947,7 +2451,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1947
2451
|
confluence.command("list-comments").description("List comments on a Confluence page").requiredOption("--id <page-id>", "Page ID").action(async (opts) => {
|
|
1948
2452
|
const start = Date.now();
|
|
1949
2453
|
try {
|
|
1950
|
-
const client =
|
|
2454
|
+
const client = getClient4(program2);
|
|
1951
2455
|
const data = await client.listComments(opts.id);
|
|
1952
2456
|
success(data, "confluence", "list-comments", start);
|
|
1953
2457
|
} catch (err) {
|
|
@@ -1957,7 +2461,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1957
2461
|
confluence.command("add-comment").description("Add a comment to a Confluence page").requiredOption("--id <page-id>", "Page ID").requiredOption("--body <text>", "Comment body (storage format HTML)").option("--representation <format>", "Body format: storage (default) or wiki", "storage").action(async (opts) => {
|
|
1958
2462
|
const start = Date.now();
|
|
1959
2463
|
try {
|
|
1960
|
-
const client =
|
|
2464
|
+
const client = getClient4(program2);
|
|
1961
2465
|
const data = await client.addComment(opts.id, opts.body, opts.representation);
|
|
1962
2466
|
success(data, "confluence", "add-comment", start);
|
|
1963
2467
|
} catch (err) {
|
|
@@ -1967,7 +2471,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1967
2471
|
confluence.command("add-label").description("Add labels to a Confluence page").requiredOption("--id <page-id>", "Page ID").requiredOption("--labels <names>", "Comma-separated label names").action(async (opts) => {
|
|
1968
2472
|
const start = Date.now();
|
|
1969
2473
|
try {
|
|
1970
|
-
const client =
|
|
2474
|
+
const client = getClient4(program2);
|
|
1971
2475
|
const labels = opts.labels.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1972
2476
|
const data = await client.addLabel(opts.id, labels);
|
|
1973
2477
|
success(data, "confluence", "add-label", start);
|
|
@@ -1978,7 +2482,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1978
2482
|
confluence.command("remove-label").description("Remove a label from a Confluence page").requiredOption("--id <page-id>", "Page ID").requiredOption("--label <name>", "Label name to remove").action(async (opts) => {
|
|
1979
2483
|
const start = Date.now();
|
|
1980
2484
|
try {
|
|
1981
|
-
const client =
|
|
2485
|
+
const client = getClient4(program2);
|
|
1982
2486
|
await client.removeLabel(opts.id, opts.label);
|
|
1983
2487
|
success({ removed: opts.label, from: opts.id }, "confluence", "remove-label", start);
|
|
1984
2488
|
} catch (err) {
|
|
@@ -1988,7 +2492,7 @@ function registerConfluenceCommands(program2) {
|
|
|
1988
2492
|
confluence.command("list-spaces").description("List Confluence spaces").option("--type <type>", "Space type: global or personal").option("--limit <n>", "Max total spaces to return (default: all)").action(async (opts) => {
|
|
1989
2493
|
const start = Date.now();
|
|
1990
2494
|
try {
|
|
1991
|
-
const client =
|
|
2495
|
+
const client = getClient4(program2);
|
|
1992
2496
|
const data = await client.listSpaces({
|
|
1993
2497
|
type: opts.type,
|
|
1994
2498
|
limit: opts.limit ? parseInt(opts.limit, 10) : void 0
|
|
@@ -2001,7 +2505,7 @@ function registerConfluenceCommands(program2) {
|
|
|
2001
2505
|
confluence.command("get-space").description("Get a Confluence space by key").requiredOption("--key <space-key>", "Space key").action(async (opts) => {
|
|
2002
2506
|
const start = Date.now();
|
|
2003
2507
|
try {
|
|
2004
|
-
const client =
|
|
2508
|
+
const client = getClient4(program2);
|
|
2005
2509
|
const data = await client.getSpace(opts.key);
|
|
2006
2510
|
success(data, "confluence", "get-space", start);
|
|
2007
2511
|
} catch (err) {
|
|
@@ -2011,7 +2515,7 @@ function registerConfluenceCommands(program2) {
|
|
|
2011
2515
|
confluence.command("list-attachments").description("List attachments on a Confluence page").requiredOption("--id <page-id>", "Page ID").action(async (opts) => {
|
|
2012
2516
|
const start = Date.now();
|
|
2013
2517
|
try {
|
|
2014
|
-
const client =
|
|
2518
|
+
const client = getClient4(program2);
|
|
2015
2519
|
const data = await client.listAttachments(opts.id);
|
|
2016
2520
|
success(data, "confluence", "list-attachments", start);
|
|
2017
2521
|
} catch (err) {
|
|
@@ -2123,7 +2627,7 @@ var SonarClient = class {
|
|
|
2123
2627
|
|
|
2124
2628
|
// src/services/sonar/commands.ts
|
|
2125
2629
|
var DEFAULT_METRICS = "coverage,duplicated_lines_density,bugs,vulnerabilities,code_smells,sqale_rating,reliability_rating,security_rating,ncloc";
|
|
2126
|
-
function
|
|
2630
|
+
function getClient5(program2) {
|
|
2127
2631
|
const opts = program2.optsWithGlobals();
|
|
2128
2632
|
const config = loadConfig({ configPath: opts.config });
|
|
2129
2633
|
if (!config.sonar.baseUrl) throw new PncliError("SonarQube not configured. Run: pncli config init");
|
|
@@ -2140,7 +2644,7 @@ function registerSonarCommands(program2) {
|
|
|
2140
2644
|
sonar.command("quality-gate").description("Get quality gate status for a project").option("--project <key>", "SonarQube project key (or set defaults.sonar.project in config)").option("--branch <name>", "Branch name").action(async (opts) => {
|
|
2141
2645
|
const start = Date.now();
|
|
2142
2646
|
try {
|
|
2143
|
-
const { client, config } =
|
|
2647
|
+
const { client, config } = getClient5(program2);
|
|
2144
2648
|
const projectKey = resolveProject(config, opts.project);
|
|
2145
2649
|
const data = await client.getQualityGate(projectKey, opts.branch);
|
|
2146
2650
|
success(data, "sonar", "quality-gate", start);
|
|
@@ -2151,7 +2655,7 @@ function registerSonarCommands(program2) {
|
|
|
2151
2655
|
sonar.command("issues").description("Search/list issues for a project").option("--project <key>", "SonarQube project key (or set defaults.sonar.project in config)").option("--severities <list>", "Filter by severity: BLOCKER,CRITICAL,MAJOR,MINOR,INFO (comma-separated)").option("--types <list>", "Filter by type: BUG,VULNERABILITY,CODE_SMELL (comma-separated)").option("--statuses <list>", "Filter by status: OPEN,CONFIRMED,REOPENED,RESOLVED,CLOSED (comma-separated)").option("--branch <name>", "Branch name").option("--resolved <bool>", "Filter resolved issues: true or false").option("--page <n>", "Page number (1-based)", "1").option("--page-size <n>", "Results per page (max 500)", "100").option("--all", "Fetch all pages (consider --output-file for large results; ignores --page/--page-size)").action(async (opts) => {
|
|
2152
2656
|
const start = Date.now();
|
|
2153
2657
|
try {
|
|
2154
|
-
const { client, config } =
|
|
2658
|
+
const { client, config } = getClient5(program2);
|
|
2155
2659
|
const projectKey = resolveProject(config, opts.project);
|
|
2156
2660
|
const baseOpts = {
|
|
2157
2661
|
projectKey,
|
|
@@ -2179,7 +2683,7 @@ function registerSonarCommands(program2) {
|
|
|
2179
2683
|
sonar.command("measures").description("Get key metrics for a project").option("--project <key>", "SonarQube project key (or set defaults.sonar.project in config)").option("--metrics <list>", "Comma-separated metric keys", DEFAULT_METRICS).option("--branch <name>", "Branch name").action(async (opts) => {
|
|
2180
2684
|
const start = Date.now();
|
|
2181
2685
|
try {
|
|
2182
|
-
const { client, config } =
|
|
2686
|
+
const { client, config } = getClient5(program2);
|
|
2183
2687
|
const projectKey = resolveProject(config, opts.project);
|
|
2184
2688
|
const data = await client.getMeasures({
|
|
2185
2689
|
projectKey,
|
|
@@ -2194,7 +2698,7 @@ function registerSonarCommands(program2) {
|
|
|
2194
2698
|
sonar.command("projects").description("Search/list projects").option("--query <text>", "Search query").option("--page <n>", "Page number (1-based)", "1").option("--page-size <n>", "Results per page", "100").option("--all", "Fetch all pages (consider --output-file for large results)").action(async (opts) => {
|
|
2195
2699
|
const start = Date.now();
|
|
2196
2700
|
try {
|
|
2197
|
-
const { client } =
|
|
2701
|
+
const { client } = getClient5(program2);
|
|
2198
2702
|
if (opts.all) {
|
|
2199
2703
|
const data = await client.searchAllProjects(opts.query);
|
|
2200
2704
|
success(data, "sonar", "projects", start);
|
|
@@ -2213,7 +2717,7 @@ function registerSonarCommands(program2) {
|
|
|
2213
2717
|
sonar.command("hotspots").description("List security hotspots for a project").option("--project <key>", "SonarQube project key (or set defaults.sonar.project in config)").option("--status <status>", "Filter: TO_REVIEW or REVIEWED").option("--resolution <list>", "Filter: FIXED,SAFE,ACKNOWLEDGED (comma-separated)").option("--branch <name>", "Branch name").option("--page <n>", "Page number (1-based)", "1").option("--page-size <n>", "Results per page", "100").option("--all", "Fetch all pages (consider --output-file for large results)").action(async (opts) => {
|
|
2214
2718
|
const start = Date.now();
|
|
2215
2719
|
try {
|
|
2216
|
-
const { client, config } =
|
|
2720
|
+
const { client, config } = getClient5(program2);
|
|
2217
2721
|
const projectKey = resolveProject(config, opts.project);
|
|
2218
2722
|
const baseOpts = {
|
|
2219
2723
|
projectKey,
|
|
@@ -2369,7 +2873,7 @@ var SdeClient = class {
|
|
|
2369
2873
|
};
|
|
2370
2874
|
|
|
2371
2875
|
// src/services/sde/commands.ts
|
|
2372
|
-
function
|
|
2876
|
+
function getClient6(program2) {
|
|
2373
2877
|
const opts = program2.optsWithGlobals();
|
|
2374
2878
|
const config = loadConfig({ configPath: opts.config });
|
|
2375
2879
|
if (!config.sde.baseUrl) throw new PncliError("SDElements not configured. Run: pncli config init");
|
|
@@ -2401,7 +2905,7 @@ function registerSdeCommands(program2) {
|
|
|
2401
2905
|
sde.command("server-info").description("Get server version and platform info (requires super-user)").action(async () => {
|
|
2402
2906
|
const start = Date.now();
|
|
2403
2907
|
try {
|
|
2404
|
-
const { client } =
|
|
2908
|
+
const { client } = getClient6(program2);
|
|
2405
2909
|
const data = await client.getServerInfo();
|
|
2406
2910
|
success(data, "sde", "server-info", start);
|
|
2407
2911
|
} catch (err) {
|
|
@@ -2411,7 +2915,7 @@ function registerSdeCommands(program2) {
|
|
|
2411
2915
|
sde.command("whoami").description("Get current authenticated user").action(async () => {
|
|
2412
2916
|
const start = Date.now();
|
|
2413
2917
|
try {
|
|
2414
|
-
const { client } =
|
|
2918
|
+
const { client } = getClient6(program2);
|
|
2415
2919
|
const data = await client.getMe();
|
|
2416
2920
|
success(data, "sde", "whoami", start);
|
|
2417
2921
|
} catch (err) {
|
|
@@ -2421,7 +2925,7 @@ function registerSdeCommands(program2) {
|
|
|
2421
2925
|
sde.command("users").description("List users").option("--email <email>", "Filter by email address").option("--first-name <name>", "Filter by first name").option("--last-name <name>", "Filter by last name").option("--active <bool>", "Filter by active status: true or false").option("--page <n>", "Page number (1-based)", "1").option("--page-size <n>", "Results per page", "100").option("--all", "Fetch all pages (consider --output-file for large results)").action(async (opts) => {
|
|
2422
2926
|
const start = Date.now();
|
|
2423
2927
|
try {
|
|
2424
|
-
const { client } =
|
|
2928
|
+
const { client } = getClient6(program2);
|
|
2425
2929
|
const baseOpts = {
|
|
2426
2930
|
email: opts.email,
|
|
2427
2931
|
firstName: opts.firstName,
|
|
@@ -2446,7 +2950,7 @@ function registerSdeCommands(program2) {
|
|
|
2446
2950
|
sde.command("projects").description("List projects").option("--name <name>", "Filter by project name").option("--search <text>", "Text search on name and profile").option("--active <val>", "Filter by active status: true, false, or all").option("--ordering <field>", "Sort by: name, created, updated (prefix with - for descending)").option("--expand <fields>", "Expand nested fields (comma-separated): application,business_unit,creator").option("--include <fields>", "Include extra fields (comma-separated): task_counts,permissions").option("--page <n>", "Page number (1-based)", "1").option("--page-size <n>", "Results per page", "100").option("--all", "Fetch all pages (consider --output-file for large results)").action(async (opts) => {
|
|
2447
2951
|
const start = Date.now();
|
|
2448
2952
|
try {
|
|
2449
|
-
const { client } =
|
|
2953
|
+
const { client } = getClient6(program2);
|
|
2450
2954
|
const baseOpts = {
|
|
2451
2955
|
name: opts.name,
|
|
2452
2956
|
search: opts.search,
|
|
@@ -2473,7 +2977,7 @@ function registerSdeCommands(program2) {
|
|
|
2473
2977
|
sde.command("project").description("Get a single project by ID").option("--id <id>", "Project ID (or set defaults.sde.project in config)").option("--expand <fields>", "Expand nested fields (comma-separated): application,business_unit,creator").option("--include <fields>", "Include extra fields (comma-separated): task_counts,permissions").action(async (opts) => {
|
|
2474
2978
|
const start = Date.now();
|
|
2475
2979
|
try {
|
|
2476
|
-
const { client, config } =
|
|
2980
|
+
const { client, config } = getClient6(program2);
|
|
2477
2981
|
const projectId = resolveProject2(config, opts.id);
|
|
2478
2982
|
const data = await client.getProject(projectId, opts.expand, opts.include);
|
|
2479
2983
|
success(data, "sde", "project", start);
|
|
@@ -2484,7 +2988,7 @@ function registerSdeCommands(program2) {
|
|
|
2484
2988
|
sde.command("tasks").description("List countermeasures for a project").option("--project <id>", "Project ID (or set defaults.sde.project in config)").option("--phase <slug>", "Filter by phase slug (e.g. development, architecture-design)").option("--priority <n>", "Filter by priority (1-10)").option("--status <id>", "Filter by status ID (e.g. TS1, TS2)").option("--assigned-to <email>", "Filter by assignee email").option("--source <val>", "Filter by source: default, custom, manual, project").option("--verification <val>", "Filter by verification: pass, fail, partial, none").option("--tag <name>", "Filter by tag name").option("--accepted <bool>", "Filter by accepted status: true or false").option("--relevant <bool>", "Filter by relevant status: true or false").option("--expand <fields>", "Expand nested fields (comma-separated): status,phase,problem,text").option("--include <fields>", "Include extra fields (comma-separated): how_tos,last_note,references,regulation_sections").option("--page <n>", "Page number (1-based)", "1").option("--page-size <n>", "Results per page", "100").option("--all", "Fetch all pages (consider --output-file for large results)").action(async (opts) => {
|
|
2485
2989
|
const start = Date.now();
|
|
2486
2990
|
try {
|
|
2487
|
-
const { client, config } =
|
|
2991
|
+
const { client, config } = getClient6(program2);
|
|
2488
2992
|
const projectId = resolveProject2(config, opts.project);
|
|
2489
2993
|
const baseOpts = {
|
|
2490
2994
|
projectId,
|
|
@@ -2518,7 +3022,7 @@ function registerSdeCommands(program2) {
|
|
|
2518
3022
|
sde.command("task").description("Get a single countermeasure").option("--project <id>", "Project ID (or set defaults.sde.project in config)").requiredOption("--task <id>", "Task ID (e.g. T21)").option("--expand <fields>", "Expand nested fields (comma-separated): status,phase,problem,text").option("--include <fields>", "Include extra fields (comma-separated): how_tos,last_note,references").action(async (opts) => {
|
|
2519
3023
|
const start = Date.now();
|
|
2520
3024
|
try {
|
|
2521
|
-
const { client, config } =
|
|
3025
|
+
const { client, config } = getClient6(program2);
|
|
2522
3026
|
const projectId = resolveProject2(config, opts.project);
|
|
2523
3027
|
const data = await client.getTask(projectId, opts.task, opts.expand, opts.include);
|
|
2524
3028
|
success(data, "sde", "task", start);
|
|
@@ -2529,7 +3033,7 @@ function registerSdeCommands(program2) {
|
|
|
2529
3033
|
sde.command("threats").description("List threats for a project").option("--project <id>", "Project ID (or set defaults.sde.project in config)").option("--severity <n>", "Filter by severity (1-10)").option("--search <text>", "Full-text search on title and threat ID").option("--ordering <field>", "Sort by: threat__severity, threat_id, status (prefix - for descending)").option("--capec-id <id>", "Filter by CAPEC attack pattern ID").option("--component-id <id>", "Filter by component ID").option("--page <n>", "Page number (1-based)", "1").option("--page-size <n>", "Results per page", "100").option("--all", "Fetch all pages (consider --output-file for large results)").action(async (opts) => {
|
|
2530
3034
|
const start = Date.now();
|
|
2531
3035
|
try {
|
|
2532
|
-
const { client, config } =
|
|
3036
|
+
const { client, config } = getClient6(program2);
|
|
2533
3037
|
const projectId = resolveProject2(config, opts.project);
|
|
2534
3038
|
const baseOpts = {
|
|
2535
3039
|
projectId,
|
|
@@ -2557,7 +3061,7 @@ function registerSdeCommands(program2) {
|
|
|
2557
3061
|
}
|
|
2558
3062
|
|
|
2559
3063
|
// src/services/deps/commands.ts
|
|
2560
|
-
import { Option } from "commander";
|
|
3064
|
+
import { Option as Option2 } from "commander";
|
|
2561
3065
|
|
|
2562
3066
|
// src/services/deps/parsers/index.ts
|
|
2563
3067
|
import fs from "fs";
|
|
@@ -4241,7 +4745,7 @@ async function runLicenseCheck(config, opts) {
|
|
|
4241
4745
|
// src/services/deps/commands.ts
|
|
4242
4746
|
function registerDepsCommands(program2) {
|
|
4243
4747
|
const deps = program2.command("deps").description("Dependency scanning, CVE detection, and license auditing");
|
|
4244
|
-
deps.command("frisk").description("Scan all dependencies for CVEs and output remediation paths (requires OSV.dev, Sonatype OSS Index, or Sonatype IQ Server)").option("--ecosystem <ecosystem>", "Filter to one ecosystem: npm, nuget, maven, all", "all").option("--direct-only", "Only scan direct dependencies (default: include transitive)", false).option("--include-dev", "Include dev/test dependencies", false).addOption(new
|
|
4748
|
+
deps.command("frisk").description("Scan all dependencies for CVEs and output remediation paths (requires OSV.dev, Sonatype OSS Index, or Sonatype IQ Server)").option("--ecosystem <ecosystem>", "Filter to one ecosystem: npm, nuget, maven, all", "all").option("--direct-only", "Only scan direct dependencies (default: include transitive)", false).option("--include-dev", "Include dev/test dependencies", false).addOption(new Option2("--source <source>", "Vulnerability source").choices(["osv", "sonatype", "sonatypeiq", "all"]).default("osv")).option("--application-id <id>", "Sonatype IQ Server application ID (required when --source sonatypeiq)").action(async (opts, cmd) => {
|
|
4245
4749
|
const startTime = Date.now();
|
|
4246
4750
|
try {
|
|
4247
4751
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -4600,6 +5104,16 @@ function registerConfigCommands(program2) {
|
|
|
4600
5104
|
} else {
|
|
4601
5105
|
results.bitbucket = { ok: null, message: "not configured" };
|
|
4602
5106
|
}
|
|
5107
|
+
if (cfg.github.baseUrl) {
|
|
5108
|
+
try {
|
|
5109
|
+
await http.github("/user");
|
|
5110
|
+
results.github = { ok: true, message: "connected" };
|
|
5111
|
+
} catch (err) {
|
|
5112
|
+
results.github = { ok: false, message: err instanceof Error ? err.message : String(err) };
|
|
5113
|
+
}
|
|
5114
|
+
} else {
|
|
5115
|
+
results.github = { ok: null, message: "not configured" };
|
|
5116
|
+
}
|
|
4603
5117
|
if (cfg.confluence.baseUrl) {
|
|
4604
5118
|
try {
|
|
4605
5119
|
await http.confluence("/rest/api/space", { params: { limit: 1 } });
|
|
@@ -4770,6 +5284,18 @@ function registerConfigCommands(program2) {
|
|
|
4770
5284
|
results.bitbucket = categorize2(err);
|
|
4771
5285
|
}
|
|
4772
5286
|
}
|
|
5287
|
+
if (!cfg.github.token) {
|
|
5288
|
+
results.github = { status: "blank", message: "not configured" };
|
|
5289
|
+
} else if (!cfg.github.baseUrl) {
|
|
5290
|
+
results.github = { status: "error", message: "baseUrl not configured" };
|
|
5291
|
+
} else {
|
|
5292
|
+
try {
|
|
5293
|
+
await http.github("/user", { timeoutMs: 1e4 });
|
|
5294
|
+
results.github = { status: "valid", message: "ok" };
|
|
5295
|
+
} catch (err) {
|
|
5296
|
+
results.github = categorize2(err);
|
|
5297
|
+
}
|
|
5298
|
+
}
|
|
4773
5299
|
if (!cfg.confluence.apiTokenExplicit && !cfg.jira.apiToken) {
|
|
4774
5300
|
results.confluence = { status: "blank", message: "not configured" };
|
|
4775
5301
|
} else if (!cfg.confluence.apiToken) {
|
|
@@ -4922,7 +5448,7 @@ function registerConfigCommands(program2) {
|
|
|
4922
5448
|
if (statuses.includes("invalid")) process.exitCode = ExitCode.AUTH_ERROR;
|
|
4923
5449
|
else if (statuses.includes("error")) process.exitCode = ExitCode.NETWORK_ERROR;
|
|
4924
5450
|
if (cmdOpts.output === "table") {
|
|
4925
|
-
const services = ["jira", "bitbucket", "confluence", "sonar", "sde", "ado", "jenkins", "udeploy", "artifactory", "checkmarx", "servicenow", "contrast", "sonatypeiq", "openshift"];
|
|
5451
|
+
const services = ["jira", "bitbucket", "github", "confluence", "sonar", "sde", "ado", "jenkins", "udeploy", "artifactory", "checkmarx", "servicenow", "contrast", "sonatypeiq", "openshift"];
|
|
4926
5452
|
const labelWidth = 14;
|
|
4927
5453
|
const statusWidth = 9;
|
|
4928
5454
|
for (const svc of services) {
|
|
@@ -4936,7 +5462,7 @@ function registerConfigCommands(program2) {
|
|
|
4936
5462
|
process.stdout.write("\n");
|
|
4937
5463
|
} else {
|
|
4938
5464
|
if (opts.pretty) {
|
|
4939
|
-
const services = ["jira", "bitbucket", "confluence", "sonar", "sde", "ado", "jenkins", "udeploy", "artifactory", "checkmarx", "servicenow", "contrast", "sonatypeiq", "openshift"];
|
|
5465
|
+
const services = ["jira", "bitbucket", "github", "confluence", "sonar", "sde", "ado", "jenkins", "udeploy", "artifactory", "checkmarx", "servicenow", "contrast", "sonatypeiq", "openshift"];
|
|
4940
5466
|
const labelWidth = 14;
|
|
4941
5467
|
const statusWidth = 9;
|
|
4942
5468
|
for (const svc of services) {
|
|
@@ -4988,6 +5514,40 @@ async function initGlobalConfig(start) {
|
|
|
4988
5514
|
const bitbucketPat = await password({
|
|
4989
5515
|
message: "Bitbucket personal access token:"
|
|
4990
5516
|
});
|
|
5517
|
+
process.stderr.write("\n\u2500\u2500 GitHub \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
|
|
5518
|
+
const useGitHub = await confirm({
|
|
5519
|
+
message: "Configure GitHub for PR operations?",
|
|
5520
|
+
default: false
|
|
5521
|
+
});
|
|
5522
|
+
let githubBaseUrl = "";
|
|
5523
|
+
let githubToken = "";
|
|
5524
|
+
if (useGitHub) {
|
|
5525
|
+
githubBaseUrl = await input({
|
|
5526
|
+
message: "GitHub API base URL\n GitHub.com: api.github.com\n GitHub Enterprise: <host>/api/v3\n URL: ",
|
|
5527
|
+
default: ""
|
|
5528
|
+
});
|
|
5529
|
+
githubToken = await password({
|
|
5530
|
+
message: "GitHub personal access token (classic or fine-grained):"
|
|
5531
|
+
});
|
|
5532
|
+
if (githubBaseUrl && githubToken) {
|
|
5533
|
+
process.stderr.write("\n Verifying connection...\n");
|
|
5534
|
+
try {
|
|
5535
|
+
const tempConfig = {
|
|
5536
|
+
...loadConfig(),
|
|
5537
|
+
github: {
|
|
5538
|
+
baseUrl: normalizeBaseUrl(githubBaseUrl),
|
|
5539
|
+
token: githubToken
|
|
5540
|
+
}
|
|
5541
|
+
};
|
|
5542
|
+
const tempHttp = createHttpClient(tempConfig);
|
|
5543
|
+
await tempHttp.github("/user");
|
|
5544
|
+
process.stderr.write(" Connected.\n");
|
|
5545
|
+
} catch (err) {
|
|
5546
|
+
warn(`Could not connect to GitHub: ${err instanceof Error ? err.message : String(err)}`);
|
|
5547
|
+
warn("Config will be saved anyway. Check your URL and token and re-run pncli config init or pncli config test.");
|
|
5548
|
+
}
|
|
5549
|
+
}
|
|
5550
|
+
}
|
|
4991
5551
|
process.stderr.write("\n\u2500\u2500 Confluence \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
|
|
4992
5552
|
const confluenceBaseUrl = await input({
|
|
4993
5553
|
message: "Confluence base URL (e.g. confluence.your-company.com):",
|
|
@@ -5495,6 +6055,12 @@ async function initGlobalConfig(start) {
|
|
|
5495
6055
|
baseUrl: normalizeBaseUrl(bitbucketBaseUrl) || void 0,
|
|
5496
6056
|
pat: bitbucketPat || void 0
|
|
5497
6057
|
},
|
|
6058
|
+
...useGitHub && githubBaseUrl ? {
|
|
6059
|
+
github: {
|
|
6060
|
+
baseUrl: normalizeBaseUrl(githubBaseUrl),
|
|
6061
|
+
token: githubToken || void 0
|
|
6062
|
+
}
|
|
6063
|
+
} : {},
|
|
5498
6064
|
...confluenceBaseUrl || confluenceApiToken ? {
|
|
5499
6065
|
confluence: {
|
|
5500
6066
|
baseUrl: normalizeBaseUrl(confluenceBaseUrl) || void 0,
|
|
@@ -6554,11 +7120,11 @@ function registerAdoRepoCommands(ado) {
|
|
|
6554
7120
|
const start = Date.now();
|
|
6555
7121
|
try {
|
|
6556
7122
|
const globalOpts = ado.optsWithGlobals();
|
|
6557
|
-
const { loadConfig: lc } = await import("./config-
|
|
7123
|
+
const { loadConfig: lc } = await import("./config-3QD5Y2O5.js");
|
|
6558
7124
|
const config = lc({ configPath: globalOpts.config });
|
|
6559
7125
|
const { collection, project, repo: repo2, gitClient } = getAdoContext(ado, true);
|
|
6560
7126
|
const { AdoCoreClient: AdoCoreClient2 } = await import("./core-SWYVXOQ4.js");
|
|
6561
|
-
const { createHttpClient: createHttpClient2 } = await import("./http-
|
|
7127
|
+
const { createHttpClient: createHttpClient2 } = await import("./http-5WRBWEM6.js");
|
|
6562
7128
|
const http = createHttpClient2(config, Boolean(globalOpts.dryRun));
|
|
6563
7129
|
const coreClient = new AdoCoreClient2(http);
|
|
6564
7130
|
const me = await coreClient.getConnectionData(collection);
|
|
@@ -6816,7 +7382,7 @@ var JenkinsClient = class {
|
|
|
6816
7382
|
};
|
|
6817
7383
|
|
|
6818
7384
|
// src/services/jenkins/commands.ts
|
|
6819
|
-
function
|
|
7385
|
+
function getClient7(program2) {
|
|
6820
7386
|
const opts = program2.optsWithGlobals();
|
|
6821
7387
|
const config = loadConfig({ configPath: opts.config });
|
|
6822
7388
|
if (!config.jenkins.baseUrl) throw new PncliError("Jenkins not configured. Run: pncli config init");
|
|
@@ -6850,7 +7416,7 @@ function registerJenkinsCommands(program2) {
|
|
|
6850
7416
|
pipeline.command("list").description("List all jobs on the Jenkins instance (or within a folder)").option("--folder <name>", "Folder name to enumerate (supports nested folders: parentFolder/childFolder)").action(async (opts) => {
|
|
6851
7417
|
const start = Date.now();
|
|
6852
7418
|
try {
|
|
6853
|
-
const client =
|
|
7419
|
+
const client = getClient7(program2);
|
|
6854
7420
|
const data = await client.listJobs(opts.folder);
|
|
6855
7421
|
success(data, "jenkins", "pipeline-list", start);
|
|
6856
7422
|
} catch (err) {
|
|
@@ -6860,7 +7426,7 @@ function registerJenkinsCommands(program2) {
|
|
|
6860
7426
|
pipeline.command("get").description("Get details for a specific job").requiredOption("--name <job>", "Job name (use folder/job for folder-scoped jobs)").action(async (opts) => {
|
|
6861
7427
|
const start = Date.now();
|
|
6862
7428
|
try {
|
|
6863
|
-
const client =
|
|
7429
|
+
const client = getClient7(program2);
|
|
6864
7430
|
const data = await client.getJob(opts.name);
|
|
6865
7431
|
success(data, "jenkins", "pipeline-get", start);
|
|
6866
7432
|
} catch (err) {
|
|
@@ -6873,7 +7439,7 @@ function registerJenkinsCommands(program2) {
|
|
|
6873
7439
|
}, []).option("--wait", "Wait for the build to complete before returning").option("--timeout <s>", "Max wait time in seconds per phase (queue-wait and build-wait each get this budget; default 600)", "600").option("--poll <s>", "Poll interval in seconds (default 10)", "10").action(async (opts) => {
|
|
6874
7440
|
const start = Date.now();
|
|
6875
7441
|
try {
|
|
6876
|
-
const client =
|
|
7442
|
+
const client = getClient7(program2);
|
|
6877
7443
|
for (const p of opts.parameter) {
|
|
6878
7444
|
if (!p.includes("=")) throw new PncliError(`Invalid --parameter "${p}". Expected format: key=value`, 1);
|
|
6879
7445
|
}
|
|
@@ -6906,7 +7472,7 @@ function registerJenkinsCommands(program2) {
|
|
|
6906
7472
|
pipeline.command("list-runs").description("List recent builds for a job").requiredOption("--name <job>", "Job name (use folder/job for folder-scoped jobs)").option("--top <n>", "Maximum number of builds to return (default 25)", "25").action(async (opts) => {
|
|
6907
7473
|
const start = Date.now();
|
|
6908
7474
|
try {
|
|
6909
|
-
const client =
|
|
7475
|
+
const client = getClient7(program2);
|
|
6910
7476
|
const top = parseInt(opts.top, 10);
|
|
6911
7477
|
if (isNaN(top) || top <= 0) throw new PncliError(`Invalid --top "${opts.top}". Expected a positive integer.`, 1);
|
|
6912
7478
|
const data = await client.listBuilds(opts.name, top);
|
|
@@ -6918,7 +7484,7 @@ function registerJenkinsCommands(program2) {
|
|
|
6918
7484
|
pipeline.command("get-run").description("Get details for a specific build").requiredOption("--name <job>", "Job name (use folder/job for folder-scoped jobs)").requiredOption("--number <n>", "Build number").action(async (opts) => {
|
|
6919
7485
|
const start = Date.now();
|
|
6920
7486
|
try {
|
|
6921
|
-
const client =
|
|
7487
|
+
const client = getClient7(program2);
|
|
6922
7488
|
const buildNumber = parseInt(opts.number, 10);
|
|
6923
7489
|
if (isNaN(buildNumber)) throw new PncliError(`Invalid --number "${opts.number}". Expected an integer.`, 1);
|
|
6924
7490
|
const data = await client.getBuild(opts.name, buildNumber);
|
|
@@ -6930,7 +7496,7 @@ function registerJenkinsCommands(program2) {
|
|
|
6930
7496
|
pipeline.command("logs").description("Fetch console log for a build (consider --output-file for large logs)").requiredOption("--name <job>", "Job name (use folder/job for folder-scoped jobs)").requiredOption("--number <n>", "Build number").action(async (opts) => {
|
|
6931
7497
|
const start = Date.now();
|
|
6932
7498
|
try {
|
|
6933
|
-
const client =
|
|
7499
|
+
const client = getClient7(program2);
|
|
6934
7500
|
const buildNumber = parseInt(opts.number, 10);
|
|
6935
7501
|
if (isNaN(buildNumber)) throw new PncliError(`Invalid --number "${opts.number}". Expected an integer.`, 1);
|
|
6936
7502
|
const text = await client.getConsoleLog(opts.name, buildNumber);
|
|
@@ -7022,7 +7588,7 @@ var ArtifactoryClient = class {
|
|
|
7022
7588
|
};
|
|
7023
7589
|
|
|
7024
7590
|
// src/services/artifactory/commands.ts
|
|
7025
|
-
function
|
|
7591
|
+
function getClient8(program2) {
|
|
7026
7592
|
const opts = program2.optsWithGlobals();
|
|
7027
7593
|
const config = loadConfig({ configPath: opts.config });
|
|
7028
7594
|
if (!config.artifactory.baseUrl) throw new PncliError("Artifactory not configured. Run: pncli config init");
|
|
@@ -7035,7 +7601,7 @@ function registerArtifactoryCommands(program2) {
|
|
|
7035
7601
|
art.command("ping").description("Check Artifactory connectivity and authentication").action(async () => {
|
|
7036
7602
|
const start = Date.now();
|
|
7037
7603
|
try {
|
|
7038
|
-
const client =
|
|
7604
|
+
const client = getClient8(program2);
|
|
7039
7605
|
const data = await client.ping();
|
|
7040
7606
|
success(data, "artifactory", "ping", start);
|
|
7041
7607
|
} catch (err) {
|
|
@@ -7045,7 +7611,7 @@ function registerArtifactoryCommands(program2) {
|
|
|
7045
7611
|
art.command("repos").description("List repositories").option("--type <type>", "Filter by type: local, virtual, remote, federated").option("--package-type <type>", "Filter by package type: npm, maven, nuget, docker, pypi, etc.").action(async (opts) => {
|
|
7046
7612
|
const start = Date.now();
|
|
7047
7613
|
try {
|
|
7048
|
-
const client =
|
|
7614
|
+
const client = getClient8(program2);
|
|
7049
7615
|
const data = await client.listRepos({ type: opts.type, packageType: opts.packageType });
|
|
7050
7616
|
success(data, "artifactory", "repos", start);
|
|
7051
7617
|
} catch (err) {
|
|
@@ -7055,7 +7621,7 @@ function registerArtifactoryCommands(program2) {
|
|
|
7055
7621
|
art.command("artifact-info <repo> <path>").description("Get metadata for an artifact or folder (checksums, size, timestamps)").action(async (repo, path8) => {
|
|
7056
7622
|
const start = Date.now();
|
|
7057
7623
|
try {
|
|
7058
|
-
const client =
|
|
7624
|
+
const client = getClient8(program2);
|
|
7059
7625
|
const data = await client.getStorageInfo(repo, path8);
|
|
7060
7626
|
success(data, "artifactory", "artifact-info", start);
|
|
7061
7627
|
} catch (err) {
|
|
@@ -7065,7 +7631,7 @@ function registerArtifactoryCommands(program2) {
|
|
|
7065
7631
|
art.command("properties-get <repo> <path>").description("Read custom properties on an artifact").action(async (repo, path8) => {
|
|
7066
7632
|
const start = Date.now();
|
|
7067
7633
|
try {
|
|
7068
|
-
const client =
|
|
7634
|
+
const client = getClient8(program2);
|
|
7069
7635
|
const data = await client.getProperties(repo, path8);
|
|
7070
7636
|
success(data, "artifactory", "properties-get", start);
|
|
7071
7637
|
} catch (err) {
|
|
@@ -7082,7 +7648,7 @@ function registerArtifactoryCommands(program2) {
|
|
|
7082
7648
|
if (eq < 1) throw new PncliError(`Invalid property format: "${kv}" \u2014 expected key=value`);
|
|
7083
7649
|
properties[kv.slice(0, eq)] = kv.slice(eq + 1);
|
|
7084
7650
|
}
|
|
7085
|
-
const client =
|
|
7651
|
+
const client = getClient8(program2);
|
|
7086
7652
|
await client.setProperties(repo, path8, properties, { recursive: opts.recursive });
|
|
7087
7653
|
success({ repo, path: path8, properties }, "artifactory", "properties-set", start);
|
|
7088
7654
|
} catch (err) {
|
|
@@ -7095,7 +7661,7 @@ function registerArtifactoryCommands(program2) {
|
|
|
7095
7661
|
if (!opts.repo && !opts.name && !opts.path) {
|
|
7096
7662
|
throw new PncliError("Provide at least one filter: --repo, --name, or --path");
|
|
7097
7663
|
}
|
|
7098
|
-
const client =
|
|
7664
|
+
const client = getClient8(program2);
|
|
7099
7665
|
const data = await client.searchAql({
|
|
7100
7666
|
repo: opts.repo,
|
|
7101
7667
|
name: opts.name,
|
|
@@ -7113,7 +7679,7 @@ function registerArtifactoryCommands(program2) {
|
|
|
7113
7679
|
art.command("builds").description('List builds registered in Artifactory Build Integration (names may differ from ADO pipeline or uDeploy component names; use "search --repo" when empty)').option("--timeout <s>", "Request timeout in seconds (default 60; increase for large Artifactory instances)", "60").action(async (opts) => {
|
|
7114
7680
|
const start = Date.now();
|
|
7115
7681
|
try {
|
|
7116
|
-
const client =
|
|
7682
|
+
const client = getClient8(program2);
|
|
7117
7683
|
const timeoutSecs = parseInt(opts.timeout, 10);
|
|
7118
7684
|
if (isNaN(timeoutSecs) || timeoutSecs <= 0) throw new PncliError("--timeout must be a positive integer (seconds)", 1);
|
|
7119
7685
|
const timeoutMs = timeoutSecs * 1e3;
|
|
@@ -7126,7 +7692,7 @@ function registerArtifactoryCommands(program2) {
|
|
|
7126
7692
|
art.command("build-runs <name>").description("List all run numbers for a build").action(async (name) => {
|
|
7127
7693
|
const start = Date.now();
|
|
7128
7694
|
try {
|
|
7129
|
-
const client =
|
|
7695
|
+
const client = getClient8(program2);
|
|
7130
7696
|
const data = await client.listBuildRuns(name);
|
|
7131
7697
|
success(data, "artifactory", "build-runs", start);
|
|
7132
7698
|
} catch (err) {
|
|
@@ -7136,7 +7702,7 @@ function registerArtifactoryCommands(program2) {
|
|
|
7136
7702
|
art.command("build-info <name> <number>").description("Get build info (artifacts, dependencies, VCS revision) for a specific run").action(async (name, number) => {
|
|
7137
7703
|
const start = Date.now();
|
|
7138
7704
|
try {
|
|
7139
|
-
const client =
|
|
7705
|
+
const client = getClient8(program2);
|
|
7140
7706
|
const data = await client.getBuildInfo(name, number);
|
|
7141
7707
|
success(data, "artifactory", "build-info", start);
|
|
7142
7708
|
} catch (err) {
|
|
@@ -7208,7 +7774,7 @@ var UdeployClient = class {
|
|
|
7208
7774
|
// src/services/udeploy/commands.ts
|
|
7209
7775
|
var POLL_INTERVAL_MS2 = 5e3;
|
|
7210
7776
|
var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
7211
|
-
function
|
|
7777
|
+
function getClient9(program2) {
|
|
7212
7778
|
const opts = program2.optsWithGlobals();
|
|
7213
7779
|
const config = loadConfig({ configPath: opts.config });
|
|
7214
7780
|
if (!config.udeploy.baseUrl) {
|
|
@@ -7232,7 +7798,7 @@ function registerUdeployCommands(program2) {
|
|
|
7232
7798
|
udeploy.command("apps").description("List all applications").action(async () => {
|
|
7233
7799
|
const start = Date.now();
|
|
7234
7800
|
try {
|
|
7235
|
-
const { client } =
|
|
7801
|
+
const { client } = getClient9(program2);
|
|
7236
7802
|
const apps = await client.listApplications();
|
|
7237
7803
|
success(apps, "udeploy", "apps", start);
|
|
7238
7804
|
} catch (err) {
|
|
@@ -7242,7 +7808,7 @@ function registerUdeployCommands(program2) {
|
|
|
7242
7808
|
udeploy.command("environments").description("List environments for an application").action(async () => {
|
|
7243
7809
|
const start = Date.now();
|
|
7244
7810
|
try {
|
|
7245
|
-
const { client, config } =
|
|
7811
|
+
const { client, config } = getClient9(program2);
|
|
7246
7812
|
const parentOpts = udeploy.opts();
|
|
7247
7813
|
const application = resolveApplication(config, parentOpts.application);
|
|
7248
7814
|
const envs = await client.listEnvironments(application);
|
|
@@ -7254,7 +7820,7 @@ function registerUdeployCommands(program2) {
|
|
|
7254
7820
|
udeploy.command("components").description("List all components").action(async () => {
|
|
7255
7821
|
const start = Date.now();
|
|
7256
7822
|
try {
|
|
7257
|
-
const { client } =
|
|
7823
|
+
const { client } = getClient9(program2);
|
|
7258
7824
|
const components = await client.listComponents();
|
|
7259
7825
|
success(components, "udeploy", "components", start);
|
|
7260
7826
|
} catch (err) {
|
|
@@ -7264,7 +7830,7 @@ function registerUdeployCommands(program2) {
|
|
|
7264
7830
|
udeploy.command("versions").description("List versions for a component").requiredOption("--component <name>", "Component name or ID").action(async (cmdOpts) => {
|
|
7265
7831
|
const start = Date.now();
|
|
7266
7832
|
try {
|
|
7267
|
-
const { client } =
|
|
7833
|
+
const { client } = getClient9(program2);
|
|
7268
7834
|
const versions = await client.listVersions(cmdOpts.component);
|
|
7269
7835
|
success(versions, "udeploy", "versions", start);
|
|
7270
7836
|
} catch (err) {
|
|
@@ -7274,7 +7840,7 @@ function registerUdeployCommands(program2) {
|
|
|
7274
7840
|
udeploy.command("import-version").description("Create a component version and mark it ready for deployment").requiredOption("--component <name>", "Component name or ID").requiredOption("--name <name>", "Version name").option("--no-finish", "Skip marking the version as finished importing").action(async (cmdOpts) => {
|
|
7275
7841
|
const start = Date.now();
|
|
7276
7842
|
try {
|
|
7277
|
-
const { client } =
|
|
7843
|
+
const { client } = getClient9(program2);
|
|
7278
7844
|
const created = await client.createVersion(cmdOpts.component, cmdOpts.name);
|
|
7279
7845
|
if (cmdOpts.finish) {
|
|
7280
7846
|
await client.finishImporting(cmdOpts.component, cmdOpts.name);
|
|
@@ -7287,7 +7853,7 @@ function registerUdeployCommands(program2) {
|
|
|
7287
7853
|
udeploy.command("run").description("Run an application deployment process").requiredOption("--process <name>", "Application process name or ID").option("--component <name>", "Component name (repeatable)", collect, []).option("--component-version <name>", "Component version (repeatable; positionally paired with --component)", collect, []).option("--snapshot <name>", "Snapshot name or ID (alternative to specifying versions)").option("--only-changed", "Deploy only changed components", false).option("--wait", "Poll until the process completes", false).option("--timeout <ms>", "Max wait time in milliseconds", String(DEFAULT_TIMEOUT_MS)).action(async (cmdOpts) => {
|
|
7288
7854
|
const start = Date.now();
|
|
7289
7855
|
try {
|
|
7290
|
-
const { client, config } =
|
|
7856
|
+
const { client, config } = getClient9(program2);
|
|
7291
7857
|
const parentOpts = udeploy.opts();
|
|
7292
7858
|
const application = resolveApplication(config, parentOpts.application);
|
|
7293
7859
|
const environment = resolveEnvironment(config, parentOpts.environment);
|
|
@@ -7340,7 +7906,7 @@ function registerUdeployCommands(program2) {
|
|
|
7340
7906
|
udeploy.command("request-status").description("Get the current status of a deployment process request").requiredOption("--request-id <id>", "Request ID returned by udeploy run").action(async (cmdOpts) => {
|
|
7341
7907
|
const start = Date.now();
|
|
7342
7908
|
try {
|
|
7343
|
-
const { client } =
|
|
7909
|
+
const { client } = getClient9(program2);
|
|
7344
7910
|
const status = await client.getRequestStatus(cmdOpts.requestId);
|
|
7345
7911
|
success(status, "udeploy", "request-status", start);
|
|
7346
7912
|
} catch (err) {
|
|
@@ -7350,7 +7916,7 @@ function registerUdeployCommands(program2) {
|
|
|
7350
7916
|
udeploy.command("request-info").description("Get full details of a deployment process request").requiredOption("--request-id <id>", "Request ID returned by udeploy run").action(async (cmdOpts) => {
|
|
7351
7917
|
const start = Date.now();
|
|
7352
7918
|
try {
|
|
7353
|
-
const { client } =
|
|
7919
|
+
const { client } = getClient9(program2);
|
|
7354
7920
|
const info = await client.getRequestInfo(cmdOpts.requestId);
|
|
7355
7921
|
success(info, "udeploy", "request-info", start);
|
|
7356
7922
|
} catch (err) {
|
|
@@ -7394,7 +7960,7 @@ var CheckmarxClient = class {
|
|
|
7394
7960
|
};
|
|
7395
7961
|
|
|
7396
7962
|
// src/services/checkmarx/commands.ts
|
|
7397
|
-
function
|
|
7963
|
+
function getClient10(program2) {
|
|
7398
7964
|
const opts = program2.optsWithGlobals();
|
|
7399
7965
|
const config = loadConfig({ configPath: opts.config });
|
|
7400
7966
|
if (!config.checkmarx.baseUrl) throw new PncliError("Checkmarx not configured. Run: pncli config init");
|
|
@@ -7408,7 +7974,7 @@ function registerCheckmarxCommands(program2) {
|
|
|
7408
7974
|
project.command("list").description("List all projects").action(async () => {
|
|
7409
7975
|
const start = Date.now();
|
|
7410
7976
|
try {
|
|
7411
|
-
const data = await
|
|
7977
|
+
const data = await getClient10(program2).listProjects();
|
|
7412
7978
|
success(data, "checkmarx", "project-list", start);
|
|
7413
7979
|
} catch (err) {
|
|
7414
7980
|
fail(err, "checkmarx", "project-list", start);
|
|
@@ -7419,7 +7985,7 @@ function registerCheckmarxCommands(program2) {
|
|
|
7419
7985
|
try {
|
|
7420
7986
|
const id = parseInt(opts.id, 10);
|
|
7421
7987
|
if (isNaN(id)) throw new PncliError(`Invalid --id "${opts.id}". Expected an integer.`, 1);
|
|
7422
|
-
const data = await
|
|
7988
|
+
const data = await getClient10(program2).getProject(id);
|
|
7423
7989
|
success(data, "checkmarx", "project-get", start);
|
|
7424
7990
|
} catch (err) {
|
|
7425
7991
|
fail(err, "checkmarx", "project-get", start);
|
|
@@ -7432,7 +7998,7 @@ function registerCheckmarxCommands(program2) {
|
|
|
7432
7998
|
const last = opts.last ? parseInt(opts.last, 10) : void 0;
|
|
7433
7999
|
if (opts.project && isNaN(projectId)) throw new PncliError(`Invalid --project "${opts.project}". Expected an integer.`, 1);
|
|
7434
8000
|
if (opts.last && isNaN(last)) throw new PncliError(`Invalid --last "${opts.last}". Expected an integer.`, 1);
|
|
7435
|
-
const data = await
|
|
8001
|
+
const data = await getClient10(program2).listScans({ projectId, last });
|
|
7436
8002
|
success(data, "checkmarx", "scan-list", start);
|
|
7437
8003
|
} catch (err) {
|
|
7438
8004
|
fail(err, "checkmarx", "scan-list", start);
|
|
@@ -7443,7 +8009,7 @@ function registerCheckmarxCommands(program2) {
|
|
|
7443
8009
|
try {
|
|
7444
8010
|
const id = parseInt(opts.id, 10);
|
|
7445
8011
|
if (isNaN(id)) throw new PncliError(`Invalid --id "${opts.id}". Expected an integer.`, 1);
|
|
7446
|
-
const data = await
|
|
8012
|
+
const data = await getClient10(program2).getScan(id);
|
|
7447
8013
|
success(data, "checkmarx", "scan-get", start);
|
|
7448
8014
|
} catch (err) {
|
|
7449
8015
|
fail(err, "checkmarx", "scan-get", start);
|
|
@@ -7454,7 +8020,7 @@ function registerCheckmarxCommands(program2) {
|
|
|
7454
8020
|
try {
|
|
7455
8021
|
const id = parseInt(opts.id, 10);
|
|
7456
8022
|
if (isNaN(id)) throw new PncliError(`Invalid --id "${opts.id}". Expected an integer.`, 1);
|
|
7457
|
-
const data = await
|
|
8023
|
+
const data = await getClient10(program2).getScanResultsStatistics(id);
|
|
7458
8024
|
success(data, "checkmarx", "scan-stats", start);
|
|
7459
8025
|
} catch (err) {
|
|
7460
8026
|
fail(err, "checkmarx", "scan-stats", start);
|
|
@@ -7876,7 +8442,7 @@ function registerSkillsCommands(program2) {
|
|
|
7876
8442
|
}
|
|
7877
8443
|
});
|
|
7878
8444
|
const marketplace = skills.command("marketplace").description("Manage a git-hosted skills marketplace");
|
|
7879
|
-
marketplace.command("setup").description("Clone a skills marketplace repo
|
|
8445
|
+
marketplace.command("setup").description("Clone a skills marketplace repo, register it in global config, and install all plugins").argument("<url>", "Git clone URL of the marketplace repository").argument("[localPath]", "Local directory to clone into (default: ~/.agents/marketplaces/<repo-name>)").option("--branch <branch>", "Branch to clone (default: remote HEAD)").option("--token <token>", "HTTP access token for authenticated clone and pull (GitHub PAT or Bitbucket token)").option("--agent <agent>", "Target agent host for plugin install: github-copilot | claude-code (default: github-copilot)").option("--claude", "Shorthand for --agent claude-code").action(async (url, localPath, opts) => {
|
|
7880
8446
|
const start = Date.now();
|
|
7881
8447
|
try {
|
|
7882
8448
|
const resolvedPath = path7.resolve(localPath ?? defaultMarketplacePath(url));
|
|
@@ -7885,7 +8451,7 @@ function registerSkillsCommands(program2) {
|
|
|
7885
8451
|
throw new Error(`Directory already exists and is not a git repo: ${resolvedPath}`);
|
|
7886
8452
|
}
|
|
7887
8453
|
if (hasGit) {
|
|
7888
|
-
warn(`Directory already contains a git repo at ${resolvedPath} \u2014 skipping clone, updating config
|
|
8454
|
+
warn(`Directory already contains a git repo at ${resolvedPath} \u2014 skipping clone, updating config and re-installing plugins.`);
|
|
7889
8455
|
} else {
|
|
7890
8456
|
const branchLabel = opts.branch ?? "remote default";
|
|
7891
8457
|
warn(`Cloning ${url} (branch: ${branchLabel}) \u2192 ${resolvedPath}...`);
|
|
@@ -7904,12 +8470,51 @@ function registerSkillsCommands(program2) {
|
|
|
7904
8470
|
const existing = loadJsonFile(configPath) ?? {};
|
|
7905
8471
|
existing.marketplace = { repoUrl: url, localPath: resolvedPath, ...opts.token ? { token: opts.token } : {} };
|
|
7906
8472
|
writeGlobalConfig(existing, configPath);
|
|
7907
|
-
|
|
8473
|
+
const agentName = opts.claude ? "claude-code" : opts.agent ?? "github-copilot";
|
|
8474
|
+
const agentConfig = AGENT_PATHS[agentName];
|
|
8475
|
+
if (!agentConfig) {
|
|
8476
|
+
throw new Error(`Unknown agent: "${agentName}". Use: ${Object.keys(AGENT_PATHS).join(" | ")}`);
|
|
8477
|
+
}
|
|
8478
|
+
const targetDir = agentConfig.user;
|
|
8479
|
+
const pluginChoices = resolvePluginChoices(resolvedPath);
|
|
8480
|
+
const pluginResults = {};
|
|
8481
|
+
let totalInstalled = 0;
|
|
8482
|
+
if (pluginChoices.length === 0) {
|
|
8483
|
+
warn("No plugins found in marketplace. Check the marketplace repository structure.");
|
|
8484
|
+
} else {
|
|
8485
|
+
warn(`Installing ${pluginChoices.length} plugin(s) to ${targetDir}...`);
|
|
8486
|
+
for (const pluginChoice of pluginChoices) {
|
|
8487
|
+
const skillsSrc = resolveSkillsSrc(resolvedPath, pluginChoice.name);
|
|
8488
|
+
if (!fs4.existsSync(skillsSrc)) {
|
|
8489
|
+
pluginResults[pluginChoice.name] = { installed: [], failed: [] };
|
|
8490
|
+
warn(`No skills directory found for plugin "${pluginChoice.name}" \u2014 skipping.`);
|
|
8491
|
+
continue;
|
|
8492
|
+
}
|
|
8493
|
+
const { installed, failed } = copyPluginSkills(skillsSrc, targetDir);
|
|
8494
|
+
pluginResults[pluginChoice.name] = { installed, failed };
|
|
8495
|
+
totalInstalled += installed.length;
|
|
8496
|
+
for (const skill of installed) {
|
|
8497
|
+
warn(` ${skill}: ${path7.join(skillsSrc, skill)} \u2192 ${path7.join(targetDir, skill)}`);
|
|
8498
|
+
}
|
|
8499
|
+
if (failed.length > 0) {
|
|
8500
|
+
warn(`Skipped ${failed.length} skill(s) with invalid names in "${pluginChoice.name}": ${failed.join(", ")}`);
|
|
8501
|
+
}
|
|
8502
|
+
}
|
|
8503
|
+
}
|
|
8504
|
+
success({
|
|
8505
|
+
repoUrl: url,
|
|
8506
|
+
localPath: resolvedPath,
|
|
8507
|
+
branch: opts.branch ?? null,
|
|
8508
|
+
tokenConfigured: !!opts.token,
|
|
8509
|
+
plugins: pluginResults,
|
|
8510
|
+
total: totalInstalled,
|
|
8511
|
+
target: targetDir
|
|
8512
|
+
}, "skills", "marketplace-setup", start);
|
|
7908
8513
|
} catch (err) {
|
|
7909
8514
|
fail(err, "skills", "marketplace-setup", start);
|
|
7910
8515
|
}
|
|
7911
8516
|
});
|
|
7912
|
-
marketplace.command("sync").description("Pull latest marketplace content and install a plugin's skills").argument("[plugin]", 'Plugin name to install, or "all" to install every plugin (skips interactive selection)').option("--
|
|
8517
|
+
marketplace.command("sync").description("Pull latest marketplace content and install a plugin's skills").argument("[plugin]", 'Plugin name to install, or "all" to install every plugin (skips interactive selection)').option("--agent <agent>", "Target agent host: github-copilot | claude-code (default: github-copilot)").option("--claude", "Shorthand for --agent claude-code").option("--force", "Force reinstall even if the marketplace repo has no new changes").action(async (plugin, opts) => {
|
|
7913
8518
|
const start = Date.now();
|
|
7914
8519
|
try {
|
|
7915
8520
|
const configPath = getGlobalConfigPath();
|
|
@@ -7938,22 +8543,45 @@ function registerSkillsCommands(program2) {
|
|
|
7938
8543
|
warn(pullOutput.trim());
|
|
7939
8544
|
}
|
|
7940
8545
|
warn(marketplaceUpdated ? "Marketplace updated." : "Marketplace already up to date \u2014 no changes to sync.");
|
|
7941
|
-
if (!marketplaceUpdated && !plugin && !opts.force) {
|
|
7942
|
-
success({
|
|
7943
|
-
marketplace: marketplacePath,
|
|
7944
|
-
marketplaceUpdated: false,
|
|
7945
|
-
updated: false,
|
|
7946
|
-
skipped: true,
|
|
7947
|
-
message: "No marketplace changes detected \u2014 skipping plugin selection and install."
|
|
7948
|
-
}, "skills", "marketplace-sync", start);
|
|
7949
|
-
return;
|
|
7950
|
-
}
|
|
7951
8546
|
const pluginChoices = resolvePluginChoices(marketplacePath);
|
|
7952
8547
|
if (pluginChoices.length === 0) {
|
|
7953
8548
|
throw new Error("No plugins found in marketplace. Check the marketplace repository structure.");
|
|
7954
8549
|
}
|
|
7955
|
-
const
|
|
7956
|
-
|
|
8550
|
+
const agentName = opts.claude ? "claude-code" : opts.agent ?? "github-copilot";
|
|
8551
|
+
const agentConfig = AGENT_PATHS[agentName];
|
|
8552
|
+
if (!agentConfig) {
|
|
8553
|
+
throw new Error(`Unknown agent: "${agentName}". Use: ${Object.keys(AGENT_PATHS).join(" | ")}`);
|
|
8554
|
+
}
|
|
8555
|
+
const targetDir = agentConfig.user;
|
|
8556
|
+
let selectedPlugin;
|
|
8557
|
+
if (plugin) {
|
|
8558
|
+
if (plugin !== "all" && !pluginChoices.some((p) => p.name === plugin)) {
|
|
8559
|
+
throw new Error(`Plugin "${plugin}" not found. Available: ${pluginChoices.map((p) => p.name).join(", ")}`);
|
|
8560
|
+
}
|
|
8561
|
+
selectedPlugin = plugin;
|
|
8562
|
+
} else {
|
|
8563
|
+
selectedPlugin = await select({
|
|
8564
|
+
message: "Select a plugin to install:",
|
|
8565
|
+
choices: [
|
|
8566
|
+
{ value: "all", name: "All \u2014 install every plugin" },
|
|
8567
|
+
...pluginChoices.map((p) => ({
|
|
8568
|
+
value: p.name,
|
|
8569
|
+
name: p.description ? `${p.name} \u2014 ${p.description}` : p.name
|
|
8570
|
+
}))
|
|
8571
|
+
]
|
|
8572
|
+
});
|
|
8573
|
+
}
|
|
8574
|
+
if (selectedPlugin === "all") {
|
|
8575
|
+
if (!marketplaceUpdated && !opts.force) {
|
|
8576
|
+
success({
|
|
8577
|
+
marketplace: marketplacePath,
|
|
8578
|
+
marketplaceUpdated: false,
|
|
8579
|
+
updated: false,
|
|
8580
|
+
skipped: true,
|
|
8581
|
+
message: "No marketplace changes detected \u2014 skipping install."
|
|
8582
|
+
}, "skills", "marketplace-sync", start);
|
|
8583
|
+
return;
|
|
8584
|
+
}
|
|
7957
8585
|
const results = {};
|
|
7958
8586
|
let totalInstalled = 0;
|
|
7959
8587
|
for (const pluginChoice of pluginChoices) {
|
|
@@ -7981,21 +8609,6 @@ function registerSkillsCommands(program2) {
|
|
|
7981
8609
|
}, "skills", "marketplace-sync", start);
|
|
7982
8610
|
return;
|
|
7983
8611
|
}
|
|
7984
|
-
let selectedPlugin;
|
|
7985
|
-
if (plugin) {
|
|
7986
|
-
if (!pluginChoices.some((p) => p.name === plugin)) {
|
|
7987
|
-
throw new Error(`Plugin "${plugin}" not found. Available: ${pluginChoices.map((p) => p.name).join(", ")}`);
|
|
7988
|
-
}
|
|
7989
|
-
selectedPlugin = plugin;
|
|
7990
|
-
} else {
|
|
7991
|
-
selectedPlugin = await select({
|
|
7992
|
-
message: "Select a plugin to install:",
|
|
7993
|
-
choices: pluginChoices.map((p) => ({
|
|
7994
|
-
value: p.name,
|
|
7995
|
-
name: p.description ? `${p.name} \u2014 ${p.description}` : p.name
|
|
7996
|
-
}))
|
|
7997
|
-
});
|
|
7998
|
-
}
|
|
7999
8612
|
const skillsSrc = resolveSkillsSrc(marketplacePath, selectedPlugin);
|
|
8000
8613
|
if (!fs4.existsSync(skillsSrc)) {
|
|
8001
8614
|
throw new Error(`No skills directory found at ${skillsSrc}`);
|
|
@@ -8329,13 +8942,14 @@ if (!process.env.PNCLI_VERIFY_TLS) {
|
|
|
8329
8942
|
var require2 = createRequire(import.meta.url);
|
|
8330
8943
|
var pkg = require2("../package.json");
|
|
8331
8944
|
var TAGLINE = "One command does what three meetings couldn't.";
|
|
8332
|
-
var program = new
|
|
8333
|
-
program.name("pncli").description(`The Paperwork Nightmare CLI \u2014 ${TAGLINE}`).version(`${pkg.version} \u2014 ${TAGLINE}`, "-v, --version").option("--pretty", "Human-readable formatted output", false).option("--verbose", "Include full response metadata", false).option("--dry-run", "Print API requests without executing", false).option("--config <path>", "Override global config file location").option("--output-file <path>", "Write JSON output to file instead of stdout");
|
|
8945
|
+
var program = new Command3();
|
|
8946
|
+
program.name("pncli").description(`The Paperwork Nightmare CLI \u2014 ${TAGLINE}`).version(`${pkg.version} \u2014 ${TAGLINE}`, "-v, --version").option("--pretty", "Human-readable formatted output", false).option("--verbose", "Include full response metadata", false).option("--debug", "Print diagnostic traces (method, URL, status) for all API calls \u2014 does not log credentials", false).option("--dry-run", "Print API requests without executing", false).option("--config <path>", "Override global config file location").option("--output-file <path>", "Write JSON output to file instead of stdout");
|
|
8334
8947
|
program.hook("preAction", (thisCommand) => {
|
|
8335
8948
|
const opts = thisCommand.optsWithGlobals();
|
|
8336
8949
|
setGlobalOptions({
|
|
8337
8950
|
pretty: Boolean(opts.pretty),
|
|
8338
8951
|
verbose: Boolean(opts.verbose),
|
|
8952
|
+
debug: Boolean(opts.debug),
|
|
8339
8953
|
outputFile: opts.outputFile
|
|
8340
8954
|
});
|
|
8341
8955
|
try {
|
|
@@ -8347,6 +8961,7 @@ program.hook("preAction", (thisCommand) => {
|
|
|
8347
8961
|
registerGitCommands(program);
|
|
8348
8962
|
registerJiraCommands(program);
|
|
8349
8963
|
registerBitbucketCommands(program);
|
|
8964
|
+
registerGitHubCommands(program);
|
|
8350
8965
|
registerConfluenceCommands(program);
|
|
8351
8966
|
registerSonarCommands(program);
|
|
8352
8967
|
registerSdeCommands(program);
|
|
@@ -8369,6 +8984,7 @@ Services:
|
|
|
8369
8984
|
deps Dependency scanning, CVE detection, license auditing
|
|
8370
8985
|
jira Jira Data Cloud
|
|
8371
8986
|
bitbucket Bitbucket Server
|
|
8987
|
+
github GitHub (PRs, reviews, comments, checks)
|
|
8372
8988
|
confluence Confluence
|
|
8373
8989
|
sonar SonarQube Server (quality gates, issues, metrics, hotspots)
|
|
8374
8990
|
sde SDElements (threat modeling, countermeasures, compliance)
|