@dsh-electron/dsh-plugin-multi-root-workspace 0.1.14 → 0.1.16

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 (73) hide show
  1. package/CHANGELOG.en.md +32 -1
  2. package/CHANGELOG.md +32 -1
  3. package/README.en.md +25 -8
  4. package/README.md +25 -8
  5. package/cordis.patch.yml +5 -1
  6. package/lib/{llm-message-fYORacvh.js → agent-instructions-BXuKhOzr.js} +1 -84
  7. package/lib/auto-review.js +2 -2
  8. package/lib/client.js +969 -100
  9. package/lib/client.js.map +1 -1
  10. package/lib/{command-Dcz6nULo.js → command-DaVJ-mK3.js} +76 -11
  11. package/lib/command.js +1 -1
  12. package/lib/compat-CTJbpCxu.js +267 -0
  13. package/lib/compat.js +1 -1
  14. package/lib/{dialects-Dr4rDR-H.js → dialects-CdlG3RF9.js} +1 -1
  15. package/lib/{compat-veDqCOoa.js → dsh-version-DCwF7REk.js} +2 -264
  16. package/lib/index.js +10 -8
  17. package/lib/{instructions-KsUwUFE0.js → instructions-Ca80SkZq.js} +696 -27
  18. package/lib/instructions.js +1 -1
  19. package/lib/llm-message-CepyzEBQ.js +84 -0
  20. package/lib/lsp.js +4 -4
  21. package/lib/{metadata-DgqSdVX_.js → metadata-99jgViHQ.js} +1 -1
  22. package/lib/{method-wrapper-CFY3p3j2.js → method-wrapper-D4oUCsEF.js} +22 -2
  23. package/lib/{native-win32-CRNXr11U.js → native-win32-C5oMtt7f.js} +1 -1
  24. package/lib/ops-compatibility.js +58 -0
  25. package/lib/ops-settings-UN2oOKEp.js +40 -0
  26. package/lib/ops-tools-k4JYaOrM.js +152 -0
  27. package/lib/process-fence.js +193 -34
  28. package/lib/{protocol-CnR1KTXy.js → protocol-CwDnFEyK.js} +8 -4
  29. package/lib/{registry-DR_sMuvS.js → registry-BibiukWk.js} +236 -80
  30. package/lib/{registry-lease-win32-DDO-c7ig.js → registry-lease-win32-r4puac9m.js} +1 -1
  31. package/lib/{registry-operation-C2ZV3Jhw.js → registry-operation-CIlmt6_c.js} +5 -1
  32. package/lib/registry.js +2 -2
  33. package/lib/{review-context-NDpKeMCc.js → review-context-OxO-fMWR.js} +24 -7
  34. package/lib/review-context.js +1 -1
  35. package/lib/{roots-Ca_W1S9n.js → roots-CmaWxRVy.js} +112 -22
  36. package/lib/{sandbox-C-vCJCp3.js → sandbox-aobdyQGi.js} +7 -4
  37. package/lib/sandbox.js +1 -1
  38. package/lib/scope.js +162 -12
  39. package/lib/skills-utyuvmwr.js +104 -0
  40. package/lib/skills.js +5 -106
  41. package/lib/{tool-context-CpgIFcCB.js → tool-context-CCeY3mrK.js} +1 -1
  42. package/lib/types/authority/protocol.d.ts +5 -1
  43. package/lib/types/client/files-tree/FilesTree.d.ts +49 -6
  44. package/lib/types/client/files-tree/adapter.d.ts +69 -16
  45. package/lib/types/client/files-tree/face.d.ts +31 -2
  46. package/lib/types/client/files-tree/locate.d.ts +74 -0
  47. package/lib/types/client/files-tree/navigator.d.ts +98 -0
  48. package/lib/types/client/index.d.ts +7 -0
  49. package/lib/types/client/locales.d.ts +30 -0
  50. package/lib/types/client/ops-settings.d.ts +6 -0
  51. package/lib/types/client/skills-settings.d.ts +3 -2
  52. package/lib/types/client/styles.d.ts +1 -1
  53. package/lib/types/command.d.ts +3 -3
  54. package/lib/types/compat/files-tree.d.ts +8 -1
  55. package/lib/types/compat/forge-entrypoints.d.ts +44 -0
  56. package/lib/types/compat/instruction-activity.d.ts +32 -1
  57. package/lib/types/compat/ops-confirmation.d.ts +17 -0
  58. package/lib/types/compat/ops-settings.d.ts +11 -0
  59. package/lib/types/compat/ops-tools.d.ts +25 -0
  60. package/lib/types/compat/session-existence.d.ts +41 -0
  61. package/lib/types/compat/skills-client.d.ts +1 -0
  62. package/lib/types/compat/tool-context.d.ts +4 -0
  63. package/lib/types/compat.d.ts +2 -2
  64. package/lib/types/instructions.d.ts +6 -1
  65. package/lib/types/ops-compatibility.d.ts +34 -0
  66. package/lib/types/registry-operation.d.ts +7 -0
  67. package/lib/types/registry.d.ts +67 -8
  68. package/lib/types/review-context.d.ts +2 -0
  69. package/lib/types/roots.d.ts +116 -20
  70. package/lib/types/scope.d.ts +95 -3
  71. package/lib/workspace-files.js +4 -4
  72. package/lib/{workspace-routing-YPxaQ4V3.js → workspace-routing-D_qwMUh-.js} +4 -4
  73. package/package.json +5 -1
