opencode-swarm 7.138.3 → 7.138.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.
Files changed (56) hide show
  1. package/.opencode/skills/execute/SKILL.md +11 -2
  2. package/.opencode/skills/swarm-implement/SKILL.md +1 -1
  3. package/dist/cli/{config-doctor-2mwgdbsn.js → config-doctor-31yppse4.js} +2 -2
  4. package/dist/cli/{core-v6bte964.js → core-65c7rvqf.js} +1 -1
  5. package/dist/cli/{curation-policy-5dqexw5j.js → curation-policy-hs9pc1rp.js} +2 -2
  6. package/dist/cli/{curator-jjtp9hn2.js → curator-54n1y4j8.js} +16 -15
  7. package/dist/cli/{curator-llm-factory-wkjme59b.js → curator-llm-factory-wm27ra25.js} +16 -15
  8. package/dist/cli/{evidence-summary-service-6cttrkzw.js → evidence-summary-service-hrxcf29a.js} +1 -1
  9. package/dist/cli/{guardrail-explain-xppwfnxr.js → guardrail-explain-1729nse8.js} +17 -16
  10. package/dist/cli/{guardrail-log-swet7rch.js → guardrail-log-yjj5srkw.js} +4 -3
  11. package/dist/cli/{hive-promoter-xvq8jzbs.js → hive-promoter-es2x2b0e.js} +16 -15
  12. package/dist/cli/{index-1djv5684.js → index-1g6xpjk3.js} +4 -4
  13. package/dist/cli/{index-js7th5my.js → index-33q2gmgd.js} +1 -1
  14. package/dist/cli/{index-adde7nm2.js → index-50mwt8fx.js} +5 -5
  15. package/dist/cli/index-556ja8an.js +62 -0
  16. package/dist/cli/{index-93ky909v.js → index-57stye65.js} +1 -1
  17. package/dist/cli/{index-ab57h0yq.js → index-5q009kc4.js} +1 -1
  18. package/dist/cli/{index-99af5gvd.js → index-a18hk2fw.js} +211 -63
  19. package/dist/cli/{index-1v89yst3.js → index-a9xny52r.js} +2 -2
  20. package/dist/cli/{index-rjratees.js → index-c60whfgh.js} +1 -1
  21. package/dist/cli/{index-gda7cwqz.js → index-e1kgxchq.js} +30 -68
  22. package/dist/cli/{index-31vfewmn.js → index-gm3pjfhb.js} +271 -94
  23. package/dist/cli/{index-jhb8kjc5.js → index-jbge0dyh.js} +3 -3
  24. package/dist/cli/{index-xgmx9had.js → index-k27a4e5g.js} +18 -17
  25. package/dist/cli/{index-y6dvs5tt.js → index-m1pwkwfe.js} +1 -1
  26. package/dist/cli/{index-wqg74mwj.js → index-m40ea3zk.js} +1 -1
  27. package/dist/cli/{index-btx8j39p.js → index-m8txs2a9.js} +1 -1
  28. package/dist/cli/{index-y06a43sk.js → index-mycqmsz5.js} +4 -0
  29. package/dist/cli/index-smsy2p8n.js +1725 -0
  30. package/dist/cli/{index-tc61fybd.js → index-tjwz5tct.js} +2 -2
  31. package/dist/cli/{index-j0xx9wpj.js → index-y28n2wmq.js} +1 -1
  32. package/dist/cli/index.js +16 -15
  33. package/dist/cli/{knowledge-escalator-7n384ys1.js → knowledge-escalator-s6z1x65b.js} +3 -3
  34. package/dist/cli/{knowledge-events-yaj0yjd6.js → knowledge-events-nnyn6hst.js} +1 -1
  35. package/dist/cli/{knowledge-store-d99k0z2d.js → knowledge-store-x4yfc7v3.js} +1 -1
  36. package/dist/cli/{knowledge-validator-e5fqy9h4.js → knowledge-validator-1v047gsa.js} +4 -4
  37. package/dist/cli/{scan-cursor-9y9msabt.js → scan-cursor-jxajj6s7.js} +2 -2
  38. package/dist/cli/{schema-xg5f11md.js → schema-fj32eyae.js} +1 -1
  39. package/dist/cli/{scope-persistence-n1bryhzf.js → scope-persistence-w7zen2wz.js} +25 -2
  40. package/dist/cli/{skill-generator-arvwfdfh.js → skill-generator-rt0jqcsa.js} +5 -5
  41. package/dist/hooks/guardrails/destructive-command.d.ts +35 -0
  42. package/dist/hooks/guardrails/file-authority.d.ts +71 -26
  43. package/dist/hooks/guardrails/index.d.ts +2 -0
  44. package/dist/hooks/guardrails/tool-before.d.ts +5 -0
  45. package/dist/hooks/scope-guard.d.ts +3 -1
  46. package/dist/index.js +407 -395
  47. package/dist/scope/path-identity.d.ts +27 -0
  48. package/dist/scope/scope-binding.d.ts +90 -2
  49. package/dist/scope/scope-lease-renewal.d.ts +28 -0
  50. package/dist/scope/scope-persistence.d.ts +102 -19
  51. package/dist/scope/scope-resolution-diagnostic.d.ts +7 -0
  52. package/dist/tools/declare-scope.d.ts +3 -1
  53. package/dist/tools/save-plan.d.ts +2 -0
  54. package/dist/turbo/lean/lane-scope.d.ts +1 -1
  55. package/package.json +1 -1
  56. package/dist/cli/index-2y4jy0de.js +0 -642
