@harborppm/cli 0.14.0 → 0.15.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 +4 -3
- package/lib/cli.mjs +40 -8
- package/lib/update.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,13 +55,13 @@ Your harbor is the same one at [harborppm.com](https://harborppm.com/today?utm_s
|
|
|
55
55
|
- **GitHub**: a pull request that names a task's key (RR-42) shows on the task and moves it along.
|
|
56
56
|
- **Claude and other AI apps**, connected over MCP from [harborppm.com/ai](https://harborppm.com/ai?utm_source=npm&utm_medium=readme&utm_campaign=cli).
|
|
57
57
|
|
|
58
|
-
`harbor open RR-42` opens a task on the website (in the right harbor, even when the browser had another one open), `harbor open Ridge` a project, and `harbor open` on its own opens Today. `harbor invite sam@example.com` sends Sam the same invite letter the People page does (`--viewer` to let them look but not change anything); only a harbor's owner can invite.
|
|
58
|
+
`harbor open RR-42` opens a task on the website (in the right harbor, even when the browser had another one open), `harbor open Ridge` a project, and `harbor open` on its own opens Today. `harbor invite sam@example.com` sends Sam the same invite letter the People page does (`--viewer` to let them look but not change anything); only a harbor's owner can invite. `harbor calendar` prints your private calendar link, to add to Google, Apple or Outlook calendar: your due dates, milestones and sign-offs beside your meetings, kept up to date (`--program NAME` for everything dated in one program, `--new` to swap the link for a fresh one, `--off` to turn it off).
|
|
59
59
|
|
|
60
60
|
The website has the commands too: turn on **Command line at the bottom** in your menu, press `/`, and type `mine`, `add "Call the mill" #ridge @sam --due fri` or `done RR-12`.
|
|
61
61
|
|
|
62
62
|
## In your shell prompt
|
|
63
63
|
|
|
64
|
-
`harbor prompt` prints a few characters for your prompt: `⚓ 2 today · 1 late`, with late work in coral, and nothing at all when you're clear. It never waits on the network: it shows the counts it kept and fetches new ones in the background when they're more than five minutes old, or after you change a task. `harbor prompt --init zsh` (or `bash`, `fish`, `starship`) prints the lines to add to your shell's setup:
|
|
64
|
+
`harbor prompt` prints a few characters for your prompt: `⚓ 2 today · 1 late`, with late work in coral, and nothing at all when you're clear. It never waits on the network: it shows the counts it kept and fetches new ones in the background when they're more than five minutes old, or after you change a task. `harbor prompt --init zsh` (or `bash`, `fish`, `starship`) prints the lines to add to your shell's setup, so `harbor prompt --init starship >> ~/.config/starship.toml` does it in one go:
|
|
65
65
|
|
|
66
66
|
```zsh
|
|
67
67
|
# ~/.zshrc
|
|
@@ -71,7 +71,7 @@ RPROMPT='$(harbor prompt --shell zsh)'
|
|
|
71
71
|
|
|
72
72
|
## Staying up to date
|
|
73
73
|
|
|
74
|
-
npm doesn't update a global install by itself, so once a day `harbor` asks npm whether a newer version is out, alongside whatever command you ran, and says so in one line when there is (`npm install -g @harborppm/cli@latest` updates it). It says nothing in scripts, pipes or CI; set `HARBOR_NO_UPDATE_CHECK=1` (or `NO_UPDATE_NOTIFIER=1`) to turn it off.
|
|
74
|
+
npm doesn't update a global install by itself, so once a day `harbor` asks npm whether a newer version is out, alongside whatever command you ran, and says so in one line when there is (`npm install -g @harborppm/cli@latest --prefer-online` updates it). It says nothing in scripts, pipes or CI; set `HARBOR_NO_UPDATE_CHECK=1` (or `NO_UPDATE_NOTIFIER=1`) to turn it off.
|
|
75
75
|
|
|
76
76
|
## Text from others
|
|
77
77
|
|
|
@@ -95,6 +95,7 @@ harbor tasks [words] [--project P] [--assignee me|none|NAME] [--late] [--status
|
|
|
95
95
|
harbor show TASK one task in full, with its web link
|
|
96
96
|
harbor open [TASK|PROJECT] open it on the website (or Today)
|
|
97
97
|
harbor invite EMAIL [--viewer] invite someone to your harbor by email
|
|
98
|
+
harbor calendar [--program P] [--new|--off] your private calendar link (.ics)
|
|
98
99
|
|
|
99
100
|
harbor program "NAME" [--portfolio P] [--lead me|NAME] [--starts DATE]
|
|
100
101
|
[--ends DATE]
|
package/lib/cli.mjs
CHANGED
|
@@ -66,6 +66,7 @@ export const HELP = `harbor: Harbor from the terminal
|
|
|
66
66
|
shell prompt (never waits)
|
|
67
67
|
harbor prompt --init SHELL how to add it: zsh, bash, fish
|
|
68
68
|
or starship
|
|
69
|
+
harbor calendar [--program P] [--new|--off] your private calendar link (.ics)
|
|
69
70
|
|
|
70
71
|
harbor program "NAME" [--portfolio P] [--lead me|NAME] [--starts DATE]
|
|
71
72
|
[--ends DATE]
|
|
@@ -523,7 +524,8 @@ export async function run(argv, io = {}) {
|
|
|
523
524
|
const snippet = initSnippet(values.init);
|
|
524
525
|
if (!snippet) throw new HarborError(`Pick ${SHELLS.join(", ")} (not "${values.init}").`);
|
|
525
526
|
out(
|
|
526
|
-
|
|
527
|
+
// Comments, so the whole of it can be appended straight to the file.
|
|
528
|
+
`${snippet}\n# Shows what's due today and late, from the prompt after next;\n# nothing when you're clear. harbor prompt --refresh checks now.`,
|
|
527
529
|
);
|
|
528
530
|
return 0;
|
|
529
531
|
}
|
|
@@ -533,12 +535,14 @@ export async function run(argv, io = {}) {
|
|
|
533
535
|
const creds = await readCredentials(env);
|
|
534
536
|
const harbor = values.harbor ?? creds?.harbor ?? null;
|
|
535
537
|
const today = todayLocal(io.now ? new Date(io.now()) : new Date());
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
);
|
|
538
|
+
// A prompt with nothing to say gets nothing, not an empty line; a
|
|
539
|
+
// --refresh run by hand says what it found.
|
|
540
|
+
const show = (counts, at, byHand = false) => {
|
|
541
|
+
if (values.json) return out(jsonText({ ...(counts ?? { today: null, late: null }), at }));
|
|
542
|
+
const text = segment(counts ?? {}, shell);
|
|
543
|
+
if (text) out(text);
|
|
544
|
+
else if (byHand) out("Nothing due today or late.");
|
|
545
|
+
};
|
|
542
546
|
if (!creds) {
|
|
543
547
|
if (values.refresh) throw new HarborError("Not signed in. Run harbor login.");
|
|
544
548
|
show(null, null);
|
|
@@ -553,7 +557,7 @@ export async function run(argv, io = {}) {
|
|
|
553
557
|
const counts = promptCounts(work, today);
|
|
554
558
|
const at = io.now?.() ?? Date.now();
|
|
555
559
|
await writePromptCache({ at, day: today, harbor, counts }, env);
|
|
556
|
-
show(counts, at);
|
|
560
|
+
show(counts, at, !shell);
|
|
557
561
|
return 0;
|
|
558
562
|
}
|
|
559
563
|
// The prompt itself: what's kept, at once, and fresh counts fetched for next time.
|
|
@@ -818,6 +822,34 @@ export async function run(argv, io = {}) {
|
|
|
818
822
|
);
|
|
819
823
|
return 0;
|
|
820
824
|
}
|
|
825
|
+
case "calendar": {
|
|
826
|
+
const { values, harbor } = parse(spec(["new", "off"], ["program"]));
|
|
827
|
+
if (values.new && values.off) throw new HarborError("Say --new or --off, not both.");
|
|
828
|
+
if (!hasFullAccess(creds)) {
|
|
829
|
+
throw new HarborError("Calendar links need full access. Run harbor login, then try again.");
|
|
830
|
+
}
|
|
831
|
+
const r = await client.app({
|
|
832
|
+
op: "calendar",
|
|
833
|
+
...(harbor ? { harbor } : {}),
|
|
834
|
+
...(values.program ? { program: values.program } : {}),
|
|
835
|
+
action: values.off ? "off" : values.new ? "fresh" : "show",
|
|
836
|
+
});
|
|
837
|
+
if (asJson) {
|
|
838
|
+
out(jsonText(r));
|
|
839
|
+
return 0;
|
|
840
|
+
}
|
|
841
|
+
const what = r.program ? `everything dated in ${r.program}` : `your work in ${r.harbor}`;
|
|
842
|
+
if (!r.url) {
|
|
843
|
+
out(plain(`Turned off the calendar link for ${what}. Calendars using it stop updating.`));
|
|
844
|
+
return 0;
|
|
845
|
+
}
|
|
846
|
+
out(
|
|
847
|
+
plain(
|
|
848
|
+
`${values.new ? "A new calendar link" : "Your calendar link"} for ${what}${values.new ? " (the old one has stopped working)" : ""}:\n\n ${r.url}\n\nAdd it to Google, Apple or Outlook calendar as a calendar from a URL. Anyone with the link can see these dates; harbor calendar --new swaps it for a fresh one.`,
|
|
849
|
+
),
|
|
850
|
+
);
|
|
851
|
+
return 0;
|
|
852
|
+
}
|
|
821
853
|
case "add": {
|
|
822
854
|
const { positionals, values, harbor } = parse(
|
|
823
855
|
spec(["over-limit"], ["project", "assignee", "due", "priority", "status"]),
|
package/lib/update.mjs
CHANGED
|
@@ -68,6 +68,6 @@ export async function updateNotice({
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
return latest && isNewer(latest, version)
|
|
71
|
-
? `Harbor CLI ${latest} is out (you have ${version}): npm install -g @harborppm/cli@latest`
|
|
71
|
+
? `Harbor CLI ${latest} is out (you have ${version}): npm install -g @harborppm/cli@latest --prefer-online`
|
|
72
72
|
: null;
|
|
73
73
|
}
|