-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig-injector.ts
More file actions
116 lines (95 loc) · 3.57 KB
/
config-injector.ts
File metadata and controls
116 lines (95 loc) · 3.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { Config } from "../config/config"
import { ModesMigrator } from "./modes-migrator"
import { RulesMigrator } from "./rules-migrator" // kilocode_change
import { WorkflowsMigrator } from "./workflows-migrator"
import { IgnoreMigrator } from "./ignore-migrator" // kilocode_change
export namespace KilocodeConfigInjector {
export interface InjectionResult {
configJson: string
warnings: string[]
}
export async function buildConfig(options: {
projectDir: string
globalSettingsDir?: string
/** Skip reading from global paths (VSCode storage, home dir). Used for testing. */
skipGlobalPaths?: boolean
/** Include rules migration. Defaults to true. */
includeRules?: boolean
/** Include ignore migration. Defaults to true. */
includeIgnore?: boolean
}): Promise<InjectionResult> {
const warnings: string[] = []
// Build config object
const config: Partial<Config.Info> = {}
// Migrate custom modes
const modesMigration = await ModesMigrator.migrate(options)
// Log skipped default modes (for debugging)
for (const skipped of modesMigration.skipped) {
warnings.push(`Mode '${skipped.slug}' skipped: ${skipped.reason}`)
}
if (Object.keys(modesMigration.agents).length > 0) {
config.agent = modesMigration.agents
}
// Migrate workflows to commands
const workflowsMigration = await WorkflowsMigrator.migrate(options)
warnings.push(...workflowsMigration.warnings)
if (Object.keys(workflowsMigration.commands).length > 0) {
config.command = workflowsMigration.commands
}
// kilocode_change start - Rules migration
if (options.includeRules !== false) {
const rulesMigration = await RulesMigrator.migrate({
projectDir: options.projectDir,
includeGlobal: !options.skipGlobalPaths,
includeModeSpecific: true,
})
warnings.push(...rulesMigration.warnings)
if (rulesMigration.instructions.length > 0) {
config.instructions = rulesMigration.instructions
}
}
// kilocode_change end
// kilocode_change start - Ignore migration
if (options.includeIgnore !== false) {
const ignoreMigration = await IgnoreMigrator.migrate({
projectDir: options.projectDir,
skipGlobalPaths: options.skipGlobalPaths,
})
warnings.push(...ignoreMigration.warnings)
if (Object.keys(ignoreMigration.permission).length > 0) {
config.permission = mergePermissions(config.permission, ignoreMigration.permission)
}
}
// kilocode_change end
return {
configJson: JSON.stringify(config),
warnings,
}
}
/**
* Merge permission configs, preserving order and handling duplicates.
* Incoming rules take precedence (kilocode patterns override).
*/
function mergePermissions(existing: Config.Permission | undefined, incoming: Config.Permission): Config.Permission {
if (!existing) return incoming
const result: Config.Permission = { ...existing }
for (const [key, value] of Object.entries(incoming)) {
if (key === "read" || key === "edit") {
const existingRules = (result[key] as Record<string, Config.PermissionAction>) ?? {}
const incomingRules = value as Record<string, Config.PermissionAction>
result[key] = { ...existingRules, ...incomingRules }
} else {
result[key] = value
}
}
return result
}
export function getEnvVars(configJson: string): Record<string, string> {
if (!configJson || configJson === "{}") {
return {}
}
return {
KILO_CONFIG_CONTENT: configJson,
}
}
}