dsh-permission-rules 0.6.7 → 0.6.9
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 +19 -0
- package/lib/index.js +44 -10
- package/lib/types/runtime.d.ts +11 -0
- package/lib/types/runtime.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/runtime.ts +51 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
## v0.6.9 - 2026-09-03
|
|
2
|
+
|
|
3
|
+
### Changed
|
|
4
|
+
|
|
5
|
+
- Vendor the `dsh-auto-review 0.10.2` integration tarball (its runtime dependencies now pin the published dsh `0.1.2-alpha.5` line; `dsh-agent-spine-demo` moved to devDependencies) and update the `file:` devDependency.
|
|
6
|
+
- Dev pins `@deepseek-ai/cordis-plugin-loader ^1.0.3` / `@deepseek-ai/cordis-plugin-include ^1.0.7` aligned with the `cordis 4.0.2` peer ranges.
|
|
7
|
+
|
|
8
|
+
## v0.6.8 - 2026-09-03
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Never recursively watch a workspace root for an expected-but-absent rule
|
|
13
|
+
file (issue #13): candidate watchers are depth-limited to the immediate
|
|
14
|
+
children of the deepest existing ancestor, ignore `node_modules`/`.git`,
|
|
15
|
+
upgrade the watch when the missing path component (e.g. `.dsh/`)
|
|
16
|
+
appears, and close when their watched directory disappears. A missing
|
|
17
|
+
`.dsh/rules.yaml` used to watch the entire workspace tree — 245k inotify
|
|
18
|
+
watches, multi-GiB RSS, and stalled tool calls on large workspaces.
|
|
19
|
+
|
|
1
20
|
## v0.6.7 - 2026-09-02
|
|
2
21
|
|
|
3
22
|
### Docs
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
import { dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
5
5
|
import chokidar from "chokidar";
|
|
6
6
|
import z from "@deepseek-ai/schemastery";
|
|
7
7
|
import { parse } from "yaml";
|
|
@@ -3513,10 +3513,22 @@ var PermissionRulesRuntime = class {
|
|
|
3513
3513
|
* relevant event re-checks existence and only triggers a reload once the
|
|
3514
3514
|
* candidate actually appeared, so unrelated workspace activity while the
|
|
3515
3515
|
* file is absent costs a stat, not a reload.
|
|
3516
|
+
*
|
|
3517
|
+
* Candidate watchers never recurse past the immediate children of that
|
|
3518
|
+
* ancestor: when the walk-up landed on the workspace root (the
|
|
3519
|
+
* candidate's parent chain is missing, e.g. no `.dsh/` directory),
|
|
3520
|
+
* recursion would watch the entire workspace tree — issue #13 measured
|
|
3521
|
+
* 245k inotify watches and multi-GiB RSS from exactly this path. The
|
|
3522
|
+
* watcher therefore runs with `depth: 0` plus `node_modules`/`.git`
|
|
3523
|
+
* ignores in that case, and the `addDir` handler upgrades the watch to
|
|
3524
|
+
* the newly appeared ancestor level, preserving mid-session adoption.
|
|
3525
|
+
* A candidate watcher whose directory itself disappears closes instead
|
|
3526
|
+
* of lingering on a dead path.
|
|
3516
3527
|
*/
|
|
3517
3528
|
attachCandidateWatch(cwd, candidate) {
|
|
3518
3529
|
if (!this.config.watch) return;
|
|
3519
|
-
const
|
|
3530
|
+
const parent = dirname(candidate);
|
|
3531
|
+
const dir = this.deepestExistingDir(parent);
|
|
3520
3532
|
const existing = this.watchers.get(dir);
|
|
3521
3533
|
if (existing !== void 0) {
|
|
3522
3534
|
existing.cwds.add(cwd);
|
|
@@ -3525,16 +3537,38 @@ var PermissionRulesRuntime = class {
|
|
|
3525
3537
|
}
|
|
3526
3538
|
const cwds = /* @__PURE__ */ new Set([cwd]);
|
|
3527
3539
|
const candidates = /* @__PURE__ */ new Map([[cwd, candidate]]);
|
|
3528
|
-
const
|
|
3540
|
+
const watchOptions = {
|
|
3529
3541
|
persistent: true,
|
|
3530
|
-
ignoreInitial: true
|
|
3542
|
+
ignoreInitial: true,
|
|
3543
|
+
ignored: (path) => path.split(sep).includes("node_modules") || path.split(sep).includes(".git")
|
|
3544
|
+
};
|
|
3545
|
+
const watcher = dir === parent ? chokidar.watch(dir, watchOptions) : chokidar.watch(dir, {
|
|
3546
|
+
...watchOptions,
|
|
3547
|
+
depth: 0
|
|
3531
3548
|
});
|
|
3532
|
-
const
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3549
|
+
const samePath = (a, b) => process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
3550
|
+
const startsWithPath = (a, b) => process.platform === "win32" ? a.toLowerCase().startsWith(b.toLowerCase()) : a.startsWith(b);
|
|
3551
|
+
const onEvent = (event, path) => {
|
|
3552
|
+
if (event === "unlinkDir" && samePath(path, dir)) {
|
|
3553
|
+
this.watchers.delete(dir);
|
|
3554
|
+
const timer = this.timers.get(dir);
|
|
3555
|
+
if (timer !== void 0) {
|
|
3556
|
+
clearTimeout(timer);
|
|
3557
|
+
this.timers.delete(dir);
|
|
3558
|
+
}
|
|
3559
|
+
watcher.close().catch((error) => {
|
|
3560
|
+
this.ctx.logger.warn(`permission-rules: failed to close watcher on ${dir}: ${String(error)}`);
|
|
3561
|
+
});
|
|
3562
|
+
return;
|
|
3563
|
+
}
|
|
3564
|
+
if (dir !== parent && event === "addDir" && (samePath(path, parent) || startsWithPath(path, parent + sep))) this.attachCandidateWatch(cwd, candidate);
|
|
3565
|
+
this.scheduleReload(dir);
|
|
3566
|
+
};
|
|
3567
|
+
watcher.on("add", (path) => onEvent("add", path));
|
|
3568
|
+
watcher.on("addDir", (path) => onEvent("addDir", path));
|
|
3569
|
+
watcher.on("change", (path) => onEvent("change", path));
|
|
3570
|
+
watcher.on("unlink", (path) => onEvent("unlink", path));
|
|
3571
|
+
watcher.on("unlinkDir", (path) => onEvent("unlinkDir", path));
|
|
3538
3572
|
watcher.on("error", (error) => {
|
|
3539
3573
|
this.ctx.logger.warn(`permission-rules: watcher error on ${dir}: ${String(error)}`);
|
|
3540
3574
|
});
|
package/lib/types/runtime.d.ts
CHANGED
|
@@ -370,6 +370,17 @@ export declare class PermissionRulesRuntime {
|
|
|
370
370
|
* relevant event re-checks existence and only triggers a reload once the
|
|
371
371
|
* candidate actually appeared, so unrelated workspace activity while the
|
|
372
372
|
* file is absent costs a stat, not a reload.
|
|
373
|
+
*
|
|
374
|
+
* Candidate watchers never recurse past the immediate children of that
|
|
375
|
+
* ancestor: when the walk-up landed on the workspace root (the
|
|
376
|
+
* candidate's parent chain is missing, e.g. no `.dsh/` directory),
|
|
377
|
+
* recursion would watch the entire workspace tree — issue #13 measured
|
|
378
|
+
* 245k inotify watches and multi-GiB RSS from exactly this path. The
|
|
379
|
+
* watcher therefore runs with `depth: 0` plus `node_modules`/`.git`
|
|
380
|
+
* ignores in that case, and the `addDir` handler upgrades the watch to
|
|
381
|
+
* the newly appeared ancestor level, preserving mid-session adoption.
|
|
382
|
+
* A candidate watcher whose directory itself disappears closes instead
|
|
383
|
+
* of lingering on a dead path.
|
|
373
384
|
*/
|
|
374
385
|
private attachCandidateWatch;
|
|
375
386
|
/** The deepest existing ancestor directory of `dir` (candidate watchers target directories, never missing files). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-permission-rules",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.9",
|
|
4
4
|
"description": "Declarative Claude Code-style permission rules plus a Codex-style process-level network policy for DeepSeek Harness: ordered allow/deny/ask rules with tool-name, argument (glob/regex), workspace-path, and network-target (domain/ip/port/scheme) matching on the tools/pre-execute waterfall, a built-in local HTTP/CONNECT proxy governing shell subprocess traffic, three network modes mapped onto the official sandbox presets, full session-log audit, HMR rule reload, and a settings page with a rule editor, block counters, and recent interception lists.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -157,8 +157,8 @@
|
|
|
157
157
|
},
|
|
158
158
|
"devDependencies": {"@deepseek-ai/dsh-attachment": "0.1.2-alpha.5",
|
|
159
159
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
160
|
-
"@deepseek-ai/cordis-plugin-include": "1.0.
|
|
161
|
-
"@deepseek-ai/cordis-plugin-loader": "1.0.
|
|
160
|
+
"@deepseek-ai/cordis-plugin-include": "^1.0.7",
|
|
161
|
+
"@deepseek-ai/cordis-plugin-loader": "^1.0.3",
|
|
162
162
|
"@deepseek-ai/dsh-agent": "0.1.2-alpha.5",
|
|
163
163
|
"@deepseek-ai/dsh-brand": "0.1.2-alpha.5",
|
|
164
164
|
"@deepseek-ai/dsh-client-connection": "0.1.2-alpha.5",
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
"@eslint/js": "^10.0.1",
|
|
180
180
|
"@types/node": "^22.19.0",
|
|
181
181
|
"@vitest/coverage-v8": "^3.2.0",
|
|
182
|
-
"dsh-auto-review": "file:vendor/dsh-auto-review-0.10.
|
|
182
|
+
"dsh-auto-review": "file:vendor/dsh-auto-review-0.10.2.tgz",
|
|
183
183
|
"eslint": "^10.8.1",
|
|
184
184
|
"globals": "^17.11.0",
|
|
185
185
|
"react": "18.3.1",
|
package/src/runtime.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { createHash } from 'node:crypto'
|
|
15
15
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
16
16
|
import { createRequire } from 'node:module'
|
|
17
|
-
import { dirname, isAbsolute, join, resolve } from 'node:path'
|
|
17
|
+
import { dirname, isAbsolute, join, resolve, sep } from 'node:path'
|
|
18
18
|
import chokidar from 'chokidar'
|
|
19
19
|
import type { Context } from '@deepseek-ai/cordis'
|
|
20
20
|
import type { CommandInvocation, CommandResult } from '@deepseek-ai/dsh-commands'
|
|
@@ -1094,10 +1094,22 @@ export class PermissionRulesRuntime {
|
|
|
1094
1094
|
* relevant event re-checks existence and only triggers a reload once the
|
|
1095
1095
|
* candidate actually appeared, so unrelated workspace activity while the
|
|
1096
1096
|
* file is absent costs a stat, not a reload.
|
|
1097
|
+
*
|
|
1098
|
+
* Candidate watchers never recurse past the immediate children of that
|
|
1099
|
+
* ancestor: when the walk-up landed on the workspace root (the
|
|
1100
|
+
* candidate's parent chain is missing, e.g. no `.dsh/` directory),
|
|
1101
|
+
* recursion would watch the entire workspace tree — issue #13 measured
|
|
1102
|
+
* 245k inotify watches and multi-GiB RSS from exactly this path. The
|
|
1103
|
+
* watcher therefore runs with `depth: 0` plus `node_modules`/`.git`
|
|
1104
|
+
* ignores in that case, and the `addDir` handler upgrades the watch to
|
|
1105
|
+
* the newly appeared ancestor level, preserving mid-session adoption.
|
|
1106
|
+
* A candidate watcher whose directory itself disappears closes instead
|
|
1107
|
+
* of lingering on a dead path.
|
|
1097
1108
|
*/
|
|
1098
1109
|
private attachCandidateWatch(cwd: string, candidate: string): void {
|
|
1099
1110
|
if (!this.config.watch) return
|
|
1100
|
-
const
|
|
1111
|
+
const parent = dirname(candidate)
|
|
1112
|
+
const dir = this.deepestExistingDir(parent)
|
|
1101
1113
|
const existing = this.watchers.get(dir)
|
|
1102
1114
|
if (existing !== undefined) {
|
|
1103
1115
|
existing.cwds.add(cwd)
|
|
@@ -1106,13 +1118,43 @@ export class PermissionRulesRuntime {
|
|
|
1106
1118
|
}
|
|
1107
1119
|
const cwds = new Set([cwd])
|
|
1108
1120
|
const candidates = new Map([[cwd, candidate]])
|
|
1109
|
-
const
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
watcher
|
|
1115
|
-
|
|
1121
|
+
const watchOptions = {
|
|
1122
|
+
persistent: true,
|
|
1123
|
+
ignoreInitial: true,
|
|
1124
|
+
ignored: (path: string): boolean => path.split(sep).includes('node_modules') || path.split(sep).includes('.git'),
|
|
1125
|
+
}
|
|
1126
|
+
const watcher = dir === parent
|
|
1127
|
+
? chokidar.watch(dir, watchOptions)
|
|
1128
|
+
: chokidar.watch(dir, { ...watchOptions, depth: 0 })
|
|
1129
|
+
// Windows paths may reach the watcher with a different ASCII case than
|
|
1130
|
+
// the header-derived candidate paths (the session layer case-folds the
|
|
1131
|
+
// cache key); compare case-insensitively there or the upgrade/close
|
|
1132
|
+
// handlers silently never fire.
|
|
1133
|
+
const samePath = (a: string, b: string): boolean => (process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b)
|
|
1134
|
+
const startsWithPath = (a: string, b: string): boolean => (process.platform === 'win32' ? a.toLowerCase().startsWith(b.toLowerCase()) : a.startsWith(b))
|
|
1135
|
+
const onEvent = (event: string, path: string): void => {
|
|
1136
|
+
if (event === 'unlinkDir' && samePath(path, dir)) {
|
|
1137
|
+
this.watchers.delete(dir)
|
|
1138
|
+
const timer = this.timers.get(dir)
|
|
1139
|
+
if (timer !== undefined) {
|
|
1140
|
+
clearTimeout(timer)
|
|
1141
|
+
this.timers.delete(dir)
|
|
1142
|
+
}
|
|
1143
|
+
void watcher.close().catch((error: unknown) => {
|
|
1144
|
+
this.ctx.logger.warn(`permission-rules: failed to close watcher on ${dir}: ${String(error)}`)
|
|
1145
|
+
})
|
|
1146
|
+
return
|
|
1147
|
+
}
|
|
1148
|
+
if (dir !== parent && event === 'addDir' && (samePath(path, parent) || startsWithPath(path, parent + sep))) {
|
|
1149
|
+
this.attachCandidateWatch(cwd, candidate)
|
|
1150
|
+
}
|
|
1151
|
+
this.scheduleReload(dir)
|
|
1152
|
+
}
|
|
1153
|
+
watcher.on('add', (path: string) => onEvent('add', path))
|
|
1154
|
+
watcher.on('addDir', (path: string) => onEvent('addDir', path))
|
|
1155
|
+
watcher.on('change', (path: string) => onEvent('change', path))
|
|
1156
|
+
watcher.on('unlink', (path: string) => onEvent('unlink', path))
|
|
1157
|
+
watcher.on('unlinkDir', (path: string) => onEvent('unlinkDir', path))
|
|
1116
1158
|
watcher.on('error', (error: unknown) => {
|
|
1117
1159
|
this.ctx.logger.warn(`permission-rules: watcher error on ${dir}: ${String(error)}`)
|
|
1118
1160
|
})
|