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.
- package/.claude-plugin/marketplace.json +3 -8
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +12 -7
- package/bin/open-plan-annotator.mjs +5 -13
- package/opencode/bridge.js +3 -9
- package/package.json +13 -12
- package/shared/packageManager.mjs +39 -0
- package/shared/packageManager.test.ts +33 -0
|
@@ -5,19 +5,14 @@
|
|
|
5
5
|
},
|
|
6
6
|
"metadata": {
|
|
7
7
|
"description": "Interactive plan annotation plugin for Claude Code",
|
|
8
|
-
"version": "1.
|
|
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.
|
|
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.
|
|
4
|
+
"version": "1.1.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "ndom91"
|
|
7
7
|
},
|
package/README.md
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+

|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/open-plan-annotator)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[]()
|
|
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
|
-

|
|
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
|
+

|
|
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
|
}
|
package/opencode/bridge.js
CHANGED
|
@@ -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:
|
|
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.
|
|
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": "
|
|
41
|
-
"build": "bun run build:ui &&
|
|
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": "
|
|
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": "
|
|
52
|
-
"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.
|
|
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.
|
|
65
|
-
"@open-plan-annotator/runtime-darwin-x64": "1.
|
|
66
|
-
"@open-plan-annotator/runtime-linux-arm64": "1.
|
|
67
|
-
"@open-plan-annotator/runtime-linux-x64": "1.
|
|
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
|
+
});
|