pinsay-cli 0.13.0 → 0.14.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 -0
- package/dist/cli.js +179 -107
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -62,6 +62,11 @@ Full guides: https://pinsay.dev/docs/ · Issues: https://github.com/moamen-ui/pi
|
|
|
62
62
|
|
|
63
63
|
## Changelog
|
|
64
64
|
|
|
65
|
+
### 0.14.0
|
|
66
|
+
|
|
67
|
+
- Custom statuses: `list --status`, `apply --status` and `status <number> <status>` (and the MCP `pinsay_list_comments` / `pinsay_set_status` tools) take a custom status by label or key (`c<id>`), case-insensitive. Output shows the status label; `--json` adds `statusKey` and `statusLabel` next to `status`.
|
|
68
|
+
- An unknown status now exits 2 with the workspace's statuses (MCP: `invalid_input`) instead of listing everything. `apply` alone still means Ready; `applied` stays Completed and is set only by `apply --mark`.
|
|
69
|
+
|
|
65
70
|
### 0.13.0
|
|
66
71
|
|
|
67
72
|
- Comment media in `get` (human output and `--json`) and in the MCP `pinsay_get_comment` / `pinsay_get_queue` tools: recording steps (each with its screenshot), annotated screenshots, voice messages and the files on replies. Each file is named by its saved path (`media[].path`, `element.screenshotPath`; MCP `untrusted.media[].path`).
|
package/dist/cli.js
CHANGED
|
@@ -392,7 +392,7 @@ var init_build_constants = __esm({
|
|
|
392
392
|
"src/build-constants.ts"() {
|
|
393
393
|
"use strict";
|
|
394
394
|
BUILD_DEFAULT_SERVER = true ? "https://app.pinsay.dev" : "https://app.pinsay.dev";
|
|
395
|
-
BUILD_CLI_VERSION = true ? "0.
|
|
395
|
+
BUILD_CLI_VERSION = true ? "0.14.0" : "0.0.0-dev";
|
|
396
396
|
}
|
|
397
397
|
});
|
|
398
398
|
|
|
@@ -3010,23 +3010,84 @@ var init_shared = __esm({
|
|
|
3010
3010
|
}
|
|
3011
3011
|
});
|
|
3012
3012
|
|
|
3013
|
-
// src/
|
|
3014
|
-
function
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
if (
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
if (
|
|
3025
|
-
return
|
|
3026
|
-
if (
|
|
3027
|
-
return
|
|
3013
|
+
// src/statuses.ts
|
|
3014
|
+
function fetchStatuses(client) {
|
|
3015
|
+
const id = `${client.server}|${client.token ?? ""}`;
|
|
3016
|
+
let hit = cache.get(id);
|
|
3017
|
+
if (!hit) {
|
|
3018
|
+
hit = api(client.server, "/api/statuses", { token: client.token }).then((res) => Array.isArray(res) ? res : []).catch(() => []);
|
|
3019
|
+
cache.set(id, hit);
|
|
3020
|
+
}
|
|
3021
|
+
return hit;
|
|
3022
|
+
}
|
|
3023
|
+
function builtinKeyFor(norm) {
|
|
3024
|
+
if (norm in BUILTIN_KEYS)
|
|
3025
|
+
return norm;
|
|
3026
|
+
if (norm in BUILTIN_ALIASES)
|
|
3027
|
+
return BUILTIN_ALIASES[norm];
|
|
3028
|
+
for (const [k, n] of Object.entries(BUILTIN_KEYS))
|
|
3029
|
+
if (String(n) === norm)
|
|
3030
|
+
return k;
|
|
3028
3031
|
return void 0;
|
|
3029
3032
|
}
|
|
3033
|
+
function resolveStatus(input, catalog = []) {
|
|
3034
|
+
const norm = String(input ?? "").trim().toLowerCase();
|
|
3035
|
+
if (!norm)
|
|
3036
|
+
return void 0;
|
|
3037
|
+
const builtin = builtinKeyFor(norm);
|
|
3038
|
+
if (builtin) {
|
|
3039
|
+
const status = BUILTIN_KEYS[builtin];
|
|
3040
|
+
return { key: builtin, status, label: BUILTIN_LABELS[status] };
|
|
3041
|
+
}
|
|
3042
|
+
const custom2 = catalog.filter((c) => c.isCustom !== false && typeof c.key === "string" && !(c.key in BUILTIN_KEYS));
|
|
3043
|
+
const hit = custom2.find((c) => c.key.toLowerCase() === norm) ?? custom2.find((c) => typeof c.label === "string" && c.label.trim().toLowerCase() === norm);
|
|
3044
|
+
if (!hit)
|
|
3045
|
+
return void 0;
|
|
3046
|
+
return { key: hit.key, status: CUSTOM_STATUS, label: hit.label ?? hit.key };
|
|
3047
|
+
}
|
|
3048
|
+
function statusLabel(comment, catalog = []) {
|
|
3049
|
+
if (comment.customStatus?.label)
|
|
3050
|
+
return comment.customStatus.label;
|
|
3051
|
+
if (comment.statusKey) {
|
|
3052
|
+
const hit = catalog.find((c) => c.key === comment.statusKey && c.label);
|
|
3053
|
+
if (hit)
|
|
3054
|
+
return hit.label;
|
|
3055
|
+
}
|
|
3056
|
+
const n = Number(comment.status);
|
|
3057
|
+
if (BUILTIN_NAMES[n])
|
|
3058
|
+
return BUILTIN_NAMES[n];
|
|
3059
|
+
if (n === CUSTOM_STATUS)
|
|
3060
|
+
return "custom";
|
|
3061
|
+
return String(comment.status);
|
|
3062
|
+
}
|
|
3063
|
+
function unknownStatusError(input, catalog = []) {
|
|
3064
|
+
const names = Object.keys(BUILTIN_KEYS);
|
|
3065
|
+
for (const c of catalog) {
|
|
3066
|
+
if (c.isCustom && c.key)
|
|
3067
|
+
names.push(`"${c.label ?? c.key}" (${c.key})`);
|
|
3068
|
+
}
|
|
3069
|
+
return `Unknown status "${input}". This workspace's statuses: ${names.join(", ")}`;
|
|
3070
|
+
}
|
|
3071
|
+
function statusJson(comment, catalog) {
|
|
3072
|
+
const n = Number(comment.status);
|
|
3073
|
+
const key = comment.statusKey ?? Object.entries(BUILTIN_KEYS).find(([, v]) => v === n)?.[0] ?? null;
|
|
3074
|
+
return { statusKey: key, statusLabel: statusLabel(comment, catalog) };
|
|
3075
|
+
}
|
|
3076
|
+
var BUILTIN_KEYS, BUILTIN_ALIASES, BUILTIN_NAMES, BUILTIN_LABELS, CUSTOM_STATUS, cache;
|
|
3077
|
+
var init_statuses = __esm({
|
|
3078
|
+
"src/statuses.ts"() {
|
|
3079
|
+
"use strict";
|
|
3080
|
+
init_api();
|
|
3081
|
+
BUILTIN_KEYS = { open: 1, ready: 2, applied: 3, archived: 4 };
|
|
3082
|
+
BUILTIN_ALIASES = { readytoapply: "ready", completed: "applied" };
|
|
3083
|
+
BUILTIN_NAMES = { 1: "Open", 2: "ReadyToApply", 3: "Applied", 4: "Archived" };
|
|
3084
|
+
BUILTIN_LABELS = { 1: "Open", 2: "Ready", 3: "Applied", 4: "Archived" };
|
|
3085
|
+
CUSTOM_STATUS = 5;
|
|
3086
|
+
cache = /* @__PURE__ */ new Map();
|
|
3087
|
+
}
|
|
3088
|
+
});
|
|
3089
|
+
|
|
3090
|
+
// src/apply/queue.ts
|
|
3030
3091
|
function mapEnvironmentToNumber(env) {
|
|
3031
3092
|
if (env === void 0 || env === null)
|
|
3032
3093
|
return void 0;
|
|
@@ -3045,11 +3106,16 @@ async function fetchQueue(ctx, filter) {
|
|
|
3045
3106
|
return (await fetchQueueShared(ctx, filter)).items;
|
|
3046
3107
|
}
|
|
3047
3108
|
async function fetchQueueShared(ctx, filter) {
|
|
3048
|
-
const statusNum = filter?.status !== void 0 ? mapStatusToNumber(filter.status) : 2;
|
|
3049
3109
|
const envNum = mapEnvironmentToNumber(filter?.environment);
|
|
3050
3110
|
const queryParts = [];
|
|
3051
|
-
if (
|
|
3052
|
-
queryParts.push(
|
|
3111
|
+
if (filter?.status === void 0) {
|
|
3112
|
+
queryParts.push("status=2");
|
|
3113
|
+
} else {
|
|
3114
|
+
const resolved = resolveStatus(filter.status, await fetchStatuses(ctx));
|
|
3115
|
+
if (!resolved)
|
|
3116
|
+
throw new Error(unknownStatusError(String(filter.status), await fetchStatuses(ctx)));
|
|
3117
|
+
queryParts.push(`statusKey=${encodeURIComponent(resolved.key)}`);
|
|
3118
|
+
}
|
|
3053
3119
|
if (envNum !== void 0)
|
|
3054
3120
|
queryParts.push(`environment=${envNum}`);
|
|
3055
3121
|
const qs = queryParts.length > 0 ? `?${queryParts.join("&")}` : "";
|
|
@@ -3072,6 +3138,8 @@ async function fetchQueueShared(ctx, filter) {
|
|
|
3072
3138
|
id: item.id,
|
|
3073
3139
|
number: item.number,
|
|
3074
3140
|
status: item.status,
|
|
3141
|
+
statusKey: item.statusKey ?? null,
|
|
3142
|
+
customStatus: item.customStatus ?? null,
|
|
3075
3143
|
environment: item.environment,
|
|
3076
3144
|
body: item.body ?? "",
|
|
3077
3145
|
authorName: item.authorName ?? null,
|
|
@@ -3157,6 +3225,8 @@ async function fetchQueueShared(ctx, filter) {
|
|
|
3157
3225
|
id: item.id,
|
|
3158
3226
|
number: item.number,
|
|
3159
3227
|
status: item.status,
|
|
3228
|
+
statusKey: item.statusKey ?? null,
|
|
3229
|
+
customStatus: item.customStatus ?? null,
|
|
3160
3230
|
environment: item.environment,
|
|
3161
3231
|
body: item.body ?? "",
|
|
3162
3232
|
authorName: item.authorName ?? null,
|
|
@@ -3203,6 +3273,7 @@ var init_queue = __esm({
|
|
|
3203
3273
|
init_member_rules();
|
|
3204
3274
|
init_media();
|
|
3205
3275
|
init_shared();
|
|
3276
|
+
init_statuses();
|
|
3206
3277
|
warnedNonAdminFallback = false;
|
|
3207
3278
|
}
|
|
3208
3279
|
});
|
|
@@ -3294,6 +3365,7 @@ function toAiCommentView(raw, page, saved) {
|
|
|
3294
3365
|
aiRules,
|
|
3295
3366
|
replies,
|
|
3296
3367
|
status: raw?.status,
|
|
3368
|
+
...statusJson(raw ?? {}),
|
|
3297
3369
|
media: toMediaViews(raw?.media, saved?.media),
|
|
3298
3370
|
textSource: typeof raw?.textSource === "string" ? raw.textSource : null
|
|
3299
3371
|
};
|
|
@@ -3310,36 +3382,12 @@ var init_projection = __esm({
|
|
|
3310
3382
|
"src/apply/projection.ts"() {
|
|
3311
3383
|
"use strict";
|
|
3312
3384
|
init_media();
|
|
3385
|
+
init_statuses();
|
|
3313
3386
|
init_shared();
|
|
3314
3387
|
}
|
|
3315
3388
|
});
|
|
3316
3389
|
|
|
3317
3390
|
// src/commands/comments.ts
|
|
3318
|
-
function mapStatusToNumber2(status) {
|
|
3319
|
-
if (!status)
|
|
3320
|
-
return void 0;
|
|
3321
|
-
const s = status.toLowerCase();
|
|
3322
|
-
if (s === "open" || s === "1")
|
|
3323
|
-
return 1;
|
|
3324
|
-
if (s === "ready" || s === "readytoapply" || s === "2")
|
|
3325
|
-
return 2;
|
|
3326
|
-
if (s === "applied" || s === "3")
|
|
3327
|
-
return 3;
|
|
3328
|
-
if (s === "archived" || s === "4")
|
|
3329
|
-
return 4;
|
|
3330
|
-
return void 0;
|
|
3331
|
-
}
|
|
3332
|
-
function mapStatusToString(status) {
|
|
3333
|
-
if (status === 1 || status === "1")
|
|
3334
|
-
return "Open";
|
|
3335
|
-
if (status === 2 || status === "2")
|
|
3336
|
-
return "ReadyToApply";
|
|
3337
|
-
if (status === 3 || status === "3")
|
|
3338
|
-
return "Applied";
|
|
3339
|
-
if (status === 4 || status === "4")
|
|
3340
|
-
return "Archived";
|
|
3341
|
-
return String(status);
|
|
3342
|
-
}
|
|
3343
3391
|
function mapEnvironmentToNumber2(env) {
|
|
3344
3392
|
if (!env)
|
|
3345
3393
|
return void 0;
|
|
@@ -3395,18 +3443,18 @@ function exitOnUnresolvedProject(resolved, flag) {
|
|
|
3395
3443
|
}
|
|
3396
3444
|
process.exit(2);
|
|
3397
3445
|
}
|
|
3398
|
-
async function fetchCommentsFor(server, token, project,
|
|
3446
|
+
async function fetchCommentsFor(server, token, project, statusKey, envNum) {
|
|
3399
3447
|
const queryParts = ["view=summary"];
|
|
3400
|
-
if (
|
|
3401
|
-
queryParts.push(`
|
|
3448
|
+
if (statusKey !== void 0)
|
|
3449
|
+
queryParts.push(`statusKey=${encodeURIComponent(statusKey)}`);
|
|
3402
3450
|
if (envNum !== void 0)
|
|
3403
3451
|
queryParts.push(`environment=${envNum}`);
|
|
3404
3452
|
const url = `/api/projects/${encodeURIComponent(project)}/comments?${queryParts.join("&")}`;
|
|
3405
3453
|
const res = await api(server, url, { token });
|
|
3406
3454
|
return res?.items ?? [];
|
|
3407
3455
|
}
|
|
3408
|
-
function printCommentLine(item) {
|
|
3409
|
-
const st =
|
|
3456
|
+
function printCommentLine(item, catalog) {
|
|
3457
|
+
const st = statusLabel(item, catalog);
|
|
3410
3458
|
const env = mapEnvironmentToString(item.environment);
|
|
3411
3459
|
const author = item.authorName || "Anonymous";
|
|
3412
3460
|
const loc = item.route || item.sourcePath || "";
|
|
@@ -3416,14 +3464,23 @@ async function listCommand(cwd2, parsed, positionals = []) {
|
|
|
3416
3464
|
const { server, token, root, config } = await getClient(cwd2, parsed, { requireProject: false });
|
|
3417
3465
|
const statusArg = (typeof parsed["status"] === "string" ? parsed["status"] : positionals[1]) || void 0;
|
|
3418
3466
|
const envArg = (typeof parsed["env"] === "string" ? parsed["env"] : positionals[2]) || void 0;
|
|
3419
|
-
const
|
|
3467
|
+
const catalog = await fetchStatuses({ server, token });
|
|
3468
|
+
let statusKey;
|
|
3469
|
+
if (statusArg !== void 0) {
|
|
3470
|
+
const resolvedStatus = resolveStatus(statusArg, catalog);
|
|
3471
|
+
if (!resolvedStatus) {
|
|
3472
|
+
console.error(unknownStatusError(statusArg, catalog));
|
|
3473
|
+
process.exit(2);
|
|
3474
|
+
}
|
|
3475
|
+
statusKey = resolvedStatus.key;
|
|
3476
|
+
}
|
|
3420
3477
|
const envNum = mapEnvironmentToNumber2(envArg);
|
|
3421
3478
|
const flag = typeof parsed["project"] === "string" ? parsed["project"] : void 0;
|
|
3422
3479
|
const resolved = resolveProject(config, cwd2, root, flag);
|
|
3423
3480
|
if (resolved.ok) {
|
|
3424
|
-
const items = await fetchCommentsFor(server, token, resolved.project.key,
|
|
3481
|
+
const items = await fetchCommentsFor(server, token, resolved.project.key, statusKey, envNum);
|
|
3425
3482
|
if (parsed["json"] === true) {
|
|
3426
|
-
console.log(JSON.stringify(items.map(({ id, ...rest }) => ({ number: rest.number, internalId: id, ...rest })), null, 2));
|
|
3483
|
+
console.log(JSON.stringify(items.map(({ id, ...rest }) => ({ number: rest.number, internalId: id, ...rest, ...statusJson(rest, catalog) })), null, 2));
|
|
3427
3484
|
process.exit(0);
|
|
3428
3485
|
}
|
|
3429
3486
|
if (items.length === 0) {
|
|
@@ -3431,7 +3488,7 @@ async function listCommand(cwd2, parsed, positionals = []) {
|
|
|
3431
3488
|
process.exit(0);
|
|
3432
3489
|
}
|
|
3433
3490
|
for (const item of items)
|
|
3434
|
-
printCommentLine(item);
|
|
3491
|
+
printCommentLine(item, catalog);
|
|
3435
3492
|
process.exit(0);
|
|
3436
3493
|
}
|
|
3437
3494
|
if (resolved.reason === "not-found") {
|
|
@@ -3444,11 +3501,11 @@ async function listCommand(cwd2, parsed, positionals = []) {
|
|
|
3444
3501
|
const projects = listProjects(config);
|
|
3445
3502
|
const grouped = [];
|
|
3446
3503
|
for (const p of projects) {
|
|
3447
|
-
const comments = await fetchCommentsFor(server, token, p.key,
|
|
3504
|
+
const comments = await fetchCommentsFor(server, token, p.key, statusKey, envNum);
|
|
3448
3505
|
grouped.push({ key: p.key, path: p.path, comments });
|
|
3449
3506
|
}
|
|
3450
3507
|
if (parsed["json"] === true) {
|
|
3451
|
-
console.log(JSON.stringify(grouped.map((g) => ({ project: g.key, comments: g.comments.map(({ id, ...rest }) => ({ number: rest.number, internalId: id, ...rest })) })), null, 2));
|
|
3508
|
+
console.log(JSON.stringify(grouped.map((g) => ({ project: g.key, comments: g.comments.map(({ id, ...rest }) => ({ number: rest.number, internalId: id, ...rest, ...statusJson(rest, catalog) })) })), null, 2));
|
|
3452
3509
|
process.exit(0);
|
|
3453
3510
|
}
|
|
3454
3511
|
for (const g of grouped) {
|
|
@@ -3457,7 +3514,7 @@ async function listCommand(cwd2, parsed, positionals = []) {
|
|
|
3457
3514
|
console.log("No comments found.");
|
|
3458
3515
|
} else {
|
|
3459
3516
|
for (const item of g.comments)
|
|
3460
|
-
printCommentLine(item);
|
|
3517
|
+
printCommentLine(item, catalog);
|
|
3461
3518
|
}
|
|
3462
3519
|
console.log("");
|
|
3463
3520
|
}
|
|
@@ -3492,12 +3549,13 @@ async function getCommand(cwd2, parsed, positionals = []) {
|
|
|
3492
3549
|
await pruneMedia(root);
|
|
3493
3550
|
const saved = await saveIfRooted(raw, { root, projectKey: project, server, token });
|
|
3494
3551
|
const view = toAiCommentView(raw, void 0, saved);
|
|
3552
|
+
const catalog = await fetchStatuses({ server, token });
|
|
3495
3553
|
if (parsed["json"] === true) {
|
|
3496
3554
|
const resolved = resolveSource(cwd2, view.element?.sourcePath);
|
|
3497
|
-
console.log(JSON.stringify({ ...view, resolvedSource: resolved }, null, 2));
|
|
3555
|
+
console.log(JSON.stringify({ ...view, ...statusJson(raw, catalog), resolvedSource: resolved }, null, 2));
|
|
3498
3556
|
process.exit(0);
|
|
3499
3557
|
}
|
|
3500
|
-
console.log(`Comment #${n} [${
|
|
3558
|
+
console.log(`Comment #${n} [${statusLabel(raw, catalog)}] [${mapEnvironmentToString(view.environment)}]`);
|
|
3501
3559
|
console.log(`Author: ${view.authorName || "Anonymous"} | Created: ${view.createdAt}`);
|
|
3502
3560
|
if (view.element.route || view.element.sourcePath) {
|
|
3503
3561
|
console.log(`Location: ${view.element.route || ""} ${view.element.sourcePath ? `(${view.element.sourcePath})` : ""}`);
|
|
@@ -3588,7 +3646,7 @@ async function statusCommand(cwd2, parsed, positionals = []) {
|
|
|
3588
3646
|
const numStr = positionals[1];
|
|
3589
3647
|
const newStatusStr = positionals[2];
|
|
3590
3648
|
if (!numStr || !newStatusStr) {
|
|
3591
|
-
console.error(
|
|
3649
|
+
console.error('Usage: pinsay status <number> <open|ready|applied|archived|"custom status">');
|
|
3592
3650
|
process.exit(2);
|
|
3593
3651
|
}
|
|
3594
3652
|
const n = parseCommentNumber(numStr);
|
|
@@ -3596,12 +3654,13 @@ async function statusCommand(cwd2, parsed, positionals = []) {
|
|
|
3596
3654
|
console.error(invalidNumberMessage(numStr));
|
|
3597
3655
|
process.exit(2);
|
|
3598
3656
|
}
|
|
3599
|
-
const
|
|
3600
|
-
|
|
3601
|
-
|
|
3657
|
+
const catalog = await fetchStatuses({ server, token });
|
|
3658
|
+
const resolvedStatus = resolveStatus(newStatusStr, catalog);
|
|
3659
|
+
if (!resolvedStatus) {
|
|
3660
|
+
console.error(unknownStatusError(newStatusStr, catalog));
|
|
3602
3661
|
process.exit(2);
|
|
3603
3662
|
}
|
|
3604
|
-
if (
|
|
3663
|
+
if (resolvedStatus.status === 3) {
|
|
3605
3664
|
console.error(
|
|
3606
3665
|
'Marking a comment as \'applied\' is not permitted via `pinsay status`.\nUse `pinsay apply --mark <number> --reply "<explanation>"` (or `pinsay reply <number> "<text>"`) to record a properly structured reply.'
|
|
3607
3666
|
);
|
|
@@ -3617,12 +3676,20 @@ async function statusCommand(cwd2, parsed, positionals = []) {
|
|
|
3617
3676
|
}
|
|
3618
3677
|
throw err;
|
|
3619
3678
|
}
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3679
|
+
try {
|
|
3680
|
+
await api(server, `/api/comments/${raw.id}`, {
|
|
3681
|
+
method: "PATCH",
|
|
3682
|
+
body: { statusKey: resolvedStatus.key },
|
|
3683
|
+
token
|
|
3684
|
+
});
|
|
3685
|
+
} catch (err) {
|
|
3686
|
+
if (err instanceof ApiError && err.code === 403) {
|
|
3687
|
+
console.error(err.message);
|
|
3688
|
+
process.exit(1);
|
|
3689
|
+
}
|
|
3690
|
+
throw err;
|
|
3691
|
+
}
|
|
3692
|
+
console.log(`Updated comment #${n} status to ${resolvedStatus.label}.`);
|
|
3626
3693
|
process.exit(0);
|
|
3627
3694
|
}
|
|
3628
3695
|
async function replyCommand(cwd2, parsed, positionals = []) {
|
|
@@ -3667,6 +3734,7 @@ var init_comments = __esm({
|
|
|
3667
3734
|
init_projection();
|
|
3668
3735
|
init_media();
|
|
3669
3736
|
init_server();
|
|
3737
|
+
init_statuses();
|
|
3670
3738
|
}
|
|
3671
3739
|
});
|
|
3672
3740
|
|
|
@@ -9103,6 +9171,16 @@ init_queue();
|
|
|
9103
9171
|
init_projection();
|
|
9104
9172
|
init_media();
|
|
9105
9173
|
init_server();
|
|
9174
|
+
init_statuses();
|
|
9175
|
+
async function exitOnUnknownStatus(server, token, status) {
|
|
9176
|
+
if (typeof status !== "string")
|
|
9177
|
+
return;
|
|
9178
|
+
const catalog = await fetchStatuses({ server, token });
|
|
9179
|
+
if (!resolveStatus(status, catalog)) {
|
|
9180
|
+
console.error(unknownStatusError(status, catalog));
|
|
9181
|
+
process.exit(2);
|
|
9182
|
+
}
|
|
9183
|
+
}
|
|
9106
9184
|
async function exitIfWorkspaceFrozen(server, token) {
|
|
9107
9185
|
if (!token)
|
|
9108
9186
|
return void 0;
|
|
@@ -9213,6 +9291,7 @@ async function applyCommand(cwd2, parsed, positionals = []) {
|
|
|
9213
9291
|
cwd: root,
|
|
9214
9292
|
workspaceName
|
|
9215
9293
|
};
|
|
9294
|
+
await exitOnUnknownStatus(server, token, parsed["status"]);
|
|
9216
9295
|
if (parsed["mark"] !== void 0) {
|
|
9217
9296
|
const markVal2 = parsed["mark"];
|
|
9218
9297
|
let markId;
|
|
@@ -9369,6 +9448,7 @@ async function applyAllProjects(root, cwd2, config, server, parsed) {
|
|
|
9369
9448
|
process.exit(3);
|
|
9370
9449
|
}
|
|
9371
9450
|
const workspaceName = await exitIfWorkspaceFrozen(server, token);
|
|
9451
|
+
await exitOnUnknownStatus(server, token, parsed["status"]);
|
|
9372
9452
|
const projects = listProjects(config);
|
|
9373
9453
|
const plan = parsed["plan"] === true;
|
|
9374
9454
|
const status = typeof parsed["status"] === "string" ? parsed["status"] : void 0;
|
|
@@ -14756,8 +14836,7 @@ var TOOL_PINSAY_LIST_COMMENTS = {
|
|
|
14756
14836
|
},
|
|
14757
14837
|
status: {
|
|
14758
14838
|
type: "string",
|
|
14759
|
-
|
|
14760
|
-
description: "Filter by comment status"
|
|
14839
|
+
description: "Filter by comment status: open, ready, applied, archived, or a custom status label/key"
|
|
14761
14840
|
}
|
|
14762
14841
|
},
|
|
14763
14842
|
additionalProperties: false
|
|
@@ -14927,7 +15006,7 @@ var TOOL_PINSAY_REPLY = {
|
|
|
14927
15006
|
};
|
|
14928
15007
|
var TOOL_PINSAY_SET_STATUS = {
|
|
14929
15008
|
name: "pinsay_set_status",
|
|
14930
|
-
description: `Set a comment's status to open, ready or
|
|
15009
|
+
description: `Set a comment's status to open, ready, archived or a custom status (by label or key). "applied" is not accepted here: only pinsay_mark_applied and pinsay_commit_and_mark set it, because they also record the reply and the commit. Returns {number, status}. ${UNTRUSTED_NOTICE}`,
|
|
14931
15010
|
inputSchema: {
|
|
14932
15011
|
type: "object",
|
|
14933
15012
|
properties: {
|
|
@@ -14942,8 +15021,7 @@ var TOOL_PINSAY_SET_STATUS = {
|
|
|
14942
15021
|
},
|
|
14943
15022
|
status: {
|
|
14944
15023
|
type: "string",
|
|
14945
|
-
|
|
14946
|
-
description: "Status to set"
|
|
15024
|
+
description: "Status to set: open, ready, archived, or a custom status label/key (not applied)"
|
|
14947
15025
|
}
|
|
14948
15026
|
},
|
|
14949
15027
|
required: ["number", "status"],
|
|
@@ -15012,26 +15090,11 @@ init_media();
|
|
|
15012
15090
|
init_shared();
|
|
15013
15091
|
init_member_rules();
|
|
15014
15092
|
init_config();
|
|
15093
|
+
init_statuses();
|
|
15015
15094
|
init_comment_ref();
|
|
15016
15095
|
function mcpError(code, message) {
|
|
15017
15096
|
return { code, message };
|
|
15018
15097
|
}
|
|
15019
|
-
function mapStatusToNumber3(status) {
|
|
15020
|
-
if (status === void 0 || status === null)
|
|
15021
|
-
return void 0;
|
|
15022
|
-
if (typeof status === "number")
|
|
15023
|
-
return status;
|
|
15024
|
-
const s = String(status).toLowerCase();
|
|
15025
|
-
if (s === "open" || s === "1")
|
|
15026
|
-
return 1;
|
|
15027
|
-
if (s === "ready" || s === "readytoapply" || s === "2")
|
|
15028
|
-
return 2;
|
|
15029
|
-
if (s === "applied" || s === "3")
|
|
15030
|
-
return 3;
|
|
15031
|
-
if (s === "archived" || s === "4")
|
|
15032
|
-
return 4;
|
|
15033
|
-
return void 0;
|
|
15034
|
-
}
|
|
15035
15098
|
function mapEnvironmentToNumber3(env) {
|
|
15036
15099
|
if (env === void 0 || env === null)
|
|
15037
15100
|
return void 0;
|
|
@@ -15179,13 +15242,20 @@ function reshapeComment(raw, page, saved) {
|
|
|
15179
15242
|
};
|
|
15180
15243
|
}
|
|
15181
15244
|
async function handleListComments(args, ctx) {
|
|
15182
|
-
const
|
|
15245
|
+
const catalog = await fetchStatuses(ctx);
|
|
15246
|
+
let statusKey;
|
|
15247
|
+
if (args?.status !== void 0 && args.status !== null && String(args.status).trim() !== "") {
|
|
15248
|
+
const resolvedStatus = resolveStatus(args.status, catalog);
|
|
15249
|
+
if (!resolvedStatus)
|
|
15250
|
+
throw mcpError("invalid_input", unknownStatusError(String(args.status), catalog));
|
|
15251
|
+
statusKey = resolvedStatus.key;
|
|
15252
|
+
}
|
|
15183
15253
|
const envNum = mapEnvironmentToNumber3(args?.environment);
|
|
15184
15254
|
const page = typeof args?.page === "number" && args.page >= 1 ? args.page : 1;
|
|
15185
15255
|
const pageSize = typeof args?.pageSize === "number" && args.pageSize >= 1 && args.pageSize <= 100 ? args.pageSize : 50;
|
|
15186
15256
|
const queryParts = ["view=summary", `pageNumber=${page}`, `pageSize=${pageSize}`];
|
|
15187
|
-
if (
|
|
15188
|
-
queryParts.push(`
|
|
15257
|
+
if (statusKey !== void 0)
|
|
15258
|
+
queryParts.push(`statusKey=${encodeURIComponent(statusKey)}`);
|
|
15189
15259
|
if (envNum !== void 0)
|
|
15190
15260
|
queryParts.push(`environment=${envNum}`);
|
|
15191
15261
|
const url = `/api/projects/${encodeURIComponent(ctx.project)}/comments?${queryParts.join("&")}`;
|
|
@@ -15195,6 +15265,7 @@ async function handleListComments(args, ctx) {
|
|
|
15195
15265
|
number: item.number,
|
|
15196
15266
|
internalId: item.id,
|
|
15197
15267
|
status: item.status,
|
|
15268
|
+
...statusJson(item, catalog),
|
|
15198
15269
|
environment: item.environment,
|
|
15199
15270
|
body: item.body ?? "",
|
|
15200
15271
|
untrusted: {
|
|
@@ -15647,19 +15718,20 @@ async function handleReply(args, ctx) {
|
|
|
15647
15718
|
}
|
|
15648
15719
|
async function handleSetStatus(args, ctx) {
|
|
15649
15720
|
const number = parseCommentNumber(args?.number);
|
|
15650
|
-
const statusStr = String(args?.status || "").
|
|
15721
|
+
const statusStr = String(args?.status || "").trim();
|
|
15651
15722
|
if (number === null) {
|
|
15652
15723
|
throw mcpError("invalid_input", invalidNumberMessage(args?.number, args?.id));
|
|
15653
15724
|
}
|
|
15654
15725
|
if (!statusStr) {
|
|
15655
15726
|
throw mcpError("invalid_input", "number and status are required");
|
|
15656
15727
|
}
|
|
15657
|
-
|
|
15658
|
-
|
|
15728
|
+
const catalog = await fetchStatuses(ctx);
|
|
15729
|
+
const resolvedStatus = resolveStatus(statusStr, catalog);
|
|
15730
|
+
if (!resolvedStatus) {
|
|
15731
|
+
throw mcpError("invalid_input", unknownStatusError(statusStr, catalog));
|
|
15659
15732
|
}
|
|
15660
|
-
|
|
15661
|
-
|
|
15662
|
-
throw mcpError("invalid_input", `Invalid status: ${args.status}`);
|
|
15733
|
+
if (resolvedStatus.status === 3) {
|
|
15734
|
+
throw mcpError("invalid_input", 'Status "applied" is only settable via mark tools');
|
|
15663
15735
|
}
|
|
15664
15736
|
let id;
|
|
15665
15737
|
try {
|
|
@@ -15673,10 +15745,10 @@ async function handleSetStatus(args, ctx) {
|
|
|
15673
15745
|
}
|
|
15674
15746
|
await api(ctx.server, `/api/comments/${id}`, {
|
|
15675
15747
|
method: "PATCH",
|
|
15676
|
-
body: {
|
|
15748
|
+
body: { statusKey: resolvedStatus.key },
|
|
15677
15749
|
token: ctx.token
|
|
15678
15750
|
});
|
|
15679
|
-
return { number, status:
|
|
15751
|
+
return { number, status: resolvedStatus.key };
|
|
15680
15752
|
}
|
|
15681
15753
|
async function handleResolveSource(args, ctx) {
|
|
15682
15754
|
const hash = args?.hash;
|
|
@@ -16379,7 +16451,7 @@ var HELP_TEXTS = {
|
|
|
16379
16451
|
},
|
|
16380
16452
|
status: {
|
|
16381
16453
|
purpose: "Who you are, this folder's project, comments waiting",
|
|
16382
|
-
usage: "npx pinsay-cli status\n npx pinsay-cli status <number> <open|ready|
|
|
16454
|
+
usage: "npx pinsay-cli status\n npx pinsay-cli status <number> <open|ready|archived|status>\n npx pinsay-cli status --deployed [sha]",
|
|
16383
16455
|
common: [
|
|
16384
16456
|
["--json", "Overview as JSON"],
|
|
16385
16457
|
["--deployed [sha]", "Mark applied comments live (default HEAD)"],
|
|
@@ -16395,7 +16467,7 @@ var HELP_TEXTS = {
|
|
|
16395
16467
|
],
|
|
16396
16468
|
examples: [
|
|
16397
16469
|
["npx pinsay-cli status", "Who you are and what's waiting"],
|
|
16398
|
-
["npx pinsay-cli status 42 ready", "
|
|
16470
|
+
["npx pinsay-cli status 42 ready", "Move #42 to Ready (or a custom status)"],
|
|
16399
16471
|
["npx pinsay-cli status --deployed", "Mark this build's applied comments live"]
|
|
16400
16472
|
]
|
|
16401
16473
|
},
|
|
@@ -16421,13 +16493,13 @@ var HELP_TEXTS = {
|
|
|
16421
16493
|
purpose: "List feedback comments",
|
|
16422
16494
|
usage: "npx pinsay-cli list [status] [environment]",
|
|
16423
16495
|
common: [
|
|
16424
|
-
["--status <status>", "Filter
|
|
16496
|
+
["--status <status>", "Filter: open, ready, applied, archived, custom"],
|
|
16425
16497
|
["--env <env>", "Filter (local, staging, production)"],
|
|
16426
16498
|
["--project <key>", "Project (default: this folder's)"],
|
|
16427
16499
|
["--json", "Comments as JSON"]
|
|
16428
16500
|
],
|
|
16429
16501
|
all: [
|
|
16430
|
-
["--status <status>", "Filter
|
|
16502
|
+
["--status <status>", "Filter: open, ready, applied, archived, custom"],
|
|
16431
16503
|
["--env <env>", "Filter (local, staging, production)"],
|
|
16432
16504
|
["--project <key>", "Project (default: this folder's)"],
|
|
16433
16505
|
["--key <key>", "API key"],
|
|
@@ -16469,7 +16541,7 @@ var HELP_TEXTS = {
|
|
|
16469
16541
|
["--mark <number>|all", "Commit and mark applied (needs --models)"],
|
|
16470
16542
|
["--reply <text>", "Reply recorded with --mark"],
|
|
16471
16543
|
["--models <list>", '"<id>=<role>", mandatory with --mark'],
|
|
16472
|
-
["--status <status>", "
|
|
16544
|
+
["--status <status>", "Queue status (default ready; custom label/key)"],
|
|
16473
16545
|
["--env <env>", "Filter (local, staging, production)"],
|
|
16474
16546
|
["--json", "Queue as JSON"]
|
|
16475
16547
|
],
|
|
@@ -16485,7 +16557,7 @@ var HELP_TEXTS = {
|
|
|
16485
16557
|
["--dry-run", "Print what --mark would do; change nothing"],
|
|
16486
16558
|
["--fail <number>", "Mark apply failed with a reply"],
|
|
16487
16559
|
["--reason <text>", "Why it failed (required with --fail)"],
|
|
16488
|
-
["--status <status>", "
|
|
16560
|
+
["--status <status>", "Queue status (default ready; custom label/key)"],
|
|
16489
16561
|
["--env <env>", "Filter (local, staging, production)"],
|
|
16490
16562
|
["--key <key>", "API key"],
|
|
16491
16563
|
["--project <key>", "Project for the queue"],
|
package/package.json
CHANGED