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.
- package/package.json +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.
|
|
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.
|
|
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
|
-
// ──
|
|
157
|
-
|
|
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
|
-
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
}
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
})()
|
|
182
|
-
})
|
|
183
|
-
}
|
|
193
|
+
})()
|
|
194
|
+
}
|
|
184
195
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
}
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
})()
|
|
214
|
+
})()
|
|
215
|
+
}
|
|
208
216
|
})
|
|
209
217
|
}
|
|
210
218
|
|