open-plan-annotator 1.0.20 → 1.1.1

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,19 +5,14 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "Interactive plan annotation plugin for Claude Code",
8
- "version": "1.0.20"
8
+ "version": "1.1.1"
9
9
  },
10
10
  "plugins": [
11
11
  {
12
12
  "name": "open-plan-annotator",
13
- "source": {
14
- "npm": {
15
- "package": "open-plan-annotator",
16
- "version": "1.0.20"
17
- }
18
- },
13
+ "source": "./",
19
14
  "description": "Interactive plan annotation UI: review, strikethrough, and comment on Claude's plans before approving. Fully local, no external services.",
20
- "version": "1.0.20",
15
+ "version": "1.1.1",
21
16
  "author": {
22
17
  "name": "ndom91"
23
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.20",
4
+ "version": "1.1.1",
5
5
  "author": {
6
6
  "name": "ndom91"
7
7
  },
package/README.md CHANGED
@@ -1,14 +1,13 @@
1
- # open-plan-annotator
1
+ ![](.github/assets/header.jpg)
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/open-plan-annotator?style=flat-square)](https://www.npmjs.com/package/open-plan-annotator)
4
- [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT)
5
- [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux-pink?style=flat-square)]()
3
+ [![npm version](https://img.shields.io/npm/v/open-plan-annotator?style=for-the-badge&labelColor=black&color=black)](https://www.npmjs.com/package/open-plan-annotator)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-orange.svg?style=for-the-badge&labelColor=black&color=black)](https://opensource.org/licenses/MIT)
5
+ [![Platform](https://img.shields.io/badge/platform-Linux%20%7C%20macOS-pink?style=for-the-badge&labelColor=black&color=black)]()
6
6
 
7
7
  A fully local agentic coding plugin that intercepts plan mode and opens an annotation UI in your browser. Mark up the plan, send structured feedback to the agent, and receive a revised version — iterate as many times as you need until you're ready to approve.
8
8
 
9
9
  Select text to <code>strikethrough</code>, <code>replace</code>, <code>insert</code>, or <code>comment</code> — then approve the plan or request changes
10
10
 
11
- ![](.github/assets/screenshot.png)
12
11
 
13
12
  ## How It Works
14
13
 
@@ -20,6 +19,8 @@ Select text to <code>strikethrough</code>, <code>replace</code>, <code>insert</c
20
19
 
21
20
  Everything runs locally. Nothing leaves your machine.
22
21
 
22
+ ![](.github/assets/screenshot.png)
23
+
23
24
  ## Install
24
25
 
25
26
  > [!NOTE]
@@ -36,7 +37,7 @@ From within Claude Code, add the marketplace and install the plugin:
36
37
  /plugin install open-plan-annotator@ndom91-open-plan-annotator
37
38
  ```
38
39
 
39
- This installs the npm-backed plugin and registers the `ExitPlanMode` hook that launches the annotation UI.
40
+ This installs the npm-backed plugin and registers the `ExitPlanMode` hook that launches the annotation UI. In Claude Code, third-party marketplaces have auto-update disabled by default, so also enable auto-update for the `ndom91-open-plan-annotator` marketplace in the Marketplace UI.
40
41
 
41
42
  ### OpenCode
42
43
 
@@ -44,7 +45,7 @@ Add `open-plan-annotator` to the `plugin` array in your OpenCode config (`openco
44
45
 
45
46
  ```json
46
47
  {
47
- "plugin": ["open-plan-annotator"]
48
+ "plugin": ["open-plan-annotator@latest"]
48
49
  }
49
50
  ```
50
51
 
@@ -57,6 +58,9 @@ OpenCode will install the package and load it automatically. The plugin:
57
58
 
58
59
  To update, refresh the plugin through OpenCode and restart the app so it reloads the latest package-managed runtime.
59
60
 
61
+ > [!NOTE]
62
+ > The update mechanism changed significantly in `1.0.20+`: OpenCode now loads the npm package plus a platform runtime package instead of using the old in-place binary updater. If OpenCode appears to be stuck on an older plugin build, clear the cached `open-plan-annotator` entries under `~/.cache/opencode/node_modules/` and restart OpenCode.
63
+
60
64
  #### Implementation Handoff
61
65
 
62
66
  By default, after a plan is approved the plugin sends "Proceed with implementation." to a `build` agent. To customize or disable this, create `open-plan-annotator.json` in your project's `.opencode/` directory or globally in `~/.config/opencode/`:
@@ -77,6 +81,7 @@ Set `enabled` to `false` to disable auto-handoff. Project config overrides globa
77
81
  If you want to run the CLI standalone or install the package globally:
78
82
 
79
83
  ```sh
84
+ pnpm add -g open-plan-annotator
80
85
  npm install -g open-plan-annotator
81
86
  ```
82
87
 
@@ -6,6 +6,7 @@ import path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { buildCliHelpText, buildUnknownCommandPrefix } from "../shared/cliHelp.mjs";
8
8
  import { resolveCliMode } from "../shared/cliMode.mjs";
9
+ import { detectPackageManager } from "../shared/packageManager.mjs";
9
10
  import { resolveRuntimeBinary } from "../shared/runtimeResolver.mjs";
10
11
  import { buildUpdateInstructions } from "../shared/updateHints.mjs";
11
12
 
@@ -50,19 +51,10 @@ if (cliMode === "hook") {
50
51
  }
51
52
 
52
53
  if (cliMode === "update") {
53
- console.log(buildUpdateInstructions({ host: process.env.OPEN_PLAN_HOST, packageManager: detectPackageManager() }));
54
+ console.log(buildUpdateInstructions({ host: process.env.OPEN_PLAN_HOST, packageManager: detectPackageManager({ installPath: fileURLToPath(import.meta.url) }) }));
54
55
  process.exit(0);
55
56
  }
56
57
 
57
- // Detect package manager so the binary can suggest the right update command
58
- function detectPackageManager() {
59
- const ua = process.env.npm_config_user_agent || "";
60
- if (ua.startsWith("pnpm")) return "pnpm";
61
- if (ua.startsWith("yarn")) return "yarn";
62
- if (ua.startsWith("bun")) return "bun";
63
- return "npm";
64
- }
65
-
66
58
  let runtime;
67
59
  try {
68
60
  runtime = resolveRuntimeBinary({ parentUrl: import.meta.url });
@@ -77,7 +69,7 @@ const child = spawn(runtime.binaryPath, process.argv.slice(2), {
77
69
  env: {
78
70
  ...process.env,
79
71
  OPEN_PLAN_HOST: process.env.OPEN_PLAN_HOST || "claude-code",
80
- OPEN_PLAN_PKG_MANAGER: detectPackageManager(),
72
+ OPEN_PLAN_PKG_MANAGER: detectPackageManager({ installPath: fileURLToPath(import.meta.url) }),
81
73
  },
82
74
  });
83
75
 
@@ -136,7 +128,7 @@ function printDoctor() {
136
128
  `platform: ${platformKey}`,
137
129
  `runtime package: ${runtime.packageName}`,
138
130
  `runtime path: ${runtime.binaryPath}`,
139
- `update: ${buildUpdateInstructions({ host: process.env.OPEN_PLAN_HOST, packageManager: detectPackageManager() })}`,
131
+ `update: ${buildUpdateInstructions({ host: process.env.OPEN_PLAN_HOST, packageManager: detectPackageManager({ installPath: fileURLToPath(import.meta.url) }) })}`,
140
132
  ].join("\n"));
141
133
  } catch (error) {
142
134
  console.log([
@@ -144,7 +136,7 @@ function printDoctor() {
144
136
  `platform: ${platformKey}`,
145
137
  `runtime: missing`,
146
138
  `error: ${error instanceof Error ? error.message : String(error)}`,
147
- `update: ${buildUpdateInstructions({ host: process.env.OPEN_PLAN_HOST, packageManager: detectPackageManager() })}`,
139
+ `update: ${buildUpdateInstructions({ host: process.env.OPEN_PLAN_HOST, packageManager: detectPackageManager({ installPath: fileURLToPath(import.meta.url) }) })}`,
148
140
  ].join("\n"));
149
141
  }
150
142
  }
@@ -3,6 +3,7 @@ import { randomUUID } from "node:crypto";
3
3
  import { existsSync, statSync } from "node:fs";
4
4
  import { dirname } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
+ import { detectPackageManager } from "../shared/packageManager.mjs";
6
7
  import { resolveRuntimeBinary } from "../shared/runtimeResolver.mjs";
7
8
 
8
9
  const PKG_ROOT = fileURLToPath(new URL("..", import.meta.url));
@@ -98,14 +99,6 @@ function validateHookOutput(value) {
98
99
  throw new Error("unsupported decision payload");
99
100
  }
100
101
 
101
- function detectPackageManager() {
102
- const ua = process.env.npm_config_user_agent || "";
103
- if (ua.startsWith("pnpm")) return "pnpm";
104
- if (ua.startsWith("yarn")) return "yarn";
105
- if (ua.startsWith("bun")) return "bun";
106
- return "npm";
107
- }
108
-
109
102
  /**
110
103
  * @param {{ plan: string, sessionId?: string, cwd?: string }} options
111
104
  */
@@ -134,7 +127,8 @@ export async function runPlanReview(options) {
134
127
  env: {
135
128
  ...process.env,
136
129
  OPEN_PLAN_HOST: "opencode",
137
- OPEN_PLAN_PKG_MANAGER: process.env.OPEN_PLAN_PKG_MANAGER || detectPackageManager(),
130
+ OPEN_PLAN_PKG_MANAGER:
131
+ process.env.OPEN_PLAN_PKG_MANAGER || detectPackageManager({ installPath: fileURLToPath(import.meta.url) }),
138
132
  },
139
133
  detached: true,
140
134
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-plan-annotator",
3
- "version": "1.0.20",
3
+ "version": "1.1.1",
4
4
  "type": "module",
5
5
  "description": "Fully local plugin for interactive plan annotation from your Agentic assistants",
6
6
  "author": "ndom91",
@@ -37,10 +37,10 @@
37
37
  "test": "bun test",
38
38
  "typecheck": "tsgo --noEmit --project ui/tsconfig.json && tsgo --noEmit --project server/tsconfig.json",
39
39
  "build:ui": "cd ui && bun run vite build",
40
- "build:platforms": "node scripts/build-platforms.mjs",
41
- "build": "bun run build:ui && node scripts/build-platforms.mjs",
40
+ "build:platforms": "bun scripts/build-platforms.mjs",
41
+ "build": "bun run build:ui && bun run build:platforms",
42
42
  "release": "bun run build",
43
- "pack:check": "node scripts/check-package-files.mjs",
43
+ "pack:check": "bun scripts/check-package-files.mjs",
44
44
  "dev:ui": "cd ui && bun run vite --port 5173",
45
45
  "dev:server": "NODE_ENV=development bun run server/index.ts",
46
46
  "dev": "NODE_ENV=development bun run server/index.ts & cd ui && bun run vite --port 5173",
@@ -48,11 +48,11 @@
48
48
  "lint:fix": "biome check --write .",
49
49
  "format": "biome format --write .",
50
50
  "do-release": "./scripts/release.sh",
51
- "prepack": "node scripts/claude-pack-docs.mjs prepack",
52
- "postpack": "node scripts/claude-pack-docs.mjs postpack"
51
+ "prepack": "bun scripts/claude-pack-docs.mjs prepack",
52
+ "postpack": "bun scripts/claude-pack-docs.mjs postpack"
53
53
  },
54
54
  "devDependencies": {
55
- "@biomejs/biome": "^2.4.4",
55
+ "@biomejs/biome": "^2.4.6",
56
56
  "@types/node": "^25.3.0",
57
57
  "@types/bun": "^1.3.9",
58
58
  "@typescript/native-preview": "^7.0.0-dev.20260224.1"
@@ -61,9 +61,10 @@
61
61
  "@opencode-ai/plugin": "^1.2.14"
62
62
  },
63
63
  "optionalDependencies": {
64
- "@open-plan-annotator/runtime-darwin-arm64": "1.0.20",
65
- "@open-plan-annotator/runtime-darwin-x64": "1.0.20",
66
- "@open-plan-annotator/runtime-linux-arm64": "1.0.20",
67
- "@open-plan-annotator/runtime-linux-x64": "1.0.20"
68
- }
64
+ "@open-plan-annotator/runtime-darwin-arm64": "1.1.1",
65
+ "@open-plan-annotator/runtime-darwin-x64": "1.1.1",
66
+ "@open-plan-annotator/runtime-linux-arm64": "1.1.1",
67
+ "@open-plan-annotator/runtime-linux-x64": "1.1.1"
68
+ },
69
+ "packageManager": "bun@1.3.9"
69
70
  }
@@ -0,0 +1,39 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+
4
+ function detectFromValue(value) {
5
+ if (!value) return undefined;
6
+ const normalized = value.toLowerCase();
7
+ if (normalized.includes("pnpm")) return "pnpm";
8
+ if (normalized.includes("yarn")) return "yarn";
9
+ if (normalized.includes("bun")) return "bun";
10
+ if (normalized.includes("npm")) return "npm";
11
+ return undefined;
12
+ }
13
+
14
+ export function detectPackageManager(options = {}) {
15
+ const env = options.env ?? process.env;
16
+ const installPath = options.installPath;
17
+
18
+ const explicit = detectFromValue(env.OPEN_PLAN_PKG_MANAGER);
19
+ if (explicit) return explicit;
20
+
21
+ const userAgent = env.npm_config_user_agent;
22
+ if (typeof userAgent === "string") {
23
+ const name = userAgent.split("/")[0];
24
+ const detected = detectFromValue(name);
25
+ if (detected) return detected;
26
+ }
27
+
28
+ const packageManager = detectFromValue(env.npm_package_manager);
29
+ if (packageManager) return packageManager;
30
+
31
+ const execPath = detectFromValue(env.npm_execpath);
32
+ if (execPath) return execPath;
33
+
34
+ const resolvedInstallPath = installPath ?? fileURLToPath(import.meta.url);
35
+ const pathHint = detectFromValue(path.normalize(resolvedInstallPath));
36
+ if (pathHint) return pathHint;
37
+
38
+ return "npm";
39
+ }
@@ -0,0 +1,33 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { detectPackageManager } from "./packageManager.mjs";
3
+
4
+ describe("detectPackageManager", () => {
5
+ test("prefers explicit OPEN_PLAN_PKG_MANAGER", () => {
6
+ expect(detectPackageManager({ env: { OPEN_PLAN_PKG_MANAGER: "pnpm" } })).toBe("pnpm");
7
+ });
8
+
9
+ test("detects package manager from npm user agent", () => {
10
+ expect(detectPackageManager({ env: { npm_config_user_agent: "pnpm/10.0.0 node/v22.0.0" } })).toBe("pnpm");
11
+ });
12
+
13
+ test("detects package manager from npm execpath", () => {
14
+ expect(detectPackageManager({ env: { npm_execpath: "/usr/local/lib/node_modules/pnpm/bin/pnpm.cjs" } })).toBe(
15
+ "pnpm",
16
+ );
17
+ });
18
+
19
+ test("detects package manager from install path hints", () => {
20
+ expect(
21
+ detectPackageManager({
22
+ env: {},
23
+ installPath: "/Users/test/Library/pnpm/global/5/node_modules/open-plan-annotator/bin/open-plan-annotator.mjs",
24
+ }),
25
+ ).toBe("pnpm");
26
+ });
27
+
28
+ test("falls back to npm", () => {
29
+ expect(detectPackageManager({ env: {}, installPath: "/tmp/open-plan-annotator/bin/open-plan-annotator.mjs" })).toBe(
30
+ "npm",
31
+ );
32
+ });
33
+ });