@@ -1,2 +1,2 @@
1
- import { a as composeInstructionMessage, i as apply, n as DEFAULT_MAX_SOURCE_BYTES, o as inject, r as PLUGIN_SOURCE, s as touchedPathOfToolCall, t as DEFAULT_MAX_BYTES } from "./instructions-KsUwUFE0.js";
1
+ import { a as composeInstructionMessage, i as apply, l as touchedPathOfToolCall, n as DEFAULT_MAX_SOURCE_BYTES, o as inject, r as PLUGIN_SOURCE, t as DEFAULT_MAX_BYTES } from "./instructions-Ca80SkZq.js";
2
2
  export { DEFAULT_MAX_BYTES, DEFAULT_MAX_SOURCE_BYTES, PLUGIN_SOURCE, apply, composeInstructionMessage, inject, touchedPathOfToolCall };
@@ -0,0 +1,84 @@
1
+ //#region src/compat/llm-message.ts
2
+ /**
3
+ * This plugin's own producer kind.
4
+ *
5
+ * Session format 4 rejects the shared `kind: 'plugin'` (`format v4 message
6
+ * requires a producer-owned source kind`). The kind is ours, not
7
+ * `agent-instructions`: upstream treats that kind's `changes` array as its
8
+ * own reconciliation authority.
9
+ */
10
+ const PRODUCER_SOURCE_KIND = "multi-root-workspace";
11
+ /**
12
+ * The first session format whose encoder refuses `kind: 'plugin'`.
13
+ * Earlier formats declare that kind on `MessageSourceMap` and require it.
14
+ */
15
+ const PRODUCER_OWNED_FORMAT = 4;
16
+ /**
17
+ * Which source kind the installed session format will persist.
18
+ * @param formatVersion - `SESSION_FORMAT_VERSION`, when the session package is installed.
19
+ * @returns `plugin` through format 3, and this plugin's own kind from format 4 on.
20
+ */
21
+ function instructionSourceKind(formatVersion) {
22
+ return formatVersion !== void 0 && formatVersion >= PRODUCER_OWNED_FORMAT ? PRODUCER_SOURCE_KIND : "plugin";
23
+ }
24
+ /**
25
+ * The installed session format, when that package is present.
26
+ *
27
+ * A composition that never persists a session can omit the package; format 3
28
+ * is then the spelling that still declares `kind: 'plugin'`. Any other failure
29
+ * is a broken install and must surface.
30
+ * @returns the format version, or `undefined` when the package is not installed.
31
+ */
32
+ async function installedFormatVersion() {
33
+ try {
34
+ const session = await import("@deepseek-ai/dsh-session");
35
+ return typeof session.SESSION_FORMAT_VERSION === "number" ? session.SESSION_FORMAT_VERSION : void 0;
36
+ } catch (error) {
37
+ const code = error.code;
38
+ if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") return void 0;
39
+ throw error;
40
+ }
41
+ }
42
+ /**
43
+ * Build one user-role instruction message.
44
+ *
45
+ * Format 3 and earlier: `{ kind: 'plugin', plugin, form: 'instructions' }`.
46
+ * Format 4 and later: `{ kind: 'multi-root-workspace', plugin, form: 'instructions' }`.
47
+ * @param input - the body and the plugin attribution.
48
+ * @returns the frozen message upstream's helper produced.
49
+ * @throws {Error} when the optional peer is absent: a step that has instruction
50
+ * text to deliver cannot be served without it, and staying silent would drop
51
+ * user-visible context instead of reporting a misconfigured composition.
52
+ */
53
+ async function createInstructionMessage(input) {
54
+ let module;
55
+ try {
56
+ module = await import("@deepseek-ai/dsh-llm");
57
+ } catch (error) {
58
+ throw new Error(`multi-root workspace: @deepseek-ai/dsh-llm is not installed, so additional roots' instruction files cannot be delivered as messages (${error instanceof Error ? error.message : String(error)}).`);
59
+ }
60
+ const create = module.createUserMessage;
61
+ return create({
62
+ content: [{
63
+ type: "text",
64
+ text: input.text
65
+ }],
66
+ source: instructionSource(input.plugin, await installedFormatVersion())
67
+ });
68
+ }
69
+ /** The source object the installed format will persist. */
70
+ function instructionSource(plugin, formatVersion) {
71
+ const kind = instructionSourceKind(formatVersion);
72
+ if (kind === "plugin") return {
73
+ kind,
74
+ plugin,
75
+ form: "instructions"
76
+ };
77
+ return {
78
+ kind,
79
+ plugin,
80
+ form: "instructions"
81
+ };
82
+ }
83
+ //#endregion
84
+ export { createInstructionMessage as t };
package/lib/lsp.js CHANGED
@@ -1,7 +1,7 @@
1
- import { t as wrapMethod } from "./method-wrapper-CFY3p3j2.js";
2
- import { c as withRegistryRead } from "./registry-operation-C2ZV3Jhw.js";
3
- import { t as aroundTool } from "./tool-context-CpgIFcCB.js";
4
- import { t as routeWorkspacePath } from "./workspace-routing-YPxaQ4V3.js";
1
+ import { t as wrapMethod } from "./method-wrapper-D4oUCsEF.js";
2
+ import { l as withRegistryRead } from "./registry-operation-CIlmt6_c.js";
3
+ import { t as aroundTool } from "./tool-context-CCeY3mrK.js";
4
+ import { t as routeWorkspacePath } from "./workspace-routing-D_qwMUh-.js";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
6
  //#region src/lsp.ts
