@massa-ai/codex-plugin 1.53.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "massa-ai",
3
- "version": "1.53.0",
3
+ "version": "1.54.1",
4
4
  "description": "massa-ai — semantic code search, memory, and context compression for Codex",
5
5
  "author": {
6
6
  "name": "Luiz Massa",
package/install.sh CHANGED
@@ -184,8 +184,28 @@ if (typeof cfg.hooks !== "object" || cfg.hooks === null) {
184
184
  cfg.hooks = {};
185
185
  }
186
186
 
187
+ // Ownership test — marker first, command shape as the fallback. The marker is
188
+ // precise but not the only way our entries reach this file: an entry written by
189
+ // a release before the marker existed, or copied by hand from documentation,
190
+ // carries none, and was invisible to BOTH directions here — never deduped on
191
+ // install, never removed on uninstall. Claude's copy of this merge had exactly
192
+ // that gap and it double-fired every lifecycle event (measured live
193
+ // 2026-08-17). Referencing the massa-ai-hook binary is unambiguous; a user hook
194
+ // that merely mentions massa-ai elsewhere does not match.
195
+ //
196
+ // isOwned covers both shapes this file has ever held: the flat pre-fix entry
197
+ // (command at the top level) and the matcher group (commands inside hooks[]).
198
+ const OWNED_COMMAND = /massa-ai-hook/;
199
+
200
+ function commandIsOwned(h) {
201
+ return Boolean(h) && typeof h.command === "string" && OWNED_COMMAND.test(h.command);
202
+ }
203
+
187
204
  function isOwned(e) {
188
- return Boolean(e) && e._massaAiOwned === true;
205
+ if (!e || typeof e !== "object") return false;
206
+ if (e._massaAiOwned === true) return true;
207
+ if (commandIsOwned(e)) return true;
208
+ return Array.isArray(e.hooks) && e.hooks.length > 0 && e.hooks.every(commandIsOwned);
189
209
  }
190
210
 
191
211
  // A correctly-shaped owned entry is a matcher group: its "hooks" is an array.
@@ -202,10 +222,18 @@ if (mode === "uninstall") {
202
222
  // Remove owned entries from nested location + perform flat→nested migration
203
223
  const hooks = cfg.hooks;
204
224
 
205
- // First, remove owned entries from the correct nested location
206
- for (const [evt] of EVENTS) {
225
+ // Back up before removing: this now deletes unmarked entries it did not
226
+ // necessarily write, so the install path's backup discipline applies here too.
227
+ if (existed) {
228
+ fs.copyFileSync(file, `${file}.massa-ai.bak-${ts}`);
229
+ }
230
+
231
+ // Remove owned entries from the correct nested location. Every event, not
232
+ // just the ones this release writes — the predicate identifies our commands
233
+ // rather than a location.
234
+ for (const evt of Object.keys(hooks)) {
207
235
  if (Array.isArray(hooks[evt])) {
208
- hooks[evt] = hooks[evt].filter((e) => !(e && e._massaAiOwned === true));
236
+ hooks[evt] = hooks[evt].filter((e) => !isOwned(e));
209
237
  if (hooks[evt].length === 0) delete hooks[evt];
210
238
  }
211
239
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massa-ai/codex-plugin",
3
- "version": "1.53.0",
3
+ "version": "1.54.1",
4
4
  "description": "massa-ai plugin for Codex — semantic code search, memory, and context compression",
5
5
  "files": [
6
6
  "agents",