@@ -1,25 +1,25 @@
1
1
  // @bun
2
2
  import {
3
- DC_SAFE_TARGETS,
4
3
  HUMAN_ONLY_SWARM_COMMANDS,
5
4
  dcCheckJunctionCreation,
5
+ dcEvaluateRecursiveDeleteTargets,
6
6
  dcExtractPowerShellTargets,
7
+ dcExtractRecursiveRmTargets,
7
8
  dcExtractWindowsCmdTargets,
8
9
  dcNormalizeCommand,
9
10
  dcSplitSegments,
10
11
  dcUnwrapWrappers,
11
- dcValidateTargets,
12
12
  detectPosixWrites,
13
13
  detectWindowsWrites,
14
14
  resolveWriteTargets
15
- } from "./index-99af5gvd.js";
15
+ } from "./index-a18hk2fw.js";
16
16
  import {
17
17
  checkFileAuthority,
18
18
  classifyFile,
19
19
  isInDeclaredScope,
20
20
  redactPath,
21
21
  redactShellCommand
22
- } from "./index-31vfewmn.js";
22
+ } from "./index-gm3pjfhb.js";
23
23
 
24
24
  // src/services/guardrail-explain-service.ts
25
25
  import path from "path";
@@ -90,98 +90,60 @@ function evaluateDestructiveDecision(rawCommand, cwd, declaredScope) {
90
90
  firingRule: "destructive_block: junction creation"
91
91
  };
92
92
  }