7
7
  const inject = [
@@ -1,4 +1,4 @@
1
- import { t as RootValidationError } from "./roots-Ca_W1S9n.js";
1
+ import { t as RootValidationError } from "./roots-CmaWxRVy.js";
2
2
  import { createHash } from "node:crypto";
3
3
  import { basename } from "node:path";
4
4
  //#region src/skills/metadata.ts
@@ -1,4 +1,14 @@
1
1
  //#region src/method-wrapper.ts
2
+ const layers = /* @__PURE__ */ new WeakMap();
3
+ function liveDescriptor(target, key, descriptor) {
4
+ let current = descriptor;
5
+ while (typeof current?.value === "function") {
6
+ const layer = layers.get(current.value);
7
+ if (layer === void 0 || layer.active || layer.target !== target || layer.key !== key) break;
8
+ current = layer.own;
9
+ }
10
+ return current;
11
+ }
2
12
  /** Wrap a public method on a Cordis service without capturing a caller-context proxy. */
3
13
  function wrapMethod(target, key, wrap) {
4
14
  const own = Object.getOwnPropertyDescriptor(target, key);
@@ -10,6 +20,14 @@ function wrapMethod(target, key, wrap) {
10
20
  }
11
21
  if (typeof descriptor?.value !== "function") throw new Error(`multi-root: ${String(key)} is not a public method`);
12
22
  const value = wrap(descriptor.value);
23
+ if (value === descriptor.value) return () => {};
24
+ const layer = {
25
+ target,
26
+ key,
27
+ own,
28
+ active: true
29
+ };
30
+ layers.set(value, layer);
13
31
  Object.defineProperty(target, key, {
14
32
  configurable: true,
15
33
  writable: true,
@@ -17,9 +35,11 @@ function wrapMethod(target, key, wrap) {
17
35
  value
18
36
  });
19
37
  return () => {
38
+ layer.active = false;
20
39
  if (Object.getOwnPropertyDescriptor(target, key)?.value !== value) return;
21
- if (own === void 0) Reflect.deleteProperty(target, key);
22
- else Object.defineProperty(target, key, own);
40
+ const previous = liveDescriptor(target, key, own);
41
+ if (previous === void 0) Reflect.deleteProperty(target, key);
42
+ else Object.defineProperty(target, key, previous);
23
43
  };
24
44
  }
25
45
  //#endregion
@@ -1,4 +1,4 @@
1
- import { c as loadHostKoffi } from "./protocol-CnR1KTXy.js";
1
+ import { c as loadHostKoffi } from "./protocol-CwDnFEyK.js";
2
2
  import { EventEmitter } from "node:events";
3
3
  //#region src/authority/native-win32.ts
4
4
  /** Windows local pipes: tokens, never a caller-supplied PID or a bearer file. */
@@ -0,0 +1,58 @@
1
+ import { n as opsCompatibilityField, t as installOpsCompatibilitySettings } from "./ops-settings-UN2oOKEp.js";
2
+ import { t as configValue } from "./skills-utyuvmwr.js";
3
+ import { randomUUID } from "node:crypto";
4
+ import { Service } from "@deepseek-ai/cordis";
5
+ import z from "@deepseek-ai/schemastery";
6
+ //#region src/ops-compatibility.ts
7
+ const enabledField = opsCompatibilityField(z.boolean().default(false));
8
+ const experimental = enabledField.experimental;
9
+ const described = typeof experimental === "function" ? experimental.call(enabledField) : enabledField;
10
+ const Config = z.object({ enabled: described.description("OPS 兼容模式(实验性,仅限 DSH 0.2.*):可能存在功能、版本和平台限制。启用 OPS 写保护、实时活动与 Review 增强;受限模式可能拒绝附加根操作(包括读取),后台缓存可能残留;关闭时显式只读附加根可能被 OPS 写入。") });
11
+ var MultiRootOpsCompatibility = class extends Service {
12
+ settingsConfig;
13
+ static Config = Config;
14
+ static provide = "multiRootOpsCompatibility";
15
+ static inject = [
16
+ "multiRootCompat",
17
+ "multiRootProviders",
18
+ "multiRootScope"
19
+ ];
20
+ constructor(ctx, settingsConfig = {}) {
21
+ super(ctx, "multiRootOpsCompatibility");
22
+ this.settingsConfig = settingsConfig;
23
+ const settings = installOpsCompatibilitySettings(ctx, () => this.settingsConfig.enabled, () => this.sync());
24
+ this.settingsRead = settings.read;
25
+ ctx.effect(() => () => {
26
+ this.closing = true;
27
+ this.enabledNow = false;
28
+ this.currentToken = void 0;
29
+ });
30
+ this.sync();
31
+ }
32
+ settingsRead;
33
+ currentToken;
34
+ enabledNow = false;
35
+ closing = false;
36
+ get token() {
37
+ this.sync();
38
+ return this.currentToken;
39
+ }
40
+ get enabled() {
41
+ this.sync();
42
+ return this.enabledNow;
43
+ }
44
+ sync() {
45
+ if (this.closing) {
46
+ this.enabledNow = false;
47
+ this.currentToken = void 0;
48
+ return;
49
+ }
50
+ const raw = this.settingsRead?.();
51
+ const enabled = configValue(raw) === true;
52
+ if (enabled === this.enabledNow) return;
53
+ this.enabledNow = enabled;
54
+ this.currentToken = enabled ? Object.freeze({ id: randomUUID() }) : void 0;
55
+ }
56
+ };
57
+ //#endregion
58
+ export { Config, MultiRootOpsCompatibility, MultiRootOpsCompatibility as default };
@@ -0,0 +1,40 @@
1
+ import { d as readInstalledVersion } from "./dsh-version-DCwF7REk.js";
2
+ /** Product availability policy, independent of structural Settings adaptation. */
3
+ function opsCompatibilityRelease(release) {
4
+ return release !== void 0 && /^0\.2\.\d+(?:[-+].*)?$/.test(release);
5
+ }
6
+ /** Unsupported hosts retain the config input but expose no editable live field. */
7
+ function opsCompatibilityField(schema) {
8
+ if (!opsCompatibilityRelease(readInstalledVersion("@deepseek-ai/dsh-sandbox"))) return schema;
9
+ const method = schema.volatile;
10
+ return typeof method === "function" ? method.call(schema) : schema;
11
+ }
12
+ function installOpsCompatibilitySettings(ctx, initial, changed) {
13
+ let active = false;
14
+ return {
15
+ fiber: ctx.inject(["settings"], (scope) => {
16
+ if (!opsCompatibilityRelease(scope.get("multiRootCompat")?.release)) return;
17
+ const settings = scope.get("settings");
18
+ if (typeof settings.configure !== "function") return;
19
+ const stop = settings.configure({ auto: false }, ctx.fiber);
20
+ active = true;
21
+ const stopEvent = scope.on("settings/document-updated", (id) => {
22
+ if (id === "multi-root-ops-compatibility") changed();
23
+ });
24
+ changed();
25
+ return () => {
26
+ active = false;
27
+ stopEvent();
28
+ stop();
29
+ changed();
30
+ };
31
+ }),
32
+ read: () => active && opsCompatibilityRelease(ctx.get("multiRootCompat")?.release) ? initial() : void 0
33
+ };
34
+ }
35
+ function opsCompatibilityToken(ctx) {
36
+ const service = ctx.get("multiRootOpsCompatibility");
37
+ return service === void 0 ? void 0 : service.token;
38
+ }
39
+ //#endregion
40
+ export { opsCompatibilityField as n, opsCompatibilityToken as r, installOpsCompatibilitySettings as t };
@@ -0,0 +1,152 @@
1
+ import { r as opsCompatibilityToken } from "./ops-settings-UN2oOKEp.js";
2
+ import { realpathSync } from "node:fs";
3
+ import { isAbsolute, relative } from "node:path";
4
+ import { AsyncLocalStorage } from "node:async_hooks";
5
+ import { tmpdir } from "node:os";
6
+ //#region src/compat/ops-tools.ts
7
+ const OPS_TOOL_PREFIX = "ops_";
8
+ const OPS_EXEC_RAW_NAMES = [
9
+ "inspect_local_file",
10
+ "grep",
11
+ "glob",
12
+ "replace",
13
+ "write_file",
14
+ "edit_file",
15
+ "diff",
16
+ "stat",
17
+ "copy",
18
+ "move",
19
+ "remove",
20
+ "read_files",
21
+ "read_table",
22
+ "read_docx",
23
+ "read_pdf",
24
+ "batch",
25
+ "result",
26
+ "bash"
27
+ ];
28
+ const OPS_PUBLISH_RAW_NAMES = ["discover_tools", "load_sdk"];
29
+ OPS_EXEC_RAW_NAMES.map((raw) => OPS_TOOL_PREFIX + raw);
30
+ function classifyOpsTool(name) {
31
+ if (typeof name !== "string" || !name.startsWith("ops_")) return "other";
32
+ const raw = name.slice(4);
33
+ if (OPS_EXEC_RAW_NAMES.includes(raw)) return "exec";
34
+ if (OPS_PUBLISH_RAW_NAMES.includes(raw)) return "publish";
35
+ return "unknown";
36
+ }
37
+ const spawnPermit = new AsyncLocalStorage();
38
+ function withOpsSpawnPermit(state, body) {
39
+ const permit = {
40
+ state,
41
+ active: true
42
+ };
43
+ try {
44
+ return spawnPermit.run(permit, body);
45
+ } finally {
46
+ permit.active = false;
47
+ }
48
+ }
49
+ function opsSpawnPermitted(state) {
50
+ const permit = spawnPermit.getStore();
51
+ return permit?.state === state && permit.active;
52
+ }
53
+ function createOpsProtectionState() {
54
+ return {
55
+ owner: void 0,
56
+ entered: 0,
57
+ drainWaiters: /* @__PURE__ */ new Set()
58
+ };
59
+ }
60
+ function claimOpsProtection(state) {
61
+ const owner = {};
62
+ state.owner = owner;
63
+ return owner;
64
+ }
65
+ function revokeOpsProtection(state, token) {
66
+ if (state.owner === token) state.owner = void 0;
67
+ }
68
+ function opsProtectionReady(state) {
69
+ return state.owner !== void 0;
70
+ }
71
+ function assertOpsProtectionOwner(state, token) {
72
+ if (state.owner !== token) throw new Error("multi-root workspace: the OPS execution protection generation was replaced during dispatch");
73
+ }
74
+ function enterOpsProtection(state) {
75
+ if (state.owner === void 0) throw new Error("multi-root workspace: the OPS execution protection is not installed on this scope");
76
+ state.entered += 1;
77
+ return state.owner;
78
+ }
79
+ function leaveOpsProtection(state) {
80
+ state.entered -= 1;
81
+ if (state.entered === 0) {
82
+ for (const resolve of state.drainWaiters) resolve();
83
+ state.drainWaiters.clear();
84
+ }
85
+ }
86
+ async function drainOpsProtection(state) {
87
+ if (state.entered === 0) return;
88
+ await new Promise((resolve) => state.drainWaiters.add(resolve));
89
+ }
90
+ const OPS_RESULT_CACHE_LEAF = /^dsh-ops-results-[0-9a-f]{64}$/u;
91
+ function cacheRefusal(detail) {
92
+ return /* @__PURE__ */ new Error(`multi-root workspace: ${detail}; refusing to prepare the OPS execution`);
93
+ }
94
+ function containsPath(root, path) {
95
+ if (root === path) return true;
96
+ const rel = relative(root, path);
97
+ return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
98
+ }
99
+ function assertOpsPosixCacheAdmission(deniedRoots) {
100
+ let canonicalTmp;
101
+ try {
102
+ canonicalTmp = realpathSync.native(tmpdir());
103
+ } catch (error) {
104
+ throw cacheRefusal(`the canonical temporary directory cannot be resolved (${error.message})`);
105
+ }
106
+ if (!isAbsolute(canonicalTmp)) throw cacheRefusal("the canonical temporary directory is not absolute");
107
+ const rawTmp = tmpdir();
108
+ const spellings = /* @__PURE__ */ new Set();
109
+ for (const root of deniedRoots) {
110
+ if (root === "") continue;
111
+ spellings.add(root);
112
+ try {
113
+ spellings.add(realpathSync.native(root));
114
+ } catch {}
115
+ if (containsPath(rawTmp, root) || root === rawTmp) {
116
+ const rel = relative(rawTmp, root);
117
+ spellings.add(rel === "" ? canonicalTmp : canonicalTmp + "/" + rel);
118
+ }
119
+ }
120
+ for (const deny of spellings) {
121
+ if (containsPath(deny, canonicalTmp)) throw cacheRefusal(`a deny boundary ${JSON.stringify(deny)} covers the temporary directory`);
122
+ const rel = relative(canonicalTmp, deny);
123
+ if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) continue;
124
+ const first = rel.split("/")[0];
125
+ if (first !== void 0 && OPS_RESULT_CACHE_LEAF.test(first)) throw cacheRefusal(`a deny boundary ${JSON.stringify(deny)} overlaps the OPS result cache`);
126
+ }
127
+ }
128
+ const object = (value) => typeof value === "object" && value !== null;
129
+ function opsDispatchBarrier(ctx, scope, exec) {
130
+ if (opsCompatibilityToken(ctx) === void 0) return void 0;
131
+ const kind = classifyOpsTool(exec.name);
132
+ if (kind === "other" || kind === "publish") return void 0;
133
+ if (ctx.get("multiRootCompat") === void 0 || ctx.get("multiRootProviders") === void 0) return void 0;
134
+ const session = exec.agent?.session;
135
+ const policyService = ctx.get("sandboxPolicy");
136
+ let policy;
137
+ if (session !== void 0 && policyService !== void 0) try {
138
+ policy = policyService.resolve({ session });
139
+ } catch {
140
+ policy = void 0;
141
+ }
142
+ if (policy === void 0) return `the OPS tool ${JSON.stringify(exec.name)} cannot be confirmed against a trusted session and policy`;
143
+ const preview = scope.previewForTool(policy, exec.name);
144
+ if (preview.authority === "unavailable") return `the multi-root registry authority is unavailable; the OPS call ${JSON.stringify(exec.name)} is refused before dispatch`;
145
+ if (preview.deniedRoots.length === 0) return void 0;
146
+ if (policy.mode !== "danger-full-access") return `the OPS call ${JSON.stringify(exec.name)} is refused in ${policy.mode}: private preparation and worker write boundaries cannot be proven without OPS integration`;
147
+ if (kind === "unknown") return `the unrecognized OPS capability ${JSON.stringify(exec.name)} is refused while write boundaries apply`;
148
+ if (!opsProtectionReady(scope.opsProtection)) return `the OPS execution protection is not installed; the call ${JSON.stringify(exec.name)} is refused`;
149
+ if (exec.name === `ops_bash` && object(exec.arguments) && exec.arguments.run_in_background === true) return "run_in_background is refused while danger-full-access write boundaries apply";
150
+ }
151
+ //#endregion
152
+ export { createOpsProtectionState as a, leaveOpsProtection as c, revokeOpsProtection as d, withOpsSpawnPermit as f, classifyOpsTool as i, opsDispatchBarrier as l, assertOpsProtectionOwner as n, drainOpsProtection as o, claimOpsProtection as r, enterOpsProtection as s, assertOpsPosixCacheAdmission as t, opsSpawnPermitted as u };