|
|
@@ -15,7 +15,10 @@ import type { Argv } from "yargs"
|
|
|
|
|
|
type AgentMode = "all" | "primary" | "subagent"
|
|
|
|
|
|
-const AVAILABLE_TOOLS = ["bash", "read", "write", "edit", "glob", "grep", "webfetch", "task", "todowrite"]
|
|
|
+// Permission keys (not raw tool names). Multiple tools can map to a single
|
|
|
+// permission — e.g. write/edit/apply_patch all gate on `edit` — so we configure
|
|
|
+// agents at the permission level to match how the runtime actually enforces it.
|
|
|
+const AVAILABLE_PERMISSIONS = ["bash", "read", "edit", "glob", "grep", "webfetch", "task", "todowrite", "websearch", "codesearch", "lsp", "skill"]
|
|
|
|
|
|
const AgentCreateCommand = cmd({
|
|
|
command: "create",
|
|
|
@@ -35,9 +38,10 @@ const AgentCreateCommand = cmd({
|
|
|
describe: "agent mode",
|
|
|
choices: ["all", "primary", "subagent"] as const,
|
|
|
})
|
|
|
- .option("tools", {
|
|
|
+ .option("permissions", {
|
|
|
type: "string",
|
|
|
- describe: `comma-separated list of tools to enable (default: all). Available: "${AVAILABLE_TOOLS.join(", ")}"`,
|
|
|
+ alias: ["tools"],
|
|
|
+ describe: `comma-separated list of permissions to allow (default: all). Available: "${AVAILABLE_PERMISSIONS.join(", ")}"`,
|
|
|
})
|
|
|
.option("model", {
|
|
|
type: "string",
|
|
|
@@ -51,9 +55,9 @@ const AgentCreateCommand = cmd({
|
|
|
const cliPath = args.path
|
|
|
const cliDescription = args.description
|
|
|
const cliMode = args.mode as AgentMode | undefined
|
|
|
- const cliTools = args.tools
|
|
|
+ const perms = args.permissions
|
|
|
|
|
|
- const isFullyNonInteractive = cliPath && cliDescription && cliMode && cliTools !== undefined
|
|
|
+ const isFullyNonInteractive = cliPath && cliDescription && cliMode && perms !== undefined
|
|
|
|
|
|
if (!isFullyNonInteractive) {
|
|
|
UI.empty()
|
|
|
@@ -120,21 +124,21 @@ const AgentCreateCommand = cmd({
|
|
|
})
|
|
|
spinner.stop(`Agent ${generated.identifier} generated`)
|
|
|
|
|
|
- // Select tools
|
|
|
- let selectedTools: string[]
|
|
|
- if (cliTools !== undefined) {
|
|
|
- selectedTools = cliTools ? cliTools.split(",").map((t) => t.trim()) : AVAILABLE_TOOLS
|
|
|
+ // Select permissions to allow
|
|
|
+ let selected: string[]
|
|
|
+ if (perms !== undefined) {
|
|
|
+ selected = perms ? perms.split(",").map((t) => t.trim()) : AVAILABLE_PERMISSIONS
|
|
|
} else {
|
|
|
const result = await prompts.multiselect({
|
|
|
- message: "Select tools to enable (Space to toggle)",
|
|
|
- options: AVAILABLE_TOOLS.map((tool) => ({
|
|
|
- label: tool,
|
|
|
- value: tool,
|
|
|
+ message: "Select permissions to allow (Space to toggle)",
|
|
|
+ options: AVAILABLE_PERMISSIONS.map((permission) => ({
|
|
|
+ label: permission,
|
|
|
+ value: permission,
|
|
|
})),
|
|
|
- initialValues: AVAILABLE_TOOLS,
|
|
|
+ initialValues: AVAILABLE_PERMISSIONS,
|
|
|
})
|
|
|
if (prompts.isCancel(result)) throw new UI.CancelledError()
|
|
|
- selectedTools = result
|
|
|
+ selected = result
|
|
|
}
|
|
|
|
|
|
// Get mode
|
|
|
@@ -167,11 +171,11 @@ const AgentCreateCommand = cmd({
|
|
|
mode = modeResult
|
|
|
}
|
|
|
|
|
|
- // Build tools config
|
|
|
- const tools: Record<string, boolean> = {}
|
|
|
- for (const tool of AVAILABLE_TOOLS) {
|
|
|
- if (!selectedTools.includes(tool)) {
|
|
|
- tools[tool] = false
|
|
|
+ // Build permissions config — deny anything not explicitly selected.
|
|
|
+ const permissions: Record<string, "deny"> = {}
|
|
|
+ for (const permission of AVAILABLE_PERMISSIONS) {
|
|
|
+ if (!selected.includes(permission)) {
|
|
|
+ permissions[permission] = "deny"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -179,13 +183,13 @@ const AgentCreateCommand = cmd({
|
|
|
const frontmatter: {
|
|
|
description: string
|
|
|
mode: AgentMode
|
|
|
- tools?: Record<string, boolean>
|
|
|
+ permission?: Record<string, "deny">
|
|
|
} = {
|
|
|
description: generated.whenToUse,
|
|
|
mode,
|
|
|
}
|
|
|
- if (Object.keys(tools).length > 0) {
|
|
|
- frontmatter.tools = tools
|
|
|
+ if (Object.keys(permissions).length > 0) {
|
|
|
+ frontmatter.permission = permissions
|
|
|
}
|
|
|
|
|
|
// Write file
|