@harborppm/cli 0.78.0 → 0.79.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 +15 -0
- package/lib/cli.mjs +18 -3
- package/package.json +1 -1
package/dist/app.mjs
CHANGED
|
@@ -9834,6 +9834,7 @@ init_work();
|
|
|
9834
9834
|
init_clock();
|
|
9835
9835
|
init_soundings();
|
|
9836
9836
|
const KIND_RANK = {
|
|
9837
|
+
harbor: -1,
|
|
9837
9838
|
waiting: 0,
|
|
9838
9839
|
approval: 1,
|
|
9839
9840
|
review: 2,
|
|
@@ -9843,6 +9844,7 @@ const KIND_RANK = {
|
|
|
9843
9844
|
mention: 6
|
|
9844
9845
|
};
|
|
9845
9846
|
const PING_KIND_LABEL = {
|
|
9847
|
+
harbor: "Your harbor",
|
|
9846
9848
|
waiting: "Waiting on you",
|
|
9847
9849
|
approval: "Sign-offs",
|
|
9848
9850
|
review: "Reviews due",
|
|
@@ -9882,6 +9884,19 @@ function inboxOf(data, personId, now = clockNow()) {
|
|
|
9882
9884
|
const pings = [];
|
|
9883
9885
|
const mine = data.tasks.filter((t) => t.assigneeId === personId && t.status !== "done");
|
|
9884
9886
|
const since = subDays(now, ASSIGNED_DAYS).toISOString();
|
|
9887
|
+
const me = data.people.find((p) => p.id === personId);
|
|
9888
|
+
if (me?.harborHandedAt && me.harborHandedAt >= since && me.harborHandedById !== personId) {
|
|
9889
|
+
const by = data.people.find((p) => p.id === me.harborHandedById);
|
|
9890
|
+
pings.push({
|
|
9891
|
+
id: `harbor:${me.harborHandedAt}`,
|
|
9892
|
+
kind: "harbor",
|
|
9893
|
+
title: `${by ? firstName$3(by.name) : "The owner"} handed this harbor to you`,
|
|
9894
|
+
detail: "You own it now: invites, roles, billing, webhooks and the whole-harbor download. Settings has them all.",
|
|
9895
|
+
at: me.harborHandedAt,
|
|
9896
|
+
personId: by?.id ?? null,
|
|
9897
|
+
href: "/settings"
|
|
9898
|
+
});
|
|
9899
|
+
}
|
|
9885
9900
|
for (const task of mine) {
|
|
9886
9901
|
if (!task.assignedBy || task.assignedBy === personId || !task.assignedAt) continue;
|
|
9887
9902
|
if (task.assignedAt < since) continue;
|
package/lib/cli.mjs
CHANGED
|
@@ -557,17 +557,30 @@ async function readTitles(client, harbor, titles, values, today = todayLocal())
|
|
|
557
557
|
});
|
|
558
558
|
}
|
|
559
559
|
|
|
560
|
-
/**
|
|
560
|
+
/** "Fri 2026-11-13": a day with its weekday, so "next friday" shows which Friday it became. */
|
|
561
|
+
export function dayWithWeekday(iso) {
|
|
562
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(iso)) return iso;
|
|
563
|
+
const day = WEEKDAYS[new Date(`${iso}T12:00:00`).getDay()];
|
|
564
|
+
return day ? `${day.charAt(0).toUpperCase()}${day.slice(1, 3)} ${iso}` : iso;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/** What a title's words said, in a line: "Quinn (@Quinn), due Fri 2026-11-06 (by Friday)". */
|
|
561
568
|
function wordsLine(r) {
|
|
562
569
|
const bits = [
|
|
563
570
|
r.owner && `${r.owner.value} (${r.owner.text})`,
|
|
564
|
-
r.due && `due ${r.due.value} (${r.due.text})`,
|
|
571
|
+
r.due && `due ${dayWithWeekday(r.due.value)} (${r.due.text})`,
|
|
565
572
|
r.priority && `${r.priority.value} priority (${r.priority.text})`,
|
|
566
573
|
r.project && `in ${r.project.value} (${r.project.text})`,
|
|
567
574
|
].filter(Boolean);
|
|
568
575
|
return bits.length ? `Read from your words: ${bits.join(", ")}.` : null;
|
|
569
576
|
}
|
|
570
577
|
|
|
578
|
+
/** --due given in words rather than as a date or +N, when it reads as a day. */
|
|
579
|
+
function dueWords(v) {
|
|
580
|
+
if (typeof v !== "string" || /^(\d{4}-\d{2}-\d{2}|\+\d{1,3})$/.test(v) || PILOT.has(v.toLowerCase())) return false;
|
|
581
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(dueDate(v));
|
|
582
|
+
}
|
|
583
|
+
|
|
571
584
|
/** --due pilot: the date the owner's queue suggests, set by Harbor. */
|
|
572
585
|
const PILOT = new Set(["pilot", "suggested"]);
|
|
573
586
|
const duePilot = (v) => (v !== undefined && PILOT.has(v.toLowerCase()) ? true : undefined);
|
|
@@ -2537,7 +2550,7 @@ export async function run(argv, io = {}) {
|
|
|
2537
2550
|
[
|
|
2538
2551
|
`Would add ${n} to ${where.join(" and ")}:`,
|
|
2539
2552
|
...reads.flatMap((r, i) => [
|
|
2540
|
-
` ${r.title}${pilot ? ` (due ${pilot[i].earliest})` : values.due ? ` (due ${dueDate(values.due)})` : ""}`,
|
|
2553
|
+
` ${r.title}${pilot ? ` (due ${pilot[i].earliest})` : values.due ? ` (due ${dueWords(values.due) ? dayWithWeekday(dueDate(values.due)) : dueDate(values.due)})` : ""}`,
|
|
2541
2554
|
...(wordsLine(r) ? [` ${wordsLine(r)}`] : []),
|
|
2542
2555
|
]),
|
|
2543
2556
|
...(pilot
|
|
@@ -2598,6 +2611,8 @@ export async function run(argv, io = {}) {
|
|
|
2598
2611
|
`Added: ${taskLine(r.created, opts)}${r.comment ? ", with your comment" : ""}`,
|
|
2599
2612
|
// What the title's words said, so nothing is read without being seen.
|
|
2600
2613
|
...(r.read ? [`${r.read} --literal keeps the words in the title.`] : []),
|
|
2614
|
+
// --due in words ("next friday"): the day it became, weekday and all.
|
|
2615
|
+
...(dueWords(values.due) ? [`--due ${values.due}: ${dayWithWeekday(dueDate(values.due))}.`] : []),
|
|
2601
2616
|
// Pilot speaks up only when a date was given that the queue says won't hold.
|
|
2602
2617
|
...(values.due ? pilotLines(r, r.created) : []),
|
|
2603
2618
|
].join("\n"),
|