@harborppm/cli 0.75.0 → 0.76.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/app.mjs CHANGED
@@ -18813,10 +18813,17 @@ function harborExport(data, harbor, now) {
18813
18813
  * through Import.
18814
18814
  */
18815
18815
  function allTasksCsv(data) {
18816
+ return tasksSheetCsv(data, data.tasks);
18817
+ }
18818
+ /**
18819
+ * These tasks, one row each, as `allTasksCsv` lays them out: the whole
18820
+ * harbor's, or a program's for a sheet link (src/lib/sheet-feed.ts).
18821
+ */
18822
+ function tasksSheetCsv(data, rows) {
18816
18823
  const projects = byId(data.projects);
18817
18824
  const programs = byId(data.programs);
18818
18825
  const people = byId(data.people);
18819
- const tasks = byId(data.tasks);
18826
+ const tasks = byId(rows);
18820
18827
  const keyOf = (t) => taskKey(t, projects.get(t.projectId)) ?? t.title;
18821
18828
  return toCsv([
18822
18829
  "Key",
@@ -18831,7 +18838,7 @@ function allTasksCsv(data) {
18831
18838
  "Blocked by",
18832
18839
  "Created",
18833
18840
  "Description"
18834
- ], data.tasks.map((t) => {
18841
+ ], rows.map((t) => {
18835
18842
  const project = projects.get(t.projectId);
18836
18843
  const program = project ? programs.get(project.programId) : void 0;
18837
18844
  return [
@@ -21340,10 +21347,11 @@ function viewerUpdate(state, partial) {
21340
21347
  }
21341
21348
  /**
21342
21349
  * Whether this saved harbor can't be changed from here: the person is a
21343
- * viewer, or its free trial has ended with nobody keeping it (keep.ts).
21350
+ * viewer, its free trial has ended with nobody keeping it (keep.ts), or it
21351
+ * was opened offline from this device's copy (`offlineCopy`).
21344
21352
  */
21345
21353
  function readOnlyHarbor(s) {
21346
- return s.cloud && (s.myRole === "viewer" || Boolean(s.keepPaused));
21354
+ return s.cloud && (s.myRole === "viewer" || Boolean(s.keepPaused) || Boolean(s.offlineCopy));
21347
21355
  }
21348
21356
  var VIEWER_LOCAL, documentKeys;
21349
21357
  var init_view_only = __esmMin((() => {
@@ -21798,6 +21806,7 @@ function sessionSlice({ set, get, write }) {
21798
21806
  }),
21799
21807
  setWorkspaceVersion: (workspaceVersion) => set({ workspaceVersion }),
21800
21808
  setPhase: (phase) => set({ phase }),
21809
+ setOfflineCopy: (offlineCopy) => set({ offlineCopy }),
21801
21810
  setMyRole: (myRole) => set({ myRole }),
21802
21811
  setHarborName: (harborName) => set({ harborName }),
21803
21812
  setKeep: (k) => set({
@@ -24828,6 +24837,7 @@ function shoreService(raw) {
24828
24837
  if ((host === "discord.com" || host === "discordapp.com" || host === "ptb.discord.com" || host === "canary.discord.com") && /^\/api\/webhooks\/\d+\/[\w-]+$/.test(path)) return "discord";
24829
24838
  if (/^[a-z0-9-]+\.webhook\.office\.com$/.test(host) && path.startsWith("/webhookb2/")) return "teams";
24830
24839
  if ((/^[a-z0-9.-]+\.logic\.azure\.com$/.test(host) || /^[a-z0-9.-]+\.environment\.api\.powerplatform\.com$/.test(host)) && path.includes("/workflows/")) return "teams-workflow";
24840
+ if (host === "chat.googleapis.com" && /^\/v1\/spaces\/[\w-]+\/messages$/.test(path) && url.searchParams.get("key") && url.searchParams.get("token")) return "google-chat";
24831
24841
  return null;
24832
24842
  }
24833
24843
  /** "hooks.slack.com/…8f2Q": enough to recognise an address without showing the secret in it. */
@@ -24846,7 +24856,8 @@ var init_shore = __esmMin((() => {
24846
24856
  slack: "Slack",
24847
24857
  discord: "Discord",
24848
24858
  teams: "Teams",
24849
- "teams-workflow": "Teams"
24859
+ "teams-workflow": "Teams",
24860
+ "google-chat": "Google Chat"
24850
24861
  };
24851
24862
  SHORE_KINDS = [
24852
24863
  {
@@ -24938,7 +24949,7 @@ function memoryHarbor(start, opts) {
24938
24949
  }
24939
24950
  let row = hooks.get(program.id);
24940
24951
  if (ask.url || ask.on?.length || ask.off?.length) {
24941
- if (ask.url && !shoreService(ask.url)) throw new TransportError("That isn’t a Slack, Discord or Teams incoming-webhook address.", 400);
24952
+ if (ask.url && !shoreService(ask.url)) throw new TransportError("That isn’t a Slack, Discord, Teams or Google Chat incoming-webhook address.", 400);
24942
24953
  const url = ask.url || row?.url;
24943
24954
  if (!url) throw new TransportError("Paste the channel’s address first.", 400);
24944
24955
  row = {
@@ -26555,7 +26566,7 @@ function LifeboatsPanel({ id, width, height, go, active, onClose }) {
26555
26566
 
26556
26567
  // src/tui/views/shore.tsx
26557
26568
  /**
26558
- * Ship to shore in the terminal: a program's Slack, Discord or Teams channel
26569
+ * Ship to shore in the terminal: a program's Slack, Discord, Teams or Google Chat channel
26559
26570
  * and which posts go there, as the website's dialog sets it (shore.ts). The
26560
26571
  * address is a secret, so once saved only a hint of it shows. Asks /api/app's
26561
26572
  * `shore` (the in-memory server keeps a pretend one).
@@ -26608,7 +26619,7 @@ function ShorePanel({ id, width, height, go, active, onClose }) {
26608
26619
  if (input === "p") return go.ask("The channel's incoming-webhook address", (text) => {
26609
26620
  const url = text.trim();
26610
26621
  if (!url) return;
26611
- if (!shoreService(url)) return go.notify("That isn't a Slack, Discord or Teams incoming-webhook address. It starts https://hooks.slack.com/, https://discord.com/api/webhooks/ or a Teams workflow address.");
26622
+ if (!shoreService(url)) return go.notify("That isn't a Slack, Discord, Teams or Google Chat incoming-webhook address. It starts https://hooks.slack.com/, https://discord.com/api/webhooks/, https://chat.googleapis.com/ or a Teams workflow address.");
26612
26623
  send({ url }, (a) => `Connected to ${a.hook?.service ?? "the channel"}. Turn on what it posts.`);
26613
26624
  });
26614
26625
  if (!hook) return;
@@ -26654,7 +26665,7 @@ function ShorePanel({ id, width, height, go, active, onClose }) {
26654
26665
  /* @__PURE__ */ jsx(Text, {
26655
26666
  color: theme.muted,
26656
26667
  wrap: "wrap",
26657
- children: "Harbor posts into one Slack, Discord or Teams channel for this program instead of sending mail. Each post links back here."
26668
+ children: "Harbor posts into one Slack, Discord, Teams or Google Chat channel for this program instead of sending mail. Each post links back here."
26658
26669
  }),
26659
26670
  /* @__PURE__ */ jsx(Text, { children: " " }),
26660
26671
  failed ? /* @__PURE__ */ jsx(Text, {
package/lib/cli.mjs CHANGED
@@ -769,8 +769,8 @@ const DETAIL = {
769
769
  shore: [
770
770
  " harbor shore PROGRAM reads the program's chat channel and",
771
771
  " which posts go there",
772
- " harbor shore PROGRAM --url URL writes: posts go to this Slack, Discord",
773
- " or Teams incoming-webhook address",
772
+ " harbor shore PROGRAM --url URL writes: posts go to this Slack, Discord,",
773
+ " Teams or Google Chat webhook address",
774
774
  " harbor shore PROGRAM --on KINDS writes: turns posts on; KINDS are",
775
775
  " forecast, health and notes, with commas",
776
776
  " harbor shore PROGRAM --off KINDS writes: turns them off",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harborppm/cli",
3
- "version": "0.75.0",
3
+ "version": "0.76.0",
4
4
  "description": "Harbor from the terminal: a full-screen app with everything, plus commands for scripts and agents.",
5
5
  "keywords": [
6
6
  "harbor",