@massa-ai/claude-plugin 1.45.0 → 1.47.0
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/install.sh
CHANGED
|
@@ -44,6 +44,11 @@ source "$REPO_ROOT/scripts/lib/installer-shared.sh"
|
|
|
44
44
|
SCOPE="user"
|
|
45
45
|
UNINSTALL=0
|
|
46
46
|
DRY_RUN=0
|
|
47
|
+
# Served-plugin version on the marketplace route, filled by
|
|
48
|
+
# refresh_marketplace_cache and read by record_plugin_version. Declared at
|
|
49
|
+
# top level so routes that never refresh (file route, uninstall) cannot trip
|
|
50
|
+
# `set -u` (CMR R3).
|
|
51
|
+
PLUGIN_SERVED_VERSION=""
|
|
47
52
|
# The marketplace root to register. install-harness.sh resolves this once for
|
|
48
53
|
# the whole run (--plugin-source local|copy|auto); a direct invocation of this
|
|
49
54
|
# script defaults to the checkout it lives in.
|
|
@@ -426,7 +431,6 @@ record_plugin_version() {
|
|
|
426
431
|
fi
|
|
427
432
|
|
|
428
433
|
local version installed_at route
|
|
429
|
-
version="$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$SCRIPT_DIR/package.json" | head -n 1)"
|
|
430
434
|
installed_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
431
435
|
# installRoute (T8, design F1): installer-owned, engine-read-only. The
|
|
432
436
|
# marketplace route (register_claude_plugin succeeded) serves agents in
|
|
@@ -434,6 +438,17 @@ record_plugin_version() {
|
|
|
434
438
|
# Written on EVERY install path — an absent field is what makes the switch
|
|
435
439
|
# engine refuse loud rather than guess (hosts.ts detectRoute).
|
|
436
440
|
if [[ "$PLUGIN_ROUTE" -eq 1 ]]; then route="marketplace"; else route="file"; fi
|
|
441
|
+
# Version claim (CMR-02/03): the file route records the bundle version — it
|
|
442
|
+
# IS what was just copied. The marketplace route records what the CLI
|
|
443
|
+
# actually serves (refresh_marketplace_cache), which the version-pinned
|
|
444
|
+
# cache can hold BEHIND the bundle; recording the bundle version there is
|
|
445
|
+
# the lie that froze this host's harness gate at a stale cache. Empty
|
|
446
|
+
# served version → record no version at all (next run retries).
|
|
447
|
+
if [[ "$PLUGIN_ROUTE" -eq 1 ]]; then
|
|
448
|
+
version="$PLUGIN_SERVED_VERSION"
|
|
449
|
+
else
|
|
450
|
+
version="$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$SCRIPT_DIR/package.json" | head -n 1)"
|
|
451
|
+
fi
|
|
437
452
|
|
|
438
453
|
# Tolerant of a corrupt/missing state file (rewrites a minimal valid one —
|
|
439
454
|
# AC-8). A record-write failure warns but never fails the install: the next
|
|
@@ -458,7 +473,13 @@ const rec =
|
|
|
458
473
|
data.platforms[host] && typeof data.platforms[host] === "object" && !Array.isArray(data.platforms[host])
|
|
459
474
|
? data.platforms[host]
|
|
460
475
|
: { root, skillsOwner: "plugin", skills: [] };
|
|
461
|
-
|
|
476
|
+
// An empty version means the served version was unreadable (CMR-03): keep
|
|
477
|
+
// any prior plugin record untouched and claim nothing new — an absent/stale
|
|
478
|
+
// record is what makes the next harness run retry. installRoute is still
|
|
479
|
+
// written below on every path.
|
|
480
|
+
if (version) {
|
|
481
|
+
rec.plugin = { version, installedAt };
|
|
482
|
+
}
|
|
462
483
|
// installRoute is installer-owned (like plugin above); modelProfile is NEVER
|
|
463
484
|
// written here — the switch engine (packages/shared/src/profile-switch/) is
|
|
464
485
|
// its sole writer, and this installer only ever reads it (see
|
|
@@ -507,6 +528,89 @@ try {
|
|
|
507
528
|
NODE
|
|
508
529
|
}
|
|
509
530
|
|
|
531
|
+
# ── Marketplace install-path resolution (T19, CPP-07) ───────────────────────
|
|
532
|
+
# Mirrors packages/shared/src/profile-switch/claude-marketplace.ts's
|
|
533
|
+
# resolveClaudeMarketplaceRoot exactly (same selection rule: scope:"user"
|
|
534
|
+
# preferred, then most recent lastUpdated, then last entry in array order;
|
|
535
|
+
# require the resolved installPath to exist on disk) so the shell installer
|
|
536
|
+
# and the TS switch engine agree on which cache directory is "current".
|
|
537
|
+
# Never caches — the path is version pinned and moves on every
|
|
538
|
+
# `claude plugin update`. Prints the resolved installPath, or "" when
|
|
539
|
+
# unresolvable (absent/corrupt registry, no record, or a path that doesn't
|
|
540
|
+
# exist on disk). Never throws.
|
|
541
|
+
resolve_claude_install_path() {
|
|
542
|
+
local runner="$1"
|
|
543
|
+
"$runner" - "$PLUGIN_REGISTRY" "$PLUGIN_ID" <<'NODE'
|
|
544
|
+
const fs = require("fs");
|
|
545
|
+
const [, , file, id] = process.argv;
|
|
546
|
+
try {
|
|
547
|
+
const data = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
548
|
+
const records = data && data.plugins ? data.plugins[id] : null;
|
|
549
|
+
if (!Array.isArray(records) || records.length === 0) process.exit(0);
|
|
550
|
+
const userScoped = records.filter((r) => r && r.scope === "user");
|
|
551
|
+
const pool = userScoped.length > 0 ? userScoped : records;
|
|
552
|
+
let best;
|
|
553
|
+
let bestTime = -Infinity;
|
|
554
|
+
for (const record of pool) {
|
|
555
|
+
const parsed = record && record.lastUpdated ? Date.parse(record.lastUpdated) : NaN;
|
|
556
|
+
if (Number.isFinite(parsed) && parsed >= bestTime) {
|
|
557
|
+
best = record;
|
|
558
|
+
bestTime = parsed;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
const selected = best || pool[pool.length - 1];
|
|
562
|
+
const installPath = selected && selected.installPath;
|
|
563
|
+
if (!installPath) process.exit(0);
|
|
564
|
+
if (!fs.existsSync(installPath)) process.exit(0);
|
|
565
|
+
process.stdout.write(installPath);
|
|
566
|
+
} catch { /* unresolvable — absent file, unreadable file, unparseable JSON */ }
|
|
567
|
+
NODE
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
# Re-applies the recorded model profile to the marketplace install root after
|
|
571
|
+
# a `claude plugin update` succeeds (CPP-07). AD-015 (read-only): this
|
|
572
|
+
# function, like recorded_profile above, NEVER writes
|
|
573
|
+
# platforms.claude.modelProfile — the switch engine
|
|
574
|
+
# (packages/shared/src/profile-switch/) is its sole writer. An update moves
|
|
575
|
+
# installPath to a new version-pinned cache directory, whose agents/ ships
|
|
576
|
+
# the bundle's DEFAULT profile; without this re-apply step a switched
|
|
577
|
+
# operator would silently revert to that default on every update (context.md
|
|
578
|
+
# finding #4). Every failure path is a logged no-op, never a failure — a
|
|
579
|
+
# missing recorded profile, an unresolvable install path, or a profile the
|
|
580
|
+
# new bundle doesn't ship under agent-profiles/ all mean "nothing to
|
|
581
|
+
# re-apply", not an install error.
|
|
582
|
+
apply_recorded_profile_after_update() {
|
|
583
|
+
local runner="$1"
|
|
584
|
+
local install_path profile variant_dir copied=0 f name
|
|
585
|
+
install_path="$(resolve_claude_install_path "$runner")"
|
|
586
|
+
if [[ -z "$install_path" ]]; then
|
|
587
|
+
vecho " ↷ no resolvable marketplace install path — skipping recorded-profile re-apply"
|
|
588
|
+
return 0
|
|
589
|
+
fi
|
|
590
|
+
profile="$(recorded_profile "$runner")"
|
|
591
|
+
if [[ -z "$profile" ]]; then
|
|
592
|
+
vecho " ↷ no recorded model profile for claude — skipping recorded-profile re-apply"
|
|
593
|
+
return 0
|
|
594
|
+
fi
|
|
595
|
+
variant_dir="$install_path/agent-profiles/$profile"
|
|
596
|
+
if [[ ! -d "$variant_dir" ]]; then
|
|
597
|
+
echo " ⚠ recorded model profile '$profile' is not available under the updated bundle at $install_path — leaving its default agents in place" >&2
|
|
598
|
+
return 0
|
|
599
|
+
fi
|
|
600
|
+
mkdir -p "$install_path/agents"
|
|
601
|
+
for f in "$variant_dir/"massa-ai-*.md; do
|
|
602
|
+
[[ -f "$f" ]] || continue
|
|
603
|
+
name="$(basename "$f")"
|
|
604
|
+
cp "$f" "$install_path/agents/$name"
|
|
605
|
+
copied=$((copied + 1))
|
|
606
|
+
done
|
|
607
|
+
if [[ "$copied" -gt 0 ]]; then
|
|
608
|
+
vecho " ↷ re-applied recorded model profile '$profile' (${copied} files) to $install_path/agents"
|
|
609
|
+
else
|
|
610
|
+
vecho " ↷ recorded model profile '$profile' variant directory has no massa-ai-*.md files — nothing to re-apply"
|
|
611
|
+
fi
|
|
612
|
+
}
|
|
613
|
+
|
|
510
614
|
# ── Plugin-registry registration (delegated to the claude CLI) ──────────────
|
|
511
615
|
# The CLI owns the registry format, so it is the only supported way to make the
|
|
512
616
|
# plugin appear in /plugin. Every failure path returns non-zero and the caller
|
|
@@ -546,6 +650,81 @@ unregister_claude_plugin() {
|
|
|
546
650
|
claude plugin marketplace remove "$PLUGIN_MARKETPLACE" </dev/null >/dev/null 2>&1 || true
|
|
547
651
|
}
|
|
548
652
|
|
|
653
|
+
# ── Marketplace cache refresh (CMR-01..05) ──────────────────────────────────
|
|
654
|
+
# `claude plugin install` is an idempotent no-op on an already-installed
|
|
655
|
+
# plugin, and the CLI serves a version-pinned cache snapshot — so an upgraded
|
|
656
|
+
# bundle never reaches an already-registered host by itself (observed: cache
|
|
657
|
+
# pinned at 1.28.0 while the checkout walked to 1.44.0). `claude plugin
|
|
658
|
+
# update` re-materializes the cache from a directory-source marketplace
|
|
659
|
+
# (verified against the real CLI, spec R1), so run it exactly when the served
|
|
660
|
+
# version is OLDER than the bundle — never on equal (no-op) or newer (that
|
|
661
|
+
# would downgrade; mirrors the harness "never downgrades" policy).
|
|
662
|
+
|
|
663
|
+
# Prints the version Claude actually serves for $PLUGIN_ID, or "" when it
|
|
664
|
+
# cannot be determined. Tolerant like recorded_profile: a missing/corrupt
|
|
665
|
+
# registry, a legacy non-array entry shape, or an absent entry all mean
|
|
666
|
+
# "unknown", never a failure. Claude-specific registry format — deliberately
|
|
667
|
+
# NOT in installer-shared.sh (Codex's registry differs; don't generalize one
|
|
668
|
+
# host's file shape).
|
|
669
|
+
claude_served_plugin_version() {
|
|
670
|
+
local runner="$1"
|
|
671
|
+
"$runner" - "$PLUGIN_REGISTRY" "$PLUGIN_ID" <<'NODE'
|
|
672
|
+
const fs = require("fs");
|
|
673
|
+
const [, , file, id] = process.argv;
|
|
674
|
+
try {
|
|
675
|
+
const data = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
676
|
+
const entries = data && data.plugins ? data.plugins[id] : null;
|
|
677
|
+
if (!Array.isArray(entries) || entries.length === 0) process.exit(0);
|
|
678
|
+
const rec = entries.find((e) => e && e.scope === "user") ?? entries[0];
|
|
679
|
+
if (rec && typeof rec.version === "string") process.stdout.write(rec.version);
|
|
680
|
+
} catch { /* unknown */ }
|
|
681
|
+
NODE
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
# Fills PLUGIN_SERVED_VERSION. Every failure path degrades with a loud
|
|
685
|
+
# warning and never aborts the install (I1) — an empty result makes
|
|
686
|
+
# record_plugin_version skip the version claim, so the next harness run
|
|
687
|
+
# retries instead of trusting a lie.
|
|
688
|
+
refresh_marketplace_cache() {
|
|
689
|
+
local runner=""
|
|
690
|
+
if command -v node &>/dev/null; then runner="node"
|
|
691
|
+
elif command -v bun &>/dev/null; then runner="bun"
|
|
692
|
+
else
|
|
693
|
+
echo " ⚠ node or bun required to verify the served plugin version — skipping cache refresh" >&2
|
|
694
|
+
return 0
|
|
695
|
+
fi
|
|
696
|
+
|
|
697
|
+
local served bundle
|
|
698
|
+
served="$(claude_served_plugin_version "$runner")"
|
|
699
|
+
bundle="$(installer_bundle_version "$SCRIPT_DIR/package.json")"
|
|
700
|
+
if [[ -z "$served" ]]; then
|
|
701
|
+
echo " ⚠ could not read the served plugin version from $PLUGIN_REGISTRY — not recording a version claim" >&2
|
|
702
|
+
return 0
|
|
703
|
+
fi
|
|
704
|
+
|
|
705
|
+
if [[ "$(installer_compare_versions "$runner" "$served" "$bundle")" == "-1" ]]; then
|
|
706
|
+
if installer_host_cli_supports claude plugin update; then
|
|
707
|
+
if claude plugin update "$PLUGIN_ID" </dev/null >/dev/null 2>&1; then
|
|
708
|
+
vecho " + refreshed marketplace cache: ${served} → ${bundle}"
|
|
709
|
+
# CPP-07: an update just moved installPath to a new version-pinned
|
|
710
|
+
# cache directory; re-apply any previously recorded model profile
|
|
711
|
+
# before it silently reverts to the new bundle's default agents.
|
|
712
|
+
apply_recorded_profile_after_update "$runner"
|
|
713
|
+
else
|
|
714
|
+
echo " ⚠ 'claude plugin update ${PLUGIN_ID}' failed — Claude keeps serving ${served}; re-run the installer or run the update manually" >&2
|
|
715
|
+
fi
|
|
716
|
+
else
|
|
717
|
+
echo " ⚠ this claude CLI has no 'plugin update' — Claude keeps serving ${served}; update the CLI or reinstall the plugin" >&2
|
|
718
|
+
fi
|
|
719
|
+
# Re-read: record what the CLI serves NOW, whether or not the update
|
|
720
|
+
# succeeded (CMR-02 truthful record; a stale record keeps the harness
|
|
721
|
+
# version gate re-triggering until an update lands — self-healing).
|
|
722
|
+
served="$(claude_served_plugin_version "$runner")"
|
|
723
|
+
fi
|
|
724
|
+
|
|
725
|
+
PLUGIN_SERVED_VERSION="$served"
|
|
726
|
+
}
|
|
727
|
+
|
|
549
728
|
# Strip artifacts a previous file-route install left behind. Called on the
|
|
550
729
|
# plugin route, where the bundle supplies all three itself. Without this an
|
|
551
730
|
# upgrading user keeps their old loose commands and merged hooks *and* gains
|
|
@@ -615,6 +794,7 @@ vecho "Installing massa-ai Claude Code plugin to: $TARGET"
|
|
|
615
794
|
PLUGIN_ROUTE=0
|
|
616
795
|
if register_claude_plugin; then
|
|
617
796
|
PLUGIN_ROUTE=1
|
|
797
|
+
refresh_marketplace_cache
|
|
618
798
|
fi
|
|
619
799
|
|
|
620
800
|
command_count=0
|
package/package.json
CHANGED
|
@@ -59,7 +59,7 @@ npx @massa-ai/mcp-client --config-show
|
|
|
59
59
|
npx @massa-ai/mcp-client --config-path
|
|
60
60
|
npx @massa-ai/mcp-client --config-dir
|
|
61
61
|
npx @massa-ai/mcp-client --config-init
|
|
62
|
-
npx @massa-ai/mcp-client --config-set embedding.dimensions
|
|
62
|
+
npx @massa-ai/mcp-client --config-set embedding.dimensions 2560
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
Provider initialization supports Ollama plus `--mistral` and `--openai`
|