@staff0rd/assist 0.606.0 → 0.607.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/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@staff0rd/assist",
9
- version: "0.606.0",
9
+ version: "0.607.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -21693,6 +21693,12 @@ function registerCommentIssue(issueCommand) {
21693
21693
  );
21694
21694
  }
21695
21695
 
21696
+ // src/commands/github/issue/collectLabels.ts
21697
+ function collectLabels(value, previous) {
21698
+ const added = value.split(",").map((label2) => label2.trim()).filter((label2) => label2.length > 0);
21699
+ return [...previous, ...added];
21700
+ }
21701
+
21696
21702
  // src/commands/github/issue/addIssueToProject.ts
21697
21703
  var MUTATION3 = `mutation($projectId: ID!, $contentId: ID!) {
21698
21704
  addProjectV2ItemById(input: { projectId: $projectId, contentId: $contentId }) {
@@ -21706,6 +21712,16 @@ function addIssueToProject(projectId, contentId) {
21706
21712
  return id;
21707
21713
  }
21708
21714
 
21715
+ // src/commands/github/issue/addSubIssue.ts
21716
+ var MUTATION4 = `mutation($issueId: ID!, $subIssueId: ID!) {
21717
+ addSubIssue(input: { issueId: $issueId, subIssueId: $subIssueId }) {
21718
+ subIssue { id }
21719
+ }
21720
+ }`;
21721
+ function addSubIssue(parentId, childId) {
21722
+ runGhGraphqlJson(MUTATION4, { issueId: parentId, subIssueId: childId });
21723
+ }
21724
+
21709
21725
  // src/commands/github/issue/fetchIssueNodeId.ts
21710
21726
  var QUERY4 = `query($owner: String!, $repo: String!, $number: Int!) {
21711
21727
  repository(owner: $owner, name: $repo) {
@@ -21741,7 +21757,7 @@ function parseCreatedIssueUrl(output) {
21741
21757
  }
21742
21758
 
21743
21759
  // src/commands/github/issue/setProjectItemStatus.ts
21744
- var MUTATION4 = `mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
21760
+ var MUTATION5 = `mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
21745
21761
  updateProjectV2ItemFieldValue(input: {
21746
21762
  projectId: $projectId
21747
21763
  itemId: $itemId
@@ -21752,7 +21768,7 @@ var MUTATION4 = `mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionI
21752
21768
  }
21753
21769
  }`;
21754
21770
  function setProjectItemStatus(input) {
21755
- runGhGraphqlJson(MUTATION4, input);
21771
+ runGhGraphqlJson(MUTATION5, input);
21756
21772
  }
21757
21773
 
21758
21774
  // src/commands/github/issue/applyCreatedIssueMetadata.ts
@@ -21760,11 +21776,15 @@ function applyCreatedIssueMetadata(createOutput, metadata2) {
21760
21776
  let step2 = "identifying the created issue";
21761
21777
  try {
21762
21778
  const issueId = fetchIssueNodeId(parseCreatedIssueUrl(createOutput));
21763
- const { issueType, project } = metadata2;
21779
+ const { issueType, parent, project } = metadata2;
21764
21780
  if (issueType) {
21765
21781
  step2 = `setting its issue type to ${issueType.name}`;
21766
21782
  updateIssueType(issueId, issueType.id);
21767
21783
  }
21784
+ if (parent) {
21785
+ step2 = `adding it as a sub-issue of ${parent.owner}/${parent.repo}#${parent.number}`;
21786
+ addSubIssue(parent.id, issueId);
21787
+ }
21768
21788
  if (project) {
21769
21789
  step2 = `adding it to project ${project.number} (${project.title})`;
21770
21790
  const itemId2 = addIssueToProject(project.id, issueId);
@@ -21787,18 +21807,83 @@ function applyCreatedIssueMetadata(createOutput, metadata2) {
21787
21807
  }
21788
21808
  }
21789
21809
 
21790
- // src/commands/github/issue/buildIssuePreviewBody.ts
21791
- function buildIssuePreviewBody(metadata2, body) {
21792
- if (!metadata2) return body;
21793
- const lines2 = [`**Repository:** ${metadata2.repo}`];
21794
- if (metadata2.type) lines2.push(`**Type:** ${metadata2.type}`);
21795
- if (metadata2.project) lines2.push(`**Project:** ${metadata2.project}`);
21796
- if (metadata2.status) lines2.push(`**Status:** ${metadata2.status}`);
21797
- return `${lines2.join("\n")}
21810
+ // src/commands/github/issue/issuePreviewMetadata.ts
21811
+ function issuePreviewMetadata(resolved) {
21812
+ if (!resolved) return [];
21813
+ const { target, issueType, parent, project, labels } = resolved;
21814
+ const items2 = [
21815
+ { label: "Repository", value: `${target.owner}/${target.repo}` }
21816
+ ];
21817
+ if (issueType) items2.push({ label: "Type", value: issueType.name });
21818
+ if (parent)
21819
+ items2.push({
21820
+ label: "Parent",
21821
+ value: `${parent.owner}/${parent.repo}#${parent.number}`
21822
+ });
21823
+ if (project)
21824
+ items2.push({
21825
+ label: "Project",
21826
+ value: `${project.number} (${project.title})`
21827
+ });
21828
+ if (project?.status)
21829
+ items2.push({ label: "Status", value: project.status.optionName });
21830
+ if (labels?.length) items2.push({ label: "Labels", value: labels.join(", ") });
21831
+ return items2;
21832
+ }
21798
21833
 
21799
- ---
21834
+ // src/commands/github/issue/hasCreateIssueMetadataOptions.ts
21835
+ function hasCreateIssueMetadataOptions(options2) {
21836
+ if (options2.status && !options2.project) {
21837
+ throw new Error(
21838
+ "--status is a field on a project board, so it needs --project <number>"
21839
+ );
21840
+ }
21841
+ return Boolean(
21842
+ options2.type || options2.parent || options2.project || options2.label?.length
21843
+ );
21844
+ }
21800
21845
 
21801
- ${body}`;
21846
+ // src/commands/github/issue/resolveIssueLabels.ts
21847
+ var QUERY5 = `query($owner: String!, $repo: String!, $after: String) {
21848
+ repository(owner: $owner, name: $repo) {
21849
+ labels(first: 100, after: $after) {
21850
+ nodes { name }
21851
+ pageInfo { hasNextPage endCursor }
21852
+ }
21853
+ }
21854
+ }`;
21855
+ function readRepoLabels(target) {
21856
+ const names = [];
21857
+ let after;
21858
+ do {
21859
+ const page = JSON.parse(
21860
+ runGhGraphqlJson(QUERY5, { ...target, after })
21861
+ ).data?.repository?.labels;
21862
+ if (!page) {
21863
+ throw new Error(
21864
+ `No labels could be read for ${target.owner}/${target.repo}`
21865
+ );
21866
+ }
21867
+ for (const node of page.nodes ?? []) if (node?.name) names.push(node.name);
21868
+ after = page.pageInfo?.hasNextPage ? page.pageInfo.endCursor ?? void 0 : void 0;
21869
+ } while (after);
21870
+ return names;
21871
+ }
21872
+ function matchLabel(names, wanted) {
21873
+ const normalised = normaliseTypeName(wanted);
21874
+ return names.find((name) => name === wanted) ?? names.find((name) => name.toLowerCase() === wanted.toLowerCase()) ?? names.find((name) => normaliseTypeName(name) === normalised);
21875
+ }
21876
+ function resolveIssueLabels(target, wanted) {
21877
+ const names = readRepoLabels(target);
21878
+ return wanted.map((label2) => {
21879
+ const match = matchLabel(names, label2);
21880
+ if (!match) {
21881
+ throw new Error(
21882
+ `${target.owner}/${target.repo} has no ${label2} label. It has ${names.join(", ")}`
21883
+ );
21884
+ }
21885
+ return match;
21886
+ });
21802
21887
  }
21803
21888
 
21804
21889
  // src/commands/prs/shared.ts
@@ -21893,6 +21978,15 @@ function resolveIssueRepoTarget(repo) {
21893
21978
  return parseRepoSlug(repo);
21894
21979
  }
21895
21980
 
21981
+ // src/commands/github/issue/resolveCreateIssueParent.ts
21982
+ function resolveCreateIssueParent(target, parent) {
21983
+ const reference = resolveFixStructureTarget(
21984
+ parent,
21985
+ `${target.owner}/${target.repo}`
21986
+ );
21987
+ return { ...reference, id: fetchIssueNodeId(reference) };
21988
+ }
21989
+
21896
21990
  // src/commands/github/issue/readGhTokenScopes.ts
21897
21991
  import { spawnSync as spawnSync6 } from "child_process";
21898
21992
  var SCOPES_LINE = /Token scopes:\s*(.*)/;
@@ -22006,23 +22100,21 @@ function resolveCreateIssueProject(owner, projectNumber, statusName) {
22006
22100
 
22007
22101
  // src/commands/github/issue/resolveCreateIssueMetadata.ts
22008
22102
  function resolveCreateIssueMetadata(options2) {
22009
- if (!options2.type && !options2.project && !options2.status) return void 0;
22010
- if (options2.status && !options2.project) {
22011
- throw new Error(
22012
- "--status is a field on a project board, so it needs --project <number>"
22013
- );
22014
- }
22103
+ if (!hasCreateIssueMetadataOptions(options2)) return void 0;
22104
+ const labels = options2.label ?? [];
22015
22105
  const target = resolveIssueRepoTarget(options2.repo);
22016
22106
  return {
22017
22107
  target,
22018
22108
  issueType: options2.type ? resolveIssueType(resolveOrgIssueTypes(target.owner), options2.type) : void 0,
22019
- project: options2.project ? resolveCreateIssueProject(target.owner, options2.project, options2.status) : void 0
22109
+ parent: options2.parent ? resolveCreateIssueParent(target, options2.parent) : void 0,
22110
+ project: options2.project ? resolveCreateIssueProject(target.owner, options2.project, options2.status) : void 0,
22111
+ labels: labels.length ? resolveIssueLabels(target, labels) : void 0
22020
22112
  };
22021
22113
  }
22022
22114
 
22023
22115
  // src/commands/github/issue/reviewProposedIssue.ts
22024
22116
  import { randomUUID as randomUUID8 } from "crypto";
22025
- async function reviewProposedIssue(title, body) {
22117
+ async function reviewProposedIssue(title, body, metadata2 = []) {
22026
22118
  const sessionId = process.env.ASSIST_SESSION_ID;
22027
22119
  if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
22028
22120
  await awaitPreviewApproval("GitHub issue preview", {
@@ -22031,15 +22123,17 @@ async function reviewProposedIssue(title, body) {
22031
22123
  title,
22032
22124
  body,
22033
22125
  prNumber: null,
22034
- kind: "github-issue"
22126
+ kind: "github-issue",
22127
+ metadata: metadata2.length ? metadata2 : void 0
22035
22128
  });
22036
22129
  }
22037
22130
 
22038
22131
  // src/commands/github/issue/runGhIssueCreate.ts
22039
22132
  import { execFileSync as execFileSync7 } from "child_process";
22040
- function runGhIssueCreate(title, body, repo) {
22133
+ function runGhIssueCreate(title, body, repo, labels) {
22041
22134
  const args = ["issue", "create", "--title", title, "--body", body];
22042
22135
  if (repo) args.push("--repo", repo);
22136
+ for (const label2 of labels ?? []) args.push("--label", label2);
22043
22137
  try {
22044
22138
  return execFileSync7("gh", args, {
22045
22139
  encoding: "utf8",
@@ -22051,7 +22145,7 @@ function runGhIssueCreate(title, body, repo) {
22051
22145
  }
22052
22146
 
22053
22147
  // src/commands/github/issue/createIssue.ts
22054
- var USAGE2 = "Usage: assist github issue create --title <title> --body <body> [-R <owner>/<repo>] [--type <name>] [--project <number>] [--status <name>]";
22148
+ var USAGE2 = "Usage: assist github issue create --title <title> --body <body> [-R <owner>/<repo>] [--type <name>] [--parent <issue>] [--project <number>] [--status <name>] [--label <name>]";
22055
22149
  function preflight(options2) {
22056
22150
  try {
22057
22151
  return resolveCreateIssueMetadata(options2);
@@ -22060,15 +22154,6 @@ function preflight(options2) {
22060
22154
  process.exit(1);
22061
22155
  }
22062
22156
  }
22063
- function previewMetadata(resolved) {
22064
- if (!resolved) return void 0;
22065
- return {
22066
- repo: `${resolved.target.owner}/${resolved.target.repo}`,
22067
- type: resolved.issueType?.name,
22068
- project: resolved.project && `${resolved.project.number} (${resolved.project.title})`,
22069
- status: resolved.project?.status?.optionName
22070
- };
22071
- }
22072
22157
  async function createIssue(options2) {
22073
22158
  if (!options2.title || !options2.body) {
22074
22159
  console.error(USAGE2);
@@ -22081,11 +22166,8 @@ async function createIssue(options2) {
22081
22166
  body
22082
22167
  );
22083
22168
  const resolved = preflight(options2);
22084
- await reviewProposedIssue(
22085
- title,
22086
- buildIssuePreviewBody(previewMetadata(resolved), body)
22087
- );
22088
- const output = runGhIssueCreate(title, body, options2.repo);
22169
+ await reviewProposedIssue(title, body, issuePreviewMetadata(resolved));
22170
+ const output = runGhIssueCreate(title, body, options2.repo, resolved?.labels);
22089
22171
  console.log(output.trim());
22090
22172
  if (resolved) applyCreatedIssueMetadata(output, resolved);
22091
22173
  }
@@ -22098,15 +22180,23 @@ function registerCreateIssue(issueCommand) {
22098
22180
  ).option(
22099
22181
  "--type <name>",
22100
22182
  "Native issue type to set on the new issue (e.g. Epic)"
22183
+ ).option(
22184
+ "--parent <issue>",
22185
+ "Parent issue to file the new issue under, as owner/repo#number, a github.com issue URL, or a bare number"
22101
22186
  ).option(
22102
22187
  "--project <number>",
22103
22188
  "Number of the repo owner's GitHub Project to add the new issue to"
22104
22189
  ).option(
22105
22190
  "--status <name>",
22106
22191
  "Status option to set on the project item (requires --project)"
22192
+ ).option(
22193
+ "--label <name>",
22194
+ "Label to apply (repeat the flag, or pass a comma-separated list)",
22195
+ collectLabels,
22196
+ []
22107
22197
  ).addHelpText(
22108
22198
  "after",
22109
- "\nThere is no What/Why/How template: an issue reports a problem, and the target repo's own issue template is unknowable from here. Write the body as the repo's maintainers would expect.\nIn an assist web session the title and body are previewed for approve/reject first (with inline comments); nothing is created until it is approved.\n--type, --project and --status are all resolved before the preview, so an unknown name, a missing project scope or --status without --project creates nothing.\nThe project scope is needed for --project: gh auth refresh -h github.com -s project"
22199
+ "\nThere is no What/Why/How template: an issue reports a problem, and the target repo's own issue template is unknowable from here. Write the body as the repo's maintainers would expect.\nIn an assist web session the title and body are previewed for approve/reject first (with inline comments); nothing is created until it is approved.\n--type, --parent, --project, --status and --label are all resolved before the preview, so an unknown name, an unreadable parent, a missing project scope or --status without --project creates nothing.\nA bare --parent number is read against --repo, or the current repo; a parent in another repository is allowed.\nThe project scope is needed for --project: gh auth refresh -h github.com -s project"
22110
22200
  ).action(createIssue);
22111
22201
  }
22112
22202
 
@@ -29024,15 +29114,15 @@ function runReviewSubmission(mutation, body) {
29024
29114
  }
29025
29115
 
29026
29116
  // src/commands/review/submitBodyOnlyReview.ts
29027
- var MUTATION5 = `mutation($prId: ID!, $body: String) { addPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
29117
+ var MUTATION6 = `mutation($prId: ID!, $body: String) { addPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
29028
29118
  function submitBodyOnlyReview(body) {
29029
- runReviewSubmission(MUTATION5, body);
29119
+ runReviewSubmission(MUTATION6, body);
29030
29120
  }
29031
29121
 
29032
29122
  // src/commands/review/submitPendingReview.ts
29033
- var MUTATION6 = `mutation($prId: ID!, $body: String) { submitPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
29123
+ var MUTATION7 = `mutation($prId: ID!, $body: String) { submitPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
29034
29124
  function submitPendingReview(body) {
29035
- runReviewSubmission(MUTATION6, body);
29125
+ runReviewSubmission(MUTATION7, body);
29036
29126
  }
29037
29127
 
29038
29128
  // src/commands/review/postAndMaybeSubmit.ts
@@ -35056,6 +35146,16 @@ function isPreviewKind(value) {
35056
35146
  return PREVIEW_KINDS.includes(value);
35057
35147
  }
35058
35148
 
35149
+ // src/commands/sessions/daemon/parsePreviewMetadata.ts
35150
+ function parsePreviewMetadata(value) {
35151
+ if (!Array.isArray(value)) return void 0;
35152
+ const items2 = value.flatMap((entry) => {
35153
+ const { label: label2, value: text18 } = entry ?? {};
35154
+ return typeof label2 === "string" && typeof text18 === "string" ? [{ label: label2, value: text18 }] : [];
35155
+ });
35156
+ return items2.length > 0 ? items2 : void 0;
35157
+ }
35158
+
35059
35159
  // src/commands/sessions/daemon/previewTargetLabel.ts
35060
35160
  function previewTargetLabel(kind, itemType, prNumber, draft) {
35061
35161
  if (kind === "backlog-comment") return "backlog comment";
@@ -35092,7 +35192,8 @@ function setPrPreview(sessions, waiters, notify2, client, d) {
35092
35192
  prNumber,
35093
35193
  kind,
35094
35194
  itemType: kind === "backlog-item" ? itemType : void 0,
35095
- draft: kind === "pr" && prNumber === null ? draft : void 0
35195
+ draft: kind === "pr" && prNumber === null ? draft : void 0,
35196
+ metadata: parsePreviewMetadata(d.metadata)
35096
35197
  };
35097
35198
  waiters.set(id, client);
35098
35199
  const target = previewTargetLabel(kind, itemType, prNumber, draft);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.606.0",
3
+ "version": "0.607.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {