open-plan-annotator 1.1.2 → 1.1.4

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.1.2"
8
+ "version": "1.1.4"
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.1.2",
15
+ "version": "1.1.4",
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.1.2",
4
+ "version": "1.1.4",
5
5
  "author": {
6
6
  "name": "ndom91"
7
7
  },
@@ -8,7 +8,7 @@ import { buildCliHelpText, buildUnknownCommandPrefix } from "../shared/cliHelp.m
8
8
  import { resolveCliMode } from "../shared/cliMode.mjs";
9
9
  import { detectPackageManager } from "../shared/packageManager.mjs";
10
10
  import { resolveRuntimeBinary } from "../shared/runtimeResolver.mjs";
11
- import { buildUpdateInstructions } from "../shared/updateHints.mjs";
11
+ import { buildUpdateMessage } from "../shared/updateMessage.mjs";
12
12
 
13
13
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
14
  const VERSION = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8")).version;
@@ -27,7 +27,7 @@ if (cliMode === "help") {
27
27
  }
28
28
 
29
29
  if (cliMode === "doctor") {
30
- printDoctor();
30
+ await printDoctor();
31
31
  process.exit(0);
32
32
  }
33
33
 
@@ -51,7 +51,9 @@ if (cliMode === "hook") {
51
51
  }
52
52
 
53
53
  if (cliMode === "update") {
54
- console.log(buildUpdateInstructions({ host: process.env.OPEN_PLAN_HOST, packageManager: detectPackageManager({ installPath: fileURLToPath(import.meta.url) }) }));
54
+ console.log(
55
+ await buildUpdateMessage({ packageManager: detectPackageManager({ installPath: fileURLToPath(import.meta.url) }) }),
56
+ );
55
57
  process.exit(0);
56
58
  }
57
59
 
@@ -118,8 +120,10 @@ child.on("error", (err) => {
118
120
  process.exit(1);
119
121
  });
120
122
 
121
- function printDoctor() {
123
+ async function printDoctor() {
122
124
  const platformKey = `${process.platform}-${process.arch}`;
125
+ const packageManager = detectPackageManager({ installPath: fileURLToPath(import.meta.url) });
126
+ const latestVersionLine = `update: ${await buildUpdateMessage({ currentVersion: VERSION, packageManager })}`;
123
127
 
124
128
  try {
125
129
  const runtime = resolveRuntimeBinary({ parentUrl: import.meta.url });
@@ -128,7 +132,7 @@ function printDoctor() {
128
132
  `platform: ${platformKey}`,
129
133
  `runtime package: ${runtime.packageName}`,
130
134
  `runtime path: ${runtime.binaryPath}`,
131
- `update: ${buildUpdateInstructions({ host: process.env.OPEN_PLAN_HOST, packageManager: detectPackageManager({ installPath: fileURLToPath(import.meta.url) }) })}`,
135
+ latestVersionLine,
132
136
  ].join("\n"));
133
137
  } catch (error) {
134
138
  console.log([
@@ -136,7 +140,7 @@ function printDoctor() {
136
140
  `platform: ${platformKey}`,
137
141
  `runtime: missing`,
138
142
  `error: ${error instanceof Error ? error.message : String(error)}`,
139
- `update: ${buildUpdateInstructions({ host: process.env.OPEN_PLAN_HOST, packageManager: detectPackageManager({ installPath: fileURLToPath(import.meta.url) }) })}`,
143
+ latestVersionLine,
140
144
  ].join("\n"));
141
145
  }
142
146
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-plan-annotator",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "type": "module",
5
5
  "description": "Fully local plugin for interactive plan annotation from your Agentic assistants",
6
6
  "author": "ndom91",
@@ -29,8 +29,10 @@
29
29
  "shared/cliHelp.mjs",
30
30
  "shared/cliMode.mjs",
31
31
  "shared/packageManager.mjs",
32
+ "shared/updateMessage.mjs",
32
33
  "shared/runtimeResolver.mjs",
33
34
  "shared/updateHints.mjs",
35
+ "shared/versionInfo.mjs",
34
36
  ".claude-plugin/",
35
37
  "opencode/bridge.js",
36
38
  "opencode/config.js",
@@ -67,10 +69,9 @@
67
69
  "@opencode-ai/plugin": "^1.2.14"
68
70
  },
69
71
  "optionalDependencies": {
70
- "@open-plan-annotator/runtime-darwin-arm64": "1.1.2",
71
- "@open-plan-annotator/runtime-darwin-x64": "1.1.2",
72
- "@open-plan-annotator/runtime-linux-arm64": "1.1.2",
73
- "@open-plan-annotator/runtime-linux-x64": "1.1.2"
74
- },
75
- "packageManager": "bun@1.3.9"
72
+ "@open-plan-annotator/runtime-darwin-arm64": "1.1.4",
73
+ "@open-plan-annotator/runtime-darwin-x64": "1.1.4",
74
+ "@open-plan-annotator/runtime-linux-arm64": "1.1.4",
75
+ "@open-plan-annotator/runtime-linux-x64": "1.1.4"
76
+ }
76
77
  }
@@ -1,14 +1,23 @@
1
1
  export function buildUpdateInstructions(options = {}) {
2
2
  const host = options.host ?? process.env.OPEN_PLAN_HOST;
3
3
  const packageManager = options.packageManager ?? "npm";
4
+ const version = options.version ?? "latest";
4
5
 
5
6
  if (host === "opencode") {
6
- return "Refresh the OpenCode plugin install, then restart OpenCode.";
7
+ return "Refresh the OpenCode plugin install and restart OpenCode.";
7
8
  }
8
9
 
9
10
  if (host === "claude-code") {
10
- return "Refresh the Claude Code plugin or marketplace install, then restart Claude Code.";
11
+ return "Refresh the Claude Code plugin or marketplace install and restart Claude Code.";
11
12
  }
12
13
 
13
- return `Update open-plan-annotator via ${packageManager}, then rerun it.`;
14
+ if (packageManager === "pnpm") {
15
+ return `Run \`pnpm i -g open-plan-annotator@${version}\`.`;
16
+ }
17
+
18
+ if (packageManager === "bun") {
19
+ return `Run \`bun add -g open-plan-annotator@${version}\`.`;
20
+ }
21
+
22
+ return `Run \`npm i -g open-plan-annotator@${version}\`.`;
14
23
  }