93
- const rmShortMatch = seg.match(/^rm\s+(-[rRfF]+(?:\s+-[rRfF]+)*|-r\s+-f|-f\s+-r)\s+(.+)$/);
94
- const rmLongMatch = seg.match(/^rm\s+(?:--(?:recursive|force)\s+){1,2}(.+)$/);
95
- const rmAnyMatch = rmShortMatch ?? rmLongMatch;
96
- if (rmAnyMatch) {
97
- const targetPart = rmAnyMatch[rmShortMatch ? 2 : 1].trim();
98
- const targets = targetPart.split(/\s+/);
99
- const validateBlock = dcValidateTargets(targets, cwd);
100
- if (validateBlock) {
93
+ const targets = dcExtractRecursiveRmTargets(seg);
94
+ if (targets) {
95
+ const targetDecision = dcEvaluateRecursiveDeleteTargets({ targets, cwd });
96
+ if (!targetDecision.allowed) {
101
97
  return {
102
98
  decision: "block",
103
- firingRule: `destructive_block: rm with unsafe target: ${redactPath(targetPart)}`
99
+ firingRule: `${targetDecision.code}: ${targetDecision.reason}`
104
100
  };
105
101
  }
106
- const allSafe = targets.every((t) => DC_SAFE_TARGETS.has(t.replace(/^["']|["']$/g, "").trim()));
107
- if (!allSafe) {
108
- const scopeExempt = declaredScope != null && declaredScope.length > 0 && targets.every((t) => isInDeclaredScope(t.replace(/^["']|["']$/g, "").trim(), declaredScope, cwd));
109
- if (!scopeExempt) {
110
- return {
111
- decision: "block",
112
- firingRule: `destructive_block: rm recursive/force on unsafe path: ${redactPath(targetPart)}`
113
- };
114
- }
115
- }
116
102
  }
117
103
  if (/^(?:rmdir|rd)(?:\.exe)?\s+.*\/[sS]/i.test(seg)) {
118
- const targets = dcExtractWindowsCmdTargets(seg);
119
- if (targets.length === 0) {
104
+ const targets2 = dcExtractWindowsCmdTargets(seg);
105
+ if (targets2.length === 0) {
120
106
  return {
121
107
  decision: "block",
122
108
  firingRule: "destructive_block: Windows recursive directory delete (rmdir /s)"
123
109
  };
124
110
  }
125
- const validateBlock = dcValidateTargets(targets, cwd);
126
- if (validateBlock) {
111
+ const targetDecision = dcEvaluateRecursiveDeleteTargets({ targets: targets2, cwd });
112
+ if (!targetDecision.allowed) {
127
113
  return {
128
114
  decision: "block",
129
- firingRule: `destructive_block: rmdir /s unsafe: ${redactPath(targets.join(", "))}`
115
+ firingRule: `${targetDecision.code}: ${targetDecision.reason}`
130
116
  };
131
117
  }
132
- const allSafe = targets.every((t) => DC_SAFE_TARGETS.has(t.trim()));
133
- if (!allSafe) {
134
- const scopeExempt = declaredScope != null && declaredScope.length > 0 && targets.every((t) => isInDeclaredScope(t.trim(), declaredScope, cwd));
135
- if (!scopeExempt) {
136
- return {
137
- decision: "block",
138
- firingRule: `destructive_block: rmdir /s on unsafe path: ${redactPath(targets.join(", "))}`
139
- };
140
- }
141
- }
142
118
  }
143
119
  if (/^del(?:\.exe)?\s+.*\/[sS]/i.test(seg)) {
144
- const targets = dcExtractWindowsCmdTargets(seg);
145
- if (targets.length > 0) {
146
- const validateBlock = dcValidateTargets(targets, cwd);
147
- if (validateBlock) {
120
+ const targets2 = dcExtractWindowsCmdTargets(seg);
121
+ if (targets2.length > 0) {
122
+ const targetDecision = dcEvaluateRecursiveDeleteTargets({
123
+ targets: targets2,
124
+ cwd
125
+ });
126
+ if (!targetDecision.allowed) {
148
127
  return {
149
128
  decision: "block",
150
- firingRule: `destructive_block: del /s unsafe: ${redactPath(targets.join(", "))}`
129
+ firingRule: `${targetDecision.code}: ${targetDecision.reason}`
151
130
  };
152
131
  }
153
- const allSafe = targets.every((t) => DC_SAFE_TARGETS.has(t.trim()));
154
- if (!allSafe) {
155
- const scopeExempt = declaredScope != null && declaredScope.length > 0 && targets.every((t) => isInDeclaredScope(t.trim(), declaredScope, cwd));
156
- if (!scopeExempt) {
157
- return {
158
- decision: "block",
159
- firingRule: `destructive_block: del /s on unsafe path: ${redactPath(targets.join(", "))}`
160
- };
161
- }
162
- }
163
132
  }
164
133
  }
165
134
  if (/^(?:Remove-Item|ri|rm|rmdir|del|erase|rd)\b.*-[Rr]ecurse\b/i.test(seg) || /^(?:Remove-Item|ri|rm|rmdir|del|erase|rd)\b.*-[Rr]\b/i.test(seg)) {
166
- const targets = dcExtractPowerShellTargets(seg);
167
- if (targets.length > 0) {
168
- const validateBlock = dcValidateTargets(targets, cwd);
169
- if (validateBlock) {
135
+ const targets2 = dcExtractPowerShellTargets(seg);
136
+ if (targets2.length > 0) {
137
+ const targetDecision = dcEvaluateRecursiveDeleteTargets({
138
+ targets: targets2,
139
+ cwd
140
+ });
141
+ if (!targetDecision.allowed) {
170
142
  return {
171
143
  decision: "block",
172
- firingRule: `destructive_block: PowerShell recursive delete unsafe: ${redactPath(targets.join(", "))}`
144
+ firingRule: `${targetDecision.code}: ${targetDecision.reason}`
173
145
  };
174
146
  }
175
- const allSafe = targets.every((t) => DC_SAFE_TARGETS.has(t.trim()));
176
- if (!allSafe) {
177
- const scopeExempt = declaredScope != null && declaredScope.length > 0 && targets.every((t) => isInDeclaredScope(t.trim(), declaredScope, cwd));
178
- if (!scopeExempt) {
179
- return {
180
- decision: "block",
181
- firingRule: `destructive_block: PowerShell recursive delete on unsafe path: ${redactPath(targets.join(", "))}`
182
- };
183
- }
184
- }
185
147
  } else {
186
148
  return {
187
149
  decision: "block",
@@ -2,7 +2,16 @@
2
2
  import {
3
3
  init_schema,
4
4
  stripKnownSwarmPrefix
5
- } from "./index-ab57h0yq.js";
5
+ } from "./index-5q009kc4.js";
6
+ import {
7
+ getPathFlavor,
8
+ isOnDifferentPathRoot,
9
+ isPathIdentityWithin,
10
+ isPathWithinDeclaredScope,
11
+ pathIdentitiesEqual,
12
+ sanitizeDiagnosticText,
13
+ unsafePathTextReason
14
+ } from "./index-556ja8an.js";
6
15
  import {
7
16
  init_constants
8
17
  } from "./index-3jcyn8g6.js";
@@ -2095,11 +2104,41 @@ function getGlobMatcher(pattern, caseInsensitive = true) {
2095
2104
  return () => false;
2096
2105
  }
2097
2106
  }
2107
+ var AUTHORITY_ROLE_CAPABILITIES = {
2108
+ architect: "direct-write",
2109
+ coder: "direct-write",
2110
+ reviewer: "direct-write",
2111
+ critic: "direct-write",
2112
+ critic_oversight: "dedicated-tool-only",
2113
+ critic_finding_validator: "dedicated-tool-only",
2114
+ explorer: "read-only",
2115
+ sme: "read-only",
2116
+ researcher: "read-only",
2117
+ test_engineer: "direct-write",
2118
+ docs: "direct-write",
2119
+ docs_design: "direct-write",
2120
+ designer: "direct-write",
2121
+ critic_sounding_board: "read-only",
2122
+ critic_drift_verifier: "read-only",
2123
+ critic_hallucination_verifier: "read-only",
2124
+ critic_architecture_supervisor: "read-only",
2125
+ curator_init: "dedicated-tool-only",
2126
+ curator_phase: "dedicated-tool-only",
2127
+ curator_postmortem: "dedicated-tool-only",
2128
+ curator_consolidation: "dedicated-tool-only",
2129
+ council_generalist: "read-only",
2130
+ council_skeptic: "read-only",
2131
+ council_domain_expert: "read-only",
2132
+ skill_improver: "dedicated-tool-only",
2133
+ spec_writer: "dedicated-tool-only"
2134
+ };
2135
+ var NON_WRITING_SWARM_RULES = Object.fromEntries(Object.entries(AUTHORITY_ROLE_CAPABILITIES).filter(([, capability]) => capability === "read-only" || capability === "dedicated-tool-only").map(([agent]) => [agent, { readOnly: true }]));
2098
2136
  var DEFAULT_AGENT_AUTHORITY_RULES = {
2099
2137
  build: {},
2100
2138
  plan: {},
2101
2139
  general: {},
2102
2140
  explore: {},
2141
+ ...NON_WRITING_SWARM_RULES,
2103
2142
  architect: {
2104
2143
  blockedExact: [".swarm/plan.md", ".swarm/plan.json"],
2105
2144
  blockedZones: ["generated", "config"],
@@ -2189,6 +2228,22 @@ var DEFAULT_AGENT_AUTHORITY_RULES = {
2189
2228
  blockedZones: ["generated"]
2190
2229
  }
2191
2230
  };
2231
+ function matchesAuthorityDenyPrefix(candidate, prefix, cwd, flavor = getPathFlavor()) {
2232
+ const pathImpl = flavor === "win32" ? path.win32 : path.posix;
2233
+ const normalizeInput = (value) => flavor === "win32" ? value.replace(/\//g, "\\") : value;
2234
+ const normalizedPrefixInput = normalizeInput(prefix);
2235
+ const requiresComponentBoundary = normalizedPrefixInput.endsWith(pathImpl.sep);
2236
+ const root = pathImpl.resolve(normalizeInput(cwd));
2237
+ const target = pathImpl.resolve(root, normalizeInput(candidate));
2238
+ const denied = pathImpl.resolve(root, normalizedPrefixInput);
2239
+ if (!isPathIdentityWithin(target, root, flavor) || !isPathIdentityWithin(denied, root, flavor)) {
2240
+ return false;
2241
+ }
2242
+ const identity = (value) => flavor === "win32" ? value.toLowerCase() : value;
2243
+ const targetIdentity = identity(target);
2244
+ const deniedIdentity = identity(denied);
2245
+ return requiresComponentBoundary ? targetIdentity === deniedIdentity || targetIdentity.startsWith(`${deniedIdentity}${pathImpl.sep}`) : targetIdentity.startsWith(deniedIdentity);
2246
+ }
2192
2247
  function buildEffectiveRules(authorityConfig) {
2193
2248
  if (authorityConfig?.enabled === false || !authorityConfig?.rules) {
2194
2249
  return { ...DEFAULT_AGENT_AUTHORITY_RULES };
@@ -2220,21 +2275,37 @@ function buildEffectiveRules(authorityConfig) {
2220
2275
  return merged;
2221
2276
  }
2222
2277
  function isOnDifferentFilesystemRoot(targetAbsolute, cwdAbsolute, pathLib = path) {
2223
- return pathLib.parse(targetAbsolute).root !== pathLib.parse(cwdAbsolute).root;
2278
+ const flavor = pathLib === path.win32 || pathLib.parse("C:\\probe").root !== "" ? "win32" : "posix";
2279
+ return isOnDifferentPathRoot(targetAbsolute, cwdAbsolute, flavor);
2224
2280
  }
2225
- function isInDeclaredScope(filePath, scopeEntries, cwd) {
2226
- const dir = cwd ?? process.cwd();
2227
- const caseInsensitive = process.platform === "win32";
2228
- const resolvedFileRaw = path.resolve(dir, filePath);
2229
- const resolvedFile = caseInsensitive ? resolvedFileRaw.toLowerCase() : resolvedFileRaw;
2230
- return scopeEntries.some((scope) => {
2231
- const resolvedScopeRaw = path.resolve(dir, scope);
2232
- const resolvedScope = caseInsensitive ? resolvedScopeRaw.toLowerCase() : resolvedScopeRaw;
2233
- if (resolvedFile === resolvedScope)
2234
- return true;
2235
- const rel = path.relative(resolvedScope, resolvedFile);
2236
- return rel.length > 0 && !rel.startsWith("..") && !path.isAbsolute(rel);
2237
- });
2281
+ var BUILT_IN_VERIFIER_CONFIG_GLOBS = [
2282
+ "**/oxlintrc*",
2283
+ "**/.oxlintrc*",
2284
+ "**/.eslintrc*",
2285
+ "**/eslint.config.*",
2286
+ "**/.prettierrc*",
2287
+ "**/prettier.config.*",
2288
+ "**/biome.json",
2289
+ "**/biome.jsonc",
2290
+ "**/tsconfig*.json",
2291
+ "**/.secretscanignore",
2292
+ "**/.golangci*"
2293
+ ];
2294
+ function denyAuthority(agent, normalizedPath, input) {
2295
+ const safeAgent = sanitizeDiagnosticText(agent, 96);
2296
+ const safePath = sanitizeDiagnosticText(normalizedPath, 320);
2297
+ const safeDetail = sanitizeDiagnosticText(input.detail, 640);
2298
+ return {
2299
+ allowed: false,
2300
+ code: input.code,
2301
+ layer: input.layer,
2302
+ rule: sanitizeDiagnosticText(input.rule, 128),
2303
+ path: safePath,
2304
+ agent: safeAgent,
2305
+ reason: sanitizeDiagnosticText(`${input.code}: Path blocked: ${safeDetail} [agent=${safeAgent}; path=${safePath}]`, 1024),
2306
+ recovery: input.recovery,
2307
+ zone: input.zone
2308
+ };
2238
2309
  }
2239
2310
  var MAX_ALLOWED_HINT_ENTRIES = 20;
2240
2311
  function formatAllowedHints(rules) {
@@ -2258,10 +2329,19 @@ function formatAllowedHints(rules) {
2258
2329
  parts.push("Block rules (blocked zones/prefixes/globs/exact) and universal deny paths still apply.");
2259
2330
  return parts.join(" ");
2260
2331
  }
2261
- function checkFileAuthorityWithRules(agentName, filePath, cwd, effectiveRules, options) {
2332
+ function checkFileAuthorityWithRules(agentName, filePath, cwd, effectiveRules, options = {}) {
2262
2333
  const normalizedAgent = agentName.toLowerCase();
2263
2334
  const strippedAgent = stripKnownSwarmPrefix(agentName).toLowerCase();
2264
2335
  const dir = cwd || process.cwd();
2336
+ const unsafePathReason = unsafePathTextReason(filePath);
2337
+ if (unsafePathReason) {
2338
+ return denyAuthority(agentName, filePath, {
2339
+ code: "AUTHORITY_INVALID_PATH",
2340
+ layer: "path-validation",
2341
+ rule: "safe-path-text",
2342
+ detail: unsafePathReason
2343
+ });
2344
+ }
2265
2345
  let normalizedPath;
2266
2346
  let resolvedTarget;
2267
2347
  try {
@@ -2273,71 +2353,160 @@ function checkFileAuthorityWithRules(agentName, filePath, cwd, effectiveRules, o
2273
2353
  normalizedPath = path.relative(dir, resolvedTarget).replace(/\\/g, "/");
2274
2354
  }
2275
2355
  if (isOnDifferentFilesystemRoot(resolvedTarget, dir)) {
2276
- return {
2277
- allowed: false,
2278
- reason: `Path blocked: ${filePath} is on a different drive/root than the working directory`
2279
- };
2356
+ return denyAuthority(agentName, normalizedPath, {
2357
+ code: "AUTHORITY_ROOT_ESCAPE",
2358
+ layer: "containment",
2359
+ rule: "same-filesystem-root",
2360
+ detail: "target is on a different drive or filesystem root"
2361
+ });
2280
2362
  }
2281
2363
  if (normalizedPath === ".." || normalizedPath.startsWith("../")) {
2282
- return {
2283
- allowed: false,
2284
- reason: `Path blocked: ${normalizedPath} resolves outside the working directory`
2285
- };
2364
+ return denyAuthority(agentName, normalizedPath, {
2365
+ code: "AUTHORITY_ROOT_ESCAPE",
2366
+ layer: "containment",
2367
+ rule: "workspace-containment",
2368
+ detail: "target resolves outside the working directory"
2369
+ });
2286
2370
  }
2287
2371
  const rules = effectiveRules[normalizedAgent] ?? effectiveRules[strippedAgent];
2288
2372
  if (!rules) {
2289
- return { allowed: false, reason: `Unknown agent: ${agentName}` };
2373
+ return denyAuthority(agentName, normalizedPath, {
2374
+ code: "AUTHORITY_UNKNOWN_AGENT",
2375
+ layer: "role-capability",
2376
+ rule: "known-agent-role",
2377
+ detail: "Unknown agent: no authority classification exists"
2378
+ });
2379
+ }
2380
+ const flavor = getPathFlavor();
2381
+ const matchesPathPrefix = (candidate, prefix) => isPathIdentityWithin(path.resolve(dir, candidate), path.resolve(dir, prefix), flavor);
2382
+ const matchesGlob = (glob) => getGlobMatcher(glob)(normalizedPath);
2383
+ for (const prefix of options.universalDenyPrefixes ?? []) {
2384
+ if (matchesAuthorityDenyPrefix(normalizedPath, prefix, dir, flavor)) {
2385
+ return denyAuthority(agentName, normalizedPath, {
2386
+ code: "AUTHORITY_UNIVERSAL_DENY",
2387
+ layer: "universal-deny",
2388
+ rule: `universal:${prefix}`,
2389
+ detail: `target is under universal deny prefix ${prefix}`
2390
+ });
2391
+ }
2392
+ }
2393
+ const isCoderAgent = normalizedAgent === "coder" || strippedAgent === "coder";
2394
+ if (isCoderAgent && matchesPathPrefix(normalizedPath, ".swarm")) {
2395
+ return denyAuthority(agentName, normalizedPath, {
2396
+ code: "AUTHORITY_PROTECTED_PATH",
2397
+ layer: "protected-path",
2398
+ rule: "coder-swarm-state-protection",
2399
+ detail: "coder writes to .swarm are always protected"
2400
+ });
2401
+ }
2402
+ const isSwarmRole = Object.hasOwn(AUTHORITY_ROLE_CAPABILITIES, strippedAgent);
2403
+ if (isSwarmRole) {
2404
+ const matchedVerifier = [
2405
+ ...BUILT_IN_VERIFIER_CONFIG_GLOBS,
2406
+ ...options.verifierConfigPaths ?? []
2407
+ ].find(matchesGlob);
2408
+ if (matchedVerifier) {
2409
+ return denyAuthority(agentName, normalizedPath, {
2410
+ code: "AUTHORITY_VERIFIER_CONFIG",
2411
+ layer: "protected-path",
2412
+ rule: `verifier-config:${matchedVerifier}`,
2413
+ detail: `Path blocked (glob ${matchedVerifier}): swarm roles cannot write verifier-owned configuration in the config zone`
2414
+ });
2415
+ }
2416
+ }
2417
+ const canonicalCapability = AUTHORITY_ROLE_CAPABILITIES[strippedAgent];
2418
+ if (canonicalCapability === "read-only" || canonicalCapability === "dedicated-tool-only") {
2419
+ return denyAuthority(agentName, normalizedPath, {
2420
+ code: "AUTHORITY_ROLE_READ_ONLY",
2421
+ layer: "role-capability",
2422
+ rule: `role-capability:${canonicalCapability}`,
2423
+ detail: canonicalCapability === "dedicated-tool-only" ? "role may mutate state only through dedicated tools" : "agent role is read-only"
2424
+ });
2290
2425
  }
2291
2426
  if (rules.readOnly) {
2427
+ return denyAuthority(agentName, normalizedPath, {
2428
+ code: "AUTHORITY_ROLE_READ_ONLY",
2429
+ layer: "role-capability",
2430
+ rule: "role-policy:read-only",
2431
+ detail: "agent role is read-only"
2432
+ });
2433
+ }
2434
+ const pathIsInDeclaredScope = isCoderAgent && options.declaredScope != null && options.declaredScope.length > 0 && isPathWithinDeclaredScope(normalizedPath, options.declaredScope, dir);
2435
+ if (pathIsInDeclaredScope) {
2292
2436
  return {
2293
- allowed: false,
2294
- reason: `Path blocked: ${normalizedPath} (agent ${normalizedAgent} is read-only)`
2437
+ allowed: true,
2438
+ layer: "declared-scope",
2439
+ path: sanitizeDiagnosticText(normalizedPath, 320),
2440
+ agent: sanitizeDiagnosticText(agentName, 96)
2441
+ };
2442
+ }
2443
+ if (options.authorityEnabled === false) {
2444
+ return {
2445
+ allowed: true,
2446
+ layer: "role-policy",
2447
+ path: sanitizeDiagnosticText(normalizedPath, 320),
2448
+ agent: sanitizeDiagnosticText(agentName, 96)
2295
2449
  };
2296
2450
  }
2297
2451
  if (rules.blockedExact) {
2298
2452
  for (const blocked of rules.blockedExact) {
2299
- if (normalizedPath === blocked) {
2300
- return {
2301
- allowed: false,
2302
- reason: `Path blocked (exact): ${normalizedPath}`
2303
- };
2453
+ if (pathIdentitiesEqual(normalizedPath, blocked, flavor)) {
2454
+ return denyAuthority(agentName, normalizedPath, {
2455
+ code: "AUTHORITY_POLICY_DENY",
2456
+ layer: "role-policy",
2457
+ rule: `blockedExact:${blocked}`,
2458
+ detail: `path is blocked by exact role policy ${blocked}`,
2459
+ recovery: isCoderAgent ? "declare_scope" : undefined
2460
+ });
2304
2461
  }
2305
2462
  }
2306
2463
  }
2307
2464
  if (rules.blockedGlobs && rules.blockedGlobs.length > 0) {
2308
2465
  for (const glob of rules.blockedGlobs) {
2309
- const matcher = getGlobMatcher(glob);
2310
- if (matcher(normalizedPath)) {
2311
- return {
2312
- allowed: false,
2313
- reason: `Path blocked (glob ${glob}): ${normalizedPath}`
2314
- };
2466
+ if (matchesGlob(glob)) {
2467
+ return denyAuthority(agentName, normalizedPath, {
2468
+ code: "AUTHORITY_POLICY_DENY",
2469
+ layer: "role-policy",
2470
+ rule: `blockedGlob:${glob}`,
2471
+ detail: `Path blocked (glob ${glob}) by role policy`,
2472
+ recovery: isCoderAgent ? "declare_scope" : undefined
2473
+ });
2315
2474
  }
2316
2475
  }
2317
2476
  }
2318
2477
  if (rules.allowedExact && rules.allowedExact.length > 0) {
2319
- const isExplicitlyAllowed = rules.allowedExact.some((allowed) => normalizedPath === allowed);
2478
+ const isExplicitlyAllowed = rules.allowedExact.some((allowed) => pathIdentitiesEqual(normalizedPath, allowed, flavor));
2320
2479
  if (isExplicitlyAllowed) {
2321
- return { allowed: true };
2480
+ return {
2481
+ allowed: true,
2482
+ layer: "role-policy",
2483
+ path: normalizedPath,
2484
+ agent: agentName
2485
+ };
2322
2486
  }
2323
2487
  }
2324
2488
  if (rules.blockedZones && rules.blockedZones.length > 0) {
2325
2489
  const { zone } = classifyFile(normalizedPath);
2326
2490
  if (rules.blockedZones.includes(zone)) {
2327
- return {
2328
- allowed: false,
2329
- reason: `Path blocked: ${normalizedPath} is in ${zone} zone`,
2491
+ return denyAuthority(agentName, normalizedPath, {
2492
+ code: "AUTHORITY_POLICY_DENY",
2493
+ layer: "role-policy",
2494
+ rule: `blockedZone:${zone}`,
2495
+ detail: `path is in ${zone} zone`,
2496
+ recovery: isCoderAgent ? "declare_scope" : undefined,
2330
2497
  zone
2331
- };
2498
+ });
2332
2499
  }
2333
2500
  }
2334
2501
  if (rules.allowedGlobs && rules.allowedGlobs.length > 0) {
2335
- const isGlobAllowed = rules.allowedGlobs.some((glob) => {
2336
- const matcher = getGlobMatcher(glob);
2337
- return matcher(normalizedPath);
2338
- });
2502
+ const isGlobAllowed = rules.allowedGlobs.some(matchesGlob);
2339
2503
  if (isGlobAllowed) {
2340
- return { allowed: true };
2504
+ return {
2505
+ allowed: true,
2506
+ layer: "role-policy",
2507
+ path: normalizedPath,
2508
+ agent: agentName
2509
+ };
2341
2510
  }
2342
2511
  }
2343
2512
  if (rules.allowedCaseSensitiveGlobs && rules.allowedCaseSensitiveGlobs.length > 0) {
@@ -2346,59 +2515,67 @@ function checkFileAuthorityWithRules(agentName, filePath, cwd, effectiveRules, o
2346
2515
  return matcher(normalizedPath);
2347
2516
  });
2348
2517
  if (isCaseSensitiveGlobAllowed) {
2349
- return { allowed: true };
2518
+ return {
2519
+ allowed: true,
2520
+ layer: "role-policy",
2521
+ path: normalizedPath,
2522
+ agent: agentName
2523
+ };
2350
2524
  }
2351
2525
  }
2352
2526
  if (rules.blockedPrefix && rules.blockedPrefix.length > 0) {
2353
2527
  for (const prefix of rules.blockedPrefix) {
2354
- if (normalizedPath.startsWith(prefix)) {
2355
- return {
2356
- allowed: false,
2357
- reason: `Path blocked: ${normalizedPath} is under ${prefix}`
2358
- };
2359
- }
2360
- }
2361
- }
2362
- const isCoderAgent = normalizedAgent === "coder" || strippedAgent === "coder";
2363
- const pathIsInDeclaredScope = isCoderAgent && options?.declaredScope != null && options.declaredScope.length > 0 && isInDeclaredScope(normalizedPath, options.declaredScope, dir);
2364
- if (!pathIsInDeclaredScope) {
2365
- if (rules.allowedPrefix != null && rules.allowedPrefix.length > 0) {
2366
- const isAllowed = rules.allowedPrefix.some((prefix) => normalizedPath.startsWith(prefix));
2367
- if (!isAllowed) {
2368
- return {
2369
- allowed: false,
2370
- reason: `Path ${normalizedPath} not in allowed list for ${normalizedAgent}. ${formatAllowedHints(rules)}`
2371
- };
2372
- }
2373
- } else if (rules.allowedPrefix != null && rules.allowedPrefix.length === 0) {
2374
- return {
2375
- allowed: false,
2376
- reason: `Path ${normalizedPath} not in allowed list for ${normalizedAgent}. ${formatAllowedHints(rules)}`
2377
- };
2528
+ if (matchesPathPrefix(normalizedPath, prefix)) {
2529
+ return denyAuthority(agentName, normalizedPath, {
2530
+ code: "AUTHORITY_POLICY_DENY",
2531
+ layer: "role-policy",
2532
+ rule: `blockedPrefix:${prefix}`,
2533
+ detail: `path is under blocked role prefix ${prefix}`,
2534
+ recovery: isCoderAgent ? "declare_scope" : undefined
2535
+ });
2536
+ }
2537
+ }
2538
+ }
2539
+ if (rules.allowedPrefix != null && rules.allowedPrefix.length > 0) {
2540
+ const isAllowed = rules.allowedPrefix.some((prefix) => matchesPathPrefix(normalizedPath, prefix));
2541
+ if (!isAllowed) {
2542
+ return denyAuthority(agentName, normalizedPath, {
2543
+ code: "AUTHORITY_POLICY_DENY",
2544
+ layer: "role-policy",
2545
+ rule: "allowedPrefix",
2546
+ detail: `path is not in allowed list for this role. ${formatAllowedHints(rules)}`,
2547
+ recovery: isCoderAgent ? "declare_scope" : undefined
2548
+ });
2378
2549
  }
2550
+ } else if (rules.allowedPrefix != null && rules.allowedPrefix.length === 0) {
2551
+ return denyAuthority(agentName, normalizedPath, {
2552
+ code: "AUTHORITY_POLICY_DENY",
2553
+ layer: "role-policy",
2554
+ rule: "allowedPrefix:empty",
2555
+ detail: `path is not in allowed list because the role allowlist is empty. ${formatAllowedHints(rules)}`,
2556
+ recovery: isCoderAgent ? "declare_scope" : undefined
2557
+ });
2379
2558
  }
2380
- return { allowed: true };
2559
+ return {
2560
+ allowed: true,
2561
+ layer: "role-policy",
2562
+ path: normalizedPath,
2563
+ agent: agentName
2564
+ };
2381
2565
  }
2382
- function checkFileAuthority(agentName, filePath, cwd, authorityConfig, options) {
2383
- return checkFileAuthorityWithRules(agentName, filePath, cwd, buildEffectiveRules(authorityConfig), options);
2566
+ function checkFileAuthority(agentName, filePath, cwd, authorityConfig, options = {}) {
2567
+ return checkFileAuthorityWithRules(agentName, filePath, cwd, buildEffectiveRules(authorityConfig), {
2568
+ ...options,
2569
+ authorityEnabled: authorityConfig?.enabled ?? options.authorityEnabled,
2570
+ universalDenyPrefixes: authorityConfig?.universal_deny_prefixes ?? options.universalDenyPrefixes,
2571
+ verifierConfigPaths: authorityConfig?.verifier_config_paths ?? options.verifierConfigPaths
2572
+ });
2384
2573
  }
2385
2574
 
2386
2575
  // src/hooks/guardrails/helpers.ts
2387
2576
  init_constants();
2388
- import * as path2 from "path";
2389
- function isInDeclaredScope2(filePath, scopeEntries, cwd) {
2390
- const dir = cwd ?? process.cwd();
2391
- const caseInsensitive = process.platform === "win32";
2392
- const resolvedFileRaw = path2.resolve(dir, filePath);
2393
- const resolvedFile = caseInsensitive ? resolvedFileRaw.toLowerCase() : resolvedFileRaw;
2394
- return scopeEntries.some((scope) => {
2395
- const resolvedScopeRaw = path2.resolve(dir, scope);
2396
- const resolvedScope = caseInsensitive ? resolvedScopeRaw.toLowerCase() : resolvedScopeRaw;
2397
- if (resolvedFile === resolvedScope)
2398
- return true;
2399
- const rel = path2.relative(resolvedScope, resolvedFile);
2400
- return rel.length > 0 && !rel.startsWith("..") && !path2.isAbsolute(rel);
2401
- });
2577
+ function isInDeclaredScope(filePath, scopeEntries, cwd) {
2578
+ return isPathWithinDeclaredScope(filePath, scopeEntries, cwd);
2402
2579
  }
2403
2580
  function redactShellCommand(cmd) {
2404
2581
  if (typeof cmd !== "string")
@@ -2414,7 +2591,7 @@ function redactShellCommand(cmd) {
2414
2591
 
2415
2592
  // src/hooks/guardrails/audit-log.ts
2416
2593
  init_logger();
2417
- import * as path3 from "path";
2594
+ import * as path2 from "path";
2418
2595
  function redactPath(filePath) {
2419
2596
  if (typeof filePath !== "string" || filePath.length === 0)
2420
2597
  return filePath;
@@ -2426,7 +2603,7 @@ function redactPath(filePath) {
2426
2603
  if (rawMacHomeMatch) {
2427
2604
  return `~${rawMacHomeMatch[2]}`;
2428
2605
  }
2429
- const normalized = path3.normalize(filePath);
2606
+ const normalized = path2.normalize(filePath);
2430
2607
  const windowsHomeMatch = normalized.match(/^([A-Za-z]:\\Users\\[^\\]+)(\\.*)$/);
2431
2608
  if (windowsHomeMatch) {
2432
2609
  return `~\\${windowsHomeMatch[2]}`;
@@ -2438,4 +2615,4 @@ function redactPath(filePath) {
2438
2615
  return normalized;
2439
2616
  }
2440
2617
 
2441
- export { stableCanonicalStringify, classifyFile, checkFileAuthority, isInDeclaredScope2 as isInDeclaredScope, redactShellCommand, redactPath };
2618
+ export { stableCanonicalStringify, classifyFile, checkFileAuthority, isInDeclaredScope, redactShellCommand, redactPath };
@@ -2,18 +2,18 @@
2
2
  import {
3
3
  ALLOWED_SKILL_PATH_PREFIXES,
4
4
  validateSkillPath
5
- } from "./index-tc61fybd.js";
5
+ } from "./index-tjwz5tct.js";
6
6
  import {
7
7
  computeOutcomeSignal,
8
8
  readKnowledge,
9
9
  resolveHiveKnowledgePath,
10
10
  resolveSwarmKnowledgePath,
11
11
  transactKnowledge
12
- } from "./index-1djv5684.js";
12
+ } from "./index-1g6xpjk3.js";
13
13
  import {
14
14
  effectiveRetrievalOutcomes,
15
15
  readKnowledgeCounterRollups
16
- } from "./index-93ky909v.js";
16
+ } from "./index-57stye65.js";
17
17
  import {
18
18
  init_knowledge_types,
19
19
  isActiveStatus