@massa-ai/cursor-plugin 1.52.0 → 1.54.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/install.sh
CHANGED
|
@@ -11,15 +11,38 @@
|
|
|
11
11
|
# MCP registration is delegated to scripts/install-agents.sh, the single writer
|
|
12
12
|
# of host MCP config. This installer no longer ships a plugin-local mcp.json.
|
|
13
13
|
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
14
|
+
# LOCAL IS THE DEFAULT ROUTE. The Claude bridge is opt-in (--prefer-bridge).
|
|
15
|
+
#
|
|
16
|
+
# Cursor can bridge the Claude marketplace registry from ~/.claude — observed
|
|
17
|
+
# live in Cursor 3.14's "Cursor Plugins" exthost log on 2026-08-05
|
|
18
|
+
# ("loadClaudePlugin massa-ai@massa-ai"). This installer used to PREFER that
|
|
19
|
+
# bridge at user scope: on detection it deleted its own plugin directory and
|
|
20
|
+
# stripped its hook wiring, on the premise that the bridge loads the whole
|
|
21
|
+
# plugin.
|
|
22
|
+
#
|
|
23
|
+
# Measured on Cursor 3.16.17 (2026-08-17), with massa-ai listed and
|
|
24
|
+
# `enabledPlugins` true in ~/.claude, that premise is at best half true:
|
|
25
|
+
#
|
|
26
|
+
# hooks → fire in Cursor
|
|
27
|
+
# plugin → absent from the Cursor UI
|
|
28
|
+
# commands → absent (all 46 workflow commands)
|
|
29
|
+
#
|
|
30
|
+
# So bridge-preference silently withheld a working local install, and the user
|
|
31
|
+
# lost every workflow command with nothing replacing them. Detection reads
|
|
32
|
+
# ~/.claude, which is a fact about CLAUDE's files — never proof that Cursor
|
|
33
|
+
# loaded anything from them — and nothing here can observe the difference.
|
|
34
|
+
#
|
|
35
|
+
# The default therefore installs everything locally. --prefer-bridge (or
|
|
36
|
+
# MASSA_AI_CURSOR_PREFER_BRIDGE=1) restores the old behaviour for anyone whose
|
|
37
|
+
# bridge does deliver hooks.
|
|
38
|
+
#
|
|
39
|
+
# AD-017 TRADE-OFF, STATED PLAINLY: if the bridge IS delivering hooks and you
|
|
40
|
+
# take the default, both sources are live and every hook fires TWICE. The
|
|
41
|
+
# install warns when it detects that combination. Choose --prefer-bridge, or
|
|
42
|
+
# disable massa-ai in ~/.claude/settings.json, to keep exactly one source.
|
|
43
|
+
#
|
|
44
|
+
# Project-scope installs never consult the bridge — ~/.claude is a user
|
|
45
|
+
# surface, never a project one.
|
|
23
46
|
#
|
|
24
47
|
# Idempotent: re-running is a no-op when owned entries already present.
|
|
25
48
|
# Uninstall removes only ownership-marked entries + the plugin directory,
|
|
@@ -29,6 +52,13 @@
|
|
|
29
52
|
# apps/cursor-plugin/install.sh # install at user scope (~/.cursor)
|
|
30
53
|
# apps/cursor-plugin/install.sh --user # (same)
|
|
31
54
|
# apps/cursor-plugin/install.sh --project # install at project scope (./.cursor)
|
|
55
|
+
# apps/cursor-plugin/install.sh --prefer-bridge # leave hook wiring to the
|
|
56
|
+
# # Claude bridge instead of
|
|
57
|
+
# # installing it locally; use when
|
|
58
|
+
# # bridge-delivered hooks DO fire
|
|
59
|
+
# # in your Cursor, to avoid every
|
|
60
|
+
# # hook firing twice. Same as
|
|
61
|
+
# # MASSA_AI_CURSOR_PREFER_BRIDGE=1
|
|
32
62
|
# apps/cursor-plugin/install.sh --uninstall # remove owned entries + plugin dir
|
|
33
63
|
# apps/cursor-plugin/install.sh -h|--help # show this help
|
|
34
64
|
|
|
@@ -41,11 +71,26 @@ CLAUDE_PLUGIN_BIN="$REPO_ROOT/apps/claude-plugin/hooks/massa-ai-hook.ts"
|
|
|
41
71
|
SCOPE="user"
|
|
42
72
|
UNINSTALL=0
|
|
43
73
|
DRY_RUN=0
|
|
74
|
+
# Local is the DEFAULT route; the Claude bridge is opt-in.
|
|
75
|
+
#
|
|
76
|
+
# Bridge detection reads ~/.claude — a fact about CLAUDE's files — and infers
|
|
77
|
+
# from it that Cursor is loading massa-ai. That inference cannot be verified
|
|
78
|
+
# from here, and it was measured wrong on Cursor 3.16.17: the plugin and its
|
|
79
|
+
# 46 workflow commands were absent from the Cursor UI while ~/.claude said the
|
|
80
|
+
# plugin was installed and enabled. Preferring the bridge by default therefore
|
|
81
|
+
# meant silently withholding a working local install on the strength of a
|
|
82
|
+
# claim about a different product.
|
|
83
|
+
#
|
|
84
|
+
# So the default installs everything locally, and --prefer-bridge (or
|
|
85
|
+
# MASSA_AI_CURSOR_PREFER_BRIDGE=1) opts into leaving hook wiring to the
|
|
86
|
+
# bridge. See the AD-017 double-fire note where PREFER_BRIDGE is consumed.
|
|
87
|
+
PREFER_BRIDGE="${MASSA_AI_CURSOR_PREFER_BRIDGE:-0}"
|
|
44
88
|
|
|
45
89
|
for arg in "$@"; do
|
|
46
90
|
case "$arg" in
|
|
47
91
|
--user) SCOPE="user" ;;
|
|
48
92
|
--project) SCOPE="project" ;;
|
|
93
|
+
--prefer-bridge) PREFER_BRIDGE=1 ;;
|
|
49
94
|
--uninstall) UNINSTALL=1 ;;
|
|
50
95
|
--quiet) MASSA_AI_VERBOSE=0 ;;
|
|
51
96
|
--verbose) MASSA_AI_VERBOSE=1 ;;
|
|
@@ -249,14 +294,37 @@ if (typeof cfg.hooks !== "object" || cfg.hooks === null) cfg.hooks = {};
|
|
|
249
294
|
|
|
250
295
|
const hooks = cfg.hooks;
|
|
251
296
|
|
|
297
|
+
// Ownership test — marker first, command shape as the fallback. The marker is
|
|
298
|
+
// precise but not the only way our entries reach this file: an entry written by
|
|
299
|
+
// a release before the marker existed, or copied by hand from documentation,
|
|
300
|
+
// carries none, and was invisible to BOTH directions here — never deduped on
|
|
301
|
+
// install, never removed on uninstall. Claude's copy of this merge had exactly
|
|
302
|
+
// that gap and it double-fired every lifecycle event (measured live
|
|
303
|
+
// 2026-08-17). Referencing the massa-ai-hook binary is unambiguous; a user hook
|
|
304
|
+
// that merely mentions massa-ai elsewhere does not match.
|
|
305
|
+
const OWNED_COMMAND = /massa-ai-hook/;
|
|
306
|
+
|
|
307
|
+
function entryIsOwned(e) {
|
|
308
|
+
if (!e || typeof e !== "object") return false;
|
|
309
|
+
if (e._massaAiOwned === true) return true;
|
|
310
|
+
return typeof e.command === "string" && OWNED_COMMAND.test(e.command);
|
|
311
|
+
}
|
|
312
|
+
|
|
252
313
|
function hasOwned(arr) {
|
|
253
|
-
return Array.isArray(arr) && arr.some(
|
|
314
|
+
return Array.isArray(arr) && arr.some(entryIsOwned);
|
|
254
315
|
}
|
|
255
316
|
|
|
256
317
|
if (mode === "uninstall") {
|
|
257
|
-
|
|
318
|
+
// Back up before removing: this now deletes unmarked entries it did not
|
|
319
|
+
// necessarily write, so the install path's backup discipline applies here too.
|
|
320
|
+
if (existed) {
|
|
321
|
+
fs.copyFileSync(file, `${file}.massa-ai.bak-${ts}`);
|
|
322
|
+
}
|
|
323
|
+
// Every event, not just the ones this release writes — the predicate
|
|
324
|
+
// identifies our commands rather than a location.
|
|
325
|
+
for (const evt of Object.keys(hooks)) {
|
|
258
326
|
if (Array.isArray(hooks[evt])) {
|
|
259
|
-
hooks[evt] = hooks[evt].filter((e) => !(e
|
|
327
|
+
hooks[evt] = hooks[evt].filter((e) => !entryIsOwned(e));
|
|
260
328
|
if (hooks[evt].length === 0) delete hooks[evt];
|
|
261
329
|
}
|
|
262
330
|
}
|
|
@@ -325,7 +393,11 @@ install_bundled_skills() {
|
|
|
325
393
|
fi
|
|
326
394
|
|
|
327
395
|
local installed=0 name src dest
|
|
328
|
-
|
|
396
|
+
# Three harness skills, matching generate-skill-artifacts.ts:138's
|
|
397
|
+
# authoritative constant (D6/IPT-05) — not derived by scanning the bundle's
|
|
398
|
+
# skills/ directory, which would install 49 on cursor (every workflow skill
|
|
399
|
+
# ships as its own directory here).
|
|
400
|
+
for name in massa-ai persona-router profile; do
|
|
329
401
|
src="$SCRIPT_DIR/skills/$name"
|
|
330
402
|
[[ -d "$src" ]] || continue
|
|
331
403
|
dest="$HARNESS_SKILLS_DIR/$name"
|
|
@@ -354,7 +426,7 @@ if (typeof data.platforms !== "object" || data.platforms === null || Array.isArr
|
|
|
354
426
|
}
|
|
355
427
|
data.version = 2;
|
|
356
428
|
const prev = data.platforms[host];
|
|
357
|
-
data.platforms[host] = { root, skillsOwner: "plugin", skills: ["massa-ai", "persona-router"] };
|
|
429
|
+
data.platforms[host] = { root, skillsOwner: "plugin", skills: ["massa-ai", "persona-router", "profile"] };
|
|
358
430
|
// The whole-record replace must not drop fields a previous successful install
|
|
359
431
|
// wrote (R2) — re-attach them. installRoute (T9) is installer-owned but
|
|
360
432
|
// written by a LATER step of this same install (record_plugin_version), so it
|
|
@@ -400,7 +472,7 @@ NODE
|
|
|
400
472
|
)"
|
|
401
473
|
[[ "$raw_owner" == "plugin" ]] && {
|
|
402
474
|
local name
|
|
403
|
-
for name in massa-ai persona-router; do
|
|
475
|
+
for name in massa-ai persona-router profile; do
|
|
404
476
|
rm -rf "$HARNESS_SKILLS_DIR/$name"
|
|
405
477
|
done
|
|
406
478
|
rmdir "$HARNESS_SKILLS_DIR" 2>/dev/null || true
|
|
@@ -532,97 +604,127 @@ fi
|
|
|
532
604
|
# ── Install ──────────────────────────────────────────────────────────────────
|
|
533
605
|
# PAU-08/09: bridge-preferred, local-fallback. Computed once, used to decide
|
|
534
606
|
# both which artifacts this run writes and what installRoute gets recorded.
|
|
607
|
+
# Local by default. The probe still runs when the bridge is NOT opted into,
|
|
608
|
+
# purely so the AD-017 double-fire warning below can be accurate — its result
|
|
609
|
+
# no longer decides what gets installed.
|
|
535
610
|
IS_BRIDGE=0
|
|
611
|
+
BRIDGE_AVAILABLE=0
|
|
536
612
|
if claude_bridge_detected; then
|
|
537
|
-
|
|
613
|
+
BRIDGE_AVAILABLE=1
|
|
614
|
+
fi
|
|
615
|
+
if [[ "$PREFER_BRIDGE" == "1" ]]; then
|
|
616
|
+
if [[ "$BRIDGE_AVAILABLE" == "1" ]]; then
|
|
617
|
+
IS_BRIDGE=1
|
|
618
|
+
vecho "--prefer-bridge: leaving hook wiring to the Claude bridge."
|
|
619
|
+
else
|
|
620
|
+
# Opting into a bridge that is not there would leave the user with no hooks
|
|
621
|
+
# at all, which is strictly worse than the default. Fall back loudly.
|
|
622
|
+
echo " ⚠ --prefer-bridge requested, but ~/.claude does not list massa-ai as installed and enabled." >&2
|
|
623
|
+
echo " Falling back to a local hook install so hooks are not silently absent." >&2
|
|
624
|
+
fi
|
|
538
625
|
fi
|
|
539
626
|
|
|
540
627
|
skill_count=0
|
|
541
628
|
specialist_count=0
|
|
542
629
|
|
|
543
630
|
if [[ "$IS_BRIDGE" -eq 1 ]]; then
|
|
544
|
-
vecho "
|
|
545
|
-
#
|
|
546
|
-
#
|
|
547
|
-
#
|
|
548
|
-
# stripped with the SAME filter merge_hooks_json's "uninstall" mode already
|
|
549
|
-
# uses — the bridge delivers hooks instead.
|
|
550
|
-
if [[ -d "$LEGACY_PLUGIN_DIR" ]]; then
|
|
551
|
-
rm -rf "$LEGACY_PLUGIN_DIR"
|
|
552
|
-
echo -e " - removed pre-fix plugin copy at $LEGACY_PLUGIN_DIR"
|
|
553
|
-
fi
|
|
554
|
-
if [[ -d "$PLUGIN_DIR" ]]; then
|
|
555
|
-
rm -rf "$PLUGIN_DIR"
|
|
556
|
-
echo -e " - removed local plugin copy at $PLUGIN_DIR (Claude bridge already loads massa-ai)"
|
|
557
|
-
fi
|
|
631
|
+
vecho "Claude-bridge route: ~/.claude lists massa-ai as installed and enabled, so Cursor delivers its HOOKS via the bridge. The plugin bundle is still installed locally — see below."
|
|
632
|
+
# Hook wiring, and only hook wiring, is what the bridge actually delivers.
|
|
633
|
+
# Owned entries are stripped with the SAME filter merge_hooks_json's
|
|
634
|
+
# "uninstall" mode uses, so the bridge's copy is the only one that fires.
|
|
558
635
|
if [[ -f "$HOOKS_JSON" ]]; then
|
|
559
636
|
merge_hooks_json "$HOOKS_JSON" "uninstall"
|
|
560
637
|
echo -e " - removed massa-ai hook entries from $HOOKS_JSON (the bridge delivers hooks instead)"
|
|
561
638
|
fi
|
|
562
|
-
|
|
563
|
-
vecho "Installing massa-ai Cursor plugin to: $PLUGIN_DIR"
|
|
564
|
-
# Migration: a pre-fix install left a copy at plugins/massa-ai. Leaving it in
|
|
565
|
-
# place risks Cursor discovering both and firing every hook twice, so it goes
|
|
566
|
-
# before the new location is written.
|
|
567
|
-
if [[ -d "$LEGACY_PLUGIN_DIR" ]]; then
|
|
568
|
-
rm -rf "$LEGACY_PLUGIN_DIR"
|
|
569
|
-
echo -e " - removed pre-fix plugin copy at $LEGACY_PLUGIN_DIR"
|
|
570
|
-
fi
|
|
571
|
-
mkdir -p "$PLUGIN_DIR/.cursor-plugin" "$PLUGIN_DIR/skills" "$PLUGIN_DIR/hooks"
|
|
572
|
-
# Migration: pre-fix installs bundled agents inside the plugin dir, which
|
|
573
|
-
# Cursor never reads. Drop that copy so upgraders converge on the one real
|
|
574
|
-
# discovery surface and a future Cursor plugin scan cannot double-register.
|
|
575
|
-
if [[ -d "$PLUGIN_DIR/agents" ]]; then
|
|
576
|
-
rm -rf "$PLUGIN_DIR/agents"
|
|
577
|
-
echo -e " - removed pre-fix agents copy at $PLUGIN_DIR/agents (Cursor reads $CURSOR_AGENTS_DIR)"
|
|
578
|
-
fi
|
|
639
|
+
fi
|
|
579
640
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
641
|
+
# The plugin bundle (manifest + workflow-command skills) installs on BOTH
|
|
642
|
+
# routes. It used to be skipped whenever the bridge was detected, on the
|
|
643
|
+
# premise that the bridge loads the whole plugin.
|
|
644
|
+
#
|
|
645
|
+
# Measured against Cursor 3.16.17 on 2026-08-17, that premise is half true.
|
|
646
|
+
# With the bridge active — massa-ai listed and `enabledPlugins` true in
|
|
647
|
+
# ~/.claude — hooks DO fire in Cursor, while the plugin and its 46 workflow
|
|
648
|
+
# commands are absent from the UI entirely. The old branch therefore deleted a
|
|
649
|
+
# working local bundle and nothing replaced it: the user kept the hooks and
|
|
650
|
+
# silently lost every workflow command. The header's "Cursor 3.14 also bridges
|
|
651
|
+
# the Claude marketplace registry" was pinned against a 2026-08-05 capture and
|
|
652
|
+
# was never re-verified against a later Cursor.
|
|
653
|
+
#
|
|
654
|
+
# So the two deliveries are gated independently: hooks by $IS_BRIDGE above,
|
|
655
|
+
# the bundle never. Reinstating the bundle on the bridge route cannot
|
|
656
|
+
# double-fire hooks — .cursor-plugin/plugin.json declares only
|
|
657
|
+
# name/version/description, so the bundle carries no hook wiring of its own;
|
|
658
|
+
# $HOOKS_JSON is the only surface that does, and on the bridge route it is
|
|
659
|
+
# left stripped.
|
|
660
|
+
vecho "Installing the massa-ai Cursor plugin bundle to: $PLUGIN_DIR"
|
|
661
|
+
# Migration: a pre-fix install left a copy at plugins/massa-ai. Leaving it in
|
|
662
|
+
# place risks Cursor discovering both and firing every hook twice, so it goes
|
|
663
|
+
# before the new location is written. Runs on both routes.
|
|
664
|
+
if [[ -d "$LEGACY_PLUGIN_DIR" ]]; then
|
|
665
|
+
rm -rf "$LEGACY_PLUGIN_DIR"
|
|
666
|
+
echo -e " - removed pre-fix plugin copy at $LEGACY_PLUGIN_DIR"
|
|
667
|
+
fi
|
|
668
|
+
mkdir -p "$PLUGIN_DIR/.cursor-plugin" "$PLUGIN_DIR/skills" "$PLUGIN_DIR/hooks"
|
|
669
|
+
# Migration: pre-fix installs bundled agents inside the plugin dir, which
|
|
670
|
+
# Cursor never reads. Drop that copy so upgraders converge on the one real
|
|
671
|
+
# discovery surface and a future Cursor plugin scan cannot double-register.
|
|
672
|
+
if [[ -d "$PLUGIN_DIR/agents" ]]; then
|
|
673
|
+
rm -rf "$PLUGIN_DIR/agents"
|
|
674
|
+
echo -e " - removed pre-fix agents copy at $PLUGIN_DIR/agents (Cursor reads $CURSOR_AGENTS_DIR)"
|
|
675
|
+
fi
|
|
601
676
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
677
|
+
# Copy manifest
|
|
678
|
+
cp "$SCRIPT_DIR/.cursor-plugin/plugin.json" "$PLUGIN_DIR/.cursor-plugin/plugin.json"
|
|
679
|
+
vecho " + .cursor-plugin/plugin.json"
|
|
680
|
+
|
|
681
|
+
# Copy the host-command skills (each in a subdirectory: skills/<name>/SKILL.md),
|
|
682
|
+
# quick + generated workflow commands alike. massa-ai/, persona-router/,
|
|
683
|
+
# agents/, and profile/ are the PDO-06 harness bundle, not a Cursor command
|
|
684
|
+
# skill — they are installed separately, into the shared harness skills
|
|
685
|
+
# directory (see "Skills bundling" below), not into this plugin-cache
|
|
686
|
+
# skills/ tree. `profile` was missing from this exclusion pre-fix, which
|
|
687
|
+
# leaked it into the command-skill cache mislabeled as `/profile`.
|
|
688
|
+
for src in "$SCRIPT_DIR/skills/"*/SKILL.md; do
|
|
689
|
+
name="$(basename "$(dirname "$src")")"
|
|
690
|
+
case "$name" in
|
|
691
|
+
massa-ai|persona-router|agents|profile) continue ;;
|
|
692
|
+
esac
|
|
693
|
+
mkdir -p "$PLUGIN_DIR/skills/$name"
|
|
694
|
+
cp "$src" "$PLUGIN_DIR/skills/$name/SKILL.md"
|
|
695
|
+
vecho " + skills/$name/SKILL.md"
|
|
696
|
+
skill_count=$((skill_count + 1))
|
|
697
|
+
done
|
|
698
|
+
|
|
699
|
+
# Copy hooks.json (the placeholder version — installer replaces paths)
|
|
700
|
+
cp "$SCRIPT_DIR/hooks/hooks.json" "$PLUGIN_DIR/hooks/hooks.json"
|
|
701
|
+
vecho " + hooks/hooks.json"
|
|
702
|
+
|
|
703
|
+
# Older installs shipped a plugin-local mcp.json here. Cursor reads
|
|
704
|
+
# ~/.cursor/mcp.json, not the plugin dir, and MCP is now owned by
|
|
705
|
+
# scripts/install-agents.sh — drop the residue so upgraders converge.
|
|
706
|
+
if [[ -f "$PLUGIN_DIR/mcp.json" ]]; then
|
|
707
|
+
rm -f "$PLUGIN_DIR/mcp.json"
|
|
708
|
+
# Not gated by --quiet: this deletes a file in the user's home, so it is a
|
|
709
|
+
# mutation notice rather than per-file chatter.
|
|
710
|
+
echo -e " - removed stale mcp.json (MCP is now registered in ~/.cursor/mcp.json)"
|
|
615
711
|
fi
|
|
616
712
|
|
|
617
713
|
# Flat agents and harness skills are written in BOTH branches (PAU-08/09):
|
|
618
714
|
# Cursor discovers subagents only from the flat directory regardless of which
|
|
619
715
|
# plugin-load path is active, and MCP/harness-skills ownership is independent
|
|
620
|
-
# of it too.
|
|
621
|
-
# linger installed. All of them, navigator included, are generated from
|
|
716
|
+
# of it too. All of them, navigator included, are generated from
|
|
622
717
|
# skills/agents/*/SKILL.md and owned by the massa-ai- name prefix (CRS-04) —
|
|
623
718
|
# user-authored agents are untouched.
|
|
719
|
+
#
|
|
720
|
+
# Copy-then-prune (D1/IPT-02 AC-02.6), not prune-then-copy: this loop copies
|
|
721
|
+
# the current set first, and only afterward sheds destination entries the
|
|
722
|
+
# bundle no longer ships. `set -euo pipefail` is in force, so a mid-loop `cp`
|
|
723
|
+
# failure aborts the script — under the old prune-first order that left the
|
|
724
|
+
# user with fewer agents than before the upgrade (possibly none); under this
|
|
725
|
+
# order the worst case is a retired agent lingering one run longer, which is
|
|
726
|
+
# the pre-fix status quo this feature already tolerates.
|
|
624
727
|
mkdir -p "$CURSOR_AGENTS_DIR"
|
|
625
|
-
rm -f "$CURSOR_AGENTS_DIR/"massa-ai-*.md
|
|
626
728
|
for src in "$SCRIPT_DIR/agents/"massa-ai-*.md; do
|
|
627
729
|
[[ -f "$src" ]] || continue
|
|
628
730
|
name="$(basename "$src")"
|
|
@@ -632,6 +734,19 @@ for src in "$SCRIPT_DIR/agents/"massa-ai-*.md; do
|
|
|
632
734
|
done
|
|
633
735
|
vecho " + ${specialist_count} subagent specialists (generated from skills/agents/*/SKILL.md)"
|
|
634
736
|
|
|
737
|
+
# Shed owned members the bundle no longer ships (D2): the removal population
|
|
738
|
+
# is the destination directory; the bundle supplies only the keep-predicate.
|
|
739
|
+
# Loop over the destination, consult the bundle only to decide whether to
|
|
740
|
+
# keep — never loop over the bundle to decide removals. Ownership test is the
|
|
741
|
+
# massa-ai- name prefix (D3), same as the uninstall loop above.
|
|
742
|
+
for f in "$CURSOR_AGENTS_DIR/"massa-ai-*.md; do
|
|
743
|
+
[[ -f "$f" ]] || continue
|
|
744
|
+
name="$(basename "$f")"
|
|
745
|
+
[[ -f "$SCRIPT_DIR/agents/$name" ]] && continue # keep-list: still shipped
|
|
746
|
+
rm -f "$f"
|
|
747
|
+
vecho " - $name (retired, no longer shipped)"
|
|
748
|
+
done
|
|
749
|
+
|
|
635
750
|
# Skills bundling (PDO-08, 09): install massa-ai/persona-router into the
|
|
636
751
|
# shared harness skills directory, unless scripts/install-skills.sh already
|
|
637
752
|
# owns it for this platform. Runs in both branches (same reasoning as above).
|
|
@@ -685,9 +800,20 @@ fi
|
|
|
685
800
|
# Summary line in quiet mode
|
|
686
801
|
if [ "${MASSA_AI_VERBOSE:-0}" != "1" ]; then
|
|
687
802
|
if [[ "$IS_BRIDGE" -eq 1 ]]; then
|
|
688
|
-
ok "cursor plugin
|
|
803
|
+
ok "cursor plugin installed (${skill_count} skills, ${specialist_count} specialists) — hooks left to the Claude bridge (--prefer-bridge)"
|
|
804
|
+
ok " if massa-ai hooks do NOT fire in Cursor, the bridge is not delivering them: re-run without --prefer-bridge"
|
|
689
805
|
else
|
|
690
806
|
ok "cursor plugin installed (${skill_count} skills, ${specialist_count} specialists, 7 hooks)"
|
|
807
|
+
if [[ "$BRIDGE_AVAILABLE" -eq 1 ]]; then
|
|
808
|
+
# AD-017: both sources live. Not an error — the default is local by
|
|
809
|
+
# design — but the user must be told, because a doubled hook is silent
|
|
810
|
+
# and looks like the tool misbehaving rather than being installed twice.
|
|
811
|
+
echo " ⚠ ~/.claude also lists massa-ai as installed and enabled." >&2
|
|
812
|
+
echo " If Cursor's Claude bridge delivers those hooks, they now fire TWICE" >&2
|
|
813
|
+
echo " (once from the bridge, once from ~/.cursor/hooks.json)." >&2
|
|
814
|
+
echo " Keep one source: re-run with --prefer-bridge, or disable massa-ai" >&2
|
|
815
|
+
echo " in ~/.claude/settings.json (enabledPlugins)." >&2
|
|
816
|
+
fi
|
|
691
817
|
fi
|
|
692
818
|
else
|
|
693
819
|
vecho ""
|
package/package.json
CHANGED
package/skills/massa-ai/SKILL.md
CHANGED
|
@@ -46,7 +46,7 @@ Before reading any massa-ai file:
|
|
|
46
46
|
Never pass `workflowSessionId` in that field. Use `synapse_task_begin`/`synapse_task_end`
|
|
47
47
|
for task envelopes and `synapse_prefetch` to warm the buffer on file open.
|
|
48
48
|
- Prefer the shared v2 retrieval order; fall back gracefully if the massa-ai
|
|
49
|
-
server or Synapse is unavailable. The full tool surface includes
|
|
49
|
+
server or Synapse is unavailable. The full tool surface includes 59 tools
|
|
50
50
|
(see `references/mcp-tools.md`): indexing, search, symbol graph
|
|
51
51
|
(`trace_path`, `impact_analysis`, `get_architecture`), memory CRUD
|
|
52
52
|
(`remember`, `recall`, `memory_update`, `memory_delete`), checkpoints
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# massa-ai Tool Contracts (
|
|
1
|
+
# massa-ai Tool Contracts (59 Tools)
|
|
2
2
|
|
|
3
3
|
Load when exact MCP schemas, REST fallbacks, response modes, or
|
|
4
4
|
polling rules are needed. Prefer the active tool declaration over copied
|
|
@@ -103,6 +103,8 @@ depends on exact content.
|
|
|
103
103
|
| `handoff_accept` | Accept an open handoff (open→accepted) | Req: `id`. Opt: `projectId`. |
|
|
104
104
|
| `handoff_cancel` | Cancel/expire an open handoff | Req: `id`. Opt: `projectId`. |
|
|
105
105
|
| `handoff_list_pending` | List open handoffs, oldest-first | Req: `projectId`. Opt: `targetAgent`. |
|
|
106
|
+
| `handoff_update` | Edit targetAgent/summary/openQuestions/nextSteps/files by id | Req: `id`. Opt: `projectId`, `targetAgent`, `summary`, `openQuestions`, `nextSteps`, `files` — at least one editable field required. Unknown/restricted fields (`status`, `acceptedAt`, etc.) are rejected by name. |
|
|
107
|
+
| `handoff_delete` | Hard-delete a handoff, any status | Req: `id`. Opt: `projectId`. |
|
|
106
108
|
|
|
107
109
|
## MCP Capability Matrix — Auto-improvement (Proposals)
|
|
108
110
|
|
|
@@ -111,6 +113,9 @@ depends on exact content.
|
|
|
111
113
|
| `list_proposals` | List pending auto-improvement proposals, newest-first | Req: `projectId`. |
|
|
112
114
|
| `approve_proposal` | Approve a proposal; applies the memory edit | Req: `id`. Opt: `projectId`, `source`. |
|
|
113
115
|
| `reject_proposal` | Reject a proposal (no edit applied) | Req: `id`. Opt: `projectId`, `reason`. |
|
|
116
|
+
| `create_proposal` | Create a pending proposal by hand | Req: `projectId`, `kind` (`memory.create`\|`memory.update`\|`memory.tag`), `payload`. Opt: `rationale`, `targetMemoryId`. `payload` is validated against the same per-kind rules the store enforces on read. |
|
|
117
|
+
| `update_proposal` | Edit rationale/payload by id, any status | Req: `id`. Opt: `projectId`, `rationale`, `payload` — at least one editable field required. `kind`/`targetMemoryId`/`status`/`decidedAt` are immutable. A `payload` edit re-validates against the row's existing `kind`. |
|
|
118
|
+
| `delete_proposal` | Hard-delete a proposal, any status | Req: `id`. Opt: `projectId`. Deleting an approved proposal does not reverse its applied memory edit. |
|
|
114
119
|
|
|
115
120
|
## MCP Capability Matrix — Passive Capture
|
|
116
121
|
|