@@ -0,0 +1,25 @@
1
+ import { buildUpdateInstructions } from "./updateHints.mjs";
2
+ import { fetchLatestVersion, isNewerVersion } from "./versionInfo.mjs";
3
+
4
+ export async function buildUpdateMessage(options = {}) {
5
+ const currentVersion = options.currentVersion;
6
+ const packageManager = options.packageManager ?? "npm";
7
+ const host = options.host ?? process.env.OPEN_PLAN_HOST;
8
+
9
+ try {
10
+ const latestVersion = await fetchLatestVersion();
11
+ if (currentVersion && isNewerVersion(currentVersion, latestVersion)) {
12
+ return `latest v${latestVersion}; ${buildUpdateInstructions({ host, packageManager, version: latestVersion })}`;
13
+ }
14
+
15
+ if (currentVersion) {
16
+ return `latest v${latestVersion}; already up to date`;
17
+ }
18
+
19
+ return buildUpdateInstructions({ host, packageManager, version: latestVersion });
20
+ } catch {
21
+ return currentVersion
22
+ ? `latest unknown; ${buildUpdateInstructions({ host, packageManager })}`
23
+ : buildUpdateInstructions({ host, packageManager });
24
+ }
25
+ }
@@ -0,0 +1,85 @@
1
+ const NPM_REGISTRY_BASE_URL = "https://registry.npmjs.org";
2
+
3
+ export function normalizeVersion(version) {
4
+ return version.trim().replace(/^v/, "");
5
+ }
6
+
7
+ function parseSemver(version) {
8
+ const normalized = normalizeVersion(version);
9
+ const match = normalized.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
10
+ if (!match) return null;
11
+
12
+ return {
13
+ major: Number.parseInt(match[1], 10),
14
+ minor: Number.parseInt(match[2], 10),
15
+ patch: Number.parseInt(match[3], 10),
16
+ prerelease: match[4] ? match[4].split(".") : [],
17
+ };
18
+ }
19
+
20
+ function comparePrereleaseIdentifier(a, b) {
21
+ const aIsNum = /^[0-9]+$/.test(a);
22
+ const bIsNum = /^[0-9]+$/.test(b);
23
+
24
+ if (aIsNum && bIsNum) {
25
+ const aNum = Number.parseInt(a, 10);
26
+ const bNum = Number.parseInt(b, 10);
27
+ return aNum === bNum ? 0 : aNum > bNum ? 1 : -1;
28
+ }
29
+
30
+ if (aIsNum) return -1;
31
+ if (bIsNum) return 1;
32
+ if (a === b) return 0;
33
+ return a > b ? 1 : -1;
34
+ }
35
+
36
+ function compareSemver(a, b) {
37
+ const parsedA = parseSemver(a);
38
+ const parsedB = parseSemver(b);
39
+ if (!parsedA || !parsedB) return 0;
40
+
41
+ if (parsedA.major !== parsedB.major) return parsedA.major > parsedB.major ? 1 : -1;
42
+ if (parsedA.minor !== parsedB.minor) return parsedA.minor > parsedB.minor ? 1 : -1;
43
+ if (parsedA.patch !== parsedB.patch) return parsedA.patch > parsedB.patch ? 1 : -1;
44
+
45
+ if (parsedA.prerelease.length === 0 && parsedB.prerelease.length === 0) return 0;
46
+ if (parsedA.prerelease.length === 0) return 1;
47
+ if (parsedB.prerelease.length === 0) return -1;
48
+
49
+ const maxLen = Math.max(parsedA.prerelease.length, parsedB.prerelease.length);
50
+ for (let i = 0; i < maxLen; i += 1) {
51
+ const aPart = parsedA.prerelease[i];
52
+ const bPart = parsedB.prerelease[i];
53
+ if (aPart === undefined) return -1;
54
+ if (bPart === undefined) return 1;
55
+ const diff = comparePrereleaseIdentifier(aPart, bPart);
56
+ if (diff !== 0) return diff;
57
+ }
58
+
59
+ return 0;
60
+ }
61
+
62
+ export function isNewerVersion(current, latest) {
63
+ const parsedCurrent = parseSemver(current);
64
+ const parsedLatest = parseSemver(latest);
65
+ if (!parsedCurrent || !parsedLatest) return false;
66
+ return compareSemver(latest, current) > 0;
67
+ }
68
+
69
+ export async function fetchLatestVersion(packageName = "open-plan-annotator") {
70
+ const response = await fetch(`${NPM_REGISTRY_BASE_URL}/${encodeURIComponent(packageName)}/latest`, {
71
+ headers: { "User-Agent": "open-plan-annotator-update-check", Accept: "application/json" },
72
+ signal: AbortSignal.timeout(10_000),
73
+ });
74
+
75
+ if (!response.ok) {
76
+ throw new Error(`npm registry responded with ${response.status}`);
77
+ }
78
+
79
+ const payload = await response.json();
80
+ if (!payload || typeof payload !== "object" || typeof payload.version !== "string") {
81
+ throw new Error("npm registry response did not include a version string");
82
+ }
83
+
84
+ return normalizeVersion(payload.version);
85
+ }