@bli-cockpit/cli 0.2.190 → 0.2.192

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.
@@ -41,9 +41,11 @@ export function parseSearchArgs(args) {
41
41
  let kinds;
42
42
  if (kindFlag) {
43
43
  kinds = [];
44
- for (const part of kindFlag.split(",").map((entry) => entry.trim()).filter(Boolean)) {
44
+ // BLI-12947: `ticket` is the new spelling of the `issue` kind (input only).
45
+ for (const raw of kindFlag.split(",").map((entry) => entry.trim()).filter(Boolean)) {
46
+ const part = raw === "ticket" ? "issue" : raw;
45
47
  if (!SEARCH_KINDS.includes(part)) {
46
- throw new Error(`search --kind must be one or more of ${SEARCH_KINDS.join(", ")} — not "${part}".`);
48
+ throw new Error(`search --kind must be one or more of ${SEARCH_KINDS.join(", ")} — not "${raw}".`);
47
49
  }
48
50
  if (!kinds.includes(part))
49
51
  kinds.push(part);
@@ -1,10 +1,13 @@
1
1
  import { optionalNonEmpty, optionalUrl, parseNamedArgs } from "./local-arg-values.js";
2
2
  export function parseSetupArgs(args) {
3
- const values = parseNamedArgs(args, { allowedFlags: ["--person", "--compare", "--json", "--home", "--dashboard-url"], valueFlags: ["--person", "--compare", "--home", "--dashboard-url"] });
3
+ const values = parseNamedArgs(args, { allowedFlags: ["--person", "--compare", "--since", "--details", "--json", "--home", "--dashboard-url"], valueFlags: ["--since", "--person", "--compare", "--home", "--dashboard-url"] });
4
4
  if (values.positionals.length)
5
5
  throw new Error("setup takes --person or --compare, not a subcommand.");
6
6
  const compare = optionalNonEmpty(values.flags.get("--compare"));
7
7
  if (compare && (compare.split(",").length !== 2 || compare.split(",").some(value => !value.trim())))
8
8
  throw new Error("--compare takes two emails separated by a comma.");
9
- return { kind: "setup", person: optionalNonEmpty(values.flags.get("--person")), compare, json: values.booleans.has("--json"), homeDir: optionalNonEmpty(values.flags.get("--home")), dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")) };
9
+ const since = optionalNonEmpty(values.flags.get("--since"));
10
+ if (since && since !== "7d" && since !== "30d" && (!/^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z)?$/.test(since) || !Number.isFinite(Date.parse(since)) || new Date(since).toISOString().slice(0, 10) !== since.slice(0, 10) || Date.parse(since) >= Date.now()))
11
+ throw new Error("--since takes 7d, 30d, or an ISO date before now.");
12
+ return { kind: "setup", since, details: values.booleans.has("--details"), person: optionalNonEmpty(values.flags.get("--person")), compare, json: values.booleans.has("--json"), homeDir: optionalNonEmpty(values.flags.get("--home")), dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")) };
10
13
  }
@@ -27,7 +27,7 @@ export function localSubcommandHelp(command) {
27
27
  // BLI-3709: the Tower nouns live next door, split along the same seam the
28
28
  // argument parsers already use — see `local-help-commands-tower.ts`.
29
29
  ...TOWER_COMMAND_HELP,
30
- ["setup", ["Usage: cockpit setup [--person <email>] [--compare <email,email>] [--json]", "Read agent setups beside 30-day outcomes, or compare two exact emails."]],
30
+ ["setup", ["Usage: cockpit setup [--since <7d|30d|date>] [--details] [--person <email>] [--compare <email,email>] [--json]", "Read agent setups beside windowed outcomes (default 30 days), or compare two exact emails."]],
31
31
  [
32
32
  "onboard",
33
33
  [
@@ -400,13 +400,13 @@ export function localSubcommandHelp(command) {
400
400
  ]);
401
401
  // BLI-10431: a Tower page name answers with its own usage line first, then
402
402
  // the manual of the noun it routes to, so `cockpit work --help` names every
403
- // Work verb instead of `Unknown command: work`.
403
+ // ticket verb instead of `Unknown command: work`.
404
404
  const aliasTarget = SURFACE_ALIASES.get(command);
405
405
  if (aliasTarget) {
406
406
  return [
407
407
  `Usage: cockpit ${command} [same verbs and flags as cockpit ${aliasTarget}]`,
408
408
  `\`cockpit ${command}\` is the Tower page's name for \`cockpit ${aliasTarget}\`; both spellings run the same command.`,
409
- ...(command === "work" ? ["Projects the issues are filed under: `cockpit project list`."] : []),
409
+ ...(aliasTarget === "issue" ? ["Projects the Tower tickets are filed under: `cockpit project list`."] : []),
410
410
  "",
411
411
  ...(helpByCommand.get(aliasTarget) ?? [localCommandHelp()]),
412
412
  ].join("\n");
@@ -14,17 +14,21 @@ import { localSubcommandHelp } from "./local-help-commands.js";
14
14
  * The Tower PAGE names a person reads in the rail, each routed to the CLI noun
15
15
  * that already serves that page (BLI-10431).
16
16
  *
17
- * The rail says WORK, CALENDAR, MESSAGES and MEETING NOTES; the MCP server
17
+ * The rail says TICKETS, CALENDAR, MESSAGES and MEETING NOTES; the MCP server
18
18
  * says `work_list_issues`; the CLI spelled the same doors `issue`, `cal`,
19
19
  * `msg` and `notes`. `cockpit work --help` answered `Unknown command: work` on
20
- * 0.2.133 while every Work verb existed one word away. An alias here is a
21
- * second spelling of the same parser, never a second parser: `cockpit work
22
- * list` IS `cockpit issue list`, byte for byte.
20
+ * 0.2.133 while every verb existed one word away. An alias here is a
21
+ * second spelling of the same parser, never a second parser: `cockpit ticket
22
+ * list` IS `cockpit issue list`, byte for byte. BLI-12947 renamed the Work
23
+ * page to Tickets and added `ticket` and `tickets`; `work` stays for every
24
+ * agent and doc that already says it.
23
25
  *
24
26
  * `surface-doors.test.ts` reads the rail and the MCP tool names and fails when
25
27
  * a page or a tool family has no spelling here or in `rootCommandNames`.
26
28
  */
27
29
  export const SURFACE_ALIASES = new Map([
30
+ ["ticket", "issue"],
31
+ ["tickets", "issue"],
28
32
  ["work", "issue"],
29
33
  ["calendar", "cal"],
30
34
  ["messages", "msg"],
@@ -139,11 +143,13 @@ export function localCommandHelp(command) {
139
143
  " cockpit rename [list|resolve <id> --scope <page|everywhere|undo>] [--dashboard-url <url>] [--json]",
140
144
  " cockpit logs <collector|dashboard|railway|railway:<service>|-> [--since 15m|1h|2d|<iso>] [--raw <template-id> [--limit <n>]] [--all-levels] [--table <file>] [--json]",
141
145
  " cockpit brain status [--project <id>] [--show open|running|needs_human|fixed|not_actionable|cleared] [--dashboard-url <url>] [--json]",
142
- " cockpit setup [--person <email>] [--compare <email,email>] [--json]",
146
+ " cockpit setup [--since <7d|30d|date>] [--details] [--person <email>] [--compare <email,email>] [--json]",
143
147
  " cockpit usage sessions [--task <BLI-NNNN> | --subject <name>] [--repo <label>] [--since <window>] [--json]",
144
148
  " cockpit usage sessions --session <id> [--from-window <n>] [--json]",
145
149
  " --by-topic groups work types; --by-subject groups open subjects from session summaries.",
146
- " cockpit work [same verbs and flags as cockpit issue] (the Work page; projects: `cockpit project list`)",
150
+ " cockpit ticket [same verbs and flags as cockpit issue] (the Tickets page; projects: `cockpit project list`)",
151
+ " cockpit tickets ... same as cockpit ticket",
152
+ " cockpit work ... same as cockpit ticket (the older name)",
147
153
  " cockpit calendar [same verbs and flags as cockpit cal]",
148
154
  " cockpit messages [same verbs and flags as cockpit msg]",
149
155
  " cockpit meeting-notes [same verbs and flags as cockpit notes]",
@@ -21,7 +21,7 @@ export async function runCockpitCli(argv, io) {
21
21
  }
22
22
 
23
23
  if (command === "--version" || command === "-V" || command === "version") {
24
- writeLine(io?.stdout ?? process.stdout, "0.2.190");
24
+ writeLine(io?.stdout ?? process.stdout, "0.2.192");
25
25
  return 0;
26
26
  }
27
27
 
@@ -37,7 +37,7 @@ const READ_DEADLINE_MS = 30_000;
37
37
  const KIND_LABELS = {
38
38
  doc: "DOCUMENTS",
39
39
  msg: "MESSAGES",
40
- issue: "ISSUES",
40
+ issue: "TICKETS",
41
41
  note: "MEETING NOTES",
42
42
  mail: "MAIL",
43
43
  cal: "CALENDAR",
@@ -3,6 +3,8 @@ import { writeLine } from "./cli-io.js";
3
3
  export async function runSetup(command, io) {
4
4
  const door = await openAgentDoor("setup", command, io);
5
5
  const query = new URLSearchParams();
6
+ if (command.since)
7
+ query.set("since", command.since);
6
8
  if (command.person)
7
9
  query.set("person", command.person);
8
10
  if (command.compare)
@@ -16,6 +18,8 @@ export async function runSetup(command, io) {
16
18
  const number = (value) => value === null ? "unknown" : value.toLocaleString(undefined, { maximumFractionDigits: 1 });
17
19
  for (const person of body.people ?? []) {
18
20
  writeLine(io.stdout, `${person.rank ? `#${person.rank} ` : "Unranked · "}${person.display_name ?? person.email ?? "Unknown person"}: ${number(person.prs_per_week)} merged PRs/week · ${number(person.tokens_per_pr)} tokens/merged PR · ${person.yield === null ? "unknown yield" : `${number(person.yield * 100)}% session yield`}`);
21
+ if (person.tokens_basis)
22
+ writeLine(io.stdout, ` Token basis: ${person.tokens_basis === "total_fallback" ? "total (input/cache breakdown unavailable)" : "input + output, excluding cache reads"}`);
19
23
  if (!person.machines.length)
20
24
  writeLine(io.stdout, " No setup received.");
21
25
  for (const machine of person.machines) {
@@ -30,7 +34,7 @@ export async function runSetup(command, io) {
30
34
  }
31
35
  for (const pair of body.comparison ?? []) {
32
36
  writeLine(io.stdout, `${pair.first ?? "Unknown person"} / ${pair.second ?? "Unknown person"}`);
33
- for (const difference of pair.differences)
37
+ for (const difference of command.details ? [...pair.differences, ...(pair.details ?? [])] : pair.differences)
34
38
  writeLine(io.stdout, ` ${difference}`);
35
39
  }
36
40
  if (body.note)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/cli",
3
- "version": "0.2.190",
3
+ "version": "0.2.192",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@bli-cockpit/memory-mcp": "0.1.57",
31
- "@bli-cockpit/mcp": "0.1.102",
31
+ "@bli-cockpit/mcp": "0.1.104",
32
32
  "@bli-cockpit/telemetry-core": "0.1.66"
33
33
  },
34
34
  "repository": {