ccdesk 0.2.2 → 0.2.4
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 +46 -0
- package/README.md +7 -4
- package/dist/core/agent-edit.d.ts +6 -0
- package/dist/{server → core}/agent-edit.js +15 -21
- package/dist/core/backups.d.ts +19 -0
- package/dist/{server → core}/backups.js +64 -48
- package/dist/core/core.d.ts +96 -0
- package/dist/core/core.js +57 -0
- package/dist/core/index.d.ts +22 -0
- package/dist/core/index.js +38 -0
- package/dist/core/mcp-edit.d.ts +23 -0
- package/dist/{server → core}/mcp-edit.js +121 -100
- package/dist/core/mutations.d.ts +20 -0
- package/dist/{server → core}/mutations.js +8 -15
- package/dist/core/open.d.ts +28 -0
- package/dist/{server → core}/open.js +38 -13
- package/dist/core/parse-edit.d.ts +12 -0
- package/dist/core/parse-edit.js +64 -0
- package/dist/core/reference.d.ts +3 -0
- package/dist/core/reference.js +11 -0
- package/dist/core/scan/compare.d.ts +7 -0
- package/dist/{server → core}/scan/compare.js +2 -2
- package/dist/core/scan/context.d.ts +13 -0
- package/dist/{server → core}/scan/context.js +55 -32
- package/dist/core/scan/data.d.ts +14 -0
- package/dist/core/scan/data.js +26 -0
- package/dist/core/scan/env.d.ts +28 -0
- package/dist/{server → core}/scan/env.js +15 -4
- package/dist/core/scan/files.d.ts +68 -0
- package/dist/core/scan/files.js +270 -0
- package/dist/core/scan/git.d.ts +20 -0
- package/dist/core/scan/git.js +106 -0
- package/dist/core/scan/index.d.ts +5 -0
- package/dist/{server → core}/scan/index.js +119 -82
- package/dist/core/scan/instructions.d.ts +54 -0
- package/dist/{server → core}/scan/instructions.js +141 -73
- package/dist/core/scan/inventory.d.ts +38 -0
- package/dist/{server → core}/scan/inventory.js +134 -115
- package/dist/core/scan/mcp.d.ts +28 -0
- package/dist/{server → core}/scan/mcp.js +153 -95
- package/dist/core/scan/memory.d.ts +8 -0
- package/dist/{server → core}/scan/memory.js +8 -8
- package/dist/core/scan/path-test.d.ts +9 -0
- package/dist/core/scan/path-test.js +156 -0
- package/dist/core/scan/permissions.d.ts +31 -0
- package/dist/{server → core}/scan/permissions.js +5 -8
- package/dist/core/scan/plugins.d.ts +39 -0
- package/dist/{server → core}/scan/plugins.js +36 -27
- package/dist/core/scan/projects.d.ts +9 -0
- package/dist/{server → core}/scan/projects.js +7 -5
- package/dist/core/scan/sandbox.d.ts +14 -0
- package/dist/{server → core}/scan/sandbox.js +87 -59
- package/dist/core/scan/settings.d.ts +37 -0
- package/dist/{server → core}/scan/settings.js +98 -93
- package/dist/core/scan/tools.d.ts +10 -0
- package/dist/{server → core}/scan/tools.js +28 -20
- package/dist/core/scan/usage.d.ts +19 -0
- package/dist/{server → core}/scan/usage.js +122 -97
- package/dist/core/schema.d.ts +8 -0
- package/dist/core/schema.js +67 -0
- package/dist/core/secrets.d.ts +45 -0
- package/dist/core/secrets.js +207 -0
- package/dist/core/settings-edit.d.ts +9 -0
- package/dist/{server → core}/settings-edit.js +91 -112
- package/dist/core/watch.d.ts +45 -0
- package/dist/{server → core}/watch.js +54 -17
- package/dist/core/write.d.ts +117 -0
- package/dist/{server → core}/write.js +61 -8
- package/dist/server/args.d.ts +32 -0
- package/dist/server/args.js +106 -0
- package/dist/server/cli.d.ts +2 -0
- package/dist/server/cli.js +58 -83
- package/dist/server/commands.d.ts +8 -0
- package/dist/server/commands.js +39 -0
- package/dist/server/server.d.ts +12 -0
- package/dist/server/server.js +80 -195
- package/dist/server/start.d.ts +13 -0
- package/dist/server/start.js +21 -0
- package/dist/shared/compare.d.ts +25 -0
- package/dist/shared/memory.d.ts +6 -0
- package/dist/shared/memory.js +18 -2
- package/dist/shared/requests.d.ts +104 -0
- package/dist/shared/requests.js +73 -0
- package/dist/shared/scopes.d.ts +10 -0
- package/dist/shared/settings-catalog.json +2199 -0
- package/dist/shared/types.d.ts +535 -0
- package/dist/shared/types.js +11 -0
- package/dist/ui/assets/index-C9qqEI5Z.js +60 -0
- package/dist/ui/index.html +1 -1
- package/dist/view/diff.d.ts +16 -0
- package/dist/view/diff.js +85 -0
- package/dist/view/format.d.ts +17 -0
- package/dist/view/format.js +47 -0
- package/dist/view/index.d.ts +11 -0
- package/dist/view/index.js +13 -0
- package/dist/view/lines.d.ts +9 -0
- package/dist/view/lines.js +12 -0
- package/dist/view/path-test.d.ts +3 -0
- package/dist/view/path-test.js +7 -0
- package/dist/view/sections/catalog.d.ts +9 -0
- package/dist/view/sections/catalog.js +47 -0
- package/dist/view/sections/extensions.d.ts +1 -0
- package/dist/view/sections/extensions.js +48 -0
- package/dist/view/sections/hooks.d.ts +1 -0
- package/dist/view/sections/hooks.js +32 -0
- package/dist/view/sections/index.d.ts +6 -0
- package/dist/view/sections/index.js +27 -0
- package/dist/view/sections/instructions.d.ts +6 -0
- package/dist/view/sections/instructions.js +38 -0
- package/dist/view/sections/mcp.d.ts +3 -0
- package/dist/view/sections/mcp.js +38 -0
- package/dist/view/sections/memory.d.ts +1 -0
- package/dist/view/sections/memory.js +31 -0
- package/dist/view/sections/permissions.d.ts +17 -0
- package/dist/view/sections/permissions.js +87 -0
- package/dist/view/sections/settings.d.ts +1 -0
- package/dist/view/sections/settings.js +33 -0
- package/dist/view/sections/tools.d.ts +6 -0
- package/dist/view/sections/tools.js +57 -0
- package/dist/view/sections/types.d.ts +123 -0
- package/dist/view/sections/types.js +10 -0
- package/dist/view/settings.d.ts +12 -0
- package/dist/view/settings.js +31 -0
- package/dist/view/usage.d.ts +8 -0
- package/dist/view/usage.js +18 -0
- package/package.json +13 -2
- package/dist/server/scan/files.js +0 -480
- package/dist/server/scan/path-test.js +0 -136
- package/dist/server/schema.js +0 -15
- package/dist/server/secrets.js +0 -63
- package/dist/ui/assets/index-Dg9dxngR.js +0 -60
|
@@ -2,8 +2,11 @@ import { lstat } from "node:fs/promises";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { allowedScopes, EVERY_FILE, ignoredReason } from "../../shared/scopes.js";
|
|
4
4
|
import {} from "../../shared/types.js";
|
|
5
|
+
import { redactSecrets } from "../secrets.js";
|
|
5
6
|
import {} from "./env.js";
|
|
6
|
-
import {
|
|
7
|
+
import { isFile, listDir, readJsonObject } from "./files.js";
|
|
8
|
+
import { isRecord } from "./data.js";
|
|
9
|
+
import { mainWorktreeRoot } from "./git.js";
|
|
7
10
|
import { sandboxFilter } from "./sandbox.js";
|
|
8
11
|
/** Lowest precedence first, so later layers override earlier ones. */
|
|
9
12
|
const PRECEDENCE = ["user", "project", "local", "managed"];
|
|
@@ -132,12 +135,15 @@ export async function settingsFiles(env, dir) {
|
|
|
132
135
|
files.push({ scope: "user", path: userFile });
|
|
133
136
|
return files;
|
|
134
137
|
}
|
|
135
|
-
/**
|
|
136
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Settings files that apply in `dir`, highest precedence first. `managed` is what
|
|
140
|
+
* readManagedSettings read, so a scan reads the managed files once.
|
|
141
|
+
*/
|
|
142
|
+
export async function readSettingsLayers(env, dir, managed) {
|
|
137
143
|
const layers = [];
|
|
138
144
|
for (const file of await settingsFiles(env, dir)) {
|
|
139
145
|
if (file.scope === "managed") {
|
|
140
|
-
layers.push(
|
|
146
|
+
layers.push(managedLayer(file.path, managed));
|
|
141
147
|
continue;
|
|
142
148
|
}
|
|
143
149
|
const result = await readJsonObject(env, file.path);
|
|
@@ -183,10 +189,17 @@ export async function readManagedSettings(env) {
|
|
|
183
189
|
sources.push(source);
|
|
184
190
|
data = data ? mergeSettings(data, result.data) : result.data;
|
|
185
191
|
}
|
|
186
|
-
|
|
192
|
+
// Server-managed settings, then MDM, outrank the files; by default Claude Code uses the first
|
|
193
|
+
// source that sets a policy key and skips the rest (docs: managed-settings#how-claude-code-combines-managed-sources).
|
|
194
|
+
const candidates = [join(env.claudeDir, "remote-settings.json"), ...(env.managedProfiles ?? [])];
|
|
195
|
+
const higher = [];
|
|
196
|
+
for (const source of candidates)
|
|
197
|
+
if (await isFile(source))
|
|
198
|
+
higher.push(source);
|
|
199
|
+
return { data, sources, dropIns, higher, errors, blocksStart };
|
|
187
200
|
}
|
|
188
|
-
|
|
189
|
-
const { data, sources, dropIns, errors, blocksStart } =
|
|
201
|
+
function managedLayer(path, managed) {
|
|
202
|
+
const { data, sources, dropIns, higher, errors, blocksStart } = managed;
|
|
190
203
|
const layer = { scope: "managed", path, exists: false, data: null };
|
|
191
204
|
if (data)
|
|
192
205
|
layer.data = redactSecrets(data);
|
|
@@ -197,6 +210,8 @@ async function readManagedLayer(env, path) {
|
|
|
197
210
|
layer.error = errors.join("; ");
|
|
198
211
|
if (blocksStart)
|
|
199
212
|
layer.blocksStart = true;
|
|
213
|
+
if (higher.length > 0)
|
|
214
|
+
layer.higherSources = higher;
|
|
200
215
|
return layer;
|
|
201
216
|
}
|
|
202
217
|
/** The value Claude Code ends up with for each top-level key, and where it came from. */
|
|
@@ -211,90 +226,80 @@ export function effectiveSettings(layers) {
|
|
|
211
226
|
}
|
|
212
227
|
const keys = new Set([...byScope.values()].flatMap((data) => Object.keys(data)));
|
|
213
228
|
const filterSandbox = sandboxFilter((key, scope) => allowedScopes(key).includes(scope) ? byScope.get(scope)?.[key] : undefined);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
values.every((v) => Array.isArray(v.value) || isRecord(v.value));
|
|
248
|
-
const strict = STRICTEST[key];
|
|
249
|
-
const decided = strict && strictWinner(strict, values);
|
|
250
|
-
if (strict && decided) {
|
|
251
|
-
const { winner } = decided;
|
|
252
|
-
// Only files that may just tighten it set the key, and none tightens it past the default.
|
|
253
|
-
if (!winner)
|
|
254
|
-
for (const v of values)
|
|
255
|
-
ignored.push({ ...v, reason: "it is not stricter than Claude Code's default" });
|
|
256
|
-
out.push({
|
|
257
|
-
key,
|
|
258
|
-
value: winner?.value,
|
|
259
|
-
from: winner ? [winner.scope] : [],
|
|
260
|
-
merged: false,
|
|
261
|
-
overridden: winner ? values.filter((v) => v !== winner).reverse() : [],
|
|
262
|
-
ignored,
|
|
263
|
-
note: strictNote(strict),
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
else if (mergeable && values.length > 1) {
|
|
267
|
-
out.push({
|
|
268
|
-
key,
|
|
269
|
-
value: withStrictFields(key, values.slice(1).reduce((acc, v) => mergeKey(key, acc, v.value), values[0]?.value), values),
|
|
270
|
-
from: defined,
|
|
271
|
-
merged: true,
|
|
272
|
-
overridden: [],
|
|
273
|
-
ignored,
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
else if (isRecord(top.value)) {
|
|
277
|
-
out.push({
|
|
278
|
-
key,
|
|
279
|
-
value: withStrictFields(key, top.value, values),
|
|
280
|
-
from: [top.scope],
|
|
281
|
-
merged: false,
|
|
282
|
-
overridden: values.slice(0, -1).reverse(),
|
|
283
|
-
ignored,
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
out.push({
|
|
288
|
-
key,
|
|
289
|
-
value: top.value,
|
|
290
|
-
from: [top.scope],
|
|
291
|
-
merged: false,
|
|
292
|
-
overridden: values.slice(0, -1).reverse(),
|
|
293
|
-
ignored,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
229
|
+
return [...keys]
|
|
230
|
+
.sort()
|
|
231
|
+
.map((key) => effectiveSetting(key, (scope) => byScope.get(scope)?.[key], filterSandbox));
|
|
232
|
+
}
|
|
233
|
+
/** One key's value, from its value in each scope, lowest precedence first. */
|
|
234
|
+
function effectiveSetting(key, valueIn, filterSandbox) {
|
|
235
|
+
const { defined, ignored } = scopesThatCount(key, valueIn);
|
|
236
|
+
const values = defined.map((scope) => {
|
|
237
|
+
const { value, dropped } = withoutIgnoredFields(key, scope, valueIn(scope), filterSandbox);
|
|
238
|
+
for (const d of dropped)
|
|
239
|
+
ignored.push({ scope, ...d });
|
|
240
|
+
return { scope, value };
|
|
241
|
+
});
|
|
242
|
+
const top = values.at(-1);
|
|
243
|
+
if (!top)
|
|
244
|
+
return { key, value: undefined, from: [], merged: false, overridden: [], ignored };
|
|
245
|
+
const strict = STRICTEST[key];
|
|
246
|
+
const decided = strict && strictWinner(strict, values);
|
|
247
|
+
if (strict && decided) {
|
|
248
|
+
const { winner } = decided;
|
|
249
|
+
// Only files that may just tighten it set the key, and none tightens it past the default.
|
|
250
|
+
if (!winner)
|
|
251
|
+
for (const v of values)
|
|
252
|
+
ignored.push({ ...v, reason: "it is not stricter than Claude Code's default" });
|
|
253
|
+
return {
|
|
254
|
+
key,
|
|
255
|
+
value: winner?.value,
|
|
256
|
+
from: winner ? [winner.scope] : [],
|
|
257
|
+
merged: false,
|
|
258
|
+
overridden: winner ? values.filter((v) => v !== winner).reverse() : [],
|
|
259
|
+
ignored,
|
|
260
|
+
note: strictNote(strict),
|
|
261
|
+
};
|
|
296
262
|
}
|
|
297
|
-
|
|
263
|
+
const mergeable = !WHOLE_VALUE_KEYS.has(key) && values.every((v) => Array.isArray(v.value) || isRecord(v.value));
|
|
264
|
+
if (mergeable && values.length > 1)
|
|
265
|
+
return {
|
|
266
|
+
key,
|
|
267
|
+
value: withStrictFields(key, values.slice(1).reduce((acc, v) => mergeKey(key, acc, v.value), values[0]?.value), values),
|
|
268
|
+
from: defined,
|
|
269
|
+
merged: true,
|
|
270
|
+
overridden: [],
|
|
271
|
+
ignored,
|
|
272
|
+
};
|
|
273
|
+
return {
|
|
274
|
+
key,
|
|
275
|
+
value: withStrictFields(key, top.value, values),
|
|
276
|
+
from: [top.scope],
|
|
277
|
+
merged: false,
|
|
278
|
+
overridden: values.slice(0, -1).reverse(),
|
|
279
|
+
ignored,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* The scopes whose value for `key` counts, lowest precedence first, and the values Claude Code
|
|
284
|
+
* ignores: ones from files the key is not read from, and, once managed settings set
|
|
285
|
+
* availableModels, every other file's list, since Claude Code uses the managed one as-is.
|
|
286
|
+
*/
|
|
287
|
+
function scopesThatCount(key, valueIn) {
|
|
288
|
+
const allowed = allowedScopes(key);
|
|
289
|
+
const present = PRECEDENCE.filter((scope) => valueIn(scope) !== undefined);
|
|
290
|
+
const ignored = present
|
|
291
|
+
.filter((scope) => !allowed.includes(scope))
|
|
292
|
+
.map((scope) => ({ scope, value: valueIn(scope), reason: ignoredReason(key) }));
|
|
293
|
+
const defined = present.filter((scope) => allowed.includes(scope));
|
|
294
|
+
if (key !== "availableModels" || !defined.includes("managed"))
|
|
295
|
+
return { defined, ignored };
|
|
296
|
+
for (const scope of defined.filter((s) => s !== "managed"))
|
|
297
|
+
ignored.push({
|
|
298
|
+
scope,
|
|
299
|
+
value: valueIn(scope),
|
|
300
|
+
reason: "Managed settings set availableModels, so Claude Code uses that list as-is",
|
|
301
|
+
});
|
|
302
|
+
return { defined: ["managed"], ignored };
|
|
298
303
|
}
|
|
299
304
|
/** An object setting with each nested strictness exception (such as permissions.x) applied. */
|
|
300
305
|
function withStrictFields(key, value, values) {
|
|
@@ -305,9 +310,9 @@ function withStrictFields(key, value, values) {
|
|
|
305
310
|
const [head, field] = path.split(".");
|
|
306
311
|
if (head !== key || !field)
|
|
307
312
|
continue;
|
|
308
|
-
const fieldValues = values
|
|
309
|
-
|
|
310
|
-
|
|
313
|
+
const fieldValues = values.flatMap((v) => isRecord(v.value) && v.value[field] !== undefined
|
|
314
|
+
? [{ scope: v.scope, value: v.value[field] }]
|
|
315
|
+
: []);
|
|
311
316
|
const decided = strictWinner(strict, fieldValues);
|
|
312
317
|
if (decided)
|
|
313
318
|
out = { ...out, [field]: decided.winner?.value };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type BuiltinTool, type Hook, type Permission, type PermissionList } from "../../shared/types.ts";
|
|
2
|
+
/** `Tool` or `Tool(specifier)`; `Tool(*)` names the whole tool too (docs: permissions#permission-rule-syntax). */
|
|
3
|
+
export declare function parseRule(rule: string): {
|
|
4
|
+
tool: string;
|
|
5
|
+
specifier: string | null;
|
|
6
|
+
};
|
|
7
|
+
/** Deny and ask rules may glob the tool name; allow rules name it exactly (docs: permissions#tool-name-wildcards). */
|
|
8
|
+
export declare function namesTool(list: PermissionList, tool: string, name: string): boolean;
|
|
9
|
+
/** Every built-in tool, with the rules and hooks that apply to it here. */
|
|
10
|
+
export declare function builtinTools(permissions: Permission[], hooks: Hook[]): BuiltinTool[];
|
|
@@ -50,31 +50,39 @@ function matcherCovers(matcher, name) {
|
|
|
50
50
|
return false;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* The rules about one tool: `whole` name the tool itself and decide it, `scoped` apply to some of
|
|
55
|
+
* its calls only. EndConversation ignores rules (see builtinTools).
|
|
56
|
+
*/
|
|
57
|
+
function rulesFor(name, rules) {
|
|
58
|
+
const whole = [];
|
|
59
|
+
const scoped = [];
|
|
60
|
+
if (name === EXEMPT)
|
|
61
|
+
return { whole, scoped };
|
|
62
|
+
for (const r of rules) {
|
|
63
|
+
const { tool, specifier } = parseRule(r.rule);
|
|
64
|
+
if (specifier === null) {
|
|
65
|
+
if (namesTool(r.list, tool, name))
|
|
66
|
+
whole.push(r);
|
|
67
|
+
// Monitor's commands follow the Bash rules; its WebSocket watches do not
|
|
68
|
+
// (docs: tools-reference#monitor-tool).
|
|
69
|
+
else if (name === "Monitor" && namesTool(r.list, tool, "Bash"))
|
|
70
|
+
scoped.push(r);
|
|
71
|
+
}
|
|
72
|
+
else if (tool === name && UNCHECKED_PATH_RULE_TOOLS.has(tool)) {
|
|
73
|
+
scoped.push({ ...r, unchecked: true });
|
|
74
|
+
}
|
|
75
|
+
else if (tool === name || coveredTools(tool, r.list).includes(name))
|
|
76
|
+
scoped.push(r);
|
|
77
|
+
}
|
|
78
|
+
return { whole, scoped };
|
|
79
|
+
}
|
|
53
80
|
/** Every built-in tool, with the rules and hooks that apply to it here. */
|
|
54
81
|
export function builtinTools(permissions, hooks) {
|
|
55
82
|
const rules = permissions.flatMap((p) => p.kind === "rule" && p.inEffect ? [{ list: p.list, rule: p.rule, scope: p.scope }] : []);
|
|
56
83
|
const preToolUse = hooks.filter((h) => h.active && h.event === "PreToolUse");
|
|
57
84
|
const tools = table.tools.map(({ name, description, asks }) => {
|
|
58
|
-
const whole =
|
|
59
|
-
const scoped = [];
|
|
60
|
-
for (const r of rules) {
|
|
61
|
-
if (name === EXEMPT)
|
|
62
|
-
break;
|
|
63
|
-
const { tool, specifier } = parseRule(r.rule);
|
|
64
|
-
if (specifier === null) {
|
|
65
|
-
if (namesTool(r.list, tool, name))
|
|
66
|
-
whole.push(r);
|
|
67
|
-
// Monitor's commands follow the Bash rules; its WebSocket watches do not
|
|
68
|
-
// (docs: tools-reference#monitor-tool).
|
|
69
|
-
else if (name === "Monitor" && namesTool(r.list, tool, "Bash"))
|
|
70
|
-
scoped.push(r);
|
|
71
|
-
}
|
|
72
|
-
else if (tool === name && UNCHECKED_PATH_RULE_TOOLS.has(tool)) {
|
|
73
|
-
scoped.push({ ...r, unchecked: true });
|
|
74
|
-
}
|
|
75
|
-
else if (tool === name || coveredTools(tool, r.list).includes(name))
|
|
76
|
-
scoped.push(r);
|
|
77
|
-
}
|
|
85
|
+
const { whole, scoped } = rulesFor(name, rules);
|
|
78
86
|
const decidedBy = CHECK_ORDER.map((list) => whole.find((r) => r.list === list)).find(Boolean);
|
|
79
87
|
const tool = {
|
|
80
88
|
name,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type PermissionList, type Usage } from "../../shared/types.ts";
|
|
2
|
+
import { type ScanEnv } from "./env.ts";
|
|
3
|
+
/** A rule in effect here, as the scan found it. */
|
|
4
|
+
export interface RuleInEffect {
|
|
5
|
+
list: PermissionList;
|
|
6
|
+
rule: string;
|
|
7
|
+
}
|
|
8
|
+
/** A count that stopped before it finished, because it took too long or nobody wanted it. */
|
|
9
|
+
export declare class CountStopped extends Error {
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A counter with its own cache of transcripts and its own queue: counts made through it run one at
|
|
13
|
+
* a time and reuse what earlier ones read. Each core has one.
|
|
14
|
+
*/
|
|
15
|
+
export declare function usageCounter(): (env: ScanEnv, dir: string, rules: RuleInEffect[], { signal, timeLimitMs, maxCachedCalls, }?: {
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
timeLimitMs?: number;
|
|
18
|
+
maxCachedCalls?: number;
|
|
19
|
+
}) => Promise<Usage>;
|