Install a rule for an agent, handling both "file" (standalone) and "append" (AGENTS.md) types.
( agentName: SetupAgent, mode: SetupMode, scope: Scope )
| 227 | |
| 228 | /** Install a rule for an agent, handling both "file" (standalone) and "append" (AGENTS.md) types. */ |
| 229 | async function installRule( |
| 230 | agentName: SetupAgent, |
| 231 | mode: SetupMode, |
| 232 | scope: Scope |
| 233 | ): Promise<{ status: string; path: string }> { |
| 234 | const agent = getAgent(agentName); |
| 235 | const rule = agent.rule; |
| 236 | const content = await getRuleContent(mode, agentName); |
| 237 | |
| 238 | if (rule.kind === "file") { |
| 239 | const ruleDir = |
| 240 | scope === "global" ? rule.dir("global") : join(process.cwd(), rule.dir("project")); |
| 241 | const rulePath = join(ruleDir, rule.filename); |
| 242 | await mkdir(dirname(rulePath), { recursive: true }); |
| 243 | await writeFile(rulePath, content, "utf-8"); |
| 244 | return { status: "installed", path: rulePath }; |
| 245 | } |
| 246 | |
| 247 | const filePath = |
| 248 | scope === "global" ? rule.file("global") : join(process.cwd(), rule.file("project")); |
| 249 | const escapedMarker = rule.sectionMarker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); |
| 250 | const section = `${rule.sectionMarker}\n${content}${rule.sectionMarker}`; |
| 251 | |
| 252 | let existing = ""; |
| 253 | try { |
| 254 | existing = await readFile(filePath, "utf-8"); |
| 255 | } catch { |
| 256 | // File doesn't exist yet |
| 257 | } |
| 258 | |
| 259 | if (existing.includes(rule.sectionMarker)) { |
| 260 | const regex = new RegExp(`${escapedMarker}\\n[\\s\\S]*?${escapedMarker}`); |
| 261 | const updated = existing.replace(regex, section); |
| 262 | await writeFile(filePath, updated, "utf-8"); |
| 263 | return { status: "updated", path: filePath }; |
| 264 | } |
| 265 | |
| 266 | const separator = |
| 267 | existing.length > 0 && !existing.endsWith("\n") ? "\n\n" : existing.length > 0 ? "\n" : ""; |
| 268 | await mkdir(dirname(filePath), { recursive: true }); |
| 269 | await writeFile(filePath, existing + separator + section + "\n", "utf-8"); |
| 270 | return { status: "installed", path: filePath }; |
| 271 | } |
| 272 | |
| 273 | /** |
| 274 | * For stdio transport, preserve an existing `@upstash/context7-mcp` invocation |
no test coverage detected