@harborppm/cli 0.16.0 → 0.18.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/README.md CHANGED
@@ -117,9 +117,10 @@ harbor issue "TITLE" --project P|--program P [--impact 1-5] [--owner NAME]
117
117
  harbor decision "TITLE" --project P|--program P [--owner NAME] [--due DATE]
118
118
  harbor risks [words] [--kind risk,issue,decision] [--project P] [--closed]
119
119
  harbor premortem PROJECT ["WHAT WENT WRONG"] [--start]
120
+ harbor voyage PROJECT ["YOUR LINE"]
120
121
  ```
121
122
 
122
- `harbor premortem` runs a pre-mortem with your crew: `--start` asks everyone "it's after the end date and this project failed: what happened?", each person adds answers alone for five minutes, and then the answers show together on the project's Risks & issues tab, where each becomes a risk in one click. On its own it prints the question and the answers you can see.
123
+ `harbor premortem` runs a pre-mortem with your crew: `--start` asks everyone "it's after the end date and this project failed: what happened?", each person adds answers alone for five minutes, and then the answers show together on the project's Risks & issues tab, where each becomes a risk in one click. On its own it prints the question and the answers you can see. Once a project is Done, `harbor voyage` prints its voyage log (planned against actual dates, the biggest slips, the risks that came true, who closed the most, and the crew's lines) and adds yours.
123
124
 
124
125
  Every command takes `--json` for the raw result (a refusal then comes out as `{"error": "…"}` on standard output, still with exit code 1), and `harbor COMMAND --help` shows just that command. Statuses are backlog, todo, doing, review and done. A `DATE` is YYYY-MM-DD, `today`, `tomorrow`, or `+N` for N days from today.
125
126
 
package/dist/app.mjs CHANGED
@@ -855,7 +855,8 @@ function normalizeRaidItem(r) {
855
855
  createdAt: r.createdAt ?? now,
856
856
  updatedAt: r.updatedAt ?? r.createdAt ?? now,
857
857
  updates: Array.isArray(r.updates) ? r.updates : [],
858
- scoreHistory: Array.isArray(r.scoreHistory) && r.scoreHistory.length ? r.scoreHistory : void 0
858
+ scoreHistory: Array.isArray(r.scoreHistory) && r.scoreHistory.length ? r.scoreHistory : void 0,
859
+ ...kind === "risk" && typeof r.happened === "boolean" ? { happened: r.happened } : {}
859
860
  };
860
861
  }
861
862
  /** Active first, then by score, then most recently touched. */
@@ -9336,6 +9337,33 @@ function milestonesRaidSlice({ set, get, write }) {
9336
9337
  ...r,
9337
9338
  skipped
9338
9339
  } : r) });
9340
+ },
9341
+ writeVoyageLine: (projectId, body) => {
9342
+ const text = body.trim().slice(0, 600);
9343
+ const me = get().currentUserId;
9344
+ const all = get().reflections ?? [];
9345
+ const mine = all.find((r) => r.projectId === projectId && r.kind === "voyage" && r.authorId === me);
9346
+ if (!text) {
9347
+ if (mine) write({ reflections: all.filter((r) => r.id !== mine.id) });
9348
+ return;
9349
+ }
9350
+ if (mine) {
9351
+ if (mine.body !== text) write({ reflections: all.map((r) => r.id === mine.id ? {
9352
+ ...r,
9353
+ body: text
9354
+ } : r) });
9355
+ return;
9356
+ }
9357
+ if (!get().projects.some((p) => p.id === projectId)) return;
9358
+ const row = {
9359
+ id: uid("rf"),
9360
+ projectId,
9361
+ kind: "voyage",
9362
+ authorId: me,
9363
+ body: text,
9364
+ createdAt: stamp()
9365
+ };
9366
+ write({ reflections: [...all, row] });
9339
9367
  }
9340
9368
  };
9341
9369
  }
package/lib/cli.mjs CHANGED
@@ -20,6 +20,7 @@ import {
20
20
  harbors,
21
21
  myWork,
22
22
  premortemText,
23
+ voyageText,
23
24
  raidList,
24
25
  programTree,
25
26
  projectList,
@@ -93,6 +94,8 @@ export const HELP = `harbor: Harbor from the terminal
93
94
  harbor premortem PROJECT ["WHAT WENT WRONG"] [--start]
94
95
  a project's pre-mortem: start,
95
96
  answer or read it
97
+ harbor voyage PROJECT ["YOUR LINE"] a Done project's voyage log, and
98
+ your line in it
96
99
 
97
100
  Every command takes --json, and --harbor NAME when you're in more than one
98
101
  harbor (or set one with harbor use). harbor help COMMAND shows just that one.
@@ -1015,6 +1018,20 @@ export async function run(argv, io = {}) {
1015
1018
  }
1016
1019
  return call("get_premortem", { harbor, project }, premortemText);
1017
1020
  }
1021
+ case "voyage": {
1022
+ const { positionals, harbor } = parse(spec());
1023
+ const [project, ...words] = positionals;
1024
+ if (!project) throw new HarborError("Give a project, and your line if you're adding one.");
1025
+ const line = words.join(" ").trim();
1026
+ if (line) {
1027
+ return call(
1028
+ "add_voyage_line",
1029
+ { harbor, project, line },
1030
+ (r) => `Your line is in ${r.added.project}'s voyage log.`,
1031
+ );
1032
+ }
1033
+ return call("get_voyage_log", { harbor, project }, voyageText);
1034
+ }
1018
1035
  case "risk":
1019
1036
  case "issue":
1020
1037
  case "decision": {
package/lib/format.mjs CHANGED
@@ -211,3 +211,15 @@ export function premortemText(r) {
211
211
  lines.push(` Nothing yet. Add one: harbor premortem "${r.project}" "WHAT WENT WRONG"`);
212
212
  return [...head, "", ...lines].join("\n");
213
213
  }
214
+
215
+ /** A project's voyage log, as get_voyage_log answers it. */
216
+ export function voyageText(r) {
217
+ const head = [`Voyage log · ${r.project}${r.done ? ` · Done ${r.finished}` : ""}`];
218
+ if (r.note) head.push(r.note);
219
+ head.push((r.stats ?? []).join(" · "));
220
+ const story = (r.story ?? []).map((s) => ` - ${s}`);
221
+ const crew = (r.crew ?? []).map((c) => ` - ${c.who ?? "Someone"}: ${c.line}`);
222
+ return [...head, "", ...story, ...(crew.length ? ["", "From the crew:", ...crew] : [])].join(
223
+ "\n",
224
+ );
225
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harborppm/cli",
3
- "version": "0.16.0",
3
+ "version": "0.18.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",