dsh-cc-permissions 0.4.0 → 0.4.2

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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/index.js +53 -45
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-cc-permissions",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Enforce Claude Code permission rules (.claude/settings.json allow/deny/ask, deny>ask>allow) in DSH via a tools/pre-execute gate; CC allow rules auto-answer the approval/request seam (incl. sandbox escalation). Reads CC settings as a read-only source; DSH-side approvals never write back to .claude.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -26,7 +26,7 @@
26
26
  ],
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
- "dsh-cc-loader": "^0.3.0"
29
+ "dsh-cc-loader": "^0.3.2"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@deepseek-ai/cordis": "4.0.2",
package/src/index.js CHANGED
@@ -153,58 +153,66 @@ export function apply(ctx, config = {}) {
153
153
  }, { prepend: true })
154
154
  }
155
155
 
156
- // ── bare-name deny → hide the tool from the model ─────────────────────────
157
- if (config.hideDeniedTools !== false) {
156
+ // ── agent registration: hide denied tools + apply defaultMode ─────────────
157
+ // Both concerns are registration-time — they configure the agent's tool
158
+ // registry and its approval policy before the first prompt — so they share
159
+ // one `agent/created` listener. DSH 0.2.0 removed `agent/session-start`,
160
+ // which the defaultMode half used to ride; `agent/created` carries the same
161
+ // `{ agent }` on both host generations, so neither needs the source-aware
162
+ // `onSessionStart` boundary.
163
+ const hideDenied = config.hideDeniedTools !== false
164
+ const applyDefaultMode = config.enableDefaultMode !== false
165
+ if (hideDenied || applyDefaultMode) {
158
166
  ctx.on('agent/created', ({ agent }) => {
159
- const cwd = agent.session?.header?.cwd
167
+ // `agent` itself must be guarded: 0.2.0 dispatches this event SERIALLY,
168
+ // so a synchronous throw here vetoes session publication outright.
169
+ const cwd = agent?.session?.header?.cwd
160
170
  if (cwd === undefined) return
161
- void (async () => {
162
- try {
163
- const loaded = await permissionsFor(cwd)
164
- const perm = loaded.permissions
165
- if (perm === undefined || perm.status !== 'DIRECT') return
166
- const { names } = perm.removed
167
- if (names.length === 0) return
168
- const tools = agent.ctx.tools
171
+
172
+ if (hideDenied) {
173
+ void (async () => {
169
174
  try {
170
- tools.restrict({ deny: names })
171
- } catch {
172
- // Some names may not be in the registry yet / never registered —
173
- // restrict per name so the known ones still hide.
174
- for (const name of names) {
175
- try { tools.restrict({ deny: [name] }) } catch { /* unknown tool: pre-execute still denies */ }
175
+ const loaded = await permissionsFor(cwd)
176
+ const perm = loaded.permissions
177
+ if (perm === undefined || perm.status !== 'DIRECT') return
178
+ const { names } = perm.removed
179
+ if (names.length === 0) return
180
+ const tools = agent.ctx.tools
181
+ try {
182
+ tools.restrict({ deny: names })
183
+ } catch {
184
+ // Some names may not be in the registry yet / never registered —
185
+ // restrict per name so the known ones still hide.
186
+ for (const name of names) {
187
+ try { tools.restrict({ deny: [name] }) } catch { /* unknown tool: pre-execute still denies */ }
188
+ }
176
189
  }
190
+ } catch (error) {
191
+ ctx.logger.warn(`cc-permissions: restrict failed: ${String(error)}`)
177
192
  }
178
- } catch (error) {
179
- ctx.logger.warn(`cc-permissions: restrict failed: ${String(error)}`)
180
- }
181
- })()
182
- })
183
- }
193
+ })()
194
+ }
184
195
 
185
- // ── defaultMode → approval policy / guidance ──────────────────────────────
186
- if (config.enableDefaultMode !== false) {
187
- ctx.on('agent/session-start', ({ agent }) => {
188
- const cwd = agent.session.header?.cwd
189
- if (cwd === undefined) return
190
- void (async () => {
191
- try {
192
- const loaded = await permissionsFor(cwd)
193
- const mode = loaded.permissions?.defaultMode
194
- if (mode === undefined) return
195
- const approval = ctx.get('approval')
196
- if (mode === 'dontAsk' && approval !== undefined) {
197
- approval.setPolicy(agent, 'never')
198
- ctx.logger.info(`cc-permissions: defaultMode=dontAsk → approval policy never for session`)
199
- } else if (mode === 'bypassPermissions') {
200
- ctx.logger.warn(`cc-permissions: defaultMode=bypassPermissions detected — DSH does NOT auto-map this to danger-full-access; enable it explicitly if intended`)
201
- } else if (mode !== 'default' && mode !== 'manual') {
202
- ctx.logger.info(`cc-permissions: defaultMode=${mode} noted (no direct DSH mapping; sandbox/approval presets govern)`)
196
+ if (applyDefaultMode) {
197
+ void (async () => {
198
+ try {
199
+ const loaded = await permissionsFor(cwd)
200
+ const mode = loaded.permissions?.defaultMode
201
+ if (mode === undefined) return
202
+ const approval = ctx.get('approval')
203
+ if (mode === 'dontAsk' && approval !== undefined) {
204
+ approval.setPolicy(agent, 'never')
205
+ ctx.logger.info(`cc-permissions: defaultMode=dontAsk → approval policy never for session`)
206
+ } else if (mode === 'bypassPermissions') {
207
+ ctx.logger.warn(`cc-permissions: defaultMode=bypassPermissions detected — DSH does NOT auto-map this to danger-full-access; enable it explicitly if intended`)
208
+ } else if (mode !== 'default' && mode !== 'manual') {
209
+ ctx.logger.info(`cc-permissions: defaultMode=${mode} noted (no direct DSH mapping; sandbox/approval presets govern)`)
210
+ }
211
+ } catch (error) {
212
+ ctx.logger.warn(`cc-permissions: defaultMode handling failed: ${String(error)}`)
203
213
  }
204
- } catch (error) {
205
- ctx.logger.warn(`cc-permissions: defaultMode handling failed: ${String(error)}`)
206
- }
207
- })()
214
+ })()
215
+ }
208
216
  })
209
217
  }
210
218