@bli-cockpit/cli 0.2.77 → 0.2.79

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.
@@ -136,12 +136,21 @@ function describeWindow(body, zone) {
136
136
  return from === to ? `${from} (${zone})` : `${from} to ${to} (${zone})`;
137
137
  }
138
138
  function eventLine(event, zone) {
139
- const when = event.all_day ? "all day" : `${clock(event.starts_at, zone)}–${clock(event.ends_at, zone)}`;
139
+ const when = event.all_day ? allDayLabel(event.starts_at, event.ends_at) : `${clock(event.starts_at, zone)}–${clock(event.ends_at, zone)}`;
140
140
  const marks = `${event.recurring ? "↻" : " "}${event.status === "tentative" ? "?" : " "}`;
141
141
  const where = event.location ? ` @ ${event.location.slice(0, 40)}` : "";
142
142
  const who = event.attendee_count > 0 ? ` (${event.attendee_count})` : "";
143
143
  return `${marks} ${when.padEnd(13)} ${event.title.slice(0, 52).padEnd(52)}${where}${who}`;
144
144
  }
145
+ /**
146
+ * BLI-3825: an all-day event spanning several days is ONE row from the door
147
+ * (the page draws it on every day it covers); the terminal says the span on
148
+ * that one line rather than printing it once and looking like a single day.
149
+ */
150
+ function allDayLabel(startsAt, endsAt) {
151
+ const days = Math.max(1, Math.round((Date.parse(endsAt) - Date.parse(startsAt)) / 86_400_000));
152
+ return days > 1 ? `all day ×${days}d` : "all day";
153
+ }
145
154
  /** `Mon 7 Sep`, in the reader's zone. */
146
155
  function dayLabel(instant, zone) {
147
156
  try {
@@ -285,6 +294,7 @@ async function create(command, door) {
285
294
  ...(command.location ? { location: command.location } : {}),
286
295
  ...(command.allDay ? { all_day: true } : {}),
287
296
  ...(command.attendees.length > 0 ? { attendees: command.attendees } : {}),
297
+ ...(command.meet ? { meet: true } : {}),
288
298
  time_zone: command.timeZone ?? localTimeZone(),
289
299
  },
290
300
  });
@@ -297,6 +307,11 @@ async function create(command, door) {
297
307
  writeLine(door.io.stdout, `Created "${event?.title ?? command.title}" on ${event ? `${dayLabel(event.starts_at, zone)} ${clock(event.starts_at, zone)}` : "that calendar"}.`);
298
308
  if (event?.html_link)
299
309
  writeLine(door.io.stdout, event.html_link);
310
+ if (command.meet) {
311
+ writeLine(door.io.stdout, event?.meet_link
312
+ ? `Google Meet: ${event.meet_link}`
313
+ : "Google did not attach a Meet room (meet_not_available) — the event exists without one; add the room in Google Calendar or ask a Workspace admin whether Meet is enabled.");
314
+ }
300
315
  if (command.attendees.length > 0) {
301
316
  writeLine(door.io.stdout, `Invitations went to ${command.attendees.join(", ")} from Google.`);
302
317
  }
@@ -53,6 +53,7 @@ export function parseCalArgs(args) {
53
53
  "--location",
54
54
  "--attendee",
55
55
  "--all-day",
56
+ "--meet",
56
57
  "--org-visible",
57
58
  "--private",
58
59
  "--full",
@@ -148,6 +149,7 @@ export function parseCalArgs(args) {
148
149
  location: optionalNonEmpty(values.flags.get("--location")),
149
150
  attendees: splitAddresses(values.flags.get("--attendee")),
150
151
  allDay: values.booleans.has("--all-day"),
152
+ meet: values.booleans.has("--meet"),
151
153
  orgVisible: values.booleans.has("--org-visible"),
152
154
  makePrivate: values.booleans.has("--private"),
153
155
  full: values.booleans.has("--full"),
@@ -109,7 +109,7 @@ export const TOWER_COMMAND_HELP = [
109
109
  ' PowerShell: "https://calendar.google.com/calendar/ical/…/basic.ics" | cockpit cal add-ical --name "Personal"',
110
110
  " Find it at calendar.google.com -> the calendar's Settings -> \"Secret address in iCal format\". Anybody who has that link can read the calendar, which is why it never goes on a command line.",
111
111
  " A work @buildlaunchiterate.ca calendar does not need this: connect Google in the browser and `cockpit cal calendars` will list them.",
112
- 'create --calendar <id> --title "<what>" --at <iso> --until <iso> [--location "<where>"] [--attendee a@x,b@y] [--all-day] — creates the event AT GOOGLE, then here. Attendees are invited by Google.',
112
+ 'create --calendar <id> --title "<what>" --at <iso> --until <iso> [--location "<where>"] [--attendee a@x,b@y] [--all-day] [--meet] — creates the event AT GOOGLE, then here. Attendees are invited by Google; --meet asks for a Google Meet room and prints its address (or says meet_not_available and keeps the event).',
113
113
  " Only a Google calendar can be written to: an iCal secret address is a read address, and `write_not_supported_for_provider` says so by name.",
114
114
  "share <id> --org-visible|--private — makes one of YOUR calendars readable by everyone at BLI, or private again. Sharing never lets anybody else change it.",
115
115
  "sync <id> [--full] — reads that calendar now instead of waiting for the cron. --full ignores the sync token / ETag and re-reads everything.",
@@ -100,10 +100,21 @@ export function localCommandHelp(command) {
100
100
  `Default dashboard: ${DEFAULT_DASHBOARD_URL}. Omit --dashboard-url for normal production use; pass it only for staging/custom dashboards or to force a different pairing.`,
101
101
  ].join("\n");
102
102
  }
103
- /** `cockpit <command> --help` — the command name alone, with only the help flag. */
103
+ /**
104
+ * `cockpit <command> --help`, and since BLI-3833 `cockpit <command> <verb>
105
+ * --help` too — QA tick 21 found `cockpit cal create --help` printing the whole
106
+ * usage wall to stderr and exiting 1 on all eight nouns, because the gate only
107
+ * accepted the command name alone. The verb is not validated here: a verb the
108
+ * manual does not know still gets the command's own manual, which names every
109
+ * verb it has, at exit 0.
110
+ */
104
111
  export function isLocalHelpRequest(argv) {
105
112
  const command = argv[0];
106
113
  if (!command || !rootCommandNames.has(command))
107
114
  return false;
108
- return argv.length === 2 && (argv[1] === "--help" || argv[1] === "-h");
115
+ const last = argv[argv.length - 1];
116
+ const helpFlag = last === "--help" || last === "-h";
117
+ if (argv.length === 2)
118
+ return helpFlag;
119
+ return argv.length === 3 && helpFlag && !String(argv[1]).startsWith("-");
109
120
  }
@@ -15,7 +15,7 @@ export async function runCockpitCli(argv, io) {
15
15
  }
16
16
 
17
17
  if (command === "--version" || command === "-V" || command === "version") {
18
- writeLine(io?.stdout ?? process.stdout, "0.2.77");
18
+ writeLine(io?.stdout ?? process.stdout, "0.2.79");
19
19
  return 0;
20
20
  }
21
21
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/cli",
3
- "version": "0.2.77",
3
+ "version": "0.2.79",
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.11",
31
- "@bli-cockpit/mcp": "0.1.14",
31
+ "@bli-cockpit/mcp": "0.1.15",
32
32
  "@bli-cockpit/telemetry-core": "0.1.32"
33
33
  }
34
34
  }