@mutmutco/cli 3.21.0 → 3.23.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.
Files changed (2) hide show
  1. package/dist/main.cjs +59 -7
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -10237,6 +10237,11 @@ function resolvePrViewFields(tokens2, defaultPrFields) {
10237
10237
  const provided = tokens2 !== void 0 && tokens2.length > 0;
10238
10238
  return provided ? normalizeIssueViewJsonFields(tokens2) : defaultPrFields;
10239
10239
  }
10240
+ function ensureField(fields, field) {
10241
+ const list = fields.split(",").map((f) => f.trim()).filter(Boolean);
10242
+ if (!list.includes(field)) list.push(field);
10243
+ return list.join(",");
10244
+ }
10240
10245
 
10241
10246
  // src/sub-issue.ts
10242
10247
  function parseIssueRef(ref) {
@@ -17278,6 +17283,39 @@ async function runPrForIssue(deps, issueRef, opts) {
17278
17283
  }
17279
17284
  return extractPrForIssueResponse(resp);
17280
17285
  }
17286
+ async function runIssueViewContext(deps, opts) {
17287
+ const fields = opts.comments || opts.context ? ensureField(opts.jsonFields, "comments") : opts.jsonFields;
17288
+ const base = await deps.ghJson(["issue", "view", String(opts.number), "--repo", opts.repo, "--json", fields], GH_LIST_TIMEOUT_MS);
17289
+ if (!opts.context) return base;
17290
+ const result = { ...base };
17291
+ const ref = `${opts.repo}#${opts.number}`;
17292
+ let partial = false;
17293
+ try {
17294
+ result.linkedPrs = await runPrForIssue(deps, ref, { repo: opts.repo });
17295
+ } catch {
17296
+ result.linkedPrs = [];
17297
+ partial = true;
17298
+ }
17299
+ try {
17300
+ const children = await runIssueChildren(deps, ref, { recursive: false, boardProjectId: opts.boardProjectId });
17301
+ if (children.length) result.children = children;
17302
+ } catch {
17303
+ partial = true;
17304
+ }
17305
+ if (partial) result.partial = true;
17306
+ return result;
17307
+ }
17308
+ async function runPrViewContext(deps, opts) {
17309
+ let fields = opts.jsonFields;
17310
+ if (opts.comments || opts.context) fields = ensureField(fields, "comments");
17311
+ if (opts.context) fields = ensureField(fields, "closingIssuesReferences");
17312
+ const base = await deps.ghJson(["pr", "view", String(opts.number), "--repo", opts.repo, "--json", fields], GH_LIST_TIMEOUT_MS);
17313
+ if (!opts.context) return base;
17314
+ const result = { ...base };
17315
+ result.linkedIssues = Array.isArray(base.closingIssuesReferences) ? base.closingIssuesReferences : [];
17316
+ delete result.closingIssuesReferences;
17317
+ return result;
17318
+ }
17281
17319
  function queryFail(command, e) {
17282
17320
  if (e instanceof QueryReadError) {
17283
17321
  const code = e.code === "NOT_FOUND" ? ERROR_CODES.ERR_NOT_FOUND : e.code === "NO_AUTH" ? ERROR_CODES.ERR_NO_AUTH : ERROR_CODES.ERR_BAD_ENUM;
@@ -17311,15 +17349,18 @@ async function resolveBoardProjectId(repoOption) {
17311
17349
  return void 0;
17312
17350
  }
17313
17351
  }
17314
- function registerQueryCommands(program3) {
17315
- const issue2 = program3.commands.find((c) => c.name() === "issue");
17316
- const pr2 = program3.commands.find((c) => c.name() === "pr");
17317
- if (!issue2 || !pr2) return;
17318
- const deps = {
17352
+ function queryDeps() {
17353
+ return {
17319
17354
  ghJson: async (args, timeoutMs = GH_LIST_TIMEOUT_MS) => JSON.parse((await execFileP2("gh", args, { timeout: timeoutMs })).stdout),
17320
17355
  viewer: () => githubLogin(),
17321
17356
  resolveRepo: resolveRepo2
17322
17357
  };
17358
+ }
17359
+ function registerQueryCommands(program3) {
17360
+ const issue2 = program3.commands.find((c) => c.name() === "issue");
17361
+ const pr2 = program3.commands.find((c) => c.name() === "pr");
17362
+ if (!issue2 || !pr2) return;
17363
+ const deps = queryDeps();
17323
17364
  issue2.command("list").description("bounded issue read \u2014 filter by label/state/assignee (NO free-text search); always prints JSON").option("--label <label>", "filter by label").option("--state <state>", "open | closed | all", "open").option("--assignee <login>", "filter by assignee login").option("--limit <n>", "max issues to return (capped at 100)", (v) => Number(v), DEFAULT_LIMIT).option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--json", "machine-readable output (already the default \u2014 accepted for contract uniformity)").action(async (o) => {
17324
17365
  try {
17325
17366
  const state = validateEnum("--state", ISSUE_STATES, o.state, "issue list");
@@ -21107,13 +21148,19 @@ withExamples(mutating(
21107
21148
  "--type is one of bug|feature|task.",
21108
21149
  "--dry-run and --validate-only pre-validate the create plan before any issue is written."
21109
21150
  ]);
21110
- issue.command("view <number>").description("read an issue as structured JSON \u2014 the mmi-cli path for non-board issue reads (#2347)").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--json [fields...]", 'gh --json field list (overrides the default field set). Accepts commas, spaces, or repeated --json flags \u2014 in PowerShell an unquoted comma list is an array literal, so QUOTE it: --json "number,title,body,url"').action(async (number, o) => {
21151
+ issue.command("view <number>").description('read an issue as structured JSON \u2014 the mmi-cli path for non-board issue reads (#2347). --comments folds in every comment; --context also adds linkedPrs + children (the one-shot "load the whole item" read, #2894)').option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--json [fields...]", 'gh --json field list (overrides the default field set). Accepts commas, spaces, or repeated --json flags \u2014 in PowerShell an unquoted comma list is an array literal, so QUOTE it: --json "number,title,body,url"').option("--comments", 'include every comment (body + comments in one call) \u2014 the agentic "read the whole item before working it" read (#2894)').option("--context", "full working context in one call: implies --comments and also adds linkedPrs and, for an epic, a children summary (#2894)").action(async (number, o) => {
21111
21152
  const n = Number(number);
21112
21153
  if (!Number.isInteger(n) || n <= 0) return fail("issue view: <number> must be a positive integer");
21113
21154
  const repo = await resolveRepo(o.repo);
21114
21155
  if (!repo) return fail("issue view: could not resolve repo (pass --repo <owner/repo>)");
21115
21156
  const fields = normalizeIssueViewJsonFields(o.json);
21116
21157
  try {
21158
+ if (o.comments || o.context) {
21159
+ const boardProjectId = o.context ? await resolveBoardProjectId(o.repo) : void 0;
21160
+ const data2 = await runIssueViewContext(queryDeps(), { number: n, repo, comments: Boolean(o.comments), context: Boolean(o.context), jsonFields: fields, boardProjectId });
21161
+ console.log(JSON.stringify(data2));
21162
+ return;
21163
+ }
21117
21164
  const data = await ghJson(["issue", "view", String(n), "--repo", repo, "--json", fields]);
21118
21165
  console.log(JSON.stringify(data));
21119
21166
  } catch (e) {
@@ -21357,7 +21404,7 @@ withExamples(pr.command("create").description("create a PR and print {number,url
21357
21404
  "--head and --base default to the current branch and the repo default; only pass them to override.",
21358
21405
  "Use --body-file for multiline PR bodies instead of shell-escaped inline markdown."
21359
21406
  ]);
21360
- pr.command("view <number>").description("read a PR as structured JSON (merged state, head/base, URL, merge commit) \u2014 the mmi-cli read path (#2347)").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--json [fields...]", 'gh --json field list (overrides the default field set). Accepts commas, spaces, or repeated --json flags \u2014 in PowerShell an unquoted comma list is an array literal, so QUOTE it: --json "state,baseRefName,mergeCommit"').action(async (number, o) => {
21407
+ pr.command("view <number>").description("read a PR as structured JSON (merged state, head/base, URL, merge commit) \u2014 the mmi-cli read path (#2347). --comments folds in every comment; --context also adds linkedIssues (the issues it closes/references, #2894)").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--json [fields...]", 'gh --json field list (overrides the default field set). Accepts commas, spaces, or repeated --json flags \u2014 in PowerShell an unquoted comma list is an array literal, so QUOTE it: --json "state,baseRefName,mergeCommit"').option("--comments", "include every comment (body + comments in one call) \u2014 read the whole PR before landing it (#2894)").option("--context", "full working context in one call: implies --comments and also adds linkedIssues (the issues the PR closes/references) (#2894)").action(async (number, o) => {
21361
21408
  const n = Number(number);
21362
21409
  if (!Number.isInteger(n) || n <= 0) return fail("pr view: <number> must be a positive integer");
21363
21410
  const repo = await resolveRepo(o.repo);
@@ -21365,6 +21412,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
21365
21412
  const defaultPrFields = "number,title,state,url,isDraft,mergeable,mergedAt,mergeCommit,headRefName,baseRefName,author,labels";
21366
21413
  const effective = resolvePrViewFields(o.json, defaultPrFields);
21367
21414
  try {
21415
+ if (o.comments || o.context) {
21416
+ const data2 = await runPrViewContext(queryDeps(), { number: n, repo, comments: Boolean(o.comments), context: Boolean(o.context), jsonFields: effective });
21417
+ console.log(JSON.stringify(data2));
21418
+ return;
21419
+ }
21368
21420
  const data = await ghJson(["pr", "view", String(n), "--repo", repo, "--json", effective]);
21369
21421
  console.log(JSON.stringify(data));
21370
21422
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "3.21.0",
3
+ "version": "3.23.0",
4
4
  "description": "MMI Future CLI — the org dev toolbox (board, registry, keyless secrets, release train, bootstrap, doctor) and the cross-IDE engine the plugin's session-start hook drives.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",