@skj1724/oh-my-opencode 4.0.2 → 4.0.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/dist/cli/index.js CHANGED
@@ -6165,10 +6165,121 @@ var init_session_cursor = __esm(() => {
6165
6165
  // src/shared/system-directive.ts
6166
6166
  var init_system_directive = () => {};
6167
6167
 
6168
+ // src/shared/agent-permissions.ts
6169
+ var DEFAULT_AGENT_PERMISSIONS, ALL_DEFINED_AGENTS, toolRestrictionsCache, sdkPermissionCache;
6170
+ var init_agent_permissions = __esm(() => {
6171
+ DEFAULT_AGENT_PERMISSIONS = {
6172
+ "\u6218\u7565\u53C2\u8C0B": {
6173
+ canReadFiles: true,
6174
+ canWriteFiles: false,
6175
+ canExecuteCommands: true,
6176
+ canDelegateTasks: true,
6177
+ allowedCategories: ["quick"],
6178
+ sdkPermissionOverrides: { call_omo_agent: "deny", question: "allow" }
6179
+ },
6180
+ "\u6DF1\u5EA6\u63A2\u7D22": {
6181
+ canReadFiles: true,
6182
+ canWriteFiles: false,
6183
+ canExecuteCommands: false,
6184
+ canDelegateTasks: false,
6185
+ allowedCategories: []
6186
+ },
6187
+ "\u77E5\u8BC6\u5178\u85CF": {
6188
+ canReadFiles: true,
6189
+ canWriteFiles: false,
6190
+ canExecuteCommands: false,
6191
+ canDelegateTasks: false,
6192
+ allowedCategories: [],
6193
+ sdkPermissionOverrides: { "grep_app_*": "allow" }
6194
+ },
6195
+ "\u6280\u672F\u53C2\u8C0B": {
6196
+ canReadFiles: true,
6197
+ canWriteFiles: false,
6198
+ canExecuteCommands: false,
6199
+ canDelegateTasks: false,
6200
+ allowedCategories: []
6201
+ },
6202
+ "\u9884\u5BA1\u987E\u95EE": {
6203
+ canReadFiles: true,
6204
+ canWriteFiles: false,
6205
+ canExecuteCommands: false,
6206
+ canDelegateTasks: false,
6207
+ allowedCategories: []
6208
+ },
6209
+ "\u8BA1\u5212\u5BA1\u67E5": {
6210
+ canReadFiles: true,
6211
+ canWriteFiles: false,
6212
+ canExecuteCommands: false,
6213
+ canDelegateTasks: false,
6214
+ allowedCategories: []
6215
+ },
6216
+ "\u5A92\u4F53\u89E3\u6790": {
6217
+ canReadFiles: true,
6218
+ canWriteFiles: false,
6219
+ canExecuteCommands: false,
6220
+ canDelegateTasks: false,
6221
+ allowedCategories: [],
6222
+ toolMode: "whitelist",
6223
+ toolOverrides: { read: true },
6224
+ sdkPermissionOverrides: { task: "deny", look_at: "deny" }
6225
+ },
6226
+ "BTW \u987E\u95EE": {
6227
+ canReadFiles: true,
6228
+ canWriteFiles: false,
6229
+ canExecuteCommands: false,
6230
+ canDelegateTasks: false,
6231
+ allowedCategories: [],
6232
+ toolOverrides: { slashcommand: false }
6233
+ },
6234
+ "\u4E3B\u6267\u884C\u5B98": {
6235
+ canReadFiles: true,
6236
+ canWriteFiles: true,
6237
+ canExecuteCommands: true,
6238
+ canDelegateTasks: true,
6239
+ allowedCategories: [
6240
+ "visual-engineering",
6241
+ "ultrabrain",
6242
+ "artistry",
6243
+ "quick",
6244
+ "unspecified-low",
6245
+ "unspecified-high",
6246
+ "writing"
6247
+ ],
6248
+ sdkPermissionOverrides: { call_omo_agent: "deny", question: "allow" }
6249
+ },
6250
+ "\u4EFB\u52A1\u7F16\u6392": {
6251
+ canReadFiles: true,
6252
+ canWriteFiles: true,
6253
+ canExecuteCommands: true,
6254
+ canDelegateTasks: true,
6255
+ allowedCategories: [
6256
+ "visual-engineering",
6257
+ "ultrabrain",
6258
+ "artistry",
6259
+ "quick",
6260
+ "unspecified-low",
6261
+ "unspecified-high",
6262
+ "writing"
6263
+ ],
6264
+ sdkPermissionOverrides: { task: "deny", call_omo_agent: "deny" }
6265
+ },
6266
+ "\u6267\u884C\u52A9\u7406": {
6267
+ canReadFiles: true,
6268
+ canWriteFiles: true,
6269
+ canExecuteCommands: true,
6270
+ canDelegateTasks: false,
6271
+ allowedCategories: [],
6272
+ sdkPermissionOverrides: { delegate_task: "allow" }
6273
+ }
6274
+ };
6275
+ ALL_DEFINED_AGENTS = Object.freeze(Object.keys(DEFAULT_AGENT_PERMISSIONS));
6276
+ toolRestrictionsCache = new Map;
6277
+ sdkPermissionCache = new Map;
6278
+ });
6279
+
6168
6280
  // src/shared/agent-tool-restrictions.ts
6169
6281
  var init_agent_tool_restrictions = __esm(() => {
6170
- init_case_insensitive();
6171
- init_agent_display_names();
6282
+ init_agent_permissions();
6172
6283
  });
6173
6284
 
6174
6285
  // src/shared/model-requirements.ts
@@ -6494,6 +6605,7 @@ var init_shared = __esm(() => {
6494
6605
  init_agent_variant();
6495
6606
  init_session_cursor();
6496
6607
  init_system_directive();
6608
+ init_agent_permissions();
6497
6609
  init_agent_tool_restrictions();
6498
6610
  init_model_requirements();
6499
6611
  init_model_resolver();
@@ -8737,7 +8849,7 @@ var import_picocolors2 = __toESM(require_picocolors(), 1);
8737
8849
  // package.json
8738
8850
  var package_default = {
8739
8851
  name: "@skj1724/oh-my-opencode",
8740
- version: "4.0.02",
8852
+ version: "4.0.04",
8741
8853
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
8742
8854
  main: "dist/index.js",
8743
8855
  types: "dist/index.d.ts",
@@ -1,11 +1,11 @@
1
1
  export declare const HOOK_NAME = "prometheus-md-only";
2
2
  export declare const PROMETHEUS_AGENTS: string[];
3
3
  /**
4
- * 战略参谋允许调用的 delegate_task category 白名单。
5
- * 仅允许 "quick" category(用于轻量研究),防止战略参谋
6
- * 绕过只读约束通过委派任务执行修改操作。
4
+ * 获取指定 agent 允许的 delegate_task category 白名单。
5
+ * agent-permissions.ts 统一读取,确保与权限定义一致。
6
+ * 自定义 agent 默认返回空数组(default-deny)。
7
7
  */
8
- export declare const AGENT_CATEGORY_WHITELIST: Record<string, string[]>;
8
+ export declare function getAllowedCategoriesForAgent(agentName: string): string[];
9
9
  export declare const ALLOWED_EXTENSIONS: string[];
10
10
  export declare const ALLOWED_PATH_PREFIX = ".sisyphus";
11
11
  export declare const BLOCKED_TOOLS: string[];
package/dist/index.js CHANGED
@@ -5075,47 +5075,215 @@ var sessionCursors;
5075
5075
  var init_session_cursor = __esm(() => {
5076
5076
  sessionCursors = new Map;
5077
5077
  });
5078
- // src/shared/agent-tool-restrictions.ts
5079
- function getAgentToolRestrictions(agentName) {
5080
- return findCaseInsensitive(AGENT_RESTRICTIONS, resolveAgentName(agentName)) ?? {};
5078
+ // src/shared/agent-permissions.ts
5079
+ function getAgentPermission(agentName) {
5080
+ const exact = DEFAULT_AGENT_PERMISSIONS[agentName];
5081
+ if (exact !== undefined)
5082
+ return { ...exact };
5083
+ const lower = agentName.toLowerCase();
5084
+ for (const [key, perm] of Object.entries(DEFAULT_AGENT_PERMISSIONS)) {
5085
+ if (key.toLowerCase() === lower)
5086
+ return { ...perm };
5087
+ }
5088
+ return { ...NEW_AGENT_DEFAULT };
5081
5089
  }
5082
- var EXPLORATION_AGENT_DENYLIST, AGENT_RESTRICTIONS;
5083
- var init_agent_tool_restrictions = __esm(() => {
5084
- init_case_insensitive();
5085
- init_agent_display_names();
5086
- EXPLORATION_AGENT_DENYLIST = {
5087
- write: false,
5088
- edit: false,
5089
- task: false,
5090
- delegate_task: false,
5091
- call_omo_agent: false
5092
- };
5093
- AGENT_RESTRICTIONS = {
5094
- "\u6DF1\u5EA6\u63A2\u7D22": EXPLORATION_AGENT_DENYLIST,
5095
- "\u77E5\u8BC6\u5178\u85CF": EXPLORATION_AGENT_DENYLIST,
5090
+ function deriveToolRestrictions(agentName) {
5091
+ const cached = toolRestrictionsCache.get(agentName);
5092
+ if (cached !== undefined)
5093
+ return cached;
5094
+ const perm = getAgentPermission(agentName);
5095
+ let restrictions;
5096
+ if (perm.toolMode === "whitelist") {
5097
+ restrictions = { ...perm.toolOverrides };
5098
+ } else {
5099
+ restrictions = {};
5100
+ if (!perm.canWriteFiles) {
5101
+ restrictions.write = false;
5102
+ restrictions.edit = false;
5103
+ restrictions.ast_grep_replace = false;
5104
+ restrictions.lsp_rename = false;
5105
+ }
5106
+ if (!perm.canExecuteCommands) {
5107
+ restrictions.bash = false;
5108
+ }
5109
+ if (!perm.canDelegateTasks) {
5110
+ restrictions.delegate_task = false;
5111
+ restrictions.task = false;
5112
+ restrictions.call_omo_agent = false;
5113
+ }
5114
+ if (perm.toolOverrides) {
5115
+ for (const [key, value] of Object.entries(perm.toolOverrides)) {
5116
+ restrictions[key] = value;
5117
+ }
5118
+ }
5119
+ }
5120
+ toolRestrictionsCache.set(agentName, restrictions);
5121
+ return restrictions;
5122
+ }
5123
+ function canDelegateTo(parentAgent, targetAgent, category) {
5124
+ const parent = getAgentPermission(parentAgent);
5125
+ const target = getAgentPermission(targetAgent);
5126
+ if (!parent.canDelegateTasks)
5127
+ return false;
5128
+ if (!parent.canWriteFiles) {
5129
+ if (category !== undefined) {
5130
+ const allowed = parent.allowedCategories.map((c) => c.toLowerCase());
5131
+ if (!allowed.includes(category.toLowerCase()))
5132
+ return false;
5133
+ }
5134
+ if (target.canWriteFiles)
5135
+ return false;
5136
+ }
5137
+ return true;
5138
+ }
5139
+ function deriveSdkPermission(agentName) {
5140
+ const cached = sdkPermissionCache.get(agentName);
5141
+ if (cached !== undefined)
5142
+ return cached;
5143
+ const perm = getAgentPermission(agentName);
5144
+ const permission = {};
5145
+ if (!perm.canWriteFiles) {
5146
+ permission.write = "deny";
5147
+ permission.edit = "deny";
5148
+ }
5149
+ if (!perm.canExecuteCommands) {
5150
+ permission.bash = "deny";
5151
+ }
5152
+ if (perm.canDelegateTasks) {
5153
+ permission.delegate_task = "allow";
5154
+ }
5155
+ if (perm.sdkPermissionOverrides) {
5156
+ for (const [key, value] of Object.entries(perm.sdkPermissionOverrides)) {
5157
+ permission[key] = value;
5158
+ }
5159
+ }
5160
+ sdkPermissionCache.set(agentName, permission);
5161
+ return permission;
5162
+ }
5163
+ var DEFAULT_AGENT_PERMISSIONS, ALL_DEFINED_AGENTS, NEW_AGENT_DEFAULT, toolRestrictionsCache, sdkPermissionCache;
5164
+ var init_agent_permissions = __esm(() => {
5165
+ DEFAULT_AGENT_PERMISSIONS = {
5166
+ "\u6218\u7565\u53C2\u8C0B": {
5167
+ canReadFiles: true,
5168
+ canWriteFiles: false,
5169
+ canExecuteCommands: true,
5170
+ canDelegateTasks: true,
5171
+ allowedCategories: ["quick"],
5172
+ sdkPermissionOverrides: { call_omo_agent: "deny", question: "allow" }
5173
+ },
5174
+ "\u6DF1\u5EA6\u63A2\u7D22": {
5175
+ canReadFiles: true,
5176
+ canWriteFiles: false,
5177
+ canExecuteCommands: false,
5178
+ canDelegateTasks: false,
5179
+ allowedCategories: []
5180
+ },
5181
+ "\u77E5\u8BC6\u5178\u85CF": {
5182
+ canReadFiles: true,
5183
+ canWriteFiles: false,
5184
+ canExecuteCommands: false,
5185
+ canDelegateTasks: false,
5186
+ allowedCategories: [],
5187
+ sdkPermissionOverrides: { "grep_app_*": "allow" }
5188
+ },
5096
5189
  "\u6280\u672F\u53C2\u8C0B": {
5097
- write: false,
5098
- edit: false,
5099
- task: false,
5100
- delegate_task: false
5190
+ canReadFiles: true,
5191
+ canWriteFiles: false,
5192
+ canExecuteCommands: false,
5193
+ canDelegateTasks: false,
5194
+ allowedCategories: []
5101
5195
  },
5102
- "\u5A92\u4F53\u89E3\u6790": {
5103
- read: true
5196
+ "\u9884\u5BA1\u987E\u95EE": {
5197
+ canReadFiles: true,
5198
+ canWriteFiles: false,
5199
+ canExecuteCommands: false,
5200
+ canDelegateTasks: false,
5201
+ allowedCategories: []
5104
5202
  },
5105
- "\u6267\u884C\u52A9\u7406": {
5106
- task: false,
5107
- delegate_task: false
5203
+ "\u8BA1\u5212\u5BA1\u67E5": {
5204
+ canReadFiles: true,
5205
+ canWriteFiles: false,
5206
+ canExecuteCommands: false,
5207
+ canDelegateTasks: false,
5208
+ allowedCategories: []
5209
+ },
5210
+ "\u5A92\u4F53\u89E3\u6790": {
5211
+ canReadFiles: true,
5212
+ canWriteFiles: false,
5213
+ canExecuteCommands: false,
5214
+ canDelegateTasks: false,
5215
+ allowedCategories: [],
5216
+ toolMode: "whitelist",
5217
+ toolOverrides: { read: true },
5218
+ sdkPermissionOverrides: { task: "deny", look_at: "deny" }
5108
5219
  },
5109
5220
  "BTW \u987E\u95EE": {
5110
- write: false,
5111
- edit: false,
5112
- bash: false,
5113
- task: false,
5114
- delegate_task: false,
5115
- call_omo_agent: false,
5116
- slashcommand: false
5221
+ canReadFiles: true,
5222
+ canWriteFiles: false,
5223
+ canExecuteCommands: false,
5224
+ canDelegateTasks: false,
5225
+ allowedCategories: [],
5226
+ toolOverrides: { slashcommand: false }
5227
+ },
5228
+ "\u4E3B\u6267\u884C\u5B98": {
5229
+ canReadFiles: true,
5230
+ canWriteFiles: true,
5231
+ canExecuteCommands: true,
5232
+ canDelegateTasks: true,
5233
+ allowedCategories: [
5234
+ "visual-engineering",
5235
+ "ultrabrain",
5236
+ "artistry",
5237
+ "quick",
5238
+ "unspecified-low",
5239
+ "unspecified-high",
5240
+ "writing"
5241
+ ],
5242
+ sdkPermissionOverrides: { call_omo_agent: "deny", question: "allow" }
5243
+ },
5244
+ "\u4EFB\u52A1\u7F16\u6392": {
5245
+ canReadFiles: true,
5246
+ canWriteFiles: true,
5247
+ canExecuteCommands: true,
5248
+ canDelegateTasks: true,
5249
+ allowedCategories: [
5250
+ "visual-engineering",
5251
+ "ultrabrain",
5252
+ "artistry",
5253
+ "quick",
5254
+ "unspecified-low",
5255
+ "unspecified-high",
5256
+ "writing"
5257
+ ],
5258
+ sdkPermissionOverrides: { task: "deny", call_omo_agent: "deny" }
5259
+ },
5260
+ "\u6267\u884C\u52A9\u7406": {
5261
+ canReadFiles: true,
5262
+ canWriteFiles: true,
5263
+ canExecuteCommands: true,
5264
+ canDelegateTasks: false,
5265
+ allowedCategories: [],
5266
+ sdkPermissionOverrides: { delegate_task: "allow" }
5117
5267
  }
5118
5268
  };
5269
+ ALL_DEFINED_AGENTS = Object.freeze(Object.keys(DEFAULT_AGENT_PERMISSIONS));
5270
+ NEW_AGENT_DEFAULT = {
5271
+ canReadFiles: true,
5272
+ canWriteFiles: false,
5273
+ canExecuteCommands: false,
5274
+ canDelegateTasks: false,
5275
+ allowedCategories: []
5276
+ };
5277
+ toolRestrictionsCache = new Map;
5278
+ sdkPermissionCache = new Map;
5279
+ });
5280
+
5281
+ // src/shared/agent-tool-restrictions.ts
5282
+ function getAgentToolRestrictions(agentName) {
5283
+ return deriveToolRestrictions(agentName);
5284
+ }
5285
+ var init_agent_tool_restrictions = __esm(() => {
5286
+ init_agent_permissions();
5119
5287
  });
5120
5288
 
5121
5289
  // src/shared/model-requirements.ts
@@ -6292,6 +6460,7 @@ var init_shared = __esm(() => {
6292
6460
  init_agent_variant();
6293
6461
  init_session_cursor();
6294
6462
  init_system_directive();
6463
+ init_agent_permissions();
6295
6464
  init_agent_tool_restrictions();
6296
6465
  init_model_requirements();
6297
6466
  init_model_resolver();
@@ -27218,11 +27387,12 @@ import { resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3 }
27218
27387
  // src/hooks/prometheus-md-only/constants.ts
27219
27388
  init_system_directive();
27220
27389
  init_agent_display_names();
27390
+ init_agent_permissions();
27221
27391
  var HOOK_NAME4 = "prometheus-md-only";
27222
27392
  var PROMETHEUS_AGENTS = ["\u6218\u7565\u53C2\u8C0B"];
27223
- var AGENT_CATEGORY_WHITELIST = {
27224
- "\u6218\u7565\u53C2\u8C0B": ["quick"]
27225
- };
27393
+ function getAllowedCategoriesForAgent(agentName) {
27394
+ return getAgentPermission(agentName).allowedCategories;
27395
+ }
27226
27396
  var ALLOWED_EXTENSIONS = [".md"];
27227
27397
  var BLOCKED_TOOLS = ["Write", "Edit", "write", "edit", "ast_grep_replace", "lsp_rename"];
27228
27398
  var BASH_WRITE_COMMANDS = [
@@ -27419,7 +27589,7 @@ function createPrometheusMdOnlyHook(ctx) {
27419
27589
  const category = output.args.category;
27420
27590
  const subagent_type = output.args.subagent_type;
27421
27591
  const matchedAgent = PROMETHEUS_AGENTS.find((a) => agentNameMatches(agentName, a));
27422
- const whitelist = matchedAgent ? AGENT_CATEGORY_WHITELIST[matchedAgent] ?? [] : [];
27592
+ const whitelist = matchedAgent ? getAllowedCategoriesForAgent(matchedAgent) : [];
27423
27593
  if (!subagent_type && (!category || !whitelist.includes(category))) {
27424
27594
  log(`[${HOOK_NAME4}] Blocked: Prometheus attempted delegate_task with non-allowed category`, {
27425
27595
  sessionID: input.sessionID,
@@ -28718,6 +28888,7 @@ function isActiveContinuationTrigger(sessionID, directory) {
28718
28888
  return false;
28719
28889
  }
28720
28890
  var CONTINUATION_COOLDOWN_MS = 5000;
28891
+ var CONTINUATION_CYCLE_THRESHOLD = 5;
28721
28892
  function isAbortError(error) {
28722
28893
  if (!error)
28723
28894
  return false;
@@ -28908,6 +29079,28 @@ function createAtlasHook(ctx, options) {
28908
29079
  log(`[${HOOK_NAME6}] Skipped: continuation cooldown active`, { sessionID, cooldownRemaining: CONTINUATION_COOLDOWN_MS - (now - state2.lastContinuationInjectedAt) });
28909
29080
  return;
28910
29081
  }
29082
+ const progressKey = `${progress.completed}/${progress.total}`;
29083
+ if (state2.lastContinuationProgress === progressKey) {
29084
+ state2.continuationCycleCount = (state2.continuationCycleCount ?? 0) + 1;
29085
+ } else {
29086
+ state2.continuationCycleCount = 0;
29087
+ }
29088
+ state2.lastContinuationProgress = progressKey;
29089
+ if ((state2.continuationCycleCount ?? 0) >= CONTINUATION_CYCLE_THRESHOLD) {
29090
+ if (!state2.isBlocked) {
29091
+ state2.isBlocked = true;
29092
+ await ctx.client.tui.showToast({
29093
+ body: {
29094
+ title: "\u26A0\uFE0F \u5DE5\u4F5C\u53EF\u80FD\u88AB\u963B\u585E",
29095
+ message: `\u8BA1\u5212 "${boulderState.plan_name}" \u5728 ${progressKey} \u5904\u8FDE\u7EED ${state2.continuationCycleCount} \u6B21\u65E0\u8FDB\u5C55\u3002\u8BF7\u68C0\u67E5\u662F\u5426\u9700\u8981\u4F60\u7684\u8F93\u5165\u3002`,
29096
+ variant: "warning",
29097
+ duration: 5000
29098
+ }
29099
+ }).catch(() => {});
29100
+ }
29101
+ log(`[${HOOK_NAME6}] Skipped: blocked detection`, { sessionID, count: state2.continuationCycleCount, progress: progressKey });
29102
+ return;
29103
+ }
28911
29104
  state2.lastContinuationInjectedAt = now;
28912
29105
  const remaining = progress.total - progress.completed;
28913
29106
  injectContinuation(sessionID, boulderState.plan_name, remaining, progress.total);
@@ -28922,6 +29115,15 @@ function createAtlasHook(ctx, options) {
28922
29115
  if (state2) {
28923
29116
  state2.lastEventWasAbortError = false;
28924
29117
  }
29118
+ if (info?.role === "user" && state2) {
29119
+ state2.lastEventWasAbortError = false;
29120
+ if (state2.isBlocked) {
29121
+ state2.isBlocked = false;
29122
+ state2.continuationCycleCount = 0;
29123
+ state2.lastContinuationProgress = undefined;
29124
+ log(`[${HOOK_NAME6}] Blocked state reset by user message`, { sessionID });
29125
+ }
29126
+ }
28925
29127
  return;
28926
29128
  }
28927
29129
  if (event.type === "message.part.updated") {
@@ -29043,6 +29245,15 @@ function createAtlasHook(ctx, options) {
29043
29245
  if (isBackgroundLaunch) {
29044
29246
  return;
29045
29247
  }
29248
+ if (input.sessionID) {
29249
+ const toolState = sessions.get(input.sessionID);
29250
+ if (toolState?.isBlocked) {
29251
+ toolState.isBlocked = false;
29252
+ toolState.continuationCycleCount = 0;
29253
+ toolState.lastContinuationProgress = undefined;
29254
+ log(`[${HOOK_NAME6}] Blocked state reset by delegate_task completion`, { sessionID: input.sessionID });
29255
+ }
29256
+ }
29046
29257
  if (output.output && typeof output.output === "string") {
29047
29258
  const gitStats = getGitDiffStats(ctx.directory);
29048
29259
  const fileChanges = formatFileChanges(gitStats);
@@ -30562,138 +30773,8 @@ function createToolDefinitionOptimizerHook(_ctx) {
30562
30773
  }
30563
30774
  };
30564
30775
  }
30565
- // src/shared/agent-permissions.ts
30566
- var DEFAULT_AGENT_PERMISSIONS = {
30567
- "\u6218\u7565\u53C2\u8C0B": {
30568
- canReadFiles: true,
30569
- canWriteFiles: false,
30570
- canExecuteCommands: true,
30571
- canDelegateTasks: true,
30572
- allowedCategories: ["quick"]
30573
- },
30574
- "\u6DF1\u5EA6\u63A2\u7D22": {
30575
- canReadFiles: true,
30576
- canWriteFiles: false,
30577
- canExecuteCommands: false,
30578
- canDelegateTasks: false,
30579
- allowedCategories: []
30580
- },
30581
- "\u77E5\u8BC6\u5178\u85CF": {
30582
- canReadFiles: true,
30583
- canWriteFiles: false,
30584
- canExecuteCommands: false,
30585
- canDelegateTasks: false,
30586
- allowedCategories: []
30587
- },
30588
- "\u6280\u672F\u53C2\u8C0B": {
30589
- canReadFiles: true,
30590
- canWriteFiles: false,
30591
- canExecuteCommands: false,
30592
- canDelegateTasks: false,
30593
- allowedCategories: []
30594
- },
30595
- "\u9884\u5BA1\u987E\u95EE": {
30596
- canReadFiles: true,
30597
- canWriteFiles: false,
30598
- canExecuteCommands: false,
30599
- canDelegateTasks: false,
30600
- allowedCategories: []
30601
- },
30602
- "\u8BA1\u5212\u5BA1\u67E5": {
30603
- canReadFiles: true,
30604
- canWriteFiles: false,
30605
- canExecuteCommands: false,
30606
- canDelegateTasks: false,
30607
- allowedCategories: []
30608
- },
30609
- "\u5A92\u4F53\u89E3\u6790": {
30610
- canReadFiles: true,
30611
- canWriteFiles: false,
30612
- canExecuteCommands: false,
30613
- canDelegateTasks: false,
30614
- allowedCategories: []
30615
- },
30616
- "BTW \u987E\u95EE": {
30617
- canReadFiles: true,
30618
- canWriteFiles: false,
30619
- canExecuteCommands: false,
30620
- canDelegateTasks: false,
30621
- allowedCategories: []
30622
- },
30623
- "\u4E3B\u6267\u884C\u5B98": {
30624
- canReadFiles: true,
30625
- canWriteFiles: true,
30626
- canExecuteCommands: true,
30627
- canDelegateTasks: true,
30628
- allowedCategories: [
30629
- "visual-engineering",
30630
- "ultrabrain",
30631
- "artistry",
30632
- "quick",
30633
- "unspecified-low",
30634
- "unspecified-high",
30635
- "writing"
30636
- ]
30637
- },
30638
- "\u4EFB\u52A1\u7F16\u6392": {
30639
- canReadFiles: true,
30640
- canWriteFiles: true,
30641
- canExecuteCommands: true,
30642
- canDelegateTasks: true,
30643
- allowedCategories: [
30644
- "visual-engineering",
30645
- "ultrabrain",
30646
- "artistry",
30647
- "quick",
30648
- "unspecified-low",
30649
- "unspecified-high",
30650
- "writing"
30651
- ]
30652
- },
30653
- "\u6267\u884C\u52A9\u7406": {
30654
- canReadFiles: true,
30655
- canWriteFiles: true,
30656
- canExecuteCommands: true,
30657
- canDelegateTasks: false,
30658
- allowedCategories: []
30659
- }
30660
- };
30661
- var NEW_AGENT_DEFAULT = {
30662
- canReadFiles: true,
30663
- canWriteFiles: false,
30664
- canExecuteCommands: false,
30665
- canDelegateTasks: false,
30666
- allowedCategories: []
30667
- };
30668
- function getAgentPermission(agentName) {
30669
- const exact = DEFAULT_AGENT_PERMISSIONS[agentName];
30670
- if (exact !== undefined)
30671
- return { ...exact };
30672
- const lower = agentName.toLowerCase();
30673
- for (const [key, perm] of Object.entries(DEFAULT_AGENT_PERMISSIONS)) {
30674
- if (key.toLowerCase() === lower)
30675
- return { ...perm };
30676
- }
30677
- return { ...NEW_AGENT_DEFAULT };
30678
- }
30679
- function canDelegateTo(parentAgent, targetAgent, category) {
30680
- const parent = getAgentPermission(parentAgent);
30681
- const target = getAgentPermission(targetAgent);
30682
- if (!parent.canDelegateTasks)
30683
- return false;
30684
- if (!parent.canWriteFiles) {
30685
- if (category !== undefined) {
30686
- const allowed = parent.allowedCategories.map((c) => c.toLowerCase());
30687
- if (!allowed.includes(category.toLowerCase()))
30688
- return false;
30689
- }
30690
- if (target.canWriteFiles)
30691
- return false;
30692
- }
30693
- return true;
30694
- }
30695
-
30696
30776
  // src/shared/permission-bridge.ts
30777
+ init_agent_permissions();
30697
30778
  var SISYPHUS_PATTERN = /\.sisyphus[/\\]/i;
30698
30779
  var MD_EXTENSION = /\.md$/i;
30699
30780
  function isPrometheusAllowedPath(filePath) {
@@ -30722,6 +30803,11 @@ function evaluatePermission(input, agentName) {
30722
30803
  }
30723
30804
  return { status: "allow", reason: `${agentName} \u6709\u547D\u4EE4\u6267\u884C\u6743\u9650` };
30724
30805
  }
30806
+ case "read":
30807
+ if (!perm.canReadFiles) {
30808
+ return { status: "ask", reason: `${agentName} \u65E0\u6587\u4EF6\u8BFB\u53D6\u6743\u9650` };
30809
+ }
30810
+ return { status: "allow", reason: `${agentName} \u6709\u6587\u4EF6\u8BFB\u53D6\u6743\u9650` };
30725
30811
  case "webfetch":
30726
30812
  case "doom_loop":
30727
30813
  case "external_directory":
@@ -31041,6 +31127,7 @@ var MAX_TITLE_LENGTH = 30;
31041
31127
  var namingInProgress = new Map;
31042
31128
  var lastNamedTime = new Map;
31043
31129
  var activeSubSessions = new Map;
31130
+ var sessionMessageCache = new Map;
31044
31131
  function extractTextFromResponse(response) {
31045
31132
  try {
31046
31133
  const data = response?.data;
@@ -31054,7 +31141,7 @@ function extractTextFromResponse(response) {
31054
31141
  }
31055
31142
  }
31056
31143
  function extractConversationText(messages) {
31057
- const recent = messages.slice(-4);
31144
+ const recent = messages.slice(-2);
31058
31145
  return recent.map((m) => {
31059
31146
  const role = m?.info ? m.info?.role : m?.role;
31060
31147
  const parts = m?.parts ?? [];
@@ -31111,7 +31198,12 @@ function createSessionNamingHook(_ctx) {
31111
31198
  const sessionData = sessionInfo.data;
31112
31199
  const currentModel = sessionData.model;
31113
31200
  const currentAgent = sessionData.agent;
31114
- const messagesResp = await ctx.client.session.messages({ path: { id: sessionID }, query: { limit: 4 } }).catch(() => null);
31201
+ const existingTitle = sessionData.title;
31202
+ if (existingTitle && !/^\u3010[^\u3011]+\u3011/.test(existingTitle)) {
31203
+ log("[session-naming] Manual title detected, skipping idle update", { sessionID, existingTitle });
31204
+ return;
31205
+ }
31206
+ const messagesResp = await ctx.client.session.messages({ path: { id: sessionID }, query: { limit: 2 } }).catch(() => null);
31115
31207
  if (!messagesResp) {
31116
31208
  log("[session-naming] Failed to get messages", { sessionID });
31117
31209
  return;
@@ -31121,6 +31213,9 @@ function createSessionNamingHook(_ctx) {
31121
31213
  log("[session-naming] No messages to name from", { sessionID });
31122
31214
  return;
31123
31215
  }
31216
+ const existingCache = sessionMessageCache.get(sessionID) ?? [];
31217
+ const merged = [...existingCache, ...messages];
31218
+ sessionMessageCache.set(sessionID, merged.slice(-20));
31124
31219
  const conversationText = extractConversationText(messages);
31125
31220
  if (!conversationText) {
31126
31221
  log("[session-naming] Empty conversation text", { sessionID });
@@ -31135,20 +31230,25 @@ function createSessionNamingHook(_ctx) {
31135
31230
  activeSubSessions.set(sessionID, subSessionID);
31136
31231
  subagentSessions.add(subSessionID);
31137
31232
  const resolvedAgent = currentAgent ? resolveAgentName(currentAgent) : undefined;
31233
+ const existingTitleLine = existingTitle ? `
31234
+ - \u73B0\u6709\u6807\u9898\uFF1A${existingTitle}` : "";
31138
31235
  const promptResult = await withTimeout3(ctx.client.session.prompt({
31139
31236
  path: { id: subSessionID },
31140
31237
  body: {
31141
31238
  parts: [
31142
31239
  {
31143
31240
  type: "text",
31144
- text: `\u6839\u636E\u4EE5\u4E0B\u5BF9\u8BDD\u5185\u5BB9\u751F\u6210\u4E00\u4E2A\u4E2D\u6587\u4F1A\u8BDD\u6807\u9898\uFF08\u4E0D\u8D85\u8FC7 30 \u5B57\uFF09\u3002
31241
+ text: `\u4F60\u6B63\u5728\u4E3A\u4E00\u4E2A AI \u7F16\u7A0B\u4F1A\u8BDD\u66F4\u65B0\u6807\u9898\u3002${existingTitleLine}
31242
+
31243
+ - \u6700\u65B0\u5BF9\u8BDD\uFF1A${conversationText}
31244
+
31245
+ \u8BF7\u5224\u65AD\uFF1A
31246
+ 1. \u5982\u679C\u6700\u65B0\u5BF9\u8BDD\u4E0E\u539F\u6807\u9898\u63CF\u8FF0\u7684\u4E3B\u9898\u4E00\u81F4 \u2192 \u56DE\u590D\u300C\u65E0\u9700\u66F4\u65B0\u300D
31247
+ 2. \u5982\u679C\u6700\u65B0\u5BF9\u8BDD\u8F6C\u5411\u4E86\u65B0\u4E3B\u9898\u6216\u539F\u6807\u9898\u4E0D\u591F\u51C6\u786E \u2192 \u751F\u6210\u66F4\u51C6\u786E\u7684\u6807\u9898
31248
+
31145
31249
  \u6807\u9898\u683C\u5F0F\u4E3A\uFF1A\u3010\u7C7B\u578B\u524D\u7F00\u3011\u7B80\u77ED\u63CF\u8FF0
31146
31250
  \u4F8B\u5982\uFF1A\u3010\u529F\u80FD\u3011\u6DFB\u52A0\u767B\u5F55\u9875\u9762 \u6216 \u3010\u4FEE\u590D\u3011\u4FEE\u590D\u7A7A\u6307\u9488\u5F02\u5E38
31147
- \u3010\u3011\u5185\u8BF7\u7528 2 \u4E2A\u4E2D\u6587\u5B57\u6982\u62EC\u7C7B\u578B\u3002
31148
- \u53EA\u8F93\u51FA\u6807\u9898\u672C\u8EAB\uFF0C\u4E0D\u8981\u989D\u5916\u8BF4\u660E\u3002
31149
-
31150
- \u5BF9\u8BDD\uFF1A
31151
- ${conversationText}`
31251
+ \u53EA\u8F93\u51FA\u6807\u9898\u6216\u300C\u65E0\u9700\u66F4\u65B0\u300D\uFF0C\u4E0D\u8981\u989D\u5916\u8BF4\u660E\u3002`
31152
31252
  }
31153
31253
  ],
31154
31254
  ...currentModel ? { model: { providerID: currentModel.providerID, modelID: currentModel.modelID } } : {},
@@ -31162,6 +31262,10 @@ ${conversationText}`
31162
31262
  }
31163
31263
  await ctx.client.session.abort({ path: { id: subSessionID } }).catch(() => {});
31164
31264
  activeSubSessions.delete(sessionID);
31265
+ if (title && (title.includes("\u65E0\u9700\u66F4\u65B0") || title.includes("\u4E0D\u9700\u8981\u66F4\u65B0"))) {
31266
+ log("[session-naming] AI judged no update needed", { sessionID, existingTitle });
31267
+ return;
31268
+ }
31165
31269
  if (!title) {
31166
31270
  log("[session-naming] No title from AI, falling back to first message", { sessionID });
31167
31271
  const firstMsg = messages[0];
@@ -31180,6 +31284,10 @@ ${conversationText}`
31180
31284
  }
31181
31285
  }
31182
31286
  title = normalizeTitle(title);
31287
+ if (existingTitle && title === existingTitle) {
31288
+ log("[session-naming] Title unchanged, skipping update", { sessionID, title });
31289
+ return;
31290
+ }
31183
31291
  await ctx.client.session.update({ path: { id: sessionID }, body: { title } }).catch(() => {
31184
31292
  log("[session-naming] Failed to update session title", { sessionID, title });
31185
31293
  });
@@ -31191,16 +31299,66 @@ ${conversationText}`
31191
31299
  namingInProgress.delete(sessionID);
31192
31300
  }
31193
31301
  }
31194
- function handleSessionDeleted(props) {
31302
+ async function handleSessionDeleted(props) {
31195
31303
  const sessionInfo = props?.info;
31196
31304
  if (!sessionInfo?.id)
31197
31305
  return;
31198
- namingInProgress.delete(sessionInfo.id);
31199
- lastNamedTime.delete(sessionInfo.id);
31200
- const subSessionID = activeSubSessions.get(sessionInfo.id);
31306
+ const sessionID = sessionInfo.id;
31307
+ const existingTitle = sessionInfo.title ?? "";
31308
+ try {
31309
+ const cachedMessages = sessionMessageCache.get(sessionID) ?? [];
31310
+ if (cachedMessages.length > 0) {
31311
+ const conversationText = extractConversationText(cachedMessages);
31312
+ if (conversationText) {
31313
+ const subSession = await ctx.client.session.create({ body: { parentID: sessionID } }).catch(() => null);
31314
+ if (subSession?.data?.id) {
31315
+ const subSessionID2 = subSession.data.id;
31316
+ subagentSessions.add(subSessionID2);
31317
+ const fallbackModel = { providerID: "anthropic", modelID: "claude-haiku-4-5" };
31318
+ const titleLine = existingTitle ? `
31319
+ \u539F\u6807\u9898\uFF1A${existingTitle}` : "";
31320
+ const promptResult = await withTimeout3(ctx.client.session.prompt({
31321
+ path: { id: subSessionID2 },
31322
+ body: {
31323
+ parts: [
31324
+ {
31325
+ type: "text",
31326
+ text: `\u8BF7\u4E3A\u4EE5\u4E0B AI \u7F16\u7A0B\u4F1A\u8BDD\u751F\u6210\u4E00\u4E2A\u6982\u62EC\u6027\u7684\u4E2D\u6587\u6807\u9898\uFF08\u4E0D\u8D85\u8FC7 30 \u5B57\uFF09\u3002
31327
+ \u6807\u9898\u5E94\u8986\u76D6\u6574\u4E2A\u4F1A\u8BDD\u7684\u6838\u5FC3\u4E3B\u65E8\uFF0C\u800C\u4E0D\u4EC5\u4EC5\u662F\u6700\u8FD1\u7684\u5185\u5BB9\u3002${titleLine}
31328
+
31329
+ \u4F1A\u8BDD\u5185\u5BB9\uFF1A
31330
+ ${conversationText}
31331
+
31332
+ \u6807\u9898\u683C\u5F0F\u4E3A\uFF1A\u3010\u7C7B\u578B\u524D\u7F00\u3011\u7B80\u77ED\u63CF\u8FF0
31333
+ \u4F8B\u5982\uFF1A\u3010\u529F\u80FD\u3011\u6DFB\u52A0\u767B\u5F55\u9875\u9762 \u6216 \u3010\u91CD\u6784\u3011\u91CD\u6784\u8BA4\u8BC1\u6A21\u5757
31334
+ \u53EA\u8F93\u51FA\u6807\u9898\u672C\u8EAB\uFF0C\u4E0D\u8981\u989D\u5916\u8BF4\u660E\u3002`
31335
+ }
31336
+ ],
31337
+ model: fallbackModel,
31338
+ tools: { bash: false, task: false, delegate_task: false, question: false }
31339
+ }
31340
+ }), TIMEOUT_MS).catch(() => null);
31341
+ const title = promptResult ? extractTextFromResponse(promptResult) : null;
31342
+ if (title) {
31343
+ const finalTitle = normalizeTitle(title);
31344
+ await ctx.client.session.update({ path: { id: sessionID }, body: { title: finalTitle } }).catch(() => {
31345
+ log("[session-naming] Failed to update session title on delete", { sessionID, title: finalTitle });
31346
+ });
31347
+ log("[session-naming] Final naming on delete", { sessionID, title: finalTitle });
31348
+ }
31349
+ }
31350
+ }
31351
+ }
31352
+ } catch (err) {
31353
+ log("[session-naming] Error in final naming on delete", { sessionID, error: String(err) });
31354
+ }
31355
+ namingInProgress.delete(sessionID);
31356
+ lastNamedTime.delete(sessionID);
31357
+ sessionMessageCache.delete(sessionID);
31358
+ const subSessionID = activeSubSessions.get(sessionID);
31201
31359
  if (subSessionID) {
31202
31360
  ctx.client.session.abort({ path: { id: subSessionID } }).catch(() => {});
31203
- activeSubSessions.delete(sessionInfo.id);
31361
+ activeSubSessions.delete(sessionID);
31204
31362
  }
31205
31363
  }
31206
31364
  const eventHandler = async ({ event }) => {
@@ -31212,7 +31370,7 @@ ${conversationText}`
31212
31370
  await handleSessionIdle(props);
31213
31371
  break;
31214
31372
  case "session.deleted":
31215
- handleSessionDeleted(props);
31373
+ await handleSessionDeleted(props);
31216
31374
  break;
31217
31375
  }
31218
31376
  };
@@ -31227,6 +31385,7 @@ ${conversationText}`
31227
31385
  activeSubSessions.clear();
31228
31386
  namingInProgress.clear();
31229
31387
  lastNamedTime.clear();
31388
+ sessionMessageCache.clear();
31230
31389
  }
31231
31390
  };
31232
31391
  }
@@ -49585,6 +49744,7 @@ var CALL_OMO_AGENT_DESCRIPTION = `\u542F\u52A8\u6DF1\u5EA6\u63A2\u7D22/\u77E5\u8
49585
49744
  import { existsSync as existsSync50, readdirSync as readdirSync17 } from "fs";
49586
49745
  import { join as join60 } from "path";
49587
49746
  init_shared();
49747
+ init_agent_permissions();
49588
49748
  init_agent_display_names();
49589
49749
  init_session_cursor();
49590
49750
  init_claude_code_session_state();
@@ -50204,6 +50364,7 @@ init_shared();
50204
50364
  init_agent_display_names();
50205
50365
  init_runtime_fallback();
50206
50366
  init_model_health_registry();
50367
+ init_agent_permissions();
50207
50368
  init_agent_identity_resolver();
50208
50369
  var SISYPHUS_JUNIOR_AGENT = "\u6267\u884C\u52A9\u7406";
50209
50370
  var MAX_LOOP_ATTEMPTS = 10;
@@ -50785,6 +50946,7 @@ ${supervisedResult}`;
50785
50946
  const sessionID = createResult.data.id;
50786
50947
  syncSessionID = sessionID;
50787
50948
  subagentSessions.add(sessionID);
50949
+ updateSessionAgent(sessionID, agentToUse, "delegate-task");
50788
50950
  taskId = `sync_${sessionID.slice(0, 8)}`;
50789
50951
  const startTime = new Date;
50790
50952
  if (toastManager) {
@@ -51501,6 +51663,7 @@ class BackgroundManager {
51501
51663
  }
51502
51664
  const sessionID = createResult.data.id;
51503
51665
  subagentSessions.add(sessionID);
51666
+ updateSessionAgent(sessionID, input.agent, "background-agent");
51504
51667
  task.status = "running";
51505
51668
  task.startedAt = new Date;
51506
51669
  task.sessionID = sessionID;
@@ -73740,29 +73903,14 @@ function createConfigHandler(deps) {
73740
73903
  LspCodeActions: false,
73741
73904
  LspCodeActionResolve: false
73742
73905
  };
73743
- if (agentResult["\u77E5\u8BC6\u5178\u85CF"]) {
73744
- const agent = agentResult["\u77E5\u8BC6\u5178\u85CF"];
73745
- agent.permission = { ...agent.permission, "grep_app_*": "allow" };
73746
- }
73747
- if (agentResult["\u5A92\u4F53\u89E3\u6790"]) {
73748
- const agent = agentResult["\u5A92\u4F53\u89E3\u6790"];
73749
- agent.permission = { ...agent.permission, task: "deny", look_at: "deny" };
73750
- }
73751
- if (agentResult["\u4EFB\u52A1\u7F16\u6392"]) {
73752
- const agent = agentResult["\u4EFB\u52A1\u7F16\u6392"];
73753
- agent.permission = { ...agent.permission, task: "deny", call_omo_agent: "deny", delegate_task: "allow" };
73754
- }
73755
- if (agentResult["\u4E3B\u6267\u884C\u5B98"]) {
73756
- const agent = agentResult["\u4E3B\u6267\u884C\u5B98"];
73757
- agent.permission = { ...agent.permission, call_omo_agent: "deny", delegate_task: "allow", question: "allow" };
73758
- }
73759
- if (agentResult["\u6218\u7565\u53C2\u8C0B"]) {
73760
- const agent = agentResult["\u6218\u7565\u53C2\u8C0B"];
73761
- agent.permission = { ...agent.permission, call_omo_agent: "deny", delegate_task: "allow", question: "allow" };
73762
- }
73763
- if (agentResult["\u6267\u884C\u52A9\u7406"]) {
73764
- const agent = agentResult["\u6267\u884C\u52A9\u7406"];
73765
- agent.permission = { ...agent.permission, delegate_task: "allow" };
73906
+ for (const [agentName, agent] of Object.entries(agentResult)) {
73907
+ if (!agent)
73908
+ continue;
73909
+ const typedAgent = agent;
73910
+ const sdkPermission = deriveSdkPermission(agentName);
73911
+ if (Object.keys(sdkPermission).length > 0) {
73912
+ typedAgent.permission = { ...typedAgent.permission, ...sdkPermission };
73913
+ }
73766
73914
  }
73767
73915
  config4.permission = {
73768
73916
  ...config4.permission,
@@ -8,14 +8,22 @@
8
8
  * - canDelegateTasks: 是否可以委派任务
9
9
  * - allowedCategories: 允许委派的分类列表
10
10
  */
11
+ export type ToolMode = "blacklist" | "whitelist";
11
12
  export interface AgentPermission {
12
13
  canReadFiles: boolean;
13
14
  canWriteFiles: boolean;
14
15
  canExecuteCommands: boolean;
15
16
  canDelegateTasks: boolean;
16
17
  allowedCategories: string[];
18
+ /** 工具限制模式:blacklist(从 5 维推导黑名单,其余默认允许)或 whitelist(全禁,只开放列出的工具) */
19
+ toolMode?: ToolMode;
20
+ /** 工具级覆盖,不受 5 维推导影响。在 blacklist 模式下追加到黑名单,在 whitelist 模式下追加到白名单 */
21
+ toolOverrides?: Record<string, boolean>;
22
+ /** SDK permission 覆盖,值格式为 "allow" | "deny" */
23
+ sdkPermissionOverrides?: Record<string, "allow" | "deny">;
17
24
  }
18
25
  export declare const DEFAULT_AGENT_PERMISSIONS: Record<string, AgentPermission>;
26
+ export declare const ALL_DEFINED_AGENTS: readonly string[];
19
27
  /**
20
28
  * 获取指定 agent 的权限配置。
21
29
  * 优先级:用户覆盖 > 默认配置 > 新 agent 默认值。
@@ -26,6 +34,11 @@ export declare function canWriteFiles(agentName: string): boolean;
26
34
  export declare function canExecuteCommands(agentName: string): boolean;
27
35
  export declare function canDelegateTasks(agentName: string): boolean;
28
36
  export declare function getAllowedCategories(agentName: string): string[];
37
+ /**
38
+ * 根据 agent 的 5 维权限推导工具限制。
39
+ * 结果会被 memoize 以避免重复计算。
40
+ */
41
+ export declare function deriveToolRestrictions(agentName: string): Record<string, boolean>;
29
42
  /**
30
43
  * 检查父 agent 是否可以委派给目标 agent。
31
44
  *
@@ -35,3 +48,8 @@ export declare function getAllowedCategories(agentName: string): string[];
35
48
  * 3. 如果父 agent 是只读(canWriteFiles: false),目标 agent 也必须是只读(canWriteFiles: false)
36
49
  */
37
50
  export declare function canDelegateTo(parentAgent: string, targetAgent: string, category?: string): boolean;
51
+ /**
52
+ * 根据 agent 的 5 维权限推导 SDK permission 配置。
53
+ * 结果会被 memoize 以避免重复计算。
54
+ */
55
+ export declare function deriveSdkPermission(agentName: string): Record<string, "allow" | "deny">;
@@ -1,7 +1,5 @@
1
1
  /**
2
2
  * Agent tool restrictions for session.prompt calls.
3
- * OpenCode SDK's session.prompt `tools` parameter expects boolean values.
4
- * true = tool allowed, false = tool denied.
3
+ * Delegates to deriveToolRestrictions() from the unified permissions system.
5
4
  */
6
5
  export declare function getAgentToolRestrictions(agentName: string): Record<string, boolean>;
7
- export declare function hasAgentToolRestrictions(agentName: string): boolean;
@@ -24,6 +24,7 @@ export * from "./agent-variant";
24
24
  export * from "./session-cursor";
25
25
  export * from "./shell-env";
26
26
  export * from "./system-directive";
27
+ export * from "./agent-permissions";
27
28
  export * from "./agent-tool-restrictions";
28
29
  export * from "./model-requirements";
29
30
  export * from "./model-resolver";
@@ -1,4 +1,13 @@
1
1
  export declare const AGENT_NAME_MAP: Record<string, string>;
2
+ /**
3
+ * 内置 agent 名称集合(用于配置迁移判定)。
4
+ * 与 ALL_DEFINED_AGENTS(src/shared/agent-permissions.ts)的关系:
5
+ * - 重叠:主执行官、技术参谋、知识典藏、深度探索、媒体解析、预审顾问、计划审查、战略参谋、任务编排
6
+ * - ALL_DEFINED_AGENTS 多出:"BTW 顾问"、"执行助理"(不在 BUILTIN_AGENT_NAMES 中)
7
+ * - BUILTIN_AGENT_NAMES 多出:"build"(不是 agent,是 OpenCode-Builder 的配置键)
8
+ *
9
+ * 添加新 agent 时,需要同时更新 DEFAULT_AGENT_PERMISSIONS 和此集合。
10
+ */
2
11
  export declare const BUILTIN_AGENT_NAMES: Set<string>;
3
12
  export declare const HOOK_NAME_MAP: Record<string, string | null>;
4
13
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skj1724/oh-my-opencode",
3
- "version": "4.0.02",
3
+ "version": "4.0.04",
4
4
  "description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",