@codemcp/ade 0.2.4 → 0.2.6
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/package.json +1 -1
- package/packages/cli/dist/index.js +394 -7703
- package/packages/cli/package.json +3 -2
- package/packages/cli/tsup.config.ts +6 -1
- package/packages/core/package.json +1 -1
- package/packages/core/src/catalog/catalog.spec.ts +1 -10
- package/packages/core/src/catalog/facets/autonomy.ts +4 -62
- package/packages/core/src/index.ts +1 -4
- package/packages/core/src/resolver.spec.ts +4 -22
- package/packages/core/src/resolver.ts +1 -5
- package/packages/core/src/types.ts +0 -20
- package/packages/harnesses/package.json +1 -1
- package/packages/harnesses/src/permission-policy.ts +1 -165
- package/packages/harnesses/src/util.ts +11 -0
- package/packages/harnesses/src/writers/claude-code.spec.ts +14 -46
- package/packages/harnesses/src/writers/claude-code.ts +33 -16
- package/packages/harnesses/src/writers/cline.spec.ts +1 -41
- package/packages/harnesses/src/writers/copilot.spec.ts +2 -42
- package/packages/harnesses/src/writers/copilot.ts +19 -32
- package/packages/harnesses/src/writers/cursor.spec.ts +1 -41
- package/packages/harnesses/src/writers/cursor.ts +28 -40
- package/packages/harnesses/src/writers/kiro.spec.ts +1 -41
- package/packages/harnesses/src/writers/kiro.ts +23 -24
- package/packages/harnesses/src/writers/opencode.spec.ts +1 -41
- package/packages/harnesses/src/writers/opencode.ts +157 -10
- package/packages/harnesses/src/writers/roo-code.spec.ts +2 -42
- package/packages/harnesses/src/writers/roo-code.ts +25 -10
- package/packages/harnesses/src/writers/universal.spec.ts +1 -41
- package/packages/harnesses/src/writers/universal.ts +45 -31
- package/packages/harnesses/src/writers/windsurf.spec.ts +5 -42
- package/packages/harnesses/src/writers/windsurf.ts +30 -47
|
@@ -10,47 +10,7 @@ import type {
|
|
|
10
10
|
import { copilotWriter } from "./copilot.js";
|
|
11
11
|
|
|
12
12
|
function autonomyPolicy(profile: AutonomyProfile): PermissionPolicy {
|
|
13
|
-
|
|
14
|
-
case "rigid":
|
|
15
|
-
return {
|
|
16
|
-
profile,
|
|
17
|
-
capabilities: {
|
|
18
|
-
read: "ask",
|
|
19
|
-
edit_write: "ask",
|
|
20
|
-
search_list: "ask",
|
|
21
|
-
bash_safe: "ask",
|
|
22
|
-
bash_unsafe: "ask",
|
|
23
|
-
web: "ask",
|
|
24
|
-
task_agent: "ask"
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
case "sensible-defaults":
|
|
28
|
-
return {
|
|
29
|
-
profile,
|
|
30
|
-
capabilities: {
|
|
31
|
-
read: "allow",
|
|
32
|
-
edit_write: "allow",
|
|
33
|
-
search_list: "allow",
|
|
34
|
-
bash_safe: "allow",
|
|
35
|
-
bash_unsafe: "ask",
|
|
36
|
-
web: "ask",
|
|
37
|
-
task_agent: "allow"
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
case "max-autonomy":
|
|
41
|
-
return {
|
|
42
|
-
profile,
|
|
43
|
-
capabilities: {
|
|
44
|
-
read: "allow",
|
|
45
|
-
edit_write: "allow",
|
|
46
|
-
search_list: "allow",
|
|
47
|
-
bash_safe: "allow",
|
|
48
|
-
bash_unsafe: "allow",
|
|
49
|
-
web: "ask",
|
|
50
|
-
task_agent: "allow"
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
13
|
+
return { profile };
|
|
54
14
|
}
|
|
55
15
|
|
|
56
16
|
describe("copilotWriter", () => {
|
|
@@ -224,7 +184,7 @@ describe("copilotWriter", () => {
|
|
|
224
184
|
|
|
225
185
|
expect(rigidAgent).not.toContain(" - server/workflows/*");
|
|
226
186
|
expect(rigidAgent).toContain(" - workflows/*");
|
|
227
|
-
expect(rigidAgent).
|
|
187
|
+
expect(rigidAgent).toContain(" - read");
|
|
228
188
|
expect(rigidAgent).not.toContain(" - edit");
|
|
229
189
|
expect(rigidAgent).not.toContain(" - search");
|
|
230
190
|
expect(rigidAgent).not.toContain(" - execute");
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
AutonomyProfile,
|
|
4
|
+
LogicalConfig,
|
|
5
|
+
McpServerEntry
|
|
6
|
+
} from "@codemcp/ade-core";
|
|
3
7
|
import type { HarnessWriter } from "../types.js";
|
|
4
8
|
import {
|
|
5
9
|
writeMcpServers,
|
|
6
10
|
stdioEntry,
|
|
7
11
|
writeAgentMd,
|
|
8
|
-
writeGitHooks
|
|
12
|
+
writeGitHooks,
|
|
13
|
+
formatYamlKey
|
|
9
14
|
} from "../util.js";
|
|
10
|
-
import {
|
|
11
|
-
allowsCapability,
|
|
12
|
-
hasPermissionPolicy,
|
|
13
|
-
keepsWebOnAsk
|
|
14
|
-
} from "../permission-policy.js";
|
|
15
|
+
import { getAutonomyProfile } from "../permission-policy.js";
|
|
15
16
|
|
|
16
17
|
export const copilotWriter: HarnessWriter = {
|
|
17
18
|
id: "copilot",
|
|
@@ -25,7 +26,7 @@ export const copilotWriter: HarnessWriter = {
|
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
const tools = [
|
|
28
|
-
...getBuiltInTools(config),
|
|
29
|
+
...getBuiltInTools(getAutonomyProfile(config)),
|
|
29
30
|
...getForwardedMcpTools(config.mcp_servers)
|
|
30
31
|
];
|
|
31
32
|
|
|
@@ -41,25 +42,17 @@ export const copilotWriter: HarnessWriter = {
|
|
|
41
42
|
}
|
|
42
43
|
};
|
|
43
44
|
|
|
44
|
-
function getBuiltInTools(
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
function getBuiltInTools(profile: AutonomyProfile | undefined): string[] {
|
|
46
|
+
switch (profile) {
|
|
47
|
+
case "rigid":
|
|
48
|
+
return ["read"];
|
|
49
|
+
case "sensible-defaults":
|
|
50
|
+
return ["read", "edit", "search", "agent"];
|
|
51
|
+
case "max-autonomy":
|
|
52
|
+
return ["read", "edit", "search", "execute", "agent", "todo"];
|
|
53
|
+
default:
|
|
54
|
+
return ["read", "edit", "search", "execute", "agent", "web"];
|
|
47
55
|
}
|
|
48
|
-
|
|
49
|
-
return [
|
|
50
|
-
...(allowsCapability(config, "read") ? ["read"] : []),
|
|
51
|
-
...(allowsCapability(config, "edit_write") ? ["edit"] : []),
|
|
52
|
-
...(allowsCapability(config, "search_list") ? ["search"] : []),
|
|
53
|
-
...(allowsCapability(config, "bash_unsafe") ? ["execute"] : []),
|
|
54
|
-
...(allowsCapability(config, "task_agent") ? ["agent"] : []),
|
|
55
|
-
...(allowsCapability(config, "task_agent") &&
|
|
56
|
-
allowsCapability(config, "bash_unsafe")
|
|
57
|
-
? ["todo"]
|
|
58
|
-
: []),
|
|
59
|
-
...(!keepsWebOnAsk(config) && allowsCapability(config, "web")
|
|
60
|
-
? ["web"]
|
|
61
|
-
: [])
|
|
62
|
-
];
|
|
63
56
|
}
|
|
64
57
|
|
|
65
58
|
function getForwardedMcpTools(servers: McpServerEntry[]): string[] {
|
|
@@ -97,9 +90,3 @@ function renderCopilotAgentMcpServers(servers: McpServerEntry[]): string[] {
|
|
|
97
90
|
|
|
98
91
|
return lines;
|
|
99
92
|
}
|
|
100
|
-
|
|
101
|
-
function formatYamlKey(value: string): string {
|
|
102
|
-
return /^[A-Za-z_][A-Za-z0-9_-]*$/.test(value)
|
|
103
|
-
? value
|
|
104
|
-
: JSON.stringify(value);
|
|
105
|
-
}
|
|
@@ -10,47 +10,7 @@ import type {
|
|
|
10
10
|
import { cursorWriter } from "./cursor.js";
|
|
11
11
|
|
|
12
12
|
function autonomyPolicy(profile: AutonomyProfile): PermissionPolicy {
|
|
13
|
-
|
|
14
|
-
case "rigid":
|
|
15
|
-
return {
|
|
16
|
-
profile,
|
|
17
|
-
capabilities: {
|
|
18
|
-
read: "ask",
|
|
19
|
-
edit_write: "ask",
|
|
20
|
-
search_list: "ask",
|
|
21
|
-
bash_safe: "ask",
|
|
22
|
-
bash_unsafe: "ask",
|
|
23
|
-
web: "ask",
|
|
24
|
-
task_agent: "ask"
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
case "sensible-defaults":
|
|
28
|
-
return {
|
|
29
|
-
profile,
|
|
30
|
-
capabilities: {
|
|
31
|
-
read: "allow",
|
|
32
|
-
edit_write: "allow",
|
|
33
|
-
search_list: "allow",
|
|
34
|
-
bash_safe: "allow",
|
|
35
|
-
bash_unsafe: "ask",
|
|
36
|
-
web: "ask",
|
|
37
|
-
task_agent: "allow"
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
case "max-autonomy":
|
|
41
|
-
return {
|
|
42
|
-
profile,
|
|
43
|
-
capabilities: {
|
|
44
|
-
read: "allow",
|
|
45
|
-
edit_write: "allow",
|
|
46
|
-
search_list: "allow",
|
|
47
|
-
bash_safe: "allow",
|
|
48
|
-
bash_unsafe: "allow",
|
|
49
|
-
web: "ask",
|
|
50
|
-
task_agent: "allow"
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
13
|
+
return { profile };
|
|
54
14
|
}
|
|
55
15
|
|
|
56
16
|
describe("cursorWriter", () => {
|
|
@@ -1,34 +1,13 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import type {
|
|
3
|
+
import type { AutonomyProfile, LogicalConfig } from "@codemcp/ade-core";
|
|
4
4
|
import type { HarnessWriter } from "../types.js";
|
|
5
5
|
import { writeMcpServers, writeGitHooks } from "../util.js";
|
|
6
6
|
import {
|
|
7
7
|
getAutonomyProfile,
|
|
8
|
-
getCapabilityDecision,
|
|
9
8
|
hasPermissionPolicy
|
|
10
9
|
} from "../permission-policy.js";
|
|
11
10
|
|
|
12
|
-
const CURSOR_CAPABILITY_ORDER: AutonomyCapability[] = [
|
|
13
|
-
"read",
|
|
14
|
-
"edit_write",
|
|
15
|
-
"search_list",
|
|
16
|
-
"bash_safe",
|
|
17
|
-
"bash_unsafe",
|
|
18
|
-
"web",
|
|
19
|
-
"task_agent"
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
const CURSOR_CAPABILITY_LABELS: Record<AutonomyCapability, string> = {
|
|
23
|
-
read: "read project files",
|
|
24
|
-
edit_write: "edit and write project files",
|
|
25
|
-
search_list: "search and list project contents",
|
|
26
|
-
bash_safe: "run safe local shell commands",
|
|
27
|
-
bash_unsafe: "run high-impact shell commands",
|
|
28
|
-
web: "use web or network access",
|
|
29
|
-
task_agent: "delegate or decompose work into agent tasks"
|
|
30
|
-
};
|
|
31
|
-
|
|
32
11
|
export const cursorWriter: HarnessWriter = {
|
|
33
12
|
id: "cursor",
|
|
34
13
|
label: "Cursor",
|
|
@@ -68,28 +47,37 @@ function getCursorAutonomyNotes(config: LogicalConfig): string[] {
|
|
|
68
47
|
return [];
|
|
69
48
|
}
|
|
70
49
|
|
|
71
|
-
const
|
|
72
|
-
(capability) => getCapabilityDecision(config, capability) === "allow"
|
|
73
|
-
).map((capability) => CURSOR_CAPABILITY_LABELS[capability]);
|
|
74
|
-
|
|
75
|
-
const approvalGatedCapabilities = CURSOR_CAPABILITY_ORDER.filter(
|
|
76
|
-
(capability) => getCapabilityDecision(config, capability) === "ask"
|
|
77
|
-
).map((capability) => CURSOR_CAPABILITY_LABELS[capability]);
|
|
50
|
+
const profile = getAutonomyProfile(config);
|
|
78
51
|
|
|
79
52
|
return [
|
|
80
|
-
`Cursor autonomy note (documented, not enforced): ${
|
|
53
|
+
`Cursor autonomy note (documented, not enforced): ${profile ?? "custom"}.`,
|
|
81
54
|
"Cursor has no verified committed project-local built-in ask/allow/deny config surface, so ADE documents autonomy intent here instead of writing unsupported permission config.",
|
|
82
|
-
...(
|
|
83
|
-
? [
|
|
84
|
-
`Prefer handling these built-in capabilities without extra approval when Cursor permits it: ${allowedCapabilities.join(", ")}.`
|
|
85
|
-
]
|
|
86
|
-
: []),
|
|
87
|
-
...(approvalGatedCapabilities.length > 0
|
|
88
|
-
? [
|
|
89
|
-
`Request approval before these capabilities: ${approvalGatedCapabilities.join(", ")}.`
|
|
90
|
-
]
|
|
91
|
-
: []),
|
|
55
|
+
...getCursorProfileGuidance(profile),
|
|
92
56
|
"Web and network access must remain approval-gated.",
|
|
93
57
|
"MCP server registration stays in .cursor/mcp.json; MCP tool approvals remain owned by provisioning and are not enforced or re-modeled in this rules file."
|
|
94
58
|
];
|
|
95
59
|
}
|
|
60
|
+
|
|
61
|
+
function getCursorProfileGuidance(
|
|
62
|
+
profile: AutonomyProfile | undefined
|
|
63
|
+
): string[] {
|
|
64
|
+
switch (profile) {
|
|
65
|
+
case "rigid":
|
|
66
|
+
return [
|
|
67
|
+
"Prefer handling these built-in capabilities without extra approval when Cursor permits it: read project files.",
|
|
68
|
+
"Request approval before these capabilities: edit and write project files, search and list project contents, run safe local shell commands, run high-impact shell commands, use web or network access, delegate or decompose work into agent tasks."
|
|
69
|
+
];
|
|
70
|
+
case "sensible-defaults":
|
|
71
|
+
return [
|
|
72
|
+
"Prefer handling these built-in capabilities without extra approval when Cursor permits it: read project files, edit and write project files, search and list project contents, run safe local shell commands, delegate or decompose work into agent tasks.",
|
|
73
|
+
"Request approval before these capabilities: run high-impact shell commands, use web or network access."
|
|
74
|
+
];
|
|
75
|
+
case "max-autonomy":
|
|
76
|
+
return [
|
|
77
|
+
"Prefer handling these built-in capabilities without extra approval when Cursor permits it: read project files, edit and write project files, search and list project contents, run safe local shell commands, run high-impact shell commands, delegate or decompose work into agent tasks.",
|
|
78
|
+
"Request approval before these capabilities: use web or network access."
|
|
79
|
+
];
|
|
80
|
+
default:
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -10,47 +10,7 @@ import type {
|
|
|
10
10
|
import { kiroWriter } from "./kiro.js";
|
|
11
11
|
|
|
12
12
|
function autonomyPolicy(profile: AutonomyProfile): PermissionPolicy {
|
|
13
|
-
|
|
14
|
-
case "rigid":
|
|
15
|
-
return {
|
|
16
|
-
profile,
|
|
17
|
-
capabilities: {
|
|
18
|
-
read: "ask",
|
|
19
|
-
edit_write: "ask",
|
|
20
|
-
search_list: "ask",
|
|
21
|
-
bash_safe: "ask",
|
|
22
|
-
bash_unsafe: "ask",
|
|
23
|
-
web: "ask",
|
|
24
|
-
task_agent: "ask"
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
case "sensible-defaults":
|
|
28
|
-
return {
|
|
29
|
-
profile,
|
|
30
|
-
capabilities: {
|
|
31
|
-
read: "allow",
|
|
32
|
-
edit_write: "allow",
|
|
33
|
-
search_list: "allow",
|
|
34
|
-
bash_safe: "allow",
|
|
35
|
-
bash_unsafe: "ask",
|
|
36
|
-
web: "ask",
|
|
37
|
-
task_agent: "allow"
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
case "max-autonomy":
|
|
41
|
-
return {
|
|
42
|
-
profile,
|
|
43
|
-
capabilities: {
|
|
44
|
-
read: "allow",
|
|
45
|
-
edit_write: "allow",
|
|
46
|
-
search_list: "allow",
|
|
47
|
-
bash_safe: "allow",
|
|
48
|
-
bash_unsafe: "allow",
|
|
49
|
-
web: "ask",
|
|
50
|
-
task_agent: "allow"
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
13
|
+
return { profile };
|
|
54
14
|
}
|
|
55
15
|
|
|
56
16
|
describe("kiroWriter", () => {
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
AutonomyProfile,
|
|
4
|
+
LogicalConfig,
|
|
5
|
+
McpServerEntry
|
|
6
|
+
} from "@codemcp/ade-core";
|
|
3
7
|
import type { HarnessWriter } from "../types.js";
|
|
4
8
|
import {
|
|
5
9
|
standardEntry,
|
|
@@ -7,11 +11,7 @@ import {
|
|
|
7
11
|
writeJson,
|
|
8
12
|
writeMcpServers
|
|
9
13
|
} from "../util.js";
|
|
10
|
-
import {
|
|
11
|
-
allowsCapability,
|
|
12
|
-
getCapabilityDecision,
|
|
13
|
-
hasPermissionPolicy
|
|
14
|
-
} from "../permission-policy.js";
|
|
14
|
+
import { getAutonomyProfile } from "../permission-policy.js";
|
|
15
15
|
|
|
16
16
|
export const kiroWriter: HarnessWriter = {
|
|
17
17
|
id: "kiro",
|
|
@@ -26,6 +26,7 @@ export const kiroWriter: HarnessWriter = {
|
|
|
26
26
|
})
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
+
const tools = getKiroTools(getAutonomyProfile(config), config.mcp_servers);
|
|
29
30
|
await writeJson(join(projectRoot, ".kiro", "agents", "ade.json"), {
|
|
30
31
|
name: "ade",
|
|
31
32
|
description:
|
|
@@ -34,8 +35,8 @@ export const kiroWriter: HarnessWriter = {
|
|
|
34
35
|
config.instructions.join("\n\n") ||
|
|
35
36
|
"ADE — Agentic Development Environment agent.",
|
|
36
37
|
mcpServers: getKiroAgentMcpServers(config.mcp_servers),
|
|
37
|
-
tools
|
|
38
|
-
allowedTools:
|
|
38
|
+
tools,
|
|
39
|
+
allowedTools: tools,
|
|
39
40
|
useLegacyMcpJson: true
|
|
40
41
|
});
|
|
41
42
|
|
|
@@ -43,24 +44,22 @@ export const kiroWriter: HarnessWriter = {
|
|
|
43
44
|
}
|
|
44
45
|
};
|
|
45
46
|
|
|
46
|
-
function getKiroTools(
|
|
47
|
-
|
|
47
|
+
function getKiroTools(
|
|
48
|
+
profile: AutonomyProfile | undefined,
|
|
49
|
+
servers: McpServerEntry[]
|
|
50
|
+
): string[] {
|
|
51
|
+
const mcpTools = getKiroForwardedMcpTools(servers);
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
switch (profile) {
|
|
54
|
+
case "rigid":
|
|
55
|
+
return ["read", "shell", "spec", ...mcpTools];
|
|
56
|
+
case "sensible-defaults":
|
|
57
|
+
return ["read", "write", "shell", "spec", ...mcpTools];
|
|
58
|
+
case "max-autonomy":
|
|
59
|
+
return ["read", "write", "shell(*)", "spec", ...mcpTools];
|
|
60
|
+
default:
|
|
61
|
+
return ["read", "write", "shell", "spec", ...mcpTools];
|
|
51
62
|
}
|
|
52
|
-
|
|
53
|
-
return [
|
|
54
|
-
...(getCapabilityDecision(config, "read") !== "deny" ? ["read"] : []),
|
|
55
|
-
...(allowsCapability(config, "edit_write") ? ["write"] : []),
|
|
56
|
-
...(allowsCapability(config, "bash_unsafe") ? ["shell(*)"] : ["shell"]),
|
|
57
|
-
"spec",
|
|
58
|
-
...mcpTools
|
|
59
|
-
];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function getKiroAllowedTools(config: LogicalConfig): string[] {
|
|
63
|
-
return getKiroTools(config);
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
function getKiroForwardedMcpTools(servers: McpServerEntry[]): string[] {
|
|
@@ -11,47 +11,7 @@ import { parse as parseYaml } from "yaml";
|
|
|
11
11
|
import { opencodeWriter } from "./opencode.js";
|
|
12
12
|
|
|
13
13
|
function autonomyPolicy(profile: AutonomyProfile): PermissionPolicy {
|
|
14
|
-
|
|
15
|
-
case "rigid":
|
|
16
|
-
return {
|
|
17
|
-
profile,
|
|
18
|
-
capabilities: {
|
|
19
|
-
read: "ask",
|
|
20
|
-
edit_write: "ask",
|
|
21
|
-
search_list: "ask",
|
|
22
|
-
bash_safe: "ask",
|
|
23
|
-
bash_unsafe: "ask",
|
|
24
|
-
web: "ask",
|
|
25
|
-
task_agent: "ask"
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
case "sensible-defaults":
|
|
29
|
-
return {
|
|
30
|
-
profile,
|
|
31
|
-
capabilities: {
|
|
32
|
-
read: "allow",
|
|
33
|
-
edit_write: "allow",
|
|
34
|
-
search_list: "allow",
|
|
35
|
-
bash_safe: "allow",
|
|
36
|
-
bash_unsafe: "ask",
|
|
37
|
-
web: "ask",
|
|
38
|
-
task_agent: "allow"
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
case "max-autonomy":
|
|
42
|
-
return {
|
|
43
|
-
profile,
|
|
44
|
-
capabilities: {
|
|
45
|
-
read: "allow",
|
|
46
|
-
edit_write: "allow",
|
|
47
|
-
search_list: "allow",
|
|
48
|
-
bash_safe: "allow",
|
|
49
|
-
bash_unsafe: "allow",
|
|
50
|
-
web: "ask",
|
|
51
|
-
task_agent: "allow"
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
}
|
|
14
|
+
return { profile };
|
|
55
15
|
}
|
|
56
16
|
|
|
57
17
|
describe("opencodeWriter", () => {
|
|
@@ -1,8 +1,161 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
-
import type {
|
|
2
|
+
import type { AutonomyProfile, LogicalConfig } from "@codemcp/ade-core";
|
|
3
3
|
import type { HarnessWriter } from "../types.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
writeAgentMd,
|
|
6
|
+
writeGitHooks,
|
|
7
|
+
writeMcpServers,
|
|
8
|
+
formatYamlKey
|
|
9
|
+
} from "../util.js";
|
|
10
|
+
import { getAutonomyProfile } from "../permission-policy.js";
|
|
11
|
+
|
|
12
|
+
type PermissionDecision = "ask" | "allow" | "deny";
|
|
13
|
+
type PermissionRule = PermissionDecision | Record<string, PermissionDecision>;
|
|
14
|
+
|
|
15
|
+
const RIGID_RULES: Record<string, PermissionRule> = {
|
|
16
|
+
"*": "ask",
|
|
17
|
+
webfetch: "ask",
|
|
18
|
+
websearch: "ask",
|
|
19
|
+
codesearch: "ask",
|
|
20
|
+
external_directory: "deny",
|
|
21
|
+
doom_loop: "deny"
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const SENSIBLE_DEFAULTS_RULES: Record<string, PermissionRule> = {
|
|
25
|
+
read: {
|
|
26
|
+
"*": "allow",
|
|
27
|
+
"*.env": "deny",
|
|
28
|
+
"*.env.*": "deny",
|
|
29
|
+
"*.env.example": "allow"
|
|
30
|
+
},
|
|
31
|
+
edit: "allow",
|
|
32
|
+
glob: "allow",
|
|
33
|
+
grep: "allow",
|
|
34
|
+
list: "allow",
|
|
35
|
+
lsp: "allow",
|
|
36
|
+
task: "allow",
|
|
37
|
+
todoread: "deny",
|
|
38
|
+
todowrite: "deny",
|
|
39
|
+
skill: "deny",
|
|
40
|
+
webfetch: "ask",
|
|
41
|
+
websearch: "ask",
|
|
42
|
+
codesearch: "ask",
|
|
43
|
+
bash: {
|
|
44
|
+
"*": "deny",
|
|
45
|
+
"grep *": "allow",
|
|
46
|
+
"rg *": "allow",
|
|
47
|
+
"find *": "allow",
|
|
48
|
+
"fd *": "allow",
|
|
49
|
+
ls: "allow",
|
|
50
|
+
"ls *": "allow",
|
|
51
|
+
"cat *": "allow",
|
|
52
|
+
"head *": "allow",
|
|
53
|
+
"tail *": "allow",
|
|
54
|
+
"wc *": "allow",
|
|
55
|
+
"sort *": "allow",
|
|
56
|
+
"uniq *": "allow",
|
|
57
|
+
"diff *": "allow",
|
|
58
|
+
"echo *": "allow",
|
|
59
|
+
"printf *": "allow",
|
|
60
|
+
pwd: "allow",
|
|
61
|
+
"which *": "allow",
|
|
62
|
+
"type *": "allow",
|
|
63
|
+
whoami: "allow",
|
|
64
|
+
date: "allow",
|
|
65
|
+
"date *": "allow",
|
|
66
|
+
env: "allow",
|
|
67
|
+
"tree *": "allow",
|
|
68
|
+
"file *": "allow",
|
|
69
|
+
"stat *": "allow",
|
|
70
|
+
"readlink *": "allow",
|
|
71
|
+
"realpath *": "allow",
|
|
72
|
+
"dirname *": "allow",
|
|
73
|
+
"basename *": "allow",
|
|
74
|
+
"sed *": "allow",
|
|
75
|
+
"awk *": "allow",
|
|
76
|
+
"cut *": "allow",
|
|
77
|
+
"tr *": "allow",
|
|
78
|
+
"tee *": "allow",
|
|
79
|
+
"xargs *": "allow",
|
|
80
|
+
"jq *": "allow",
|
|
81
|
+
"yq *": "allow",
|
|
82
|
+
"mkdir *": "allow",
|
|
83
|
+
"touch *": "allow",
|
|
84
|
+
"cp *": "ask",
|
|
85
|
+
"mv *": "ask",
|
|
86
|
+
"ln *": "ask",
|
|
87
|
+
"npm *": "ask",
|
|
88
|
+
"node *": "ask",
|
|
89
|
+
"pip *": "ask",
|
|
90
|
+
"python *": "ask",
|
|
91
|
+
"python3 *": "ask",
|
|
92
|
+
"rm *": "deny",
|
|
93
|
+
"rmdir *": "deny",
|
|
94
|
+
"curl *": "deny",
|
|
95
|
+
"wget *": "deny",
|
|
96
|
+
"chmod *": "deny",
|
|
97
|
+
"chown *": "deny",
|
|
98
|
+
"sudo *": "deny",
|
|
99
|
+
"su *": "deny",
|
|
100
|
+
"sh *": "deny",
|
|
101
|
+
"bash *": "deny",
|
|
102
|
+
"zsh *": "deny",
|
|
103
|
+
"eval *": "deny",
|
|
104
|
+
"exec *": "deny",
|
|
105
|
+
"source *": "deny",
|
|
106
|
+
". *": "deny",
|
|
107
|
+
"nohup *": "deny",
|
|
108
|
+
"dd *": "deny",
|
|
109
|
+
"mkfs *": "deny",
|
|
110
|
+
"mount *": "deny",
|
|
111
|
+
"umount *": "deny",
|
|
112
|
+
"kill *": "deny",
|
|
113
|
+
"killall *": "deny",
|
|
114
|
+
"pkill *": "deny",
|
|
115
|
+
"nc *": "deny",
|
|
116
|
+
"ncat *": "deny",
|
|
117
|
+
"ssh *": "deny",
|
|
118
|
+
"scp *": "deny",
|
|
119
|
+
"rsync *": "deny",
|
|
120
|
+
"docker *": "deny",
|
|
121
|
+
"kubectl *": "deny",
|
|
122
|
+
"systemctl *": "deny",
|
|
123
|
+
"service *": "deny",
|
|
124
|
+
"crontab *": "deny",
|
|
125
|
+
reboot: "deny",
|
|
126
|
+
"shutdown *": "deny",
|
|
127
|
+
"passwd *": "deny",
|
|
128
|
+
"useradd *": "deny",
|
|
129
|
+
"userdel *": "deny",
|
|
130
|
+
"iptables *": "deny"
|
|
131
|
+
},
|
|
132
|
+
external_directory: "deny",
|
|
133
|
+
doom_loop: "deny"
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const MAX_AUTONOMY_RULES: Record<string, PermissionRule> = {
|
|
137
|
+
"*": "allow",
|
|
138
|
+
webfetch: "ask",
|
|
139
|
+
websearch: "ask",
|
|
140
|
+
codesearch: "ask",
|
|
141
|
+
external_directory: "deny",
|
|
142
|
+
doom_loop: "deny"
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
function getPermissionRules(
|
|
146
|
+
profile: AutonomyProfile | undefined
|
|
147
|
+
): Record<string, PermissionRule> | undefined {
|
|
148
|
+
switch (profile) {
|
|
149
|
+
case "rigid":
|
|
150
|
+
return RIGID_RULES;
|
|
151
|
+
case "sensible-defaults":
|
|
152
|
+
return SENSIBLE_DEFAULTS_RULES;
|
|
153
|
+
case "max-autonomy":
|
|
154
|
+
return MAX_AUTONOMY_RULES;
|
|
155
|
+
default:
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
6
159
|
|
|
7
160
|
export const opencodeWriter: HarnessWriter = {
|
|
8
161
|
id: "opencode",
|
|
@@ -20,7 +173,7 @@ export const opencodeWriter: HarnessWriter = {
|
|
|
20
173
|
defaults: { $schema: "https://opencode.ai/config.json" }
|
|
21
174
|
});
|
|
22
175
|
|
|
23
|
-
const permission =
|
|
176
|
+
const permission = getPermissionRules(getAutonomyProfile(config));
|
|
24
177
|
|
|
25
178
|
await writeAgentMd(config, {
|
|
26
179
|
path: join(projectRoot, ".opencode", "agents", "ade.md"),
|
|
@@ -59,9 +212,3 @@ function renderYamlMapping(
|
|
|
59
212
|
|
|
60
213
|
return lines;
|
|
61
214
|
}
|
|
62
|
-
|
|
63
|
-
function formatYamlKey(value: string): string {
|
|
64
|
-
return /^[A-Za-z_][A-Za-z0-9_-]*$/.test(value)
|
|
65
|
-
? value
|
|
66
|
-
: JSON.stringify(value);
|
|
67
|
-
}
|