Merge pull request #47 from Kilo-Org/feat/auto-mode-for-ci-cd

feat: Add --auto mode for non-interactive CI/CD pipelines
This commit is contained in:
Marius
2026-01-28 13:04:23 +01:00
committed by GitHub
3 changed files with 155 additions and 15 deletions
+10
View File
@@ -35,6 +35,16 @@ Kilo CLI includes two built-in agents you can switch between using the `Tab` key
Also included is a **general** subagent for complex searches and multi-step tasks.
This is used internally and can be invoked using `@general` in messages.
### Autonomous Mode (CI/CD)
Use the `--auto` flag with `kilo run` to enable fully autonomous operation without user interaction. This is ideal for CI/CD pipelines and automated workflows:
```bash
kilo run --auto "run tests and fix any failures"
```
**Important:** The `--auto` flag disables all permission prompts and allows the agent to execute any action without confirmation. Only use this in trusted environments like CI/CD pipelines.
### Migrating from Kilo Code Extension
If you're coming from the Kilo Code VS Code extension, your configurations are automatically migrated:
+69 -15
View File
@@ -91,6 +91,10 @@ export const RunCommand = cmd({
type: "string",
describe: "model variant (provider-specific reasoning effort, e.g., high, max, minimal)",
})
.option("auto", { // kilocode_change
type: "boolean",
describe: "auto-approve all permissions (for autonomous/pipeline usage)",
})
},
handler: async (args) => {
let message = [...args.message, ...(args["--"] || [])]
@@ -209,6 +213,18 @@ export const RunCommand = cmd({
if (event.type === "permission.asked") {
const permission = event.properties
if (permission.sessionID !== sessionID) continue
// kilocode_change start - In auto mode, automatically approve all permissions without prompting
if (args.auto) {
await sdk.permission.respond({
sessionID,
permissionID: permission.id,
response: "always",
})
continue
}
// kilocode_change end
const result = await select({
message: `Permission required: ${permission.permission} (${permission.patterns.join(", ")})`,
options: [
@@ -292,28 +308,42 @@ export const RunCommand = cmd({
: args.title
: undefined
const basePermissions = [
{
permission: "question",
action: "deny" as const,
pattern: "*",
},
]
// kilocode_change start - In auto mode, allow all permissions by default except questions
// The question deny rule must come AFTER the wildcard to override it (findLast behavior)
const permissions = args.auto
? [
{
permission: "*",
action: "allow" as const,
pattern: "*",
},
{
permission: "question",
action: "deny" as const,
pattern: "*",
},
]
: basePermissions
const result = await sdk.session.create(
title
? {
title,
permission: [
{
permission: "question",
action: "deny",
pattern: "*",
},
],
permission: permissions,
}
: {
permission: [
{
permission: "question",
action: "deny",
pattern: "*",
},
],
permission: permissions,
},
)
// kilocode_change end
return result.data?.id
})()
@@ -367,7 +397,31 @@ export const RunCommand = cmd({
: args.title
: undefined
const result = await sdk.session.create(title ? { title } : {})
// kilocode_change start - In auto mode, allow all permissions by default except questions
// The question deny rule must come AFTER the wildcard to override it (findLast behavior)
const permissions = args.auto
? [
{
permission: "*",
action: "allow" as const,
pattern: "*",
},
{
permission: "question",
action: "deny" as const,
pattern: "*",
},
]
: undefined
const result = await sdk.session.create(
title
? { title, permission: permissions }
: permissions
? { permission: permissions }
: {},
)
// kilocode_change end
return result.data?.id
})()
@@ -0,0 +1,76 @@
// kilocode_change - new file
import { describe, expect, test } from "bun:test"
describe("Auto mode flag", () => {
test("auto mode should create session with allow-all permissions except questions", () => {
// When --auto flag is set, the session should be created with:
// 1. Wildcard allow rule for all permissions
// 2. Explicit deny rule for questions (to prevent user interaction)
const autoPermissions = [
{
permission: "*",
action: "allow" as const,
pattern: "*",
},
{
permission: "question",
action: "deny" as const,
pattern: "*",
},
]
expect(autoPermissions).toHaveLength(2)
// First rule: allow all
expect(autoPermissions[0].permission).toBe("*")
expect(autoPermissions[0].action).toBe("allow")
expect(autoPermissions[0].pattern).toBe("*")
// Second rule: deny questions (comes after wildcard to override it)
expect(autoPermissions[1].permission).toBe("question")
expect(autoPermissions[1].action).toBe("deny")
expect(autoPermissions[1].pattern).toBe("*")
})
test("non-auto mode should not set allow-all permissions", () => {
// When --auto flag is NOT set, permissions should be undefined or default
const normalPermissions = undefined
expect(normalPermissions).toBeUndefined()
})
test("permission evaluation order matters (findLast behavior)", () => {
// The permission system uses findLast, so the last matching rule wins
// This test verifies that the question deny rule comes AFTER the wildcard
const autoPermissions = [
{ permission: "*", action: "allow" as const, pattern: "*" },
{ permission: "question", action: "deny" as const, pattern: "*" },
]
// Simulate findLast behavior
const findLastMatch = (permission: string) => {
for (let i = autoPermissions.length - 1; i >= 0; i--) {
if (permission === autoPermissions[i].permission || autoPermissions[i].permission === "*") {
return autoPermissions[i]
}
}
return null
}
// Test that "question" permission resolves to "deny"
const questionRule = findLastMatch("question")
expect(questionRule?.action).toBe("deny")
// Test that other permissions resolve to "allow"
const bashRule = findLastMatch("bash")
expect(bashRule?.action).toBe("allow")
const editRule = findLastMatch("edit")
expect(editRule?.action).toBe("allow")
const externalDirRule = findLastMatch("external_directory")
expect(externalDirRule?.action).toBe("allow")
})
})