@quantiya/codevibe 2.0.16 → 2.0.17
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/bin/codevibe +387 -97
- package/package.json +1 -1
package/bin/codevibe
CHANGED
|
@@ -149,85 +149,271 @@ show_version() {
|
|
|
149
149
|
|
|
150
150
|
# ─── Update ──────────────────────────────────────────────────────────
|
|
151
151
|
#
|
|
152
|
-
#
|
|
153
|
-
#
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
|
|
157
|
-
#
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
152
|
+
# Claude's supported JSON CLI is the authority for registration state. Never
|
|
153
|
+
# infer it from Claude's private JSON files or mutate Claude-owned cache paths.
|
|
154
|
+
# A mismatched registration is removed through the CLI and reinstalled from the
|
|
155
|
+
# exact marketplace pin, then its on-disk package identity is verified.
|
|
156
|
+
|
|
157
|
+
# CodeVibe 2.x is private dogfood on this machine until GA. Keep the npm and
|
|
158
|
+
# Claude marketplace channels paired; the GA cutover changes this marketplace
|
|
159
|
+
# to codevibe-marketplace when @quantiya/codevibe moves from @next to @latest.
|
|
160
|
+
CLAUDE_MARKETPLACE="codevibe-next"
|
|
161
|
+
|
|
162
|
+
_read_next_meta_version() {
|
|
163
|
+
local raw
|
|
164
|
+
raw=$(npm view @quantiya/codevibe@next version 2>/dev/null) || return 1
|
|
165
|
+
node -e '
|
|
166
|
+
const value = process.argv[1];
|
|
167
|
+
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(value)) process.exit(1);
|
|
168
|
+
process.stdout.write(value);
|
|
169
|
+
' "$raw"
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
_resolve_installed_meta_launcher() {
|
|
173
|
+
local expected_version="$1"
|
|
174
|
+
local global_root
|
|
175
|
+
global_root=$(npm root -g 2>/dev/null) || return 1
|
|
176
|
+
node -e '
|
|
177
|
+
const fs = require("fs");
|
|
178
|
+
const path = require("path");
|
|
179
|
+
try {
|
|
180
|
+
const packageDir = path.join(process.argv[1], "@quantiya", "codevibe");
|
|
181
|
+
const packagePath = path.join(packageDir, "package.json");
|
|
182
|
+
const pkg = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
183
|
+
if (pkg.name !== "@quantiya/codevibe" || pkg.version !== process.argv[2]) {
|
|
184
|
+
throw new Error("package identity mismatch");
|
|
185
|
+
}
|
|
186
|
+
if (pkg.bin?.codevibe !== "./bin/codevibe") throw new Error("launcher declaration mismatch");
|
|
187
|
+
const realPackageDir = fs.realpathSync(packageDir);
|
|
188
|
+
const launcher = fs.realpathSync(path.resolve(packageDir, pkg.bin.codevibe));
|
|
189
|
+
if (!launcher.startsWith(`${realPackageDir}${path.sep}`)) throw new Error("launcher escaped package");
|
|
190
|
+
if (!fs.statSync(launcher).isFile()) throw new Error("launcher is not a file");
|
|
191
|
+
process.stdout.write(launcher);
|
|
192
|
+
} catch {
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
' "$global_root" "$expected_version" 2>/dev/null
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
_read_packaged_claude_version() {
|
|
199
|
+
node -e '
|
|
200
|
+
const fs = require("fs");
|
|
201
|
+
try {
|
|
202
|
+
const pkg = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
203
|
+
const value = pkg.dependencies?.["@quantiya/codevibe-claude-plugin"];
|
|
204
|
+
if (typeof value === "string" && /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(value)) {
|
|
205
|
+
process.stdout.write(value);
|
|
206
|
+
process.exit(0);
|
|
207
|
+
}
|
|
208
|
+
} catch {}
|
|
209
|
+
process.exit(1);
|
|
210
|
+
' "$PACKAGE_DIR/package.json" 2>/dev/null
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
_capture_claude_marketplaces() {
|
|
214
|
+
local raw
|
|
215
|
+
if ! raw=$(claude plugin marketplace list --json 2>/dev/null); then
|
|
216
|
+
return 1
|
|
217
|
+
fi
|
|
218
|
+
node -e '
|
|
219
|
+
const path = require("path");
|
|
220
|
+
try {
|
|
221
|
+
const rows = JSON.parse(process.argv[1]);
|
|
222
|
+
if (!Array.isArray(rows)) throw new Error("not an array");
|
|
223
|
+
const seen = new Set();
|
|
224
|
+
for (const row of rows) {
|
|
225
|
+
if (!row || typeof row !== "object" || Array.isArray(row)) throw new Error("invalid row");
|
|
226
|
+
if (typeof row.name !== "string" || !row.name) throw new Error("invalid name");
|
|
227
|
+
if (seen.has(row.name)) throw new Error("duplicate marketplace");
|
|
228
|
+
seen.add(row.name);
|
|
229
|
+
if (typeof row.installLocation !== "string" || !path.isAbsolute(row.installLocation)) {
|
|
230
|
+
throw new Error("invalid install location");
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
process.stdout.write(JSON.stringify(rows));
|
|
234
|
+
} catch {
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
' "$raw"
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
_read_marketplace_root() {
|
|
241
|
+
local marketplace="$1"
|
|
242
|
+
local marketplaces="$2"
|
|
243
|
+
node -e '
|
|
244
|
+
const rows = JSON.parse(process.argv[1]);
|
|
245
|
+
const matches = rows.filter((row) => row.name === process.argv[2]);
|
|
246
|
+
if (matches.length !== 1) process.exit(1);
|
|
247
|
+
process.stdout.write(matches[0].installLocation);
|
|
248
|
+
' "$marketplaces" "$marketplace" 2>/dev/null
|
|
249
|
+
}
|
|
169
250
|
|
|
170
251
|
_read_marketplace_version() {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
local manifest
|
|
174
|
-
|
|
175
|
-
|
|
252
|
+
local marketplace="$1"
|
|
253
|
+
local marketplaces="$2"
|
|
254
|
+
local root manifest
|
|
255
|
+
root=$(_read_marketplace_root "$marketplace" "$marketplaces") || return 1
|
|
256
|
+
manifest="$root/.claude-plugin/marketplace.json"
|
|
257
|
+
[ -f "$manifest" ] || return 1
|
|
258
|
+
node -e '
|
|
259
|
+
const fs = require("fs");
|
|
176
260
|
try {
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
261
|
+
const manifest = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
262
|
+
if (!Array.isArray(manifest.plugins)) throw new Error("missing plugins");
|
|
263
|
+
const matches = manifest.plugins.filter((item) => item?.name === "codevibe-claude");
|
|
264
|
+
if (matches.length !== 1) throw new Error("ambiguous plugin");
|
|
265
|
+
const plugin = matches[0];
|
|
266
|
+
const value = plugin?.source?.version;
|
|
267
|
+
if (typeof value !== "string" || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(value)) {
|
|
268
|
+
throw new Error("invalid version");
|
|
269
|
+
}
|
|
270
|
+
process.stdout.write(value);
|
|
271
|
+
} catch {
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
' "$manifest" 2>/dev/null
|
|
182
275
|
}
|
|
183
276
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
node -
|
|
277
|
+
_capture_claude_plugins() {
|
|
278
|
+
local raw
|
|
279
|
+
if ! raw=$(claude plugin list --json 2>/dev/null); then
|
|
280
|
+
return 1
|
|
281
|
+
fi
|
|
282
|
+
node -e '
|
|
283
|
+
const path = require("path");
|
|
190
284
|
try {
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
285
|
+
const rows = JSON.parse(process.argv[1]);
|
|
286
|
+
if (!Array.isArray(rows)) throw new Error("not an array");
|
|
287
|
+
const selected = [];
|
|
288
|
+
const seen = new Set();
|
|
289
|
+
const supported = new Set([
|
|
290
|
+
"codevibe-claude@codevibe-next",
|
|
291
|
+
"codevibe-claude@codevibe-marketplace",
|
|
292
|
+
]);
|
|
293
|
+
for (const row of rows) {
|
|
294
|
+
if (!row || typeof row !== "object" || Array.isArray(row)) throw new Error("invalid row");
|
|
295
|
+
if (typeof row.id !== "string" || !row.id) throw new Error("invalid id");
|
|
296
|
+
if (!row.id.startsWith("codevibe-claude@")) continue;
|
|
297
|
+
if (!supported.has(row.id)) throw new Error("unsupported CodeVibe registration");
|
|
298
|
+
if (seen.has(row.id)) throw new Error("duplicate registration");
|
|
299
|
+
seen.add(row.id);
|
|
300
|
+
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(row.version)) throw new Error("invalid version");
|
|
301
|
+
if (!new Set(["user", "project", "local"]).has(row.scope)) throw new Error("invalid scope");
|
|
302
|
+
if (typeof row.enabled !== "boolean") throw new Error("invalid enabled state");
|
|
303
|
+
if (typeof row.installPath !== "string" || !path.isAbsolute(row.installPath)) throw new Error("invalid install path");
|
|
304
|
+
selected.push(row);
|
|
305
|
+
}
|
|
306
|
+
process.stdout.write(JSON.stringify(selected));
|
|
307
|
+
} catch {
|
|
308
|
+
process.exit(1);
|
|
309
|
+
}
|
|
310
|
+
' "$raw"
|
|
196
311
|
}
|
|
197
312
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
313
|
+
_verify_only_preview_registration() {
|
|
314
|
+
local plugins="$1"
|
|
315
|
+
node -e '
|
|
316
|
+
const rows = JSON.parse(process.argv[1]);
|
|
317
|
+
if (rows.length !== 1 || rows[0].id !== "codevibe-claude@codevibe-next") process.exit(1);
|
|
318
|
+
' "$plugins" 2>/dev/null
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
_read_claude_plugin_state() {
|
|
322
|
+
local marketplace="$1"
|
|
323
|
+
local plugins="$2"
|
|
324
|
+
node -e '
|
|
325
|
+
const rows = JSON.parse(process.argv[1]);
|
|
326
|
+
const row = rows.find((item) => item.id === `codevibe-claude@${process.argv[2]}`);
|
|
327
|
+
if (!row) process.exit(3);
|
|
328
|
+
process.stdout.write(JSON.stringify(row));
|
|
329
|
+
' "$plugins" "$marketplace" 2>/dev/null
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
_claude_plugin_state_field() {
|
|
333
|
+
local state="$1"
|
|
334
|
+
local field="$2"
|
|
335
|
+
node -e '
|
|
336
|
+
const row = JSON.parse(process.argv[1]);
|
|
337
|
+
const value = row[process.argv[2]];
|
|
338
|
+
if (!["string", "boolean"].includes(typeof value)) process.exit(1);
|
|
339
|
+
process.stdout.write(String(value));
|
|
340
|
+
' "$state" "$field" 2>/dev/null
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
_verify_claude_plugin_files() {
|
|
344
|
+
local state="$1"
|
|
345
|
+
local expected_version="$2"
|
|
346
|
+
node -e '
|
|
347
|
+
const fs = require("fs");
|
|
348
|
+
const path = require("path");
|
|
349
|
+
try {
|
|
350
|
+
const row = JSON.parse(process.argv[1]);
|
|
351
|
+
const expected = process.argv[2];
|
|
352
|
+
if (row.version !== expected || row.enabled !== true || row.scope !== "user") throw new Error("state mismatch");
|
|
353
|
+
const installPath = fs.realpathSync(row.installPath);
|
|
354
|
+
const packagePath = path.join(installPath, "package.json");
|
|
355
|
+
const pkg = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
356
|
+
if (pkg.name !== "@quantiya/codevibe-claude-plugin" || pkg.version !== expected) throw new Error("package mismatch");
|
|
357
|
+
} catch {
|
|
358
|
+
process.exit(1);
|
|
359
|
+
}
|
|
360
|
+
' "$state" "$expected_version" 2>/dev/null
|
|
204
361
|
}
|
|
205
362
|
|
|
206
363
|
do_update() {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
364
|
+
local update_phase="${CODEVIBE_UPDATE_AFTER_META:-meta}"
|
|
365
|
+
unset CODEVIBE_UPDATE_AFTER_META
|
|
366
|
+
case "$update_phase" in
|
|
367
|
+
meta|plugins) ;;
|
|
368
|
+
*)
|
|
369
|
+
echo "Invalid internal CodeVibe update phase." >&2
|
|
370
|
+
return 1
|
|
371
|
+
;;
|
|
372
|
+
esac
|
|
210
373
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
echo
|
|
215
|
-
fi
|
|
216
|
-
echo ""
|
|
374
|
+
if [ "$update_phase" = "meta" ]; then
|
|
375
|
+
echo ""
|
|
376
|
+
echo -e "${BOLD}${PURPLE}CodeVibe Update${NC}"
|
|
377
|
+
echo ""
|
|
217
378
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
local npm_output
|
|
223
|
-
if ! npm_output=$(npm install -g --force @quantiya/codevibe@next 2>&1); then
|
|
224
|
-
echo "$npm_output" | tail -10
|
|
379
|
+
if [ -f "$PACKAGE_DIR/package.json" ]; then
|
|
380
|
+
CUR_VER=$(node -p "require('$PACKAGE_DIR/package.json').version" 2>/dev/null || echo "?")
|
|
381
|
+
echo -e " ${DIM}Current meta-package: $CUR_VER${NC}"
|
|
382
|
+
fi
|
|
225
383
|
echo ""
|
|
226
|
-
echo -e "${YELLOW}!${NC} Meta-package update failed. Check the output above, fix the issue, and retry 'codevibe update'."
|
|
227
|
-
return 1
|
|
228
384
|
fi
|
|
229
|
-
|
|
230
|
-
|
|
385
|
+
|
|
386
|
+
if [ "$update_phase" = "meta" ]; then
|
|
387
|
+
# ─── Step 1: Update the global meta-package on the CodeVibe 2.x channel ─
|
|
388
|
+
echo -e "${PURPLE}▸${NC} Updating @quantiya/codevibe..."
|
|
389
|
+
local desired_meta_version
|
|
390
|
+
local installed_launcher
|
|
391
|
+
if ! desired_meta_version=$(_read_next_meta_version); then
|
|
392
|
+
echo ""
|
|
393
|
+
echo -e "${YELLOW}!${NC} Could not resolve the exact @quantiya/codevibe@next version. No package was changed."
|
|
394
|
+
return 1
|
|
395
|
+
fi
|
|
396
|
+
local npm_output
|
|
397
|
+
if ! npm_output=$(npm install -g --force @quantiya/codevibe@next 2>&1); then
|
|
398
|
+
echo "$npm_output" | tail -10
|
|
399
|
+
echo ""
|
|
400
|
+
echo -e "${YELLOW}!${NC} Meta-package update failed. Check the output above, fix the issue, and retry 'codevibe update'."
|
|
401
|
+
return 1
|
|
402
|
+
fi
|
|
403
|
+
echo "$npm_output" | tail -3
|
|
404
|
+
echo -e "${GREEN}✓${NC} Meta-package updated"
|
|
405
|
+
|
|
406
|
+
if ! installed_launcher=$(_resolve_installed_meta_launcher "$desired_meta_version"); then
|
|
407
|
+
echo ""
|
|
408
|
+
echo -e "${YELLOW}!${NC} The installed CodeVibe package does not match @next ${desired_meta_version}; plugin state was not changed."
|
|
409
|
+
return 1
|
|
410
|
+
fi
|
|
411
|
+
|
|
412
|
+
# The current process still holds old functions. Re-exec the verified
|
|
413
|
+
# launcher inside npm's actual global package before any plugin mutation.
|
|
414
|
+
export CODEVIBE_UPDATE_AFTER_META=plugins
|
|
415
|
+
exec "$installed_launcher" update
|
|
416
|
+
fi
|
|
231
417
|
|
|
232
418
|
# ─── Step 2: Update the Claude Code plugin ─────────────────────────────────
|
|
233
419
|
if ! command -v claude >/dev/null 2>&1; then
|
|
@@ -246,37 +432,94 @@ do_update() {
|
|
|
246
432
|
echo ""
|
|
247
433
|
echo -e "${PURPLE}▸${NC} Updating Claude Code plugin..."
|
|
248
434
|
|
|
249
|
-
|
|
250
|
-
# Errors here are non-fatal at this step — the previously-cached manifest may
|
|
251
|
-
# still be usable — but the EXPECTED_VERSION read below is the real gate.
|
|
252
|
-
if claude plugin marketplace update codevibe-marketplace; then
|
|
253
|
-
echo -e "${GREEN}✓${NC} Marketplace refreshed"
|
|
254
|
-
else
|
|
255
|
-
echo -e "${YELLOW}!${NC} Marketplace refresh failed (falling back to cached manifest)"
|
|
256
|
-
fi
|
|
257
|
-
|
|
435
|
+
local DESIRED_VERSION
|
|
258
436
|
local EXPECTED_VERSION
|
|
437
|
+
local MARKETPLACES
|
|
438
|
+
local PLUGINS
|
|
439
|
+
local PREVIEW_STATE=""
|
|
440
|
+
local CONFLICT_STATE=""
|
|
441
|
+
local PREVIEW_PRESENT=false
|
|
442
|
+
local CONFLICT_PRESENT=false
|
|
259
443
|
local INSTALLED_VERSION
|
|
260
|
-
|
|
261
|
-
|
|
444
|
+
local INSTALLED_ENABLED
|
|
445
|
+
local INSTALLED_SCOPE
|
|
446
|
+
local CONFLICT_SCOPE
|
|
447
|
+
local REGISTRATION_CHANGED=false
|
|
262
448
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
# claim success we can't prove.
|
|
266
|
-
if [ -z "$EXPECTED_VERSION" ]; then
|
|
449
|
+
DESIRED_VERSION=$(_read_packaged_claude_version)
|
|
450
|
+
if [ -z "$DESIRED_VERSION" ]; then
|
|
267
451
|
echo ""
|
|
268
|
-
echo -e "${YELLOW}!${NC} Could not read
|
|
269
|
-
echo -e " ${DIM}Expected at: \$HOME/.claude/plugins/marketplaces/codevibe-marketplace/.claude-plugin/marketplace.json${NC}"
|
|
270
|
-
echo -e " ${DIM}This usually means the marketplace refresh failed or the manifest schema has drifted.${NC}"
|
|
271
|
-
echo -e " ${DIM}Try: claude plugin marketplace update codevibe-marketplace${NC}"
|
|
452
|
+
echo -e "${YELLOW}!${NC} Could not read the exact Claude plugin version required by this CodeVibe package."
|
|
272
453
|
return 1
|
|
273
454
|
fi
|
|
274
455
|
|
|
275
|
-
|
|
456
|
+
# The 2.x package is distributed on @next and must use the matching private
|
|
457
|
+
# marketplace. Do not fall back to the public 1.x marketplace on this host.
|
|
458
|
+
if ! claude plugin marketplace update "$CLAUDE_MARKETPLACE" >/dev/null 2>&1; then
|
|
459
|
+
echo ""
|
|
460
|
+
echo -e "${YELLOW}!${NC} Could not refresh marketplace ${CLAUDE_MARKETPLACE}. No registration was changed."
|
|
461
|
+
return 1
|
|
462
|
+
fi
|
|
463
|
+
if ! MARKETPLACES=$(_capture_claude_marketplaces); then
|
|
464
|
+
echo ""
|
|
465
|
+
echo -e "${YELLOW}!${NC} Claude marketplace state is invalid or unavailable. No registration was changed."
|
|
466
|
+
return 1
|
|
467
|
+
fi
|
|
468
|
+
EXPECTED_VERSION=$(_read_marketplace_version "$CLAUDE_MARKETPLACE" "$MARKETPLACES") || EXPECTED_VERSION=""
|
|
469
|
+
if [ "$EXPECTED_VERSION" != "$DESIRED_VERSION" ]; then
|
|
470
|
+
echo ""
|
|
471
|
+
echo -e "${YELLOW}!${NC} Marketplace ${CLAUDE_MARKETPLACE} does not pin the required Claude plugin."
|
|
472
|
+
echo -e " ${DIM}Required: ${DESIRED_VERSION:-<none>} observed: ${EXPECTED_VERSION:-<none>}. No registration was changed.${NC}"
|
|
473
|
+
return 1
|
|
474
|
+
fi
|
|
475
|
+
if ! PLUGINS=$(_capture_claude_plugins); then
|
|
476
|
+
echo ""
|
|
477
|
+
echo -e "${YELLOW}!${NC} Claude plugin state is invalid or unavailable. No registration was changed."
|
|
478
|
+
return 1
|
|
479
|
+
fi
|
|
480
|
+
if PREVIEW_STATE=$(_read_claude_plugin_state "$CLAUDE_MARKETPLACE" "$PLUGINS"); then
|
|
481
|
+
PREVIEW_PRESENT=true
|
|
482
|
+
INSTALLED_VERSION=$(_claude_plugin_state_field "$PREVIEW_STATE" version) || return 1
|
|
483
|
+
INSTALLED_ENABLED=$(_claude_plugin_state_field "$PREVIEW_STATE" enabled) || return 1
|
|
484
|
+
INSTALLED_SCOPE=$(_claude_plugin_state_field "$PREVIEW_STATE" scope) || return 1
|
|
485
|
+
if [ "$INSTALLED_SCOPE" != "user" ]; then
|
|
486
|
+
echo ""
|
|
487
|
+
echo -e "${YELLOW}!${NC} Claude preview registration has unsupported scope: ${INSTALLED_SCOPE}. No registration was changed."
|
|
488
|
+
return 1
|
|
489
|
+
fi
|
|
490
|
+
else
|
|
491
|
+
[ "$?" -eq 3 ] || return 1
|
|
492
|
+
INSTALLED_VERSION=""
|
|
493
|
+
INSTALLED_ENABLED=false
|
|
494
|
+
INSTALLED_SCOPE=user
|
|
495
|
+
fi
|
|
496
|
+
echo -e " ${DIM}channel: ${CLAUDE_MARKETPLACE} installed: ${INSTALLED_VERSION:-<none>} required: ${EXPECTED_VERSION}${NC}"
|
|
497
|
+
|
|
498
|
+
# This is the only 2.x dogfood machine. Remove its public 1.x registration so
|
|
499
|
+
# Claude resume cannot start competing daemons from both plugin generations.
|
|
500
|
+
if CONFLICT_STATE=$(_read_claude_plugin_state "codevibe-marketplace" "$PLUGINS"); then
|
|
501
|
+
CONFLICT_PRESENT=true
|
|
502
|
+
CONFLICT_SCOPE=$(_claude_plugin_state_field "$CONFLICT_STATE" scope) || return 1
|
|
503
|
+
if [ "$CONFLICT_SCOPE" != "user" ]; then
|
|
504
|
+
echo ""
|
|
505
|
+
echo -e "${YELLOW}!${NC} Conflicting Claude registration has unsupported scope: ${CONFLICT_SCOPE}. No registration was changed."
|
|
506
|
+
return 1
|
|
507
|
+
fi
|
|
508
|
+
else
|
|
509
|
+
[ "$?" -eq 3 ] || return 1
|
|
510
|
+
fi
|
|
511
|
+
if [ "$CONFLICT_PRESENT" = "true" ]; then
|
|
512
|
+
if ! claude plugin uninstall -s "$CONFLICT_SCOPE" -y "codevibe-claude@codevibe-marketplace" >/dev/null 2>&1; then
|
|
513
|
+
echo ""
|
|
514
|
+
echo -e "${YELLOW}!${NC} Could not remove conflicting Claude plugin registration: codevibe-claude@codevibe-marketplace"
|
|
515
|
+
return 1
|
|
516
|
+
fi
|
|
517
|
+
REGISTRATION_CHANGED=true
|
|
518
|
+
fi
|
|
276
519
|
|
|
277
520
|
# ─── Step 3: Decide if we need to force a cache-clearing reinstall ─────────
|
|
278
521
|
local NEEDS_REINSTALL=false
|
|
279
|
-
if [
|
|
522
|
+
if [ "$PREVIEW_PRESENT" != "true" ] || [ "$INSTALLED_VERSION" != "$EXPECTED_VERSION" ]; then
|
|
280
523
|
NEEDS_REINSTALL=true
|
|
281
524
|
if [ -n "$INSTALLED_VERSION" ]; then
|
|
282
525
|
echo -e "${YELLOW}!${NC} Cache is stale (${INSTALLED_VERSION} on disk, ${EXPECTED_VERSION} in marketplace)."
|
|
@@ -285,12 +528,14 @@ do_update() {
|
|
|
285
528
|
fi
|
|
286
529
|
|
|
287
530
|
if [ "$NEEDS_REINSTALL" = "true" ]; then
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
531
|
+
if [ "$PREVIEW_PRESENT" = "true" ] \
|
|
532
|
+
&& ! claude plugin uninstall -s "$INSTALLED_SCOPE" -y "codevibe-claude@$CLAUDE_MARKETPLACE" >/dev/null 2>&1; then
|
|
533
|
+
echo ""
|
|
534
|
+
echo -e "${YELLOW}!${NC} Could not remove stale Claude plugin registration: codevibe-claude@$CLAUDE_MARKETPLACE"
|
|
535
|
+
return 1
|
|
536
|
+
fi
|
|
292
537
|
|
|
293
|
-
if claude plugin install codevibe-claude
|
|
538
|
+
if claude plugin install -s user -y "codevibe-claude@$CLAUDE_MARKETPLACE"; then
|
|
294
539
|
echo -e "${GREEN}✓${NC} Claude plugin reinstalled"
|
|
295
540
|
else
|
|
296
541
|
echo ""
|
|
@@ -298,25 +543,70 @@ do_update() {
|
|
|
298
543
|
return 1
|
|
299
544
|
fi
|
|
300
545
|
else
|
|
301
|
-
# Version already matches.
|
|
302
|
-
#
|
|
303
|
-
|
|
546
|
+
# Version already matches. Re-enable the selected registration without
|
|
547
|
+
# asking Claude Code to reinstall or recache it.
|
|
548
|
+
if [ "$INSTALLED_ENABLED" != "true" ] \
|
|
549
|
+
&& ! claude plugin enable -s "$INSTALLED_SCOPE" "codevibe-claude@$CLAUDE_MARKETPLACE" >/dev/null 2>&1; then
|
|
550
|
+
echo ""
|
|
551
|
+
echo -e "${YELLOW}!${NC} Could not enable Claude plugin registration: codevibe-claude@$CLAUDE_MARKETPLACE"
|
|
552
|
+
return 1
|
|
553
|
+
fi
|
|
304
554
|
echo -e "${GREEN}✓${NC} Claude plugin already at ${INSTALLED_VERSION}"
|
|
305
555
|
fi
|
|
306
556
|
|
|
307
557
|
# ─── Step 4: Verify the installed version is now what we expected ──────────
|
|
308
558
|
# EXPECTED_VERSION is guaranteed non-empty here (we bailed earlier otherwise),
|
|
309
559
|
# so the verification is unconditional.
|
|
310
|
-
|
|
311
|
-
|
|
560
|
+
if ! PLUGINS=$(_capture_claude_plugins); then
|
|
561
|
+
echo ""
|
|
562
|
+
echo -e "${YELLOW}!${NC} Claude plugin state could not be verified after the update."
|
|
563
|
+
return 1
|
|
564
|
+
fi
|
|
565
|
+
if ! PREVIEW_STATE=$(_read_claude_plugin_state "$CLAUDE_MARKETPLACE" "$PLUGINS"); then
|
|
566
|
+
echo ""
|
|
567
|
+
echo -e "${YELLOW}!${NC} Claude preview registration is missing after the update."
|
|
568
|
+
return 1
|
|
569
|
+
fi
|
|
570
|
+
INSTALLED_VERSION=$(_claude_plugin_state_field "$PREVIEW_STATE" version) || return 1
|
|
571
|
+
INSTALLED_ENABLED=$(_claude_plugin_state_field "$PREVIEW_STATE" enabled) || return 1
|
|
572
|
+
INSTALLED_SCOPE=$(_claude_plugin_state_field "$PREVIEW_STATE" scope) || return 1
|
|
573
|
+
if [ "$INSTALLED_VERSION" != "$EXPECTED_VERSION" ] || [ "$INSTALLED_SCOPE" != "user" ]; then
|
|
312
574
|
echo ""
|
|
313
575
|
echo -e "${YELLOW}!${NC} WARNING: Installed version (${INSTALLED_VERSION:-<none>}) still doesn't match expected (${EXPECTED_VERSION})."
|
|
314
|
-
echo -e " ${DIM}Try:
|
|
576
|
+
echo -e " ${DIM}Try: codevibe update again after checking the ${CLAUDE_MARKETPLACE} manifest.${NC}"
|
|
577
|
+
return 1
|
|
578
|
+
fi
|
|
579
|
+
if [ "$INSTALLED_ENABLED" != "true" ]; then
|
|
580
|
+
echo ""
|
|
581
|
+
echo -e "${YELLOW}!${NC} Claude plugin registration is installed but disabled: codevibe-claude@$CLAUDE_MARKETPLACE"
|
|
582
|
+
return 1
|
|
583
|
+
fi
|
|
584
|
+
local conflict_check_rc
|
|
585
|
+
_read_claude_plugin_state "codevibe-marketplace" "$PLUGINS" >/dev/null 2>&1
|
|
586
|
+
conflict_check_rc=$?
|
|
587
|
+
if [ "$conflict_check_rc" -eq 0 ]; then
|
|
588
|
+
echo ""
|
|
589
|
+
echo -e "${YELLOW}!${NC} Conflicting Claude plugin registration still exists: codevibe-claude@codevibe-marketplace"
|
|
590
|
+
return 1
|
|
591
|
+
fi
|
|
592
|
+
if [ "$conflict_check_rc" -ne 3 ]; then
|
|
593
|
+
echo ""
|
|
594
|
+
echo -e "${YELLOW}!${NC} Claude plugin state became ambiguous after the update."
|
|
595
|
+
return 1
|
|
596
|
+
fi
|
|
597
|
+
if ! _verify_only_preview_registration "$PLUGINS"; then
|
|
598
|
+
echo ""
|
|
599
|
+
echo -e "${YELLOW}!${NC} Claude plugin state contains an unexpected CodeVibe registration."
|
|
600
|
+
return 1
|
|
601
|
+
fi
|
|
602
|
+
if ! _verify_claude_plugin_files "$PREVIEW_STATE" "$EXPECTED_VERSION"; then
|
|
603
|
+
echo ""
|
|
604
|
+
echo -e "${YELLOW}!${NC} Claude plugin files do not match the required package identity."
|
|
315
605
|
return 1
|
|
316
606
|
fi
|
|
317
607
|
|
|
318
608
|
# ─── Step 5: Tell the user about running sessions ──────────────────────────
|
|
319
|
-
if [ "$NEEDS_REINSTALL" = "true" ]; then
|
|
609
|
+
if [ "$NEEDS_REINSTALL" = "true" ] || [ "$REGISTRATION_CHANGED" = "true" ]; then
|
|
320
610
|
echo ""
|
|
321
611
|
echo -e "${YELLOW}!${NC} Running Claude Code sessions still have the OLD plugin server in memory."
|
|
322
612
|
echo -e " ${DIM}Exit and restart any active session to pick up the new plugin.${NC}"
|
package/package.json
CHANGED