agent-sanitizer 2.14.0 → 2.14.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.
@@ -39,14 +39,21 @@ import { pathToFileURL } from "node:url";
39
39
  * }} HookIoSharedState
40
40
  */
41
41
 
42
- /** @type {HookIoSharedState} */
43
- let shared = {
42
+ /**
43
+ * A fresh state object with every slot at its default. Called per use, never
44
+ * hoisted to one shared literal, so each caller gets its own `lazyModules`.
45
+ * @returns {HookIoSharedState}
46
+ */
47
+ const defaultSharedState = () => ({
44
48
  lazyModules: Object.create(null),
45
49
  cliEntryClaimed: false,
46
50
  missingPackageRemedy: null,
47
51
  hookgateMarker: null,
48
52
  hookgateMarkerResolved: false,
49
- };
53
+ });
54
+
55
+ /** @type {HookIoSharedState} */
56
+ let shared = defaultSharedState();
50
57
 
51
58
  /**
52
59
  * This instance's state object, for a host to hand to another instance.
@@ -98,6 +105,18 @@ export function hookIoSharedState() {
98
105
  */
99
106
  export function adoptHookIoSharedState(state) {
100
107
  if (state === shared) return;
108
+ // Fill any slot `state` omits before anything reads it. A host builds this
109
+ // object itself, so one written against an earlier version of this package
110
+ // lacks the slots added since — and every reader below tests `!== null`, which
111
+ // an ABSENT slot satisfies. Unfilled, hookgateMarkerPath returns undefined
112
+ // instead of deriving a path; probeSetupAlive then throws internally on it and
113
+ // reports setup alive forever, so awaitLazyDependency waits out its whole
114
+ // ceiling, the harness kills the hook, and a killed hook is non-blocking — the
115
+ // fail-OPEN this module exists to prevent. `??=` and not `=`: it must not
116
+ // clobber a slot the host deliberately set, including `false`.
117
+ const slots = /** @type {Record<string, any>} */ (state);
118
+ for (const [slot, value] of Object.entries(defaultSharedState()))
119
+ slots[slot] ??= value;
101
120
  for (const [specifier, namespace] of Object.entries(shared.lazyModules))
102
121
  if (state.lazyModules[specifier] === undefined)
103
122
  state.lazyModules[specifier] = namespace;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-sanitizer",
3
- "version": "2.14.0",
3
+ "version": "2.14.1",
4
4
  "description": "Defend an agent against hidden-content injection: strip payload-capable invisible Unicode and ANSI, splice out human-invisible HTML, and flag data-exfil URLs in untrusted text before any model sees it.",
5
5
  "type": "module",
6
6
  "repository": {