@islamihab/kds 0.5.0 → 0.7.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/index.js +177 -14
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -14420,9 +14420,11 @@ var printHelp = (help) => {
|
|
|
14420
14420
|
description: `${field.description ?? ""}${isRequired(field) ? " (required)" : ""}`
|
|
14421
14421
|
}));
|
|
14422
14422
|
const usageOptions = options?.length ? " [options]" : "";
|
|
14423
|
-
if (help.description)
|
|
14424
|
-
console.log(`${help.description}
|
|
14423
|
+
if (help.description) {
|
|
14424
|
+
console.log(`${help.description}${help.longDescription ? `
|
|
14425
|
+
${help.longDescription}` : ""}
|
|
14425
14426
|
`);
|
|
14427
|
+
}
|
|
14426
14428
|
console.log(`Usage: ${help.path}${usageCommands}${usageOptions}${usagePositionals}`);
|
|
14427
14429
|
const labels = [commands, positionals, options].flatMap((entries) => entries ?? []);
|
|
14428
14430
|
const width = Math.max(...labels.map(({ label }) => label.length));
|
|
@@ -14552,7 +14554,13 @@ var command = (def) => {
|
|
|
14552
14554
|
const positionalEntries = Object.entries(inputShape.shape.positionals.shape);
|
|
14553
14555
|
const optionsEntries = optionEntries(inputShape.shape.options.shape);
|
|
14554
14556
|
const run = async (args, path) => {
|
|
14555
|
-
const help = () => printHelp({
|
|
14557
|
+
const help = () => printHelp({
|
|
14558
|
+
path,
|
|
14559
|
+
description: def.description,
|
|
14560
|
+
longDescription: def.longDescription,
|
|
14561
|
+
positionals: positionalEntries,
|
|
14562
|
+
options: optionsEntries
|
|
14563
|
+
});
|
|
14556
14564
|
if (args.some(isHelpFlag))
|
|
14557
14565
|
return help();
|
|
14558
14566
|
const { values, positionals } = parseArgs({ args, positionalEntries, optionsEntries, help });
|
|
@@ -14570,7 +14578,13 @@ var group = (def) => {
|
|
|
14570
14578
|
const optionsShape = exports_external.object(def.options);
|
|
14571
14579
|
const optionsEntries = optionEntries(optionsShape.shape);
|
|
14572
14580
|
const run = async ([sub, ...rest], path) => {
|
|
14573
|
-
const help = () => printHelp({
|
|
14581
|
+
const help = () => printHelp({
|
|
14582
|
+
path,
|
|
14583
|
+
description: def.description,
|
|
14584
|
+
longDescription: def.longDescription,
|
|
14585
|
+
commands: def.commands,
|
|
14586
|
+
options: optionsEntries
|
|
14587
|
+
});
|
|
14574
14588
|
if (!sub && !def.run || sub === "help" || isHelpFlag(sub))
|
|
14575
14589
|
return help();
|
|
14576
14590
|
if (def.run && (sub?.startsWith("-") || !sub)) {
|
|
@@ -14597,7 +14611,7 @@ import { join } from "path";
|
|
|
14597
14611
|
// package.json
|
|
14598
14612
|
var package_default = {
|
|
14599
14613
|
name: "cli",
|
|
14600
|
-
version: "0.
|
|
14614
|
+
version: "0.7.0",
|
|
14601
14615
|
private: true,
|
|
14602
14616
|
type: "module",
|
|
14603
14617
|
bin: {
|
|
@@ -15188,6 +15202,14 @@ var ISSUE_OPEN_STATUSES = [
|
|
|
15188
15202
|
"changes_requested",
|
|
15189
15203
|
"approved"
|
|
15190
15204
|
];
|
|
15205
|
+
var REVIEW_FINDING_CATEGORIES = [
|
|
15206
|
+
"functional_correctness",
|
|
15207
|
+
"maintainability",
|
|
15208
|
+
"security",
|
|
15209
|
+
"performance"
|
|
15210
|
+
];
|
|
15211
|
+
var REVIEW_FINDING_SEVERITIES = ["critical", "major", "minor", "trivial"];
|
|
15212
|
+
var MAX_REVIEW_FINDINGS = 50;
|
|
15191
15213
|
var ISSUE_LABEL_COLORS = [
|
|
15192
15214
|
"gray",
|
|
15193
15215
|
"red",
|
|
@@ -18159,9 +18181,10 @@ var runInbox = async (options) => {
|
|
|
18159
18181
|
};
|
|
18160
18182
|
|
|
18161
18183
|
// src/lib/input.ts
|
|
18162
|
-
var assertSize = (size) => {
|
|
18163
|
-
if (size > MAX_PAGE_HTML_BYTES)
|
|
18164
|
-
throw new Error(
|
|
18184
|
+
var assertSize = (size, subject = "Page") => {
|
|
18185
|
+
if (size > MAX_PAGE_HTML_BYTES) {
|
|
18186
|
+
throw new Error(`${subject} is too large (${size} bytes; max ${MAX_PAGE_HTML_BYTES}).`);
|
|
18187
|
+
}
|
|
18165
18188
|
};
|
|
18166
18189
|
var readBody = async (path) => {
|
|
18167
18190
|
if (path === "-") {
|
|
@@ -18174,6 +18197,18 @@ var readBody = async (path) => {
|
|
|
18174
18197
|
return await file2.text();
|
|
18175
18198
|
};
|
|
18176
18199
|
var readTextOption = async (value) => value === "-" ? await Bun.stdin.text() : value;
|
|
18200
|
+
var readFileOption = async (path) => {
|
|
18201
|
+
if (path === "-") {
|
|
18202
|
+
const text = await Bun.stdin.text();
|
|
18203
|
+
assertSize(new TextEncoder().encode(text).length, "Input");
|
|
18204
|
+
return text;
|
|
18205
|
+
}
|
|
18206
|
+
const file2 = Bun.file(path);
|
|
18207
|
+
if (!await file2.exists())
|
|
18208
|
+
throw new Error(`No file at ${path}.`);
|
|
18209
|
+
assertSize(file2.size, "Input");
|
|
18210
|
+
return await file2.text();
|
|
18211
|
+
};
|
|
18177
18212
|
var readIssueRef = (value) => {
|
|
18178
18213
|
const trimmed = value.trim();
|
|
18179
18214
|
if (/^\d+$/.test(trimmed))
|
|
@@ -18389,7 +18424,7 @@ var comment = command({
|
|
|
18389
18424
|
body: exports_external.string().describe("Comment markdown, or - for stdin")
|
|
18390
18425
|
},
|
|
18391
18426
|
options: {
|
|
18392
|
-
attach: exports_external.array(exports_external.string()).optional().describe("Attach a file to the issue (repeatable)").meta({ short: "a" })
|
|
18427
|
+
attach: exports_external.array(exports_external.string()).optional().describe("Attach a file to the issue (repeatable); the printed URL is usable in issue markdown, and removal is dashboard-only").meta({ short: "a" })
|
|
18393
18428
|
},
|
|
18394
18429
|
run: async ({ positionals: { id, body }, options: { attach } }) => {
|
|
18395
18430
|
const client3 = await backendClient();
|
|
@@ -18415,6 +18450,7 @@ var agentConfigurationLine = (id) => {
|
|
|
18415
18450
|
var create = command({
|
|
18416
18451
|
name: "create",
|
|
18417
18452
|
description: "Create an issue and print its identifier",
|
|
18453
|
+
longDescription: "--disposition ready_for_agent requires --agent-config; the agent queue refuses an issue without one.",
|
|
18418
18454
|
positionals: {
|
|
18419
18455
|
title: exports_external.string().describe("Issue title")
|
|
18420
18456
|
},
|
|
@@ -18698,6 +18734,37 @@ More issues match; raise --limit past ${options.limit}.`);
|
|
|
18698
18734
|
}
|
|
18699
18735
|
});
|
|
18700
18736
|
|
|
18737
|
+
// src/commands/issues/mark-addressed.ts
|
|
18738
|
+
var parseFindingRef = (value) => {
|
|
18739
|
+
const match = /^(.+):([1-9]\d*)$/.exec(value);
|
|
18740
|
+
if (!match?.[1] || !match[2])
|
|
18741
|
+
throw new Error(`--finding takes path:line, got "${value}".`);
|
|
18742
|
+
return { path: match[1], line: Number(match[2]) };
|
|
18743
|
+
};
|
|
18744
|
+
var markAddressed = command({
|
|
18745
|
+
name: "mark-addressed",
|
|
18746
|
+
description: "Mark review findings addressed by a commit and resolve their conversations",
|
|
18747
|
+
positionals: {
|
|
18748
|
+
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18749
|
+
},
|
|
18750
|
+
options: {
|
|
18751
|
+
commit: exports_external.string().describe("The commit sha that addressed the findings").meta({ short: "c" }),
|
|
18752
|
+
finding: exports_external.array(exports_external.string()).optional().describe("Mark only this finding, as path:line (repeatable; default all)")
|
|
18753
|
+
},
|
|
18754
|
+
run: async ({ positionals: { id }, options: { commit, finding } }) => {
|
|
18755
|
+
const client3 = await backendClient();
|
|
18756
|
+
const issue2 = await resolveIssue(client3, id);
|
|
18757
|
+
const result = await client3.action(api2.githubReviewer.markAddressed, {
|
|
18758
|
+
id: issue2._id,
|
|
18759
|
+
commitSha: commit,
|
|
18760
|
+
findings: finding?.map(parseFindingRef)
|
|
18761
|
+
});
|
|
18762
|
+
const already = result.alreadyMarked.length ? ` (${result.alreadyMarked.length} already marked)` : "";
|
|
18763
|
+
console.log(`Marked ${result.marked.length} on ${result.identifier} as addressed in ${commit}${already}.`);
|
|
18764
|
+
console.log(result.resolved ? `Resolved ${result.resolved} conversation${result.resolved === 1 ? "" : "s"}.` : "All conversations already resolved.");
|
|
18765
|
+
}
|
|
18766
|
+
});
|
|
18767
|
+
|
|
18701
18768
|
// src/commands/issues/relate.ts
|
|
18702
18769
|
var relate = command({
|
|
18703
18770
|
name: "relate",
|
|
@@ -18735,6 +18802,8 @@ var remove2 = command({
|
|
|
18735
18802
|
var route = command({
|
|
18736
18803
|
name: "route",
|
|
18737
18804
|
description: "Route an issue to a disposition (wontfix also cancels it)",
|
|
18805
|
+
longDescription: `The disposition says who acts next; needs_triage is the default. Routing to
|
|
18806
|
+
ready_for_agent requires the issue to carry an agent configuration (set --agent-config).`,
|
|
18738
18807
|
positionals: {
|
|
18739
18808
|
id: exports_external.string().describe("Issue identifier, number, or URL"),
|
|
18740
18809
|
disposition: exports_external.enum(ISSUE_DISPOSITIONS).describe("Where the issue goes next")
|
|
@@ -18758,6 +18827,9 @@ var route = command({
|
|
|
18758
18827
|
var set2 = command({
|
|
18759
18828
|
name: "set",
|
|
18760
18829
|
description: "Set an issue's status, priority, estimate, due date, project, milestone, parent, agent configuration, or labels",
|
|
18830
|
+
longDescription: `Status normally moves through the workflow commands and the linked pull request;
|
|
18831
|
+
--status is the correction path. Clearing the agent configuration is refused while
|
|
18832
|
+
the issue sits in ready_for_agent.`,
|
|
18761
18833
|
positionals: {
|
|
18762
18834
|
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18763
18835
|
},
|
|
@@ -18832,6 +18904,8 @@ var shellArg = (value) => /^[\w./-]+$/.test(value) ? value : `'${value.replaceAl
|
|
|
18832
18904
|
var start = command({
|
|
18833
18905
|
name: "start",
|
|
18834
18906
|
description: "Claim implementation work: move unstarted or changes_requested work to in_progress with its branch",
|
|
18907
|
+
longDescription: `Starting never routes the issue: the note printed when the disposition is not
|
|
18908
|
+
ready_for_agent is informational, and --ready belongs only to an explicit hand-off.`,
|
|
18835
18909
|
positionals: {
|
|
18836
18910
|
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18837
18911
|
},
|
|
@@ -18859,15 +18933,16 @@ var start = command({
|
|
|
18859
18933
|
// src/commands/issues/start-review.ts
|
|
18860
18934
|
var startReview = command({
|
|
18861
18935
|
name: "start-review",
|
|
18862
|
-
description: "Claim review work: move a ready_for_review issue to in_review",
|
|
18936
|
+
description: "Claim review work: move a ready_for_review issue to in_review and announce the review on its pull request",
|
|
18863
18937
|
positionals: {
|
|
18864
18938
|
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18865
18939
|
},
|
|
18866
18940
|
run: async ({ positionals: { id } }) => {
|
|
18867
18941
|
const client3 = await backendClient();
|
|
18868
18942
|
const issue2 = await resolveIssue(client3, id);
|
|
18869
|
-
await client3.
|
|
18870
|
-
console.log(`Reviewing ${
|
|
18943
|
+
const started = await client3.action(api2.githubReviewer.startReview, { id: issue2._id });
|
|
18944
|
+
console.log(`Reviewing ${started.identifier}: in_review`);
|
|
18945
|
+
console.log(`Announced on ${started.prUrl}; check run open.`);
|
|
18871
18946
|
}
|
|
18872
18947
|
});
|
|
18873
18948
|
|
|
@@ -18886,11 +18961,81 @@ var submit = command({
|
|
|
18886
18961
|
}
|
|
18887
18962
|
});
|
|
18888
18963
|
|
|
18964
|
+
// src/commands/issues/submit-review.ts
|
|
18965
|
+
var findingsSchema = exports_external.array(exports_external.object({
|
|
18966
|
+
path: exports_external.string().min(1),
|
|
18967
|
+
line: exports_external.number().int().positive(),
|
|
18968
|
+
startLine: exports_external.number().int().positive().optional(),
|
|
18969
|
+
category: exports_external.enum(REVIEW_FINDING_CATEGORIES),
|
|
18970
|
+
severity: exports_external.enum(REVIEW_FINDING_SEVERITIES),
|
|
18971
|
+
summary: exports_external.string().min(1),
|
|
18972
|
+
body: exports_external.string().min(1),
|
|
18973
|
+
diff: exports_external.string().optional()
|
|
18974
|
+
})).min(1).max(MAX_REVIEW_FINDINGS);
|
|
18975
|
+
var readFindings = async (path) => {
|
|
18976
|
+
const text = await readFileOption(path);
|
|
18977
|
+
let json2;
|
|
18978
|
+
try {
|
|
18979
|
+
json2 = JSON.parse(text);
|
|
18980
|
+
} catch {
|
|
18981
|
+
throw new Error("The findings file is not valid JSON.");
|
|
18982
|
+
}
|
|
18983
|
+
const parsed = findingsSchema.safeParse(json2);
|
|
18984
|
+
if (!parsed.success)
|
|
18985
|
+
throw new Error(`The findings file is invalid:
|
|
18986
|
+
${exports_external.prettifyError(parsed.error)}`);
|
|
18987
|
+
return parsed.data;
|
|
18988
|
+
};
|
|
18989
|
+
var submitReview = command({
|
|
18990
|
+
name: "submit-review",
|
|
18991
|
+
description: "Submit the review verdict on an issue's linked pull request as the reviewer App",
|
|
18992
|
+
longDescription: `Findings are a JSON array (at most ${MAX_REVIEW_FINDINGS}) of objects with path, line, category,
|
|
18993
|
+
severity, summary, and body, plus optional startLine and diff.
|
|
18994
|
+
Categories: ${REVIEW_FINDING_CATEGORIES.join(", ")}; severities: ${REVIEW_FINDING_SEVERITIES.join(", ")}.`,
|
|
18995
|
+
positionals: {
|
|
18996
|
+
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18997
|
+
},
|
|
18998
|
+
options: {
|
|
18999
|
+
approve: exports_external.boolean().default(false).describe("Approve: bare APPROVE plus a clean bill"),
|
|
19000
|
+
"request-changes": exports_external.boolean().default(false).describe("Request changes from a findings file"),
|
|
19001
|
+
findings: exports_external.string().optional().describe("Findings JSON file, or - for stdin (with --request-changes)"),
|
|
19002
|
+
bill: exports_external.string().optional().describe("Clean-bill text, or - for stdin (with --approve)")
|
|
19003
|
+
},
|
|
19004
|
+
run: async ({ positionals: { id }, options }) => {
|
|
19005
|
+
if (options.approve === options["request-changes"]) {
|
|
19006
|
+
throw new Error("Pass exactly one of --approve or --request-changes.");
|
|
19007
|
+
}
|
|
19008
|
+
if (options.approve && options.findings !== undefined)
|
|
19009
|
+
throw new Error("--findings goes with --request-changes.");
|
|
19010
|
+
if (options["request-changes"] && options.bill !== undefined)
|
|
19011
|
+
throw new Error("--bill goes with --approve.");
|
|
19012
|
+
let verdict;
|
|
19013
|
+
if (options.approve) {
|
|
19014
|
+
if (options.bill === undefined)
|
|
19015
|
+
throw new Error("--approve needs the clean bill: --bill <text>, or - for stdin.");
|
|
19016
|
+
verdict = { kind: "approve", bill: await readTextOption(options.bill) };
|
|
19017
|
+
} else {
|
|
19018
|
+
if (options.findings === undefined) {
|
|
19019
|
+
throw new Error("--request-changes needs the findings: --findings <file>, or - for stdin.");
|
|
19020
|
+
}
|
|
19021
|
+
verdict = { kind: "request_changes", findings: await readFindings(options.findings) };
|
|
19022
|
+
}
|
|
19023
|
+
const client3 = await backendClient();
|
|
19024
|
+
const issue2 = await resolveIssue(client3, id);
|
|
19025
|
+
const submitted = await client3.action(api2.githubReviewer.submitReview, { id: issue2._id, verdict });
|
|
19026
|
+
console.log(`Submitted review on ${submitted.identifier}: ${submitted.prUrl}`);
|
|
19027
|
+
console.log(submitted.summary);
|
|
19028
|
+
}
|
|
19029
|
+
});
|
|
19030
|
+
|
|
18889
19031
|
// src/commands/issues/tasks.ts
|
|
18890
19032
|
var position = exports_external.array(exports_external.coerce.number().int().positive());
|
|
18891
19033
|
var tasks = command({
|
|
18892
19034
|
name: "tasks",
|
|
18893
19035
|
description: "Show an issue's checklist, or add, tick, promote, and drop its tasks",
|
|
19036
|
+
longDescription: `Tasks have no identifier, status, disposition, or feed, and ticking one files no
|
|
19037
|
+
activity. Task numbers resolve against the listing as printed, so one call may
|
|
19038
|
+
address several rows even as removals renumber it.`,
|
|
18894
19039
|
positionals: {
|
|
18895
19040
|
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18896
19041
|
},
|
|
@@ -18898,7 +19043,7 @@ var tasks = command({
|
|
|
18898
19043
|
add: exports_external.array(exports_external.string()).optional().describe("Add a task (repeatable)").meta({ short: "a" }),
|
|
18899
19044
|
check: position.optional().describe("Tick a task by its number (repeatable)"),
|
|
18900
19045
|
uncheck: position.optional().describe("Untick a task by its number (repeatable)"),
|
|
18901
|
-
convert: position.optional().describe("Promote a task into
|
|
19046
|
+
convert: position.optional().describe("Promote a task into a sub-issue (repeatable); the new issue inherits the project and milestone, arrives in needs_triage, and consumes the task \u2014 a related issue instead when this issue is already a sub-issue"),
|
|
18902
19047
|
remove: position.optional().describe("Drop a task by its number (repeatable)"),
|
|
18903
19048
|
json: exports_external.boolean().default(false).describe("Print as JSON")
|
|
18904
19049
|
},
|
|
@@ -18987,7 +19132,7 @@ var update2 = command({
|
|
|
18987
19132
|
options: {
|
|
18988
19133
|
title: exports_external.string().optional().describe("New title").meta({ short: "t" }),
|
|
18989
19134
|
description: exports_external.string().optional().describe("New markdown description, or - for stdin").meta({ short: "d" }),
|
|
18990
|
-
attach: exports_external.array(exports_external.string()).optional().describe("Attach a file to the issue (repeatable)").meta({ short: "a" })
|
|
19135
|
+
attach: exports_external.array(exports_external.string()).optional().describe("Attach a file to the issue (repeatable); the printed URL is usable in issue markdown, and removal is dashboard-only").meta({ short: "a" })
|
|
18991
19136
|
},
|
|
18992
19137
|
run: async ({ positionals: { id }, options: { title, description, attach } }) => {
|
|
18993
19138
|
if (title === undefined && description === undefined && attach === undefined)
|
|
@@ -19010,6 +19155,16 @@ var update2 = command({
|
|
|
19010
19155
|
var issues = group({
|
|
19011
19156
|
name: "issues",
|
|
19012
19157
|
description: "Track and triage issues",
|
|
19158
|
+
longDescription: `An issue moves on three independent axes: status (the lifecycle, in order: backlog,
|
|
19159
|
+
todo, in_progress, ready_for_review, in_review, changes_requested, approved, done,
|
|
19160
|
+
canceled), priority, and disposition (who acts next). The workflow commands \u2014 start,
|
|
19161
|
+
submit, start-review, submit-review \u2014 and the linked pull request move the status;
|
|
19162
|
+
each refuses an issue outside its own status, and \`set -s\` is for corrections.
|
|
19163
|
+
The repo link is never set by hand: work on a branch whose name contains the issue
|
|
19164
|
+
identifier and the branch, pull request, and status track automatically \u2014 a change
|
|
19165
|
+
request moves the issue to changes_requested, an approval to approved (one
|
|
19166
|
+
outstanding change request outweighs any number of approvals), and a merge lands
|
|
19167
|
+
it as done.`,
|
|
19013
19168
|
commands: [
|
|
19014
19169
|
create,
|
|
19015
19170
|
list2,
|
|
@@ -19021,6 +19176,8 @@ var issues = group({
|
|
|
19021
19176
|
start,
|
|
19022
19177
|
submit,
|
|
19023
19178
|
startReview,
|
|
19179
|
+
submitReview,
|
|
19180
|
+
markAddressed,
|
|
19024
19181
|
tasks,
|
|
19025
19182
|
relate,
|
|
19026
19183
|
unrelate,
|
|
@@ -19217,6 +19374,10 @@ var versions2 = command({
|
|
|
19217
19374
|
var pages = group({
|
|
19218
19375
|
name: "pages",
|
|
19219
19376
|
description: "Publish HTML documents to the web",
|
|
19377
|
+
longDescription: `Themed pages (the default) render inside the site chrome under a strict CSP: only
|
|
19378
|
+
the site theme's styles apply \u2014 inline style attributes and author scripts are
|
|
19379
|
+
dropped. A self-contained document with its own CSS or JS needs raw mode, which
|
|
19380
|
+
serves it verbatim. A page keeps its URL across updates and reverts.`,
|
|
19220
19381
|
commands: [create3, list3, get2, update3, versions2, revert, remove3]
|
|
19221
19382
|
});
|
|
19222
19383
|
|
|
@@ -19432,6 +19593,8 @@ var update4 = command({
|
|
|
19432
19593
|
var projects = group({
|
|
19433
19594
|
name: "projects",
|
|
19434
19595
|
description: "Manage projects",
|
|
19596
|
+
longDescription: `Connect a repository (set --repo) to make --here resolve in that checkout and to
|
|
19597
|
+
let issue branches and pull requests link automatically.`,
|
|
19435
19598
|
commands: [create4, list4, get3, update4, set3, remove4]
|
|
19436
19599
|
});
|
|
19437
19600
|
|