@goodandready/dsh-approval-gate 0.1.27 → 0.1.28

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.28
4
+
5
+ - Fix: Безопасное чтение версии хоста в lib/compat.js через ctx.get(version) и защищенный доступ без падений на строгих Proxy-контекстах Cordis при отсутствии инжекции version (Refs: #184).
6
+
3
7
  ## 0.1.27
4
8
 
5
9
  - Feature: Интерактивный визуальный редактор правил и белых списков путей (ApprovalGateSettingsCard в lib/client.js, TimelineService endpoints /rules в lib/timeline-service.js, слот settings.plugin.item) (Refs: #49).
package/lib/compat.js CHANGED
@@ -1,8 +1,10 @@
1
1
  // lib/compat.js
2
- // Host compatibility checks and polyfills across DeepSeek Harness minor versions (#106).
2
+ // Host compatibility checks and polyfills across DeepSeek Harness minor versions (#106, #184).
3
3
 
4
4
  /**
5
- * Detects available runtime capabilities and services in the Cordis host context (#106).
5
+ * Detects available runtime capabilities and services in the Cordis host context (#106, #184).
6
+ * Safely accesses properties via ctx.get() and guarded property lookup to avoid
7
+ * throwing in strict Cordis contexts where uninjected property access is forbidden.
6
8
  *
7
9
  * @param {any} ctx - Cordis / DSH host context
8
10
  * @returns {{
@@ -11,7 +13,7 @@
11
13
  * hasPreExecuteHook: boolean,
12
14
  * hasProvideApi: boolean,
13
15
  * hasLocaleService: boolean,
14
- * harnessVersion: string | null
16
+ * harnessVersion: string
15
17
  * }}
16
18
  */
17
19
  export function detectHarnessCapabilities(ctx) {
@@ -22,39 +24,48 @@ export function detectHarnessCapabilities(ctx) {
22
24
  hasPreExecuteHook: false,
23
25
  hasProvideApi: false,
24
26
  hasLocaleService: false,
25
- harnessVersion: null,
27
+ harnessVersion: "unknown",
26
28
  };
27
29
  }
28
30
 
29
- const getService = (name) => {
31
+ const safeGet = (name) => {
30
32
  try {
31
33
  if (typeof ctx.get === "function") return ctx.get(name);
32
34
  } catch {
33
35
  // ignore
34
36
  }
35
- return ctx[name];
37
+ try {
38
+ return ctx[name];
39
+ } catch {
40
+ return undefined;
41
+ }
36
42
  };
37
43
 
38
- const tools = getService("tools");
39
- const locale = getService("locale");
44
+ const tools = safeGet("tools");
45
+ const locale = safeGet("locale");
46
+ const onFn = safeGet("on");
47
+ const provideFn = safeGet("provide");
48
+
49
+ const rawVersion = safeGet("version");
40
50
 
41
51
  const harnessVersion =
42
- (typeof ctx.version === "string" && ctx.version) ||
43
- (typeof process.env.DSH_VERSION === "string" && process.env.DSH_VERSION) ||
44
- null;
52
+ (typeof rawVersion === "string" && rawVersion.trim()) ||
53
+ (rawVersion && typeof rawVersion === "object" && typeof rawVersion.version === "string" && rawVersion.version.trim()) ||
54
+ (typeof process.env.DSH_VERSION === "string" && process.env.DSH_VERSION.trim()) ||
55
+ "unknown";
45
56
 
46
57
  return {
47
58
  hasContext: true,
48
59
  hasToolsService: Boolean(tools),
49
- hasPreExecuteHook: typeof ctx.on === "function",
50
- hasProvideApi: typeof ctx.provide === "function",
60
+ hasPreExecuteHook: typeof onFn === "function",
61
+ hasProvideApi: typeof provideFn === "function",
51
62
  hasLocaleService: Boolean(locale && typeof locale.register === "function"),
52
63
  harnessVersion,
53
64
  };
54
65
  }
55
66
 
56
67
  /**
57
- * Asserts host compatibility and identifies missing optional or required features (#106).
68
+ * Asserts host compatibility and identifies missing optional or required features (#106, #184).
58
69
  *
59
70
  * @param {any} ctx
60
71
  * @param {{ requireTools?: boolean }} [options]
@@ -80,7 +91,7 @@ export function assertHarnessCompatibility(ctx, options = {}) {
80
91
  }
81
92
 
82
93
  /**
83
- * Safely provides a service to the host context with backward-compatible polyfill (#106).
94
+ * Safely provides a service to the host context with backward-compatible polyfill (#106, #184).
84
95
  *
85
96
  * @param {any} ctx
86
97
  * @param {string} serviceName
@@ -90,21 +101,32 @@ export function assertHarnessCompatibility(ctx, options = {}) {
90
101
  export function provideServicePolyfill(ctx, serviceName, serviceInstance) {
91
102
  if (!ctx || typeof ctx !== "object" || !serviceName) return false;
92
103
 
93
- if (typeof ctx.provide === "function") {
104
+ let provideFn = undefined;
105
+ try {
106
+ provideFn = ctx.provide;
107
+ } catch {
108
+ // ignore
109
+ }
110
+
111
+ if (typeof provideFn === "function") {
94
112
  try {
95
- ctx.provide(serviceName, serviceInstance);
113
+ provideFn.call(ctx, serviceName, serviceInstance);
96
114
  return true;
97
115
  } catch {
98
116
  // fallback to property assignment below
99
117
  }
100
118
  }
101
119
 
102
- ctx[serviceName] = serviceInstance;
103
- return true;
120
+ try {
121
+ ctx[serviceName] = serviceInstance;
122
+ return true;
123
+ } catch {
124
+ return false;
125
+ }
104
126
  }
105
127
 
106
128
  /**
107
- * Safely attaches an event hook to the host context with error boundary (#106).
129
+ * Safely attaches an event hook to the host context with error boundary (#106, #184).
108
130
  *
109
131
  * @param {any} ctx
110
132
  * @param {string} event
@@ -112,12 +134,23 @@ export function provideServicePolyfill(ctx, serviceName, serviceInstance) {
112
134
  * @returns {(() => void) | null} Unsubscribe dispose function or null
113
135
  */
114
136
  export function registerHookPolyfill(ctx, event, handler) {
115
- if (!ctx || typeof ctx.on !== "function" || typeof handler !== "function") {
137
+ if (!ctx || typeof ctx !== "object" || typeof handler !== "function") {
138
+ return null;
139
+ }
140
+
141
+ let onFn = undefined;
142
+ try {
143
+ onFn = ctx.on;
144
+ } catch {
145
+ // ignore
146
+ }
147
+
148
+ if (typeof onFn !== "function") {
116
149
  return null;
117
150
  }
118
151
 
119
152
  try {
120
- return ctx.on(event, handler);
153
+ return onFn.call(ctx, event, handler);
121
154
  } catch {
122
155
  return null;
123
156
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-approval-gate",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "description": "Host-only command safety gate for DeepSeek Harness: blocks recognized dangerous operations and requests DSH approval when a command cannot be inspected.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",