open-plan-annotator 1.0.12 → 1.0.14

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.
@@ -5,14 +5,14 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "Interactive plan annotation plugin for Claude Code",
8
- "version": "1.0.12"
8
+ "version": "1.0.14"
9
9
  },
10
10
  "plugins": [
11
11
  {
12
12
  "name": "open-plan-annotator",
13
13
  "source": "./",
14
14
  "description": "Interactive plan annotation UI: review, strikethrough, and comment on Claude's plans before approving. Fully local, no external services.",
15
- "version": "1.0.12",
15
+ "version": "1.0.14",
16
16
  "author": {
17
17
  "name": "ndom91"
18
18
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "open-plan-annotator",
3
3
  "description": "Interactive plan annotation UI: review, strikethrough, and comment on Claude's plans before approving. Fully local, no external services.",
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": {
6
6
  "name": "ndom91"
7
7
  },
@@ -4,6 +4,8 @@ import { execFileSync, spawn } from "node:child_process";
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
+ import { buildCliHelpText, buildUnknownCommandPrefix } from "../shared/cliHelp.mjs";
8
+ import { resolveCliMode } from "../shared/cliMode.mjs";
7
9
 
8
10
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
11
  const binaryPath = path.join(__dirname, "open-plan-annotator-binary");
@@ -11,31 +13,34 @@ const installScript = path.join(__dirname, "..", "install.mjs");
11
13
  const VERSION = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8")).version;
12
14
 
13
15
  const arg = process.argv[2];
16
+ const cliMode = resolveCliMode(arg, { stdinIsTTY: process.stdin.isTTY === true });
14
17
 
15
- if (arg === "--version" || arg === "-v") {
18
+ if (cliMode === "version") {
16
19
  console.log(VERSION);
17
20
  process.exit(0);
18
21
  }
19
22
 
20
- if (arg === "--help" || arg === "-h") {
21
- console.log(`open-plan-annotator v${VERSION}
22
-
23
- Usage:
24
- open-plan-annotator Run as a Claude Code hook (reads stdin)
25
- open-plan-annotator update Update the binary to the latest version
26
- open-plan-annotator --version Print version
27
- open-plan-annotator --help Show this help
28
-
29
- https://github.com/ndom91/open-plan-annotator`);
23
+ if (cliMode === "help") {
24
+ console.log(buildCliHelpText(VERSION));
30
25
  process.exit(0);
31
26
  }
32
27
 
28
+ if (cliMode === "unknown") {
29
+ console.error(buildUnknownCommandPrefix(arg));
30
+ console.error("Run `open-plan-annotator --help` for usage.");
31
+ process.exit(1);
32
+ }
33
+
33
34
  // Buffer stdin immediately so it's not lost if we need to download first.
34
35
  // Skip when stdin is a TTY (manual invocation) to avoid blocking forever.
35
36
  let stdinBuffer;
36
- try {
37
- stdinBuffer = process.stdin.isTTY ? Buffer.alloc(0) : fs.readFileSync(0);
38
- } catch {
37
+ if (cliMode === "hook") {
38
+ try {
39
+ stdinBuffer = process.stdin.isTTY ? Buffer.alloc(0) : fs.readFileSync(0);
40
+ } catch {
41
+ stdinBuffer = Buffer.alloc(0);
42
+ }
43
+ } else {
39
44
  stdinBuffer = Buffer.alloc(0);
40
45
  }
41
46
 
@@ -65,8 +70,8 @@ if (!fs.existsSync(binaryPath)) {
65
70
  justInstalled = true;
66
71
  }
67
72
 
68
- // Handle `open-plan-annotator update` subcommand
69
- if (process.argv[2] === "update") {
73
+ // Handle `open-plan-annotator update|upgrade` subcommand
74
+ if (cliMode === "update") {
70
75
  if (justInstalled) {
71
76
  console.log("Binary installed (v" + VERSION + ")");
72
77
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-plan-annotator",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "type": "module",
5
5
  "description": "Fully local plugin for interactive plan annotation from your Agentic assistants",
6
6
  "author": "ndom91",
@@ -0,0 +1,27 @@
1
+ const REPOSITORY_URL = "https://github.com/ndom91/open-plan-annotator";
2
+
3
+ const HELP_USAGE_LINES = [
4
+ "open-plan-annotator Show this help",
5
+ "open-plan-annotator < event.json Run as a Claude Code hook (debug)",
6
+ "open-plan-annotator update Update the binary to the latest version",
7
+ "open-plan-annotator upgrade Alias for update",
8
+ "open-plan-annotator --version Print version",
9
+ "open-plan-annotator --help Show this help",
10
+ ];
11
+
12
+ /**
13
+ * @param {string} version
14
+ * @returns {string}
15
+ */
16
+ export function buildCliHelpText(version) {
17
+ const usage = HELP_USAGE_LINES.map((line) => ` ${line}`).join("\n");
18
+ return `open-plan-annotator v${version}\n\nUsage:\n${usage}\n\n${REPOSITORY_URL}`;
19
+ }
20
+
21
+ /**
22
+ * @param {string | undefined} command
23
+ * @returns {string}
24
+ */
25
+ export function buildUnknownCommandPrefix(command) {
26
+ return `open-plan-annotator: unknown command \`${command ?? ""}\``;
27
+ }
@@ -0,0 +1,28 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { buildCliHelpText, buildUnknownCommandPrefix } from "./cliHelp.mjs";
3
+
4
+ describe("buildCliHelpText", () => {
5
+ test("builds canonical help text for all entrypoints", () => {
6
+ expect(buildCliHelpText("1.2.3")).toBe(`open-plan-annotator v1.2.3
7
+
8
+ Usage:
9
+ open-plan-annotator Show this help
10
+ open-plan-annotator < event.json Run as a Claude Code hook (debug)
11
+ open-plan-annotator update Update the binary to the latest version
12
+ open-plan-annotator upgrade Alias for update
13
+ open-plan-annotator --version Print version
14
+ open-plan-annotator --help Show this help
15
+
16
+ https://github.com/ndom91/open-plan-annotator`);
17
+ });
18
+ });
19
+
20
+ describe("buildUnknownCommandPrefix", () => {
21
+ test("formats unknown command prefix consistently", () => {
22
+ expect(buildUnknownCommandPrefix("wat")).toBe("open-plan-annotator: unknown command `wat`");
23
+ });
24
+
25
+ test("handles missing command safely", () => {
26
+ expect(buildUnknownCommandPrefix(undefined)).toBe("open-plan-annotator: unknown command ``");
27
+ });
28
+ });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @typedef {"hook" | "update" | "help" | "version" | "unknown"} CliMode
3
+ */
4
+
5
+ /**
6
+ * @typedef {{ stdinIsTTY?: boolean }} CliModeOptions
7
+ */
8
+
9
+ /**
10
+ * @param {string | undefined} arg
11
+ * @param {CliModeOptions} [options]
12
+ * @returns {CliMode}
13
+ */
14
+ export function resolveCliMode(arg, options = {}) {
15
+ if (!arg) {
16
+ return options.stdinIsTTY ? "help" : "hook";
17
+ }
18
+
19
+ if (arg === "update" || arg === "upgrade") return "update";
20
+ if (arg === "--help" || arg === "-h") return "help";
21
+ if (arg === "--version" || arg === "-v") return "version";
22
+ return "unknown";
23
+ }
@@ -0,0 +1,31 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { resolveCliMode } from "./cliMode.mjs";
3
+
4
+ describe("resolveCliMode", () => {
5
+ test("returns help for no-arg interactive invocation", () => {
6
+ expect(resolveCliMode(undefined, { stdinIsTTY: true })).toBe("help");
7
+ });
8
+
9
+ test("returns hook for no-arg piped invocation", () => {
10
+ expect(resolveCliMode(undefined, { stdinIsTTY: false })).toBe("hook");
11
+ });
12
+
13
+ test("defaults no-arg invocation to hook mode", () => {
14
+ expect(resolveCliMode(undefined)).toBe("hook");
15
+ });
16
+
17
+ test("treats upgrade as update alias", () => {
18
+ expect(resolveCliMode("upgrade")).toBe("update");
19
+ });
20
+
21
+ test("recognizes help and version flags", () => {
22
+ expect(resolveCliMode("--help")).toBe("help");
23
+ expect(resolveCliMode("-h")).toBe("help");
24
+ expect(resolveCliMode("--version")).toBe("version");
25
+ expect(resolveCliMode("-v")).toBe("version");
26
+ });
27
+
28
+ test("marks unknown commands explicitly", () => {
29
+ expect(resolveCliMode("noop")).toBe("unknown");
30
+ });
31
+ });