pingcode-cli-unofficial 1.8.3 → 1.9.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/README.md +5 -5
- package/dist/bin/pingcode.js +179 -379
- package/dist/bin/pingcode.js.map +1 -1
- package/package.json +2 -4
package/dist/bin/pingcode.js
CHANGED
|
@@ -978,7 +978,7 @@ var require_command = __commonJS({
|
|
|
978
978
|
"use strict";
|
|
979
979
|
var EventEmitter = __require("events").EventEmitter;
|
|
980
980
|
var childProcess = __require("child_process");
|
|
981
|
-
var
|
|
981
|
+
var path9 = __require("path");
|
|
982
982
|
var fs = __require("fs");
|
|
983
983
|
var process2 = __require("process");
|
|
984
984
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
@@ -1911,9 +1911,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1911
1911
|
let launchWithNode = false;
|
|
1912
1912
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1913
1913
|
function findFile(baseDir, baseName) {
|
|
1914
|
-
const localBin =
|
|
1914
|
+
const localBin = path9.resolve(baseDir, baseName);
|
|
1915
1915
|
if (fs.existsSync(localBin)) return localBin;
|
|
1916
|
-
if (sourceExt.includes(
|
|
1916
|
+
if (sourceExt.includes(path9.extname(baseName))) return void 0;
|
|
1917
1917
|
const foundExt = sourceExt.find(
|
|
1918
1918
|
(ext) => fs.existsSync(`${localBin}${ext}`)
|
|
1919
1919
|
);
|
|
@@ -1931,17 +1931,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1931
1931
|
} catch (err) {
|
|
1932
1932
|
resolvedScriptPath = this._scriptPath;
|
|
1933
1933
|
}
|
|
1934
|
-
executableDir =
|
|
1935
|
-
|
|
1934
|
+
executableDir = path9.resolve(
|
|
1935
|
+
path9.dirname(resolvedScriptPath),
|
|
1936
1936
|
executableDir
|
|
1937
1937
|
);
|
|
1938
1938
|
}
|
|
1939
1939
|
if (executableDir) {
|
|
1940
1940
|
let localFile = findFile(executableDir, executableFile);
|
|
1941
1941
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1942
|
-
const legacyName =
|
|
1942
|
+
const legacyName = path9.basename(
|
|
1943
1943
|
this._scriptPath,
|
|
1944
|
-
|
|
1944
|
+
path9.extname(this._scriptPath)
|
|
1945
1945
|
);
|
|
1946
1946
|
if (legacyName !== this._name) {
|
|
1947
1947
|
localFile = findFile(
|
|
@@ -1952,7 +1952,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1952
1952
|
}
|
|
1953
1953
|
executableFile = localFile || executableFile;
|
|
1954
1954
|
}
|
|
1955
|
-
launchWithNode = sourceExt.includes(
|
|
1955
|
+
launchWithNode = sourceExt.includes(path9.extname(executableFile));
|
|
1956
1956
|
let proc;
|
|
1957
1957
|
if (process2.platform !== "win32") {
|
|
1958
1958
|
if (launchWithNode) {
|
|
@@ -2792,7 +2792,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2792
2792
|
* @return {Command}
|
|
2793
2793
|
*/
|
|
2794
2794
|
nameFromFilename(filename) {
|
|
2795
|
-
this._name =
|
|
2795
|
+
this._name = path9.basename(filename, path9.extname(filename));
|
|
2796
2796
|
return this;
|
|
2797
2797
|
}
|
|
2798
2798
|
/**
|
|
@@ -2806,9 +2806,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2806
2806
|
* @param {string} [path]
|
|
2807
2807
|
* @return {(string|null|Command)}
|
|
2808
2808
|
*/
|
|
2809
|
-
executableDir(
|
|
2810
|
-
if (
|
|
2811
|
-
this._executableDir =
|
|
2809
|
+
executableDir(path10) {
|
|
2810
|
+
if (path10 === void 0) return this._executableDir;
|
|
2811
|
+
this._executableDir = path10;
|
|
2812
2812
|
return this;
|
|
2813
2813
|
}
|
|
2814
2814
|
/**
|
|
@@ -3425,7 +3425,7 @@ var VERSION;
|
|
|
3425
3425
|
var init_version = __esm({
|
|
3426
3426
|
"src/version.ts"() {
|
|
3427
3427
|
"use strict";
|
|
3428
|
-
VERSION = "1.
|
|
3428
|
+
VERSION = "1.9.0";
|
|
3429
3429
|
}
|
|
3430
3430
|
});
|
|
3431
3431
|
|
|
@@ -4475,9 +4475,9 @@ var init_catalog = __esm({
|
|
|
4475
4475
|
function isMutating(method) {
|
|
4476
4476
|
return MUTATING.has(method.toUpperCase());
|
|
4477
4477
|
}
|
|
4478
|
-
function buildUrl(apiBase,
|
|
4478
|
+
function buildUrl(apiBase, path9, query) {
|
|
4479
4479
|
const base = apiBase.replace(/\/+$/, "");
|
|
4480
|
-
const relative =
|
|
4480
|
+
const relative = path9.startsWith("/") ? path9 : `/${path9}`;
|
|
4481
4481
|
const url = new URL(`${base}${relative}`);
|
|
4482
4482
|
if (query !== void 0) {
|
|
4483
4483
|
for (const [key, value] of Object.entries(query)) {
|
|
@@ -5301,12 +5301,12 @@ function normalizeEnvelope(raw, requested) {
|
|
|
5301
5301
|
values
|
|
5302
5302
|
};
|
|
5303
5303
|
}
|
|
5304
|
-
async function fetchPage(ctx,
|
|
5304
|
+
async function fetchPage(ctx, path9, query = {}, page = {}) {
|
|
5305
5305
|
const pageIndex = validatePageIndex(page.pageIndex ?? 0);
|
|
5306
5306
|
const pageSize = validatePageSize(page.pageSize ?? DEFAULT_PAGE_SIZE);
|
|
5307
5307
|
const raw = await request(ctx, {
|
|
5308
5308
|
method: "GET",
|
|
5309
|
-
path:
|
|
5309
|
+
path: path9,
|
|
5310
5310
|
query: { ...query, page_index: pageIndex, page_size: pageSize }
|
|
5311
5311
|
});
|
|
5312
5312
|
return normalizeEnvelope(raw, { pageIndex, pageSize });
|
|
@@ -5339,8 +5339,8 @@ async function* walkPages(ctx, fetchOne, options, label) {
|
|
|
5339
5339
|
pageIndex += 1;
|
|
5340
5340
|
}
|
|
5341
5341
|
}
|
|
5342
|
-
async function* paginate(ctx,
|
|
5343
|
-
yield* walkPages(ctx, (page) => fetchPage(ctx,
|
|
5342
|
+
async function* paginate(ctx, path9, query = {}, options = {}) {
|
|
5343
|
+
yield* walkPages(ctx, (page) => fetchPage(ctx, path9, query, page), options, "GET-list");
|
|
5344
5344
|
}
|
|
5345
5345
|
function asReadContext(ctx) {
|
|
5346
5346
|
return ctx.dryRun ? { ...ctx, dryRun: false } : ctx;
|
|
@@ -5356,20 +5356,20 @@ function buildSearchBody(payload, page) {
|
|
|
5356
5356
|
body.page_size = page.pageSize;
|
|
5357
5357
|
return { mode: "query", payload: body };
|
|
5358
5358
|
}
|
|
5359
|
-
async function fetchSearchPage(ctx,
|
|
5359
|
+
async function fetchSearchPage(ctx, path9, payload = {}, page = {}) {
|
|
5360
5360
|
const pageIndex = validatePageIndex(page.pageIndex ?? 0);
|
|
5361
5361
|
const pageSize = validatePageSize(page.pageSize ?? DEFAULT_PAGE_SIZE);
|
|
5362
5362
|
const raw = await request(asReadContext(ctx), {
|
|
5363
5363
|
method: "POST",
|
|
5364
|
-
path:
|
|
5364
|
+
path: path9,
|
|
5365
5365
|
body: buildSearchBody(payload, { pageIndex, pageSize })
|
|
5366
5366
|
});
|
|
5367
5367
|
return normalizeEnvelope(raw, { pageIndex, pageSize });
|
|
5368
5368
|
}
|
|
5369
|
-
async function* searchPaginate(ctx,
|
|
5369
|
+
async function* searchPaginate(ctx, path9, payload = {}, options = {}) {
|
|
5370
5370
|
yield* walkPages(
|
|
5371
5371
|
ctx,
|
|
5372
|
-
(page) => fetchSearchPage(ctx,
|
|
5372
|
+
(page) => fetchSearchPage(ctx, path9, payload, page),
|
|
5373
5373
|
options,
|
|
5374
5374
|
"search"
|
|
5375
5375
|
);
|
|
@@ -7087,9 +7087,9 @@ async function loadSuiteTree(ctx, path_, query) {
|
|
|
7087
7087
|
}
|
|
7088
7088
|
const candidates = [];
|
|
7089
7089
|
for (const [id, node] of nodes) {
|
|
7090
|
-
const
|
|
7091
|
-
const candidate = { id, name: node.name, path:
|
|
7092
|
-
if (
|
|
7090
|
+
const path9 = suitePath(nodes, id);
|
|
7091
|
+
const candidate = { id, name: node.name, path: path9 };
|
|
7092
|
+
if (path9 !== void 0 && path9 !== node.name) candidate.aliases = [path9];
|
|
7093
7093
|
candidates.push(candidate);
|
|
7094
7094
|
}
|
|
7095
7095
|
return candidates;
|
|
@@ -7861,29 +7861,29 @@ endpoints; a wiki page and a code branch are the two with no recovery path at al
|
|
|
7861
7861
|
}
|
|
7862
7862
|
}
|
|
7863
7863
|
async function runVerb(method, pathArgument, flags, self) {
|
|
7864
|
-
const { candidates, path:
|
|
7864
|
+
const { candidates, path: path9 } = resolveEntry2(method, pathArgument);
|
|
7865
7865
|
const { ctx } = contextFor(self);
|
|
7866
7866
|
refuseUserTokenEndpoint(ctx, candidates);
|
|
7867
7867
|
const query = parseQueryFlags(flags.query);
|
|
7868
|
-
refuseUnconfirmedDelete(method,
|
|
7868
|
+
refuseUnconfirmedDelete(method, path9, query, flags);
|
|
7869
7869
|
const body = await readBodyFlags(flags);
|
|
7870
7870
|
const entry = chooseEntry(candidates, query, body);
|
|
7871
7871
|
const paging = readPagingFor(entry, flags);
|
|
7872
7872
|
try {
|
|
7873
|
-
await send(ctx, entry,
|
|
7873
|
+
await send(ctx, entry, path9, query, body, paging);
|
|
7874
7874
|
} catch (error) {
|
|
7875
7875
|
if (error instanceof PermissionError) errLine(paint.dim(declaredScopeLine(entry)));
|
|
7876
7876
|
throw error;
|
|
7877
7877
|
}
|
|
7878
7878
|
}
|
|
7879
|
-
async function send(ctx, entry,
|
|
7879
|
+
async function send(ctx, entry, path9, query, body, paging) {
|
|
7880
7880
|
if (entry.paged === "search") {
|
|
7881
|
-
await sendSearch(ctx,
|
|
7881
|
+
await sendSearch(ctx, path9, body, paging);
|
|
7882
7882
|
return;
|
|
7883
7883
|
}
|
|
7884
7884
|
if (entry.paged === "query" && paging.all) {
|
|
7885
7885
|
const values = await collect(
|
|
7886
|
-
paginate(ctx,
|
|
7886
|
+
paginate(ctx, path9, query, {
|
|
7887
7887
|
pageSize: paging.pageSize,
|
|
7888
7888
|
startPage: paging.pageIndex,
|
|
7889
7889
|
limit: paging.limit
|
|
@@ -7894,17 +7894,17 @@ async function send(ctx, entry, path8, query, body, paging) {
|
|
|
7894
7894
|
}
|
|
7895
7895
|
const raw = await request(ctx, {
|
|
7896
7896
|
method: entry.method,
|
|
7897
|
-
path:
|
|
7897
|
+
path: path9,
|
|
7898
7898
|
query: paging.requested ? { ...query, page_index: paging.pageIndex, page_size: paging.pageSize } : query,
|
|
7899
7899
|
...body === void 0 ? {} : { body }
|
|
7900
7900
|
});
|
|
7901
7901
|
printResponse(raw);
|
|
7902
7902
|
}
|
|
7903
|
-
async function sendSearch(ctx,
|
|
7903
|
+
async function sendSearch(ctx, path9, body, paging) {
|
|
7904
7904
|
const payload = searchPayloadOf(body);
|
|
7905
7905
|
if (paging.all) {
|
|
7906
7906
|
const values = await collect(
|
|
7907
|
-
searchPaginate(ctx,
|
|
7907
|
+
searchPaginate(ctx, path9, payload, {
|
|
7908
7908
|
pageSize: paging.pageSize,
|
|
7909
7909
|
startPage: paging.pageIndex,
|
|
7910
7910
|
limit: paging.limit
|
|
@@ -7913,7 +7913,7 @@ async function sendSearch(ctx, path8, body, paging) {
|
|
|
7913
7913
|
printJson({ values, count: values.length, all: true });
|
|
7914
7914
|
return;
|
|
7915
7915
|
}
|
|
7916
|
-
const page = await fetchSearchPage(ctx,
|
|
7916
|
+
const page = await fetchSearchPage(ctx, path9, payload, {
|
|
7917
7917
|
pageIndex: paging.pageIndex,
|
|
7918
7918
|
pageSize: paging.pageSize
|
|
7919
7919
|
});
|
|
@@ -7947,8 +7947,8 @@ function resolveEntry2(method, pathArgument) {
|
|
|
7947
7947
|
hint: `drop everything from "?" and pass the parameters as --query key=value (repeatable), so they are serialised the same way every other command does it`
|
|
7948
7948
|
});
|
|
7949
7949
|
}
|
|
7950
|
-
const
|
|
7951
|
-
const unfilled = unfilledPathParams(
|
|
7950
|
+
const path9 = normalizePath(raw);
|
|
7951
|
+
const unfilled = unfilledPathParams(path9);
|
|
7952
7952
|
if (unfilled.length > 0) {
|
|
7953
7953
|
throw new UsageError(
|
|
7954
7954
|
`the path still contains the placeholder${unfilled.length > 1 ? "s" : ""} ${unfilled.map((name) => `{${name}}`).join(", ")}`,
|
|
@@ -7957,32 +7957,32 @@ function resolveEntry2(method, pathArgument) {
|
|
|
7957
7957
|
}
|
|
7958
7958
|
);
|
|
7959
7959
|
}
|
|
7960
|
-
const onPath = matchPath(
|
|
7961
|
-
if (onPath.length === 0) throw unknownPath(
|
|
7960
|
+
const onPath = matchPath(path9);
|
|
7961
|
+
if (onPath.length === 0) throw unknownPath(path9);
|
|
7962
7962
|
const candidates = onPath.filter((candidate) => candidate.method === method);
|
|
7963
7963
|
if (candidates.length === 0) {
|
|
7964
|
-
const supported = methodsFor(
|
|
7965
|
-
throw new UsageError(`${method} ${
|
|
7964
|
+
const supported = methodsFor(path9);
|
|
7965
|
+
throw new UsageError(`${method} ${path9} is not a documented endpoint`, {
|
|
7966
7966
|
hint: `that path supports ${supported.join(", ")} \u2014 this API is missing several symmetric operations on purpose (there is no project delete, no sprint delete, and nothing in \u4EA7\u54C1\u7BA1\u7406 can be deleted at all)`
|
|
7967
7967
|
});
|
|
7968
7968
|
}
|
|
7969
|
-
return { candidates, path:
|
|
7969
|
+
return { candidates, path: path9 };
|
|
7970
7970
|
}
|
|
7971
|
-
function unknownPath(
|
|
7972
|
-
if (segmentsOf2(
|
|
7971
|
+
function unknownPath(path9) {
|
|
7972
|
+
if (segmentsOf2(path9).includes("authorize")) {
|
|
7973
7973
|
return new UsageError(
|
|
7974
|
-
`${
|
|
7974
|
+
`${path9} is the browser authorization page of the OAuth2 authorization-code flow, not a REST endpoint: it renders HTML for a human to click and redirects, it returns no JSON, and it is not under /v1`,
|
|
7975
7975
|
{ hint: AUTHORIZE_HINT }
|
|
7976
7976
|
);
|
|
7977
7977
|
}
|
|
7978
|
-
const suggestions = nearestPaths(
|
|
7979
|
-
const hint = suggestions.length === 0 ? `no documented path has ${segmentsOf2(
|
|
7980
|
-
return new UsageError(`${
|
|
7978
|
+
const suggestions = nearestPaths(path9);
|
|
7979
|
+
const hint = suggestions.length === 0 ? `no documented path has ${segmentsOf2(path9).length} segments like this one \u2014 search the catalog with \`pingcode api list --search <text>\`` : `did you mean ${suggestions.join(" , ")} ? \u2014 or search with \`pingcode api list --search <text>\``;
|
|
7980
|
+
return new UsageError(`${path9} is not in the endpoint catalog (459 documented v1 endpoints)`, {
|
|
7981
7981
|
hint
|
|
7982
7982
|
});
|
|
7983
7983
|
}
|
|
7984
|
-
function nearestPaths(
|
|
7985
|
-
const actual = segmentsOf2(
|
|
7984
|
+
function nearestPaths(path9) {
|
|
7985
|
+
const actual = segmentsOf2(path9);
|
|
7986
7986
|
const scored = /* @__PURE__ */ new Map();
|
|
7987
7987
|
for (const entry of CATALOG2) {
|
|
7988
7988
|
const template = segmentsOf2(entry.path);
|
|
@@ -8011,8 +8011,8 @@ function editDistance(a, b) {
|
|
|
8011
8011
|
}
|
|
8012
8012
|
return previous[b.length] ?? Math.max(a.length, b.length);
|
|
8013
8013
|
}
|
|
8014
|
-
function segmentsOf2(
|
|
8015
|
-
return
|
|
8014
|
+
function segmentsOf2(path9) {
|
|
8015
|
+
return path9.split("/").filter((segment) => segment !== "");
|
|
8016
8016
|
}
|
|
8017
8017
|
function isPlaceholder2(segment) {
|
|
8018
8018
|
return segment.startsWith("{") && segment.endsWith("}");
|
|
@@ -8029,9 +8029,9 @@ function refuseUserTokenEndpoint(ctx, candidates) {
|
|
|
8029
8029
|
}
|
|
8030
8030
|
);
|
|
8031
8031
|
}
|
|
8032
|
-
function refuseUnconfirmedDelete(method,
|
|
8032
|
+
function refuseUnconfirmedDelete(method, path9, query, flags) {
|
|
8033
8033
|
if (method !== "DELETE" || flags.yes === true) return;
|
|
8034
|
-
throw new UsageError(`refusing to send DELETE ${
|
|
8034
|
+
throw new UsageError(`refusing to send DELETE ${path9}${displayQuery(query)} without --yes`, {
|
|
8035
8035
|
hint: "re-run with --yes to send it, or with --yes --dry-run to print the full request plan without sending anything"
|
|
8036
8036
|
});
|
|
8037
8037
|
}
|
|
@@ -8193,22 +8193,22 @@ function registerDescribe(api) {
|
|
|
8193
8193
|
"\nAn id is exact; a method + path is matched through the same wildcard rules the\nexecutor uses. GET /v1/auth/token is the one path three entries share (the three\ngrants), so address those by id.\n--json prints the catalog entry verbatim.\n"
|
|
8194
8194
|
);
|
|
8195
8195
|
addGlobalOptions(command, { hidden: true }).action(
|
|
8196
|
-
(idOrMethod,
|
|
8196
|
+
(idOrMethod, path9, _flags, self) => {
|
|
8197
8197
|
const { ctx } = contextFor(self);
|
|
8198
|
-
const entry = lookupForDescribe(idOrMethod,
|
|
8198
|
+
const entry = lookupForDescribe(idOrMethod, path9);
|
|
8199
8199
|
printEntry(entry, modeOf(ctx));
|
|
8200
8200
|
}
|
|
8201
8201
|
);
|
|
8202
8202
|
}
|
|
8203
|
-
function lookupForDescribe(idOrMethod,
|
|
8204
|
-
if (
|
|
8203
|
+
function lookupForDescribe(idOrMethod, path9) {
|
|
8204
|
+
if (path9 !== void 0) {
|
|
8205
8205
|
const method = idOrMethod.trim().toUpperCase();
|
|
8206
8206
|
if (!METHODS.includes(method)) {
|
|
8207
8207
|
throw new UsageError(`"${idOrMethod}" is not an HTTP method`, {
|
|
8208
8208
|
hint: `the methods are ${METHODS.join(", ")} \u2014 or pass a single catalog id instead`
|
|
8209
8209
|
});
|
|
8210
8210
|
}
|
|
8211
|
-
const normalized = normalizePath(
|
|
8211
|
+
const normalized = normalizePath(path9.trim());
|
|
8212
8212
|
const matches = matchPath(normalized).filter((entry2) => entry2.method === method);
|
|
8213
8213
|
const entry = matches[0];
|
|
8214
8214
|
if (entry === void 0) {
|
|
@@ -8385,26 +8385,26 @@ function parseRefList(raw) {
|
|
|
8385
8385
|
function parseProperties(raw) {
|
|
8386
8386
|
return typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : void 0;
|
|
8387
8387
|
}
|
|
8388
|
-
async function fetchPageOf(ctx,
|
|
8389
|
-
const raw = await fetchPage(ctx,
|
|
8388
|
+
async function fetchPageOf(ctx, path9, query, page, parse) {
|
|
8389
|
+
const raw = await fetchPage(ctx, path9, query, page);
|
|
8390
8390
|
return { ...raw, values: raw.values.map(parse) };
|
|
8391
8391
|
}
|
|
8392
|
-
async function* iterateOf(ctx,
|
|
8393
|
-
for await (const raw of paginate(ctx,
|
|
8392
|
+
async function* iterateOf(ctx, path9, query, options, parse) {
|
|
8393
|
+
for await (const raw of paginate(ctx, path9, query, options)) {
|
|
8394
8394
|
yield parse(raw);
|
|
8395
8395
|
}
|
|
8396
8396
|
}
|
|
8397
|
-
async function listAllOf(ctx,
|
|
8397
|
+
async function listAllOf(ctx, path9, query, parse, options = {}) {
|
|
8398
8398
|
return await collect(
|
|
8399
|
-
iterateOf(ctx,
|
|
8399
|
+
iterateOf(ctx, path9, query, { pageSize: 100, limit: 1e3, ...options }, parse)
|
|
8400
8400
|
);
|
|
8401
8401
|
}
|
|
8402
|
-
async function fetchSearchPageOf(ctx,
|
|
8403
|
-
const raw = await fetchSearchPage(ctx,
|
|
8402
|
+
async function fetchSearchPageOf(ctx, path9, payload, page, parse) {
|
|
8403
|
+
const raw = await fetchSearchPage(ctx, path9, payload, page);
|
|
8404
8404
|
return { ...raw, values: raw.values.map(parse) };
|
|
8405
8405
|
}
|
|
8406
|
-
async function* iterateSearchOf(ctx,
|
|
8407
|
-
for await (const raw of searchPaginate(ctx,
|
|
8406
|
+
async function* iterateSearchOf(ctx, path9, payload, options, parse) {
|
|
8407
|
+
for await (const raw of searchPaginate(ctx, path9, payload, options)) {
|
|
8408
8408
|
yield parse(raw);
|
|
8409
8409
|
}
|
|
8410
8410
|
}
|
|
@@ -12936,13 +12936,13 @@ var init_projectMember = __esm({
|
|
|
12936
12936
|
|
|
12937
12937
|
// src/cli/commands/_shared/bulkEntries.ts
|
|
12938
12938
|
async function readBulkEntries(source, options) {
|
|
12939
|
-
const
|
|
12940
|
-
if (
|
|
12939
|
+
const path9 = source.file?.trim() ?? "";
|
|
12940
|
+
if (path9 === "") {
|
|
12941
12941
|
throw new UsageError("--file <path|-> is required", {
|
|
12942
12942
|
hint: "pass a JSON array of entries, or - to read it from stdin. Each entry needs name, start and end; project and assignee may be shared with --project / --assignee"
|
|
12943
12943
|
});
|
|
12944
12944
|
}
|
|
12945
|
-
const document =
|
|
12945
|
+
const document = path9 === "-" ? await readJsonStdin() : parseJsonDocument(await readTextFile(path9, "--file"), `--file ${path9}`);
|
|
12946
12946
|
const list = unwrap(document, options.wrapperKey);
|
|
12947
12947
|
if (list.length === 0) {
|
|
12948
12948
|
throw new UsageError("--file contained no entries", {
|
|
@@ -17614,21 +17614,9 @@ function skillTargets(env = process.env) {
|
|
|
17614
17614
|
}
|
|
17615
17615
|
];
|
|
17616
17616
|
}
|
|
17617
|
-
function installDir(env = process.env) {
|
|
17618
|
-
if (process.platform === "win32") {
|
|
17619
|
-
const base = env["LOCALAPPDATA"];
|
|
17620
|
-
const root3 = base !== void 0 && base !== "" ? base : path4.join(os2.homedir(), "AppData", "Local");
|
|
17621
|
-
return path4.join(root3, APP_NAME);
|
|
17622
|
-
}
|
|
17623
|
-
const xdg = env["XDG_DATA_HOME"];
|
|
17624
|
-
const root2 = xdg !== void 0 && xdg !== "" ? xdg : path4.join(os2.homedir(), ".local", "share");
|
|
17625
|
-
return path4.join(root2, APP_NAME);
|
|
17626
|
-
}
|
|
17627
|
-
var APP_NAME;
|
|
17628
17617
|
var init_paths = __esm({
|
|
17629
17618
|
"src/core/paths.ts"() {
|
|
17630
17619
|
"use strict";
|
|
17631
|
-
APP_NAME = "pingcode-cli";
|
|
17632
17620
|
}
|
|
17633
17621
|
});
|
|
17634
17622
|
|
|
@@ -17639,18 +17627,21 @@ import {
|
|
|
17639
17627
|
mkdirSync as mkdirSync3,
|
|
17640
17628
|
readFileSync as readFileSync3,
|
|
17641
17629
|
readdirSync,
|
|
17642
|
-
renameSync as renameSync2,
|
|
17643
17630
|
rmSync as rmSync3,
|
|
17644
17631
|
statSync as statSync2,
|
|
17645
17632
|
utimesSync,
|
|
17646
17633
|
writeFileSync as writeFileSync3
|
|
17647
17634
|
} from "fs";
|
|
17648
17635
|
import { execFileSync } from "child_process";
|
|
17649
|
-
import os3 from "os";
|
|
17650
17636
|
import path5 from "path";
|
|
17651
|
-
import {
|
|
17637
|
+
import { fileURLToPath } from "url";
|
|
17652
17638
|
function defaultExec(file, args) {
|
|
17653
|
-
|
|
17639
|
+
const isWindowsBatch = /\.(cmd|bat)$/i.test(file);
|
|
17640
|
+
return execFileSync(file, args, {
|
|
17641
|
+
encoding: "utf8",
|
|
17642
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
17643
|
+
...isWindowsBatch ? { shell: true } : {}
|
|
17644
|
+
});
|
|
17654
17645
|
}
|
|
17655
17646
|
function defaultFetch(input, init) {
|
|
17656
17647
|
return init === void 0 ? globalThis.fetch(input) : globalThis.fetch(input, init);
|
|
@@ -17711,180 +17702,82 @@ async function fetchLatestInfo(fetchFn = defaultFetch) {
|
|
|
17711
17702
|
}
|
|
17712
17703
|
return { version: latest, tarballUrl };
|
|
17713
17704
|
}
|
|
17714
|
-
|
|
17715
|
-
|
|
17716
|
-
|
|
17717
|
-
|
|
17718
|
-
|
|
17719
|
-
|
|
17720
|
-
|
|
17721
|
-
|
|
17722
|
-
}
|
|
17723
|
-
if (!response.ok) {
|
|
17705
|
+
function resolveNpm() {
|
|
17706
|
+
const binDir = path5.dirname(process.execPath);
|
|
17707
|
+
const candidates = process.platform === "win32" ? [path5.join(binDir, "npm.cmd"), path5.join(binDir, "npm")] : [path5.join(binDir, "npm")];
|
|
17708
|
+
return candidates.find(existsSync2);
|
|
17709
|
+
}
|
|
17710
|
+
async function installViaNpm(exec, version) {
|
|
17711
|
+
const npm = resolveNpm();
|
|
17712
|
+
if (npm === void 0) {
|
|
17724
17713
|
throw new TransportError(
|
|
17725
|
-
`
|
|
17726
|
-
{
|
|
17714
|
+
`cannot update: no npm binary found next to the node running this command (tried ${path5.join(path5.dirname(process.execPath), "npm")})`,
|
|
17715
|
+
{ hint: `install Node.js, then re-run this command` }
|
|
17727
17716
|
);
|
|
17728
17717
|
}
|
|
17729
|
-
|
|
17730
|
-
|
|
17731
|
-
}
|
|
17732
|
-
const chunks = [];
|
|
17733
|
-
const reader = response.body.getReader();
|
|
17734
|
-
const MAX_SIZE = 50 * 1024 * 1024;
|
|
17735
|
-
let total = 0;
|
|
17736
|
-
while (true) {
|
|
17737
|
-
const { done, value } = await reader.read();
|
|
17738
|
-
if (done) break;
|
|
17739
|
-
total += value.length;
|
|
17740
|
-
if (total > MAX_SIZE) {
|
|
17741
|
-
throw new TransportError(`tarball exceeds maximum size of ${MAX_SIZE} bytes`);
|
|
17742
|
-
}
|
|
17743
|
-
chunks.push(value);
|
|
17744
|
-
}
|
|
17745
|
-
return Buffer.concat(chunks);
|
|
17746
|
-
}
|
|
17747
|
-
function extractTarball(buffer, destDir) {
|
|
17748
|
-
const gzipped = gunzipSync(buffer);
|
|
17749
|
-
return extractTar(gzipped, destDir);
|
|
17750
|
-
}
|
|
17751
|
-
function extractTar(tarBuffer, destDir) {
|
|
17752
|
-
const resolvedDest = path5.resolve(destDir);
|
|
17753
|
-
mkdirSync3(resolvedDest, { recursive: true });
|
|
17754
|
-
const extracted = [];
|
|
17755
|
-
let offset = 0;
|
|
17756
|
-
while (offset < tarBuffer.length) {
|
|
17757
|
-
if (offset + 512 > tarBuffer.length) break;
|
|
17758
|
-
const headerBlock = tarBuffer.subarray(offset, offset + 512);
|
|
17759
|
-
if (headerBlock.every((b) => b === 0)) {
|
|
17760
|
-
break;
|
|
17761
|
-
}
|
|
17762
|
-
const name = readTarString(headerBlock, 0, 100);
|
|
17763
|
-
const typeflag = tarBuffer[offset + 156];
|
|
17764
|
-
const size = readTarNumber(headerBlock, 124, 12);
|
|
17765
|
-
offset += 512;
|
|
17766
|
-
const dataBlocks = Math.ceil(size / 512);
|
|
17767
|
-
const dataOffset = offset;
|
|
17768
|
-
if (typeflag === "5".charCodeAt(0)) {
|
|
17769
|
-
const cleanName = stripPackagePrefix(name);
|
|
17770
|
-
if (cleanName) {
|
|
17771
|
-
const dest = path5.resolve(resolvedDest, cleanName);
|
|
17772
|
-
if (dest.startsWith(resolvedDest + path5.sep) || dest === resolvedDest) {
|
|
17773
|
-
mkdirSync3(dest, { recursive: true });
|
|
17774
|
-
}
|
|
17775
|
-
}
|
|
17776
|
-
} else if (typeflag === "0".charCodeAt(0) || typeflag === 0) {
|
|
17777
|
-
const cleanName = stripPackagePrefix(name);
|
|
17778
|
-
if (cleanName) {
|
|
17779
|
-
const data = tarBuffer.subarray(dataOffset, dataOffset + size);
|
|
17780
|
-
const dest = path5.resolve(resolvedDest, cleanName);
|
|
17781
|
-
if (dest.startsWith(resolvedDest + path5.sep)) {
|
|
17782
|
-
mkdirSync3(path5.dirname(dest), { recursive: true });
|
|
17783
|
-
writeFileSync3(dest, data);
|
|
17784
|
-
extracted.push(cleanName);
|
|
17785
|
-
}
|
|
17786
|
-
}
|
|
17787
|
-
}
|
|
17788
|
-
offset += dataBlocks * 512;
|
|
17789
|
-
}
|
|
17790
|
-
return extracted;
|
|
17791
|
-
}
|
|
17792
|
-
function stripPackagePrefix(name) {
|
|
17793
|
-
if (name.startsWith("package/")) {
|
|
17794
|
-
return name.slice("package/".length);
|
|
17795
|
-
}
|
|
17796
|
-
return name;
|
|
17797
|
-
}
|
|
17798
|
-
function readTarString(buf, start, maxLen) {
|
|
17799
|
-
const end = buf.indexOf(0, start);
|
|
17800
|
-
const actualEnd = end < 0 ? start + maxLen : end;
|
|
17801
|
-
return buf.subarray(start, actualEnd).toString("utf8").trim();
|
|
17802
|
-
}
|
|
17803
|
-
function readTarNumber(buf, start, maxLen) {
|
|
17804
|
-
const str2 = readTarString(buf, start, maxLen);
|
|
17805
|
-
if (str2.charCodeAt(0) === 128) {
|
|
17806
|
-
return 0;
|
|
17807
|
-
}
|
|
17808
|
-
return parseInt(str2, 8) || 0;
|
|
17809
|
-
}
|
|
17810
|
-
async function atomicReplace(current, staging) {
|
|
17811
|
-
const backup = `${current}.backup`;
|
|
17812
|
-
if (existsSync2(backup)) {
|
|
17813
|
-
rmSync3(backup, { recursive: true, force: true });
|
|
17814
|
-
}
|
|
17815
|
-
const isNested = staging.startsWith(`${current}${path5.sep}`);
|
|
17816
|
-
const incoming = isNested ? `${current}.incoming` : staging;
|
|
17817
|
-
if (isNested) {
|
|
17818
|
-
if (existsSync2(incoming)) rmSync3(incoming, { recursive: true, force: true });
|
|
17819
|
-
try {
|
|
17820
|
-
renameSync2(staging, incoming);
|
|
17821
|
-
} catch (error) {
|
|
17822
|
-
throw new TransportError(
|
|
17823
|
-
`failed to move staging aside: ${errorMessage2(error)}`,
|
|
17824
|
-
{ cause: error }
|
|
17825
|
-
);
|
|
17826
|
-
}
|
|
17827
|
-
}
|
|
17828
|
-
if (existsSync2(current)) {
|
|
17829
|
-
try {
|
|
17830
|
-
renameSync2(current, backup);
|
|
17831
|
-
} catch (error) {
|
|
17832
|
-
if (isNested && existsSync2(incoming)) {
|
|
17833
|
-
try {
|
|
17834
|
-
renameSync2(incoming, staging);
|
|
17835
|
-
} catch {
|
|
17836
|
-
}
|
|
17837
|
-
}
|
|
17838
|
-
throw new TransportError(
|
|
17839
|
-
`failed to back up current install: ${errorMessage2(error)}`,
|
|
17840
|
-
{ cause: error }
|
|
17841
|
-
);
|
|
17842
|
-
}
|
|
17843
|
-
}
|
|
17718
|
+
const spec = `${PACKAGE_NAME2}@${version}`;
|
|
17719
|
+
let output;
|
|
17844
17720
|
try {
|
|
17845
|
-
|
|
17721
|
+
output = exec(npm, ["install", "--global", spec]);
|
|
17846
17722
|
} catch (error) {
|
|
17847
|
-
|
|
17848
|
-
if (existsSync2(backup)) renameSync2(backup, current);
|
|
17849
|
-
} catch (restoreError) {
|
|
17850
|
-
throw new TransportError(
|
|
17851
|
-
`CRITICAL: update failed AND backup restore failed. Restore manually: mv "${backup}" "${current}". Original error: ${errorMessage2(error)}. Restore error: ${errorMessage2(restoreError)}`,
|
|
17852
|
-
{ cause: error }
|
|
17853
|
-
);
|
|
17854
|
-
}
|
|
17723
|
+
const detail = npmOutputOf(error);
|
|
17855
17724
|
throw new TransportError(
|
|
17856
|
-
`
|
|
17725
|
+
`npm install --global ${spec} failed (exit ${exitStatusOf(error)}): ${errorMessage2(error)}`,
|
|
17857
17726
|
{
|
|
17858
|
-
hint: `
|
|
17727
|
+
hint: detail === "" ? `npm printed nothing; try running manually: ${npm} install --global ${spec}` : detail,
|
|
17859
17728
|
cause: error
|
|
17860
17729
|
}
|
|
17861
17730
|
);
|
|
17862
17731
|
}
|
|
17863
|
-
|
|
17864
|
-
|
|
17865
|
-
|
|
17866
|
-
|
|
17732
|
+
const trimmed = output.trim();
|
|
17733
|
+
if (trimmed !== "") {
|
|
17734
|
+
process.stderr.write(`${output.endsWith("\n") ? output : `${output}
|
|
17735
|
+
`}`);
|
|
17736
|
+
}
|
|
17737
|
+
const installed = readInstalledVersion();
|
|
17738
|
+
if (installed !== version) {
|
|
17739
|
+
throw new TransportError(
|
|
17740
|
+
`npm install --global ${spec} exited 0 but the installed version is ${installed ?? "unreadable"}, expected ${version}`,
|
|
17741
|
+
{ hint: `verify with: ${npm} list --global --depth=0 ${PACKAGE_NAME2}` }
|
|
17742
|
+
);
|
|
17867
17743
|
}
|
|
17868
17744
|
}
|
|
17869
|
-
function
|
|
17870
|
-
|
|
17871
|
-
|
|
17745
|
+
function readInstalledVersion() {
|
|
17746
|
+
try {
|
|
17747
|
+
const raw = readFileSync3(fileURLToPath(new URL("../../package.json", import.meta.url)), "utf8");
|
|
17748
|
+
const parsed = JSON.parse(raw);
|
|
17749
|
+
if (typeof parsed !== "object" || parsed === null) return void 0;
|
|
17750
|
+
const version = parsed.version;
|
|
17751
|
+
return typeof version === "string" ? version : void 0;
|
|
17752
|
+
} catch {
|
|
17753
|
+
return void 0;
|
|
17754
|
+
}
|
|
17872
17755
|
}
|
|
17873
|
-
function
|
|
17874
|
-
|
|
17756
|
+
function exitStatusOf(error) {
|
|
17757
|
+
if (typeof error === "object" && error !== null && "status" in error) {
|
|
17758
|
+
const status = error.status;
|
|
17759
|
+
if (typeof status === "number") return String(status);
|
|
17760
|
+
if (typeof status === "string" && status !== "") return status;
|
|
17761
|
+
}
|
|
17762
|
+
return "unknown";
|
|
17875
17763
|
}
|
|
17876
|
-
function
|
|
17877
|
-
|
|
17764
|
+
function npmOutputOf(error) {
|
|
17765
|
+
if (typeof error !== "object" || error === null) return "";
|
|
17766
|
+
const e = error;
|
|
17767
|
+
return [e.stderr, e.stdout].filter((part) => part !== void 0 && part !== null).map((part) => String(part).trim()).filter((part) => part !== "").join("\n");
|
|
17878
17768
|
}
|
|
17879
17769
|
function removeFile(filePath) {
|
|
17880
17770
|
try {
|
|
17881
|
-
rmSync3(filePath, {
|
|
17771
|
+
rmSync3(filePath, { force: true });
|
|
17882
17772
|
} catch {
|
|
17883
17773
|
}
|
|
17884
17774
|
}
|
|
17885
17775
|
function dirExists(dirPath) {
|
|
17886
17776
|
return existsSync2(dirPath);
|
|
17887
17777
|
}
|
|
17778
|
+
function packageSkillDir() {
|
|
17779
|
+
return fileURLToPath(new URL("../../skills/pingcode", import.meta.url));
|
|
17780
|
+
}
|
|
17888
17781
|
async function syncSkills(sourceDir, targets) {
|
|
17889
17782
|
const written = [];
|
|
17890
17783
|
const payload = [];
|
|
@@ -17913,43 +17806,6 @@ async function syncSkills(sourceDir, targets) {
|
|
|
17913
17806
|
}
|
|
17914
17807
|
return written;
|
|
17915
17808
|
}
|
|
17916
|
-
function verifyBundle(dir, exec, expectedVersion) {
|
|
17917
|
-
const bin = path5.join(dir, "dist", "bin", "pingcode.js");
|
|
17918
|
-
let reported;
|
|
17919
|
-
try {
|
|
17920
|
-
reported = exec("node", [bin, "--version"]).trim();
|
|
17921
|
-
} catch (error) {
|
|
17922
|
-
throw new TransportError(
|
|
17923
|
-
`failed to verify new installation: ${errorMessage2(error)}`,
|
|
17924
|
-
{
|
|
17925
|
-
hint: `try running manually: node "${bin}" --version`,
|
|
17926
|
-
cause: error
|
|
17927
|
-
}
|
|
17928
|
-
);
|
|
17929
|
-
}
|
|
17930
|
-
if (reported !== expectedVersion) {
|
|
17931
|
-
throw new TransportError(
|
|
17932
|
-
`installed bundle reports version ${reported}, expected ${expectedVersion}`,
|
|
17933
|
-
{ hint: `try running manually: node "${bin}" --version` }
|
|
17934
|
-
);
|
|
17935
|
-
}
|
|
17936
|
-
return reported;
|
|
17937
|
-
}
|
|
17938
|
-
function restoreBackup(current) {
|
|
17939
|
-
const backup = `${current}.backup`;
|
|
17940
|
-
rmSync3(current, { recursive: true, force: true });
|
|
17941
|
-
try {
|
|
17942
|
-
renameSync2(backup, current);
|
|
17943
|
-
} catch (error) {
|
|
17944
|
-
throw new TransportError(
|
|
17945
|
-
`failed to restore the previous install: ${errorMessage2(error)}`,
|
|
17946
|
-
{
|
|
17947
|
-
hint: `restore manually: mv "${backup}" "${current}"`,
|
|
17948
|
-
cause: error
|
|
17949
|
-
}
|
|
17950
|
-
);
|
|
17951
|
-
}
|
|
17952
|
-
}
|
|
17953
17809
|
function acquireLock(dir) {
|
|
17954
17810
|
const lockPath = path5.join(dir, LOCK_FILENAME);
|
|
17955
17811
|
try {
|
|
@@ -18023,7 +17879,6 @@ function removeHint(dir) {
|
|
|
18023
17879
|
removeFile(path5.join(dir, HINT_FILENAME));
|
|
18024
17880
|
}
|
|
18025
17881
|
async function runAutoUpdate(env = process.env, fetchFn = defaultFetch, exec = defaultExec) {
|
|
18026
|
-
const dir = installDir(env);
|
|
18027
17882
|
const stateDir = configDir(env);
|
|
18028
17883
|
try {
|
|
18029
17884
|
touchCooldown(stateDir);
|
|
@@ -18049,44 +17904,16 @@ async function runAutoUpdate(env = process.env, fetchFn = defaultFetch, exec = d
|
|
|
18049
17904
|
return { status: "up-to-date" };
|
|
18050
17905
|
}
|
|
18051
17906
|
const newVersion = info.version;
|
|
18052
|
-
|
|
18053
|
-
const
|
|
18054
|
-
|
|
17907
|
+
await installViaNpm(exec, newVersion);
|
|
17908
|
+
const skillSource = packageSkillDir();
|
|
17909
|
+
if (dirExists(skillSource)) {
|
|
17910
|
+
await syncSkills(skillSource, skillTargets(env));
|
|
17911
|
+
}
|
|
18055
17912
|
try {
|
|
18056
|
-
|
|
18057
|
-
|
|
18058
|
-
mkdirSync3(stagingDir, { recursive: true });
|
|
18059
|
-
extractTarball(tarballBuffer, stagingDir);
|
|
18060
|
-
if (!validateStaging(stagingDir)) {
|
|
18061
|
-
cleanStaging(stagingDir);
|
|
18062
|
-
throw new TransportError("invalid tarball: dist/bin/pingcode.js not found");
|
|
18063
|
-
}
|
|
18064
|
-
try {
|
|
18065
|
-
verifyBundle(stagingDir, exec, newVersion);
|
|
18066
|
-
} catch (error) {
|
|
18067
|
-
cleanStaging(stagingDir);
|
|
18068
|
-
throw error;
|
|
18069
|
-
}
|
|
18070
|
-
await atomicReplace(dir, stagingDir);
|
|
18071
|
-
const skillSource = path5.join(dir, "skills", "pingcode");
|
|
18072
|
-
if (dirExists(skillSource)) {
|
|
18073
|
-
await syncSkills(skillSource, skillTargets(env));
|
|
18074
|
-
}
|
|
18075
|
-
try {
|
|
18076
|
-
verifyBundle(dir, exec, newVersion);
|
|
18077
|
-
} catch (error) {
|
|
18078
|
-
restoreBackup(dir);
|
|
18079
|
-
throw error;
|
|
18080
|
-
}
|
|
18081
|
-
removeFile(`${dir}.backup`);
|
|
18082
|
-
try {
|
|
18083
|
-
removeHint(stateDir);
|
|
18084
|
-
} catch {
|
|
18085
|
-
}
|
|
18086
|
-
return { status: "updated", version: newVersion };
|
|
18087
|
-
} finally {
|
|
18088
|
-
removeFile(tmpTarball);
|
|
17913
|
+
removeHint(stateDir);
|
|
17914
|
+
} catch {
|
|
18089
17915
|
}
|
|
17916
|
+
return { status: "updated", version: newVersion };
|
|
18090
17917
|
} catch (error) {
|
|
18091
17918
|
if (info !== void 0) {
|
|
18092
17919
|
try {
|
|
@@ -18121,10 +17948,9 @@ var init_update = __esm({
|
|
|
18121
17948
|
|
|
18122
17949
|
// src/cli/commands/selfUpdate.ts
|
|
18123
17950
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
18124
|
-
import os4 from "os";
|
|
18125
17951
|
import path6 from "path";
|
|
18126
17952
|
function registerSelfUpdateCommands(program2) {
|
|
18127
|
-
const cmd = program2.command("self-update").description("update the CLI to the latest npm-published version").option("--check-only", "check for updates without
|
|
17953
|
+
const cmd = program2.command("self-update").description("update the CLI to the latest npm-published version").option("--check-only", "check for updates without installing").option("--force", "force update even if already up to date");
|
|
18128
17954
|
addGlobalOptions(cmd).action(async (flags, command) => {
|
|
18129
17955
|
await runSelfUpdate(flags, command);
|
|
18130
17956
|
});
|
|
@@ -18173,73 +17999,45 @@ async function runSelfUpdate(flags, command) {
|
|
|
18173
17999
|
}
|
|
18174
18000
|
const oldVersion = VERSION;
|
|
18175
18001
|
const newVersion = info.version;
|
|
18176
|
-
const tarballBuffer = await downloadTarball(info.tarballUrl);
|
|
18177
|
-
const tarballName = path6.basename(new URL(info.tarballUrl).pathname);
|
|
18178
|
-
const install = installDir();
|
|
18179
|
-
const stagingDir = path6.join(install, ".staging");
|
|
18180
18002
|
if (ctx.dryRun) {
|
|
18181
18003
|
printDryRunPlan({
|
|
18182
18004
|
oldVersion,
|
|
18183
18005
|
newVersion,
|
|
18184
|
-
assetName:
|
|
18006
|
+
assetName: path6.basename(new URL(info.tarballUrl).pathname),
|
|
18185
18007
|
downloadUrl: info.tarballUrl,
|
|
18186
|
-
install,
|
|
18187
|
-
stagingDir,
|
|
18188
18008
|
json: mode.json
|
|
18189
18009
|
});
|
|
18190
18010
|
return;
|
|
18191
18011
|
}
|
|
18192
|
-
errLine(paint.dim(`
|
|
18193
|
-
errLine(paint.dim("Extracting to staging..."));
|
|
18194
|
-
const tmpTarball = path6.join(os4.tmpdir(), `pingcode-cli-${newVersion}.tgz`);
|
|
18012
|
+
errLine(paint.dim(`Installing v${newVersion}...`));
|
|
18195
18013
|
try {
|
|
18196
|
-
|
|
18197
|
-
|
|
18198
|
-
|
|
18199
|
-
|
|
18200
|
-
|
|
18201
|
-
|
|
18202
|
-
throw new TransportError(
|
|
18203
|
-
"invalid tarball: dist/bin/pingcode.js not found"
|
|
18204
|
-
);
|
|
18205
|
-
}
|
|
18206
|
-
errLine(paint.dim("Verifying..."));
|
|
18207
|
-
const exec = (file, args) => String(execFileSync2(file, args, { encoding: "utf8" }));
|
|
18208
|
-
verifyBundle(stagingDir, exec, newVersion);
|
|
18209
|
-
errLine(paint.dim(`Installing v${newVersion}...`));
|
|
18210
|
-
await atomicReplace(install, stagingDir);
|
|
18211
|
-
const skillSource = path6.join(install, "skills", "pingcode");
|
|
18212
|
-
if (dirExists(skillSource)) {
|
|
18213
|
-
errLine(paint.dim("Syncing skills..."));
|
|
18214
|
-
await syncSkills(skillSource, skillTargets());
|
|
18215
|
-
}
|
|
18216
|
-
let verified;
|
|
18217
|
-
try {
|
|
18218
|
-
verified = verifyBundle(install, exec, newVersion);
|
|
18219
|
-
} catch (error) {
|
|
18220
|
-
restoreBackup(install);
|
|
18221
|
-
throw new TransportError(
|
|
18222
|
-
`installed bundle failed verification: ${error instanceof Error ? error.message : String(error)}`,
|
|
18223
|
-
{
|
|
18224
|
-
hint: `restore manually: mv "${install}.backup" "${install}"`,
|
|
18225
|
-
cause: error
|
|
18226
|
-
}
|
|
18227
|
-
);
|
|
18228
|
-
}
|
|
18229
|
-
removeFile(`${install}.backup`);
|
|
18230
|
-
if (mode.json) {
|
|
18231
|
-
printJson({
|
|
18232
|
-
status: "updated",
|
|
18233
|
-
previous_version: oldVersion,
|
|
18234
|
-
new_version: verified
|
|
18235
|
-
});
|
|
18236
|
-
} else {
|
|
18237
|
-
errLine(paint.green(`updated v${oldVersion} \u2192 v${verified}`));
|
|
18014
|
+
await installViaNpm(cliExec, newVersion);
|
|
18015
|
+
} catch (error) {
|
|
18016
|
+
if (!mode.json) {
|
|
18017
|
+
errLine(paint.red(`update failed: ${errorMessageOf(error)}`));
|
|
18018
|
+
const hint = error instanceof TransportError ? error.hint : void 0;
|
|
18019
|
+
if (hint !== void 0 && hint !== "") errLine(paint.dim(` ${hint}`));
|
|
18238
18020
|
}
|
|
18239
|
-
|
|
18240
|
-
|
|
18021
|
+
throw error;
|
|
18022
|
+
}
|
|
18023
|
+
const skillSource = packageSkillDir();
|
|
18024
|
+
if (dirExists(skillSource)) {
|
|
18025
|
+
errLine(paint.dim("Syncing skills..."));
|
|
18026
|
+
await syncSkills(skillSource, skillTargets());
|
|
18027
|
+
}
|
|
18028
|
+
if (mode.json) {
|
|
18029
|
+
printJson({
|
|
18030
|
+
status: "updated",
|
|
18031
|
+
previous_version: oldVersion,
|
|
18032
|
+
new_version: newVersion
|
|
18033
|
+
});
|
|
18034
|
+
} else {
|
|
18035
|
+
errLine(paint.green(`updated v${oldVersion} \u2192 v${newVersion}`));
|
|
18241
18036
|
}
|
|
18242
18037
|
}
|
|
18038
|
+
function errorMessageOf(error) {
|
|
18039
|
+
return error instanceof Error ? error.message : String(error);
|
|
18040
|
+
}
|
|
18243
18041
|
function printCheckResult(check, json) {
|
|
18244
18042
|
if (json) {
|
|
18245
18043
|
printJson({
|
|
@@ -18272,8 +18070,6 @@ function printDryRunPlan(plan) {
|
|
|
18272
18070
|
target_version: plan.newVersion,
|
|
18273
18071
|
asset: plan.assetName,
|
|
18274
18072
|
download_url: plan.downloadUrl,
|
|
18275
|
-
install_dir: plan.install,
|
|
18276
|
-
staging_dir: plan.stagingDir,
|
|
18277
18073
|
skill_targets: skillTargets().map((t) => t.dir)
|
|
18278
18074
|
});
|
|
18279
18075
|
return;
|
|
@@ -18282,10 +18078,9 @@ function printDryRunPlan(plan) {
|
|
|
18282
18078
|
errLine(` current: v${plan.oldVersion}`);
|
|
18283
18079
|
errLine(` target: v${plan.newVersion}`);
|
|
18284
18080
|
errLine(` asset: ${plan.assetName}`);
|
|
18285
|
-
errLine(` install: ${plan.install}`);
|
|
18286
|
-
errLine(` staging: ${plan.stagingDir}`);
|
|
18287
18081
|
errLine(` skills: ${skillTargets().map((t) => t.dir).join(", ")}`);
|
|
18288
18082
|
}
|
|
18083
|
+
var cliExec;
|
|
18289
18084
|
var init_selfUpdate = __esm({
|
|
18290
18085
|
"src/cli/commands/selfUpdate.ts"() {
|
|
18291
18086
|
"use strict";
|
|
@@ -18293,11 +18088,11 @@ var init_selfUpdate = __esm({
|
|
|
18293
18088
|
init_update_check();
|
|
18294
18089
|
init_update();
|
|
18295
18090
|
init_errors();
|
|
18296
|
-
init_update();
|
|
18297
18091
|
init_common();
|
|
18298
18092
|
init_output();
|
|
18299
18093
|
init_globals();
|
|
18300
18094
|
init_paths();
|
|
18095
|
+
cliExec = (file, args) => execFileSync2(file, args, { encoding: "utf8" });
|
|
18301
18096
|
}
|
|
18302
18097
|
});
|
|
18303
18098
|
|
|
@@ -18466,6 +18261,10 @@ var init_skill_ops = __esm({
|
|
|
18466
18261
|
});
|
|
18467
18262
|
|
|
18468
18263
|
// src/cli/commands/skill.ts
|
|
18264
|
+
import path8 from "path";
|
|
18265
|
+
function packageSkillRoot() {
|
|
18266
|
+
return path8.dirname(path8.dirname(packageSkillDir()));
|
|
18267
|
+
}
|
|
18469
18268
|
function registerSkillCommands(program2) {
|
|
18470
18269
|
const skill = program2.command("skill").description("manage the pingcode skill across agent targets");
|
|
18471
18270
|
skill.command("list").description("show where the skill is installed").action(async (flags) => {
|
|
@@ -18528,7 +18327,7 @@ async function runInstall(flags) {
|
|
|
18528
18327
|
const { ctx } = contextFor(command);
|
|
18529
18328
|
const mode = modeOf(ctx);
|
|
18530
18329
|
const targets = resolveTargets(flags);
|
|
18531
|
-
const sourceRoot =
|
|
18330
|
+
const sourceRoot = packageSkillRoot();
|
|
18532
18331
|
const results = installSkill(sourceRoot, targets, flags.force ?? false);
|
|
18533
18332
|
renderResults(results, mode);
|
|
18534
18333
|
}
|
|
@@ -18545,7 +18344,7 @@ async function runUpdate16(flags) {
|
|
|
18545
18344
|
const { ctx } = contextFor(command);
|
|
18546
18345
|
const mode = modeOf(ctx);
|
|
18547
18346
|
const targets = resolveTargets(flags);
|
|
18548
|
-
const sourceRoot =
|
|
18347
|
+
const sourceRoot = packageSkillRoot();
|
|
18549
18348
|
const results = installSkill(sourceRoot, targets, true);
|
|
18550
18349
|
renderResults(results, mode);
|
|
18551
18350
|
}
|
|
@@ -18604,6 +18403,7 @@ var init_skill = __esm({
|
|
|
18604
18403
|
"src/cli/commands/skill.ts"() {
|
|
18605
18404
|
"use strict";
|
|
18606
18405
|
init_paths();
|
|
18406
|
+
init_update();
|
|
18607
18407
|
init_skill_ops();
|
|
18608
18408
|
init_globals();
|
|
18609
18409
|
init_output();
|
|
@@ -19081,11 +18881,11 @@ var init_libraries = __esm({
|
|
|
19081
18881
|
|
|
19082
18882
|
// src/cli/commands/testhub/entries.ts
|
|
19083
18883
|
async function readEntryFile(source, schema, hint) {
|
|
19084
|
-
const
|
|
19085
|
-
if (
|
|
18884
|
+
const path9 = source.file?.trim() ?? "";
|
|
18885
|
+
if (path9 === "") {
|
|
19086
18886
|
throw new UsageError("--file <path|-> is required", { hint });
|
|
19087
18887
|
}
|
|
19088
|
-
const document =
|
|
18888
|
+
const document = path9 === "-" ? await readJsonStdin() : parseJsonDocument(await readTextFile(path9, "--file"), `--file ${path9}`);
|
|
19089
18889
|
const list = unwrap2(document, schema.wrapperKey);
|
|
19090
18890
|
if (list.length === 0) {
|
|
19091
18891
|
throw new UsageError("--file contained no entries", {
|