iosm-cli 0.2.14 → 0.2.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.
- package/CHANGELOG.md +50 -0
- package/README.md +18 -1
- package/dist/cli/args.d.ts +2 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +16 -3
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-profiles.d.ts.map +1 -1
- package/dist/core/agent-profiles.js +3 -0
- package/dist/core/agent-profiles.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +26 -10
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/agent-teams.d.ts.map +1 -1
- package/dist/core/agent-teams.js +12 -9
- package/dist/core/agent-teams.js.map +1 -1
- package/dist/core/checkpoint/fs-checkpoint.d.ts +14 -0
- package/dist/core/checkpoint/fs-checkpoint.d.ts.map +1 -0
- package/dist/core/checkpoint/fs-checkpoint.js +211 -0
- package/dist/core/checkpoint/fs-checkpoint.js.map +1 -0
- package/dist/core/command-dispatcher.d.ts +2 -0
- package/dist/core/command-dispatcher.d.ts.map +1 -1
- package/dist/core/command-dispatcher.js +78 -13
- package/dist/core/command-dispatcher.js.map +1 -1
- package/dist/core/mcp/cli.d.ts.map +1 -1
- package/dist/core/mcp/cli.js +26 -0
- package/dist/core/mcp/cli.js.map +1 -1
- package/dist/core/mcp/config.d.ts.map +1 -1
- package/dist/core/mcp/config.js +55 -0
- package/dist/core/mcp/config.js.map +1 -1
- package/dist/core/mcp/index.d.ts +1 -1
- package/dist/core/mcp/index.d.ts.map +1 -1
- package/dist/core/mcp/index.js.map +1 -1
- package/dist/core/mcp/runtime.d.ts +3 -1
- package/dist/core/mcp/runtime.d.ts.map +1 -1
- package/dist/core/mcp/runtime.js +21 -2
- package/dist/core/mcp/runtime.js.map +1 -1
- package/dist/core/mcp/types.d.ts +30 -2
- package/dist/core/mcp/types.d.ts.map +1 -1
- package/dist/core/mcp/types.js.map +1 -1
- package/dist/core/package-manager.d.ts +10 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +100 -2
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/policy/engine.d.ts +77 -0
- package/dist/core/policy/engine.d.ts.map +1 -0
- package/dist/core/policy/engine.js +614 -0
- package/dist/core/policy/engine.js.map +1 -0
- package/dist/core/policy/index.d.ts +2 -0
- package/dist/core/policy/index.d.ts.map +1 -0
- package/dist/core/policy/index.js +2 -0
- package/dist/core/policy/index.js.map +1 -0
- package/dist/core/sandbox/executor.d.ts +13 -0
- package/dist/core/sandbox/executor.d.ts.map +1 -0
- package/dist/core/sandbox/executor.js +64 -0
- package/dist/core/sandbox/executor.js.map +1 -0
- package/dist/core/sdk.d.ts +2 -2
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +3 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/security/index.d.ts +3 -0
- package/dist/core/security/index.d.ts.map +1 -0
- package/dist/core/security/index.js +3 -0
- package/dist/core/security/index.js.map +1 -0
- package/dist/core/security/source-security.d.ts +43 -0
- package/dist/core/security/source-security.d.ts.map +1 -0
- package/dist/core/security/source-security.js +94 -0
- package/dist/core/security/source-security.js.map +1 -0
- package/dist/core/security/trust-ledger.d.ts +24 -0
- package/dist/core/security/trust-ledger.d.ts.map +1 -0
- package/dist/core/security/trust-ledger.js +66 -0
- package/dist/core/security/trust-ledger.js.map +1 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +128 -15
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +6 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +22 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +9 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/task-plan.d.ts +1 -0
- package/dist/core/task-plan.d.ts.map +1 -1
- package/dist/core/task-plan.js +103 -0
- package/dist/core/task-plan.js.map +1 -1
- package/dist/core/tools/apply-patch.d.ts +29 -0
- package/dist/core/tools/apply-patch.d.ts.map +1 -0
- package/dist/core/tools/apply-patch.js +167 -0
- package/dist/core/tools/apply-patch.js.map +1 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +15 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/git-common.d.ts.map +1 -1
- package/dist/core/tools/git-common.js +15 -1
- package/dist/core/tools/git-common.js.map +1 -1
- package/dist/core/tools/index.d.ts +20 -2
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +85 -25
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/permissions.d.ts +16 -0
- package/dist/core/tools/permissions.d.ts.map +1 -1
- package/dist/core/tools/permissions.js +34 -1
- package/dist/core/tools/permissions.js.map +1 -1
- package/dist/core/tools/task.d.ts.map +1 -1
- package/dist/core/tools/task.js +68 -24
- package/dist/core/tools/task.js.map +1 -1
- package/dist/core/tools/tool-search.d.ts +24 -0
- package/dist/core/tools/tool-search.d.ts.map +1 -0
- package/dist/core/tools/tool-search.js +85 -0
- package/dist/core/tools/tool-search.js.map +1 -0
- package/dist/core/tools/tool-suggest.d.ts +18 -0
- package/dist/core/tools/tool-suggest.d.ts.map +1 -0
- package/dist/core/tools/tool-suggest.js +94 -0
- package/dist/core/tools/tool-suggest.js.map +1 -0
- package/dist/core/tools/verification-runner.d.ts.map +1 -1
- package/dist/core/tools/verification-runner.js +15 -1
- package/dist/core/tools/verification-runner.js.map +1 -1
- package/dist/core/unified-exec.d.ts +39 -0
- package/dist/core/unified-exec.d.ts.map +1 -0
- package/dist/core/unified-exec.js +286 -0
- package/dist/core/unified-exec.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +93 -11
- package/dist/main.js.map +1 -1
- package/dist/modes/acp/acp-mode.d.ts +17 -0
- package/dist/modes/acp/acp-mode.d.ts.map +1 -0
- package/dist/modes/acp/acp-mode.js +352 -0
- package/dist/modes/acp/acp-mode.js.map +1 -0
- package/dist/modes/index.d.ts +2 -1
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js +1 -0
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +217 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +8 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +159 -72
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +25 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +33 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +13 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +189 -28
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +54 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/telegram/telegram-bridge-mode.js +51 -22
- package/dist/modes/telegram/telegram-bridge-mode.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +96 -9
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/README.md +2 -0
- package/docs/acp-rpc-mapping.md +38 -0
- package/docs/configuration.generated.md +81 -0
- package/docs/configuration.md +7 -0
- package/package.json +4 -1
|
@@ -35,13 +35,15 @@ import { createAgentSession } from "../../core/sdk.js";
|
|
|
35
35
|
import { createTeamRun, getTeamRun, listTeamRuns } from "../../core/agent-teams.js";
|
|
36
36
|
import { buildSwarmPlanFromSingular, buildSwarmPlanFromTask, runSwarmScheduler, SwarmStateStore, } from "../../core/swarm/index.js";
|
|
37
37
|
import { loadCustomSubagents, resolveCustomSubagentReference, } from "../../core/subagents.js";
|
|
38
|
+
import { evaluatePermissionWithPolicy } from "../../core/policy/index.js";
|
|
38
39
|
import { getSubagentRun, listSubagentRuns } from "../../core/subagent-runs.js";
|
|
39
40
|
import { getBackgroundProcess, listBackgroundProcesses, pruneBackgroundProcesses, readBackgroundProcessLogTail, stopBackgroundProcess, } from "../../core/background-processes.js";
|
|
40
41
|
import { getSubagentBackgroundRun, listSubagentBackgroundRuns, pruneSubagentBackgroundRuns, readSubagentBackgroundRunLogTail, requestStopAllSubagentBackgroundRuns, requestStopSubagentBackgroundRun, } from "../../core/subagent-background-runs.js";
|
|
41
42
|
import { SessionManager } from "../../core/session-manager.js";
|
|
42
43
|
import { SettingsManager } from "../../core/settings-manager.js";
|
|
43
44
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
44
|
-
import {
|
|
45
|
+
import { getToolPermissionSignature } from "../../core/tools/index.js";
|
|
46
|
+
import { coerceTaskPlanSnapshot, TASK_PLAN_CUSTOM_TYPE, } from "../../core/task-plan.js";
|
|
45
47
|
import { buildIosmAutomationPrompt, buildIosmAgentVerificationPrompt, buildIosmGuideAuthoringPrompt, buildIosmPriorityChecklist, createMetricSnapshot, extractAssistantText, evaluateIosmAutomationProgress, formatMetricSnapshot, hasReachedIosmTarget, getIosmGuidePath, initIosmWorkspace, inspectIosmCycle, listIosmCycles, loadIosmConfig, planIosmCycle, readIosmCycleReport, recordIosmCycleHistory, resolveIosmAutomationSettings, summarizeMetricDelta, normalizeIosmGuideMarkdown, writeIosmGuideDocument, } from "../../iosm/index.js";
|
|
46
48
|
import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
|
|
47
49
|
import { copyToClipboard } from "../../utils/clipboard.js";
|
|
@@ -414,9 +416,12 @@ async function promptMetaWithParallelismGuard(input) {
|
|
|
414
416
|
};
|
|
415
417
|
const unsubscribe = input.session.subscribe((event) => {
|
|
416
418
|
if (event.type === "message_end" && event.message.role === "custom") {
|
|
417
|
-
if (event.message.customType === TASK_PLAN_CUSTOM_TYPE
|
|
418
|
-
|
|
419
|
-
|
|
419
|
+
if (event.message.customType === TASK_PLAN_CUSTOM_TYPE) {
|
|
420
|
+
const snapshot = coerceTaskPlanSnapshot(event.message.details);
|
|
421
|
+
if (snapshot) {
|
|
422
|
+
taskPlanSnapshot = snapshot;
|
|
423
|
+
maybeScheduleCorrection();
|
|
424
|
+
}
|
|
420
425
|
}
|
|
421
426
|
return;
|
|
422
427
|
}
|
|
@@ -932,6 +937,7 @@ export class InteractiveMode {
|
|
|
932
937
|
this.permissionAllowRules = [];
|
|
933
938
|
this.permissionDenyRules = [];
|
|
934
939
|
this.permissionPromptLock = Promise.resolve();
|
|
940
|
+
this.turnAllowedToolSignatures = new Set();
|
|
935
941
|
this.sessionAllowedToolSignatures = new Set();
|
|
936
942
|
this.singularLastEffectiveContract = {};
|
|
937
943
|
this.swarmActiveRunId = undefined;
|
|
@@ -1046,6 +1052,7 @@ export class InteractiveMode {
|
|
|
1046
1052
|
this.activeProfileName = profile.name;
|
|
1047
1053
|
this.profilePromptSuffix = profile.systemPromptAppend || undefined;
|
|
1048
1054
|
this.mcpRuntime = options.mcpRuntime;
|
|
1055
|
+
this.policyEngine = options.policyEngine;
|
|
1049
1056
|
this.contractService = new ContractService({ cwd: this.sessionManager.getCwd() });
|
|
1050
1057
|
this.singularService = new SingularService({ cwd: this.sessionManager.getCwd() });
|
|
1051
1058
|
// Apply plan mode and profile badges immediately if set
|
|
@@ -1056,8 +1063,9 @@ export class InteractiveMode {
|
|
|
1056
1063
|
this.session.setIosmAutopilotEnabled(this.activeProfileName === "iosm");
|
|
1057
1064
|
this.syncRuntimePromptSuffix();
|
|
1058
1065
|
this.permissionMode = this.settingsManager.getPermissionMode();
|
|
1059
|
-
this.
|
|
1060
|
-
this.
|
|
1066
|
+
this.policyEngine?.refresh();
|
|
1067
|
+
this.permissionAllowRules = this.policyEngine?.getLegacyRules("allow") ?? this.settingsManager.getPermissionAllowRules();
|
|
1068
|
+
this.permissionDenyRules = this.policyEngine?.getLegacyRules("deny") ?? this.settingsManager.getPermissionDenyRules();
|
|
1061
1069
|
this.session.setToolPermissionHandler((request) => this.requestToolPermission(request));
|
|
1062
1070
|
this.mcpRuntime?.setPermissionGuard((request) => this.requestToolPermission(request));
|
|
1063
1071
|
// Load hide thinking block setting
|
|
@@ -1105,8 +1113,7 @@ export class InteractiveMode {
|
|
|
1105
1113
|
return [...new Set(nextActiveTools)];
|
|
1106
1114
|
}
|
|
1107
1115
|
getToolPermissionSignature(request) {
|
|
1108
|
-
|
|
1109
|
-
return `${request.toolName}:${summary}`;
|
|
1116
|
+
return getToolPermissionSignature(request);
|
|
1110
1117
|
}
|
|
1111
1118
|
matchesPermissionRule(rule, request) {
|
|
1112
1119
|
const [ruleToolRaw, ...rest] = rule.split(":");
|
|
@@ -1137,54 +1144,77 @@ export class InteractiveMode {
|
|
|
1137
1144
|
: false;
|
|
1138
1145
|
if (this.activeProfileName === "meta" &&
|
|
1139
1146
|
!this.currentTurnSawTaskToolCall &&
|
|
1140
|
-
(request.toolName === "bash" || request.toolName === "edit" || request.toolName === "write")) {
|
|
1147
|
+
(request.toolName === "bash" || request.toolName === "edit" || request.toolName === "write" || request.toolName === "apply_patch")) {
|
|
1141
1148
|
this.showWarning(`META mode orchestration guard: direct ${request.toolName} is blocked before the first task call in a turn. Launch subagents via task or switch profile to full.`);
|
|
1142
1149
|
return false;
|
|
1143
1150
|
}
|
|
1144
1151
|
if (isReadOnlyProfileName(this.activeProfileName) &&
|
|
1145
|
-
(request.toolName === "bash" || request.toolName === "edit" || request.toolName === "write")) {
|
|
1152
|
+
(request.toolName === "bash" || request.toolName === "edit" || request.toolName === "write" || request.toolName === "apply_patch")) {
|
|
1146
1153
|
this.showWarning(`Tool ${request.toolName} is disabled in ${this.activeProfileName} profile. Switch to full/meta/iosm for mutating operations.`);
|
|
1147
1154
|
return false;
|
|
1148
1155
|
}
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1156
|
+
if (this.policyEngine) {
|
|
1157
|
+
this.policyEngine.refresh();
|
|
1158
|
+
const evaluated = evaluatePermissionWithPolicy(this.policyEngine, request, {
|
|
1159
|
+
profile: this.activeProfileName,
|
|
1160
|
+
runtimeMode: "interactive",
|
|
1161
|
+
permissionMode: this.permissionMode,
|
|
1162
|
+
strictExtensionToolEnforcement,
|
|
1163
|
+
});
|
|
1164
|
+
if (evaluated.outcome === "deny") {
|
|
1165
|
+
this.showWarning(evaluated.reason);
|
|
1152
1166
|
return false;
|
|
1153
1167
|
}
|
|
1154
|
-
|
|
1155
|
-
for (const rule of this.permissionAllowRules) {
|
|
1156
|
-
if (this.matchesPermissionRule(rule, request)) {
|
|
1168
|
+
if (evaluated.outcome === "allow") {
|
|
1157
1169
|
return true;
|
|
1158
1170
|
}
|
|
1159
1171
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
if (
|
|
1172
|
+
else {
|
|
1173
|
+
for (const rule of this.permissionDenyRules) {
|
|
1174
|
+
if (this.matchesPermissionRule(rule, request)) {
|
|
1175
|
+
this.showWarning(`Denied by rule: ${rule}`);
|
|
1176
|
+
return false;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
for (const rule of this.permissionAllowRules) {
|
|
1180
|
+
if (this.matchesPermissionRule(rule, request)) {
|
|
1163
1181
|
return true;
|
|
1164
1182
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1183
|
+
}
|
|
1184
|
+
if (strictExtensionToolEnforcement && request.toolSource === "extension") {
|
|
1185
|
+
if (this.permissionMode === "auto") {
|
|
1186
|
+
if (request.requiredPermission === "read-only") {
|
|
1187
|
+
return true;
|
|
1188
|
+
}
|
|
1189
|
+
if (!request.requiredPermission) {
|
|
1190
|
+
this.showWarning(`Extension tool ${request.toolName} is missing requiredPermission metadata. Add an allow rule or switch to ask/yolo mode.`);
|
|
1191
|
+
return false;
|
|
1192
|
+
}
|
|
1168
1193
|
}
|
|
1169
1194
|
}
|
|
1170
|
-
|
|
1171
|
-
if (this.permissionMode === "yolo") {
|
|
1172
|
-
return true;
|
|
1173
|
-
}
|
|
1174
|
-
if (this.permissionMode === "auto") {
|
|
1175
|
-
// Auto mode mirrors "accept edits": allow edit/write without prompts,
|
|
1176
|
-
// still ask for shell execution.
|
|
1177
|
-
if (request.toolName === "edit" || request.toolName === "write") {
|
|
1195
|
+
if (this.permissionMode === "yolo") {
|
|
1178
1196
|
return true;
|
|
1179
1197
|
}
|
|
1198
|
+
if (this.permissionMode === "auto") {
|
|
1199
|
+
// Auto mode mirrors "accept edits": allow edit/write without prompts,
|
|
1200
|
+
// still ask for shell execution.
|
|
1201
|
+
if (request.toolName === "edit" || request.toolName === "write" || request.toolName === "apply_patch") {
|
|
1202
|
+
return true;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1180
1205
|
}
|
|
1181
1206
|
const signature = this.getToolPermissionSignature(request);
|
|
1207
|
+
if (this.turnAllowedToolSignatures?.has(signature)) {
|
|
1208
|
+
return true;
|
|
1209
|
+
}
|
|
1182
1210
|
if (this.sessionAllowedToolSignatures.has(signature)) {
|
|
1183
1211
|
return true;
|
|
1184
1212
|
}
|
|
1185
1213
|
return this.withPermissionDialogLock(async () => {
|
|
1186
1214
|
if (this.permissionMode === "yolo")
|
|
1187
1215
|
return true;
|
|
1216
|
+
if (this.turnAllowedToolSignatures?.has(signature))
|
|
1217
|
+
return true;
|
|
1188
1218
|
if (this.sessionAllowedToolSignatures.has(signature))
|
|
1189
1219
|
return true;
|
|
1190
1220
|
const tierLabel = request.requiredPermission ? ` [${request.requiredPermission}]` : "";
|
|
@@ -1192,6 +1222,7 @@ export class InteractiveMode {
|
|
|
1192
1222
|
const label = `${request.toolName}${tierLabel}${sourceLabel}: ${request.summary}`;
|
|
1193
1223
|
const choice = await this.showExtensionSelector("Permission required", [
|
|
1194
1224
|
"Allow once",
|
|
1225
|
+
"Allow this turn",
|
|
1195
1226
|
"Deny",
|
|
1196
1227
|
"Always allow this command (session)",
|
|
1197
1228
|
]);
|
|
@@ -1199,6 +1230,12 @@ export class InteractiveMode {
|
|
|
1199
1230
|
this.showWarning(`Permission denied: ${label}`);
|
|
1200
1231
|
return false;
|
|
1201
1232
|
}
|
|
1233
|
+
if (choice === "Allow this turn") {
|
|
1234
|
+
if (!this.turnAllowedToolSignatures) {
|
|
1235
|
+
this.turnAllowedToolSignatures = new Set();
|
|
1236
|
+
}
|
|
1237
|
+
this.turnAllowedToolSignatures.add(signature);
|
|
1238
|
+
}
|
|
1202
1239
|
if (choice === "Always allow this command (session)") {
|
|
1203
1240
|
this.sessionAllowedToolSignatures.add(signature);
|
|
1204
1241
|
}
|
|
@@ -1251,6 +1288,59 @@ export class InteractiveMode {
|
|
|
1251
1288
|
: "";
|
|
1252
1289
|
return `Permissions: ${this.permissionMode}${this.permissionAllowRules.length > 0 ? ` · allow rules: ${this.permissionAllowRules.length}` : ""}${this.permissionDenyRules.length > 0 ? ` · deny rules: ${this.permissionDenyRules.length}` : ""}${hookSegment}`;
|
|
1253
1290
|
}
|
|
1291
|
+
refreshPermissionRulesFromPolicy() {
|
|
1292
|
+
if (!this.policyEngine)
|
|
1293
|
+
return;
|
|
1294
|
+
this.policyEngine.refresh();
|
|
1295
|
+
this.permissionAllowRules = this.policyEngine.getLegacyRules("allow");
|
|
1296
|
+
this.permissionDenyRules = this.policyEngine.getLegacyRules("deny");
|
|
1297
|
+
}
|
|
1298
|
+
addPermissionRule(kind, rawRule) {
|
|
1299
|
+
const normalized = rawRule.trim();
|
|
1300
|
+
if (!normalized || !normalized.includes(":"))
|
|
1301
|
+
return false;
|
|
1302
|
+
if (this.policyEngine) {
|
|
1303
|
+
const added = this.policyEngine.addLegacyRule(kind, normalized);
|
|
1304
|
+
this.refreshPermissionRulesFromPolicy();
|
|
1305
|
+
return added;
|
|
1306
|
+
}
|
|
1307
|
+
if (kind === "allow") {
|
|
1308
|
+
if (this.permissionAllowRules.includes(normalized))
|
|
1309
|
+
return false;
|
|
1310
|
+
this.permissionAllowRules.push(normalized);
|
|
1311
|
+
this.settingsManager.setPermissionAllowRules(this.permissionAllowRules);
|
|
1312
|
+
return true;
|
|
1313
|
+
}
|
|
1314
|
+
if (this.permissionDenyRules.includes(normalized))
|
|
1315
|
+
return false;
|
|
1316
|
+
this.permissionDenyRules.push(normalized);
|
|
1317
|
+
this.settingsManager.setPermissionDenyRules(this.permissionDenyRules);
|
|
1318
|
+
return true;
|
|
1319
|
+
}
|
|
1320
|
+
removePermissionRule(kind, rawRule) {
|
|
1321
|
+
const normalized = rawRule.trim();
|
|
1322
|
+
if (!normalized)
|
|
1323
|
+
return false;
|
|
1324
|
+
if (this.policyEngine) {
|
|
1325
|
+
const removed = this.policyEngine.removeLegacyRule(kind, normalized);
|
|
1326
|
+
this.refreshPermissionRulesFromPolicy();
|
|
1327
|
+
return removed;
|
|
1328
|
+
}
|
|
1329
|
+
if (kind === "allow") {
|
|
1330
|
+
const next = this.permissionAllowRules.filter((rule) => rule !== normalized);
|
|
1331
|
+
if (next.length === this.permissionAllowRules.length)
|
|
1332
|
+
return false;
|
|
1333
|
+
this.permissionAllowRules = next;
|
|
1334
|
+
this.settingsManager.setPermissionAllowRules(this.permissionAllowRules);
|
|
1335
|
+
return true;
|
|
1336
|
+
}
|
|
1337
|
+
const next = this.permissionDenyRules.filter((rule) => rule !== normalized);
|
|
1338
|
+
if (next.length === this.permissionDenyRules.length)
|
|
1339
|
+
return false;
|
|
1340
|
+
this.permissionDenyRules = next;
|
|
1341
|
+
this.settingsManager.setPermissionDenyRules(this.permissionDenyRules);
|
|
1342
|
+
return true;
|
|
1343
|
+
}
|
|
1254
1344
|
async runPermissionRulesMenu(kind) {
|
|
1255
1345
|
while (true) {
|
|
1256
1346
|
const isAllow = kind === "allow";
|
|
@@ -1281,18 +1371,7 @@ export class InteractiveMode {
|
|
|
1281
1371
|
this.showWarning(`Invalid rule "${rawRule || "(empty)"}". Expected <tool:match>.`);
|
|
1282
1372
|
continue;
|
|
1283
1373
|
}
|
|
1284
|
-
|
|
1285
|
-
if (!this.permissionAllowRules.includes(rawRule)) {
|
|
1286
|
-
this.permissionAllowRules.push(rawRule);
|
|
1287
|
-
this.settingsManager.setPermissionAllowRules(this.permissionAllowRules);
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
else {
|
|
1291
|
-
if (!this.permissionDenyRules.includes(rawRule)) {
|
|
1292
|
-
this.permissionDenyRules.push(rawRule);
|
|
1293
|
-
this.settingsManager.setPermissionDenyRules(this.permissionDenyRules);
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1374
|
+
this.addPermissionRule(isAllow ? "allow" : "deny", rawRule);
|
|
1296
1375
|
this.showStatus(`Added ${kind} rule: ${rawRule}`);
|
|
1297
1376
|
continue;
|
|
1298
1377
|
}
|
|
@@ -1304,14 +1383,7 @@ export class InteractiveMode {
|
|
|
1304
1383
|
const pickedRule = await this.showExtensionSelector(`/permissions ${kind}: remove rule`, rules.map((rule) => rule));
|
|
1305
1384
|
if (!pickedRule)
|
|
1306
1385
|
continue;
|
|
1307
|
-
|
|
1308
|
-
this.permissionAllowRules = this.permissionAllowRules.filter((rule) => rule !== pickedRule);
|
|
1309
|
-
this.settingsManager.setPermissionAllowRules(this.permissionAllowRules);
|
|
1310
|
-
}
|
|
1311
|
-
else {
|
|
1312
|
-
this.permissionDenyRules = this.permissionDenyRules.filter((rule) => rule !== pickedRule);
|
|
1313
|
-
this.settingsManager.setPermissionDenyRules(this.permissionDenyRules);
|
|
1314
|
-
}
|
|
1386
|
+
this.removePermissionRule(isAllow ? "allow" : "deny", pickedRule);
|
|
1315
1387
|
this.showStatus(`Removed ${kind} rule: ${pickedRule}`);
|
|
1316
1388
|
}
|
|
1317
1389
|
}
|
|
@@ -1380,6 +1452,7 @@ export class InteractiveMode {
|
|
|
1380
1452
|
}
|
|
1381
1453
|
}
|
|
1382
1454
|
async handlePermissionsCommand(text) {
|
|
1455
|
+
this.refreshPermissionRulesFromPolicy();
|
|
1383
1456
|
const args = this.parseSlashArgs(text).slice(1);
|
|
1384
1457
|
const value = args[0]?.toLowerCase();
|
|
1385
1458
|
if (!value) {
|
|
@@ -1426,10 +1499,7 @@ export class InteractiveMode {
|
|
|
1426
1499
|
this.showWarning("Usage: /permissions allow add <tool:match>");
|
|
1427
1500
|
return;
|
|
1428
1501
|
}
|
|
1429
|
-
|
|
1430
|
-
this.permissionAllowRules.push(rawRule);
|
|
1431
|
-
this.settingsManager.setPermissionAllowRules(this.permissionAllowRules);
|
|
1432
|
-
}
|
|
1502
|
+
this.addPermissionRule("allow", rawRule);
|
|
1433
1503
|
this.showStatus(`Added allow rule: ${rawRule}`);
|
|
1434
1504
|
return;
|
|
1435
1505
|
}
|
|
@@ -1439,8 +1509,7 @@ export class InteractiveMode {
|
|
|
1439
1509
|
this.showWarning("Usage: /permissions allow remove <tool:match>");
|
|
1440
1510
|
return;
|
|
1441
1511
|
}
|
|
1442
|
-
this.
|
|
1443
|
-
this.settingsManager.setPermissionAllowRules(this.permissionAllowRules);
|
|
1512
|
+
this.removePermissionRule("allow", rawRule);
|
|
1444
1513
|
this.showStatus(`Removed allow rule: ${rawRule}`);
|
|
1445
1514
|
return;
|
|
1446
1515
|
}
|
|
@@ -1463,10 +1532,7 @@ export class InteractiveMode {
|
|
|
1463
1532
|
this.showWarning("Usage: /permissions deny add <tool:match>");
|
|
1464
1533
|
return;
|
|
1465
1534
|
}
|
|
1466
|
-
|
|
1467
|
-
this.permissionDenyRules.push(rawRule);
|
|
1468
|
-
this.settingsManager.setPermissionDenyRules(this.permissionDenyRules);
|
|
1469
|
-
}
|
|
1535
|
+
this.addPermissionRule("deny", rawRule);
|
|
1470
1536
|
this.showStatus(`Added deny rule: ${rawRule}`);
|
|
1471
1537
|
return;
|
|
1472
1538
|
}
|
|
@@ -1476,8 +1542,7 @@ export class InteractiveMode {
|
|
|
1476
1542
|
this.showWarning("Usage: /permissions deny remove <tool:match>");
|
|
1477
1543
|
return;
|
|
1478
1544
|
}
|
|
1479
|
-
this.
|
|
1480
|
-
this.settingsManager.setPermissionDenyRules(this.permissionDenyRules);
|
|
1545
|
+
this.removePermissionRule("deny", rawRule);
|
|
1481
1546
|
this.showStatus(`Removed deny rule: ${rawRule}`);
|
|
1482
1547
|
return;
|
|
1483
1548
|
}
|
|
@@ -3822,6 +3887,7 @@ export class InteractiveMode {
|
|
|
3822
3887
|
case "agent_start":
|
|
3823
3888
|
this.currentTurnSawAssistantMessage = false;
|
|
3824
3889
|
this.currentTurnSawTaskToolCall = false;
|
|
3890
|
+
this.turnAllowedToolSignatures.clear();
|
|
3825
3891
|
// Restore main escape handler if retry handler is still active
|
|
3826
3892
|
// (retry success event fires later, but we need main handler now)
|
|
3827
3893
|
if (this.retryEscapeHandler) {
|
|
@@ -4383,17 +4449,19 @@ export class InteractiveMode {
|
|
|
4383
4449
|
case "custom": {
|
|
4384
4450
|
this.handleInternalUiMetaMessage(message);
|
|
4385
4451
|
if (message.display) {
|
|
4386
|
-
if (message.customType === TASK_PLAN_CUSTOM_TYPE
|
|
4387
|
-
const
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
component.setExpanded(this.toolOutputExpanded);
|
|
4395
|
-
this.chatContainer.addChild(component);
|
|
4452
|
+
if (message.customType === TASK_PLAN_CUSTOM_TYPE) {
|
|
4453
|
+
const snapshot = coerceTaskPlanSnapshot(message.details);
|
|
4454
|
+
if (snapshot) {
|
|
4455
|
+
const component = new TaskPlanMessageComponent(snapshot);
|
|
4456
|
+
component.setExpanded(this.toolOutputExpanded);
|
|
4457
|
+
this.chatContainer.addChild(component);
|
|
4458
|
+
break;
|
|
4459
|
+
}
|
|
4396
4460
|
}
|
|
4461
|
+
const renderer = this.session.extensionRunner?.getMessageRenderer(message.customType);
|
|
4462
|
+
const component = new CustomMessageComponent(message, renderer, this.getMarkdownThemeWithSettings());
|
|
4463
|
+
component.setExpanded(this.toolOutputExpanded);
|
|
4464
|
+
this.chatContainer.addChild(component);
|
|
4397
4465
|
}
|
|
4398
4466
|
break;
|
|
4399
4467
|
}
|
|
@@ -13182,6 +13250,25 @@ export class InteractiveMode {
|
|
|
13182
13250
|
cwd,
|
|
13183
13251
|
agentDir: getAgentDir(),
|
|
13184
13252
|
settingsManager: this.settingsManager,
|
|
13253
|
+
allowedSourceHosts: this.policyEngine?.getAllowedSourceHosts(),
|
|
13254
|
+
trustConsentProvider: async (request) => {
|
|
13255
|
+
const details = [
|
|
13256
|
+
`Source: ${request.source}`,
|
|
13257
|
+
`Host: ${request.host}`,
|
|
13258
|
+
`Identity: ${request.identity}`,
|
|
13259
|
+
`Fingerprint: ${request.fingerprint}`,
|
|
13260
|
+
];
|
|
13261
|
+
if (request.previousFingerprint) {
|
|
13262
|
+
details.push(`Previous fingerprint: ${request.previousFingerprint}`);
|
|
13263
|
+
}
|
|
13264
|
+
const answer = await this.showExtensionSelector(`Trust ${request.sourceType} ${request.action}?`, ["Trust and continue", "Deny"]);
|
|
13265
|
+
if (answer !== "Trust and continue") {
|
|
13266
|
+
this.showWarning(`Blocked untrusted source: ${request.source}`);
|
|
13267
|
+
return false;
|
|
13268
|
+
}
|
|
13269
|
+
this.showCommandTextBlock("Trust Decision", details.join("\n"));
|
|
13270
|
+
return true;
|
|
13271
|
+
},
|
|
13185
13272
|
});
|
|
13186
13273
|
}
|
|
13187
13274
|
normalizeExtensionOverrideTarget(target) {
|