()
| 380 | } |
| 381 | |
| 382 | async function main() { |
| 383 | const args = parseArgs(process.argv.slice(2)); |
| 384 | |
| 385 | if (args.help) { |
| 386 | console.log(`loop-init — scaffold loop engineering starters |
| 387 | |
| 388 | Usage: |
| 389 | loop-init [target-dir] --pattern <name> --tool <grok|claude|codex|opencode> |
| 390 | |
| 391 | Patterns: |
| 392 | daily-triage (default) |
| 393 | pr-babysitter |
| 394 | ci-sweeper |
| 395 | dependency-sweeper |
| 396 | post-merge-cleanup |
| 397 | changelog-drafter (new low-risk release notes pattern) |
| 398 | issue-triage (new low-risk issue queue health companion to daily triage) |
| 399 | |
| 400 | Options: |
| 401 | -p, --pattern Pattern to scaffold |
| 402 | -t, --tool Tool target (default: grok) |
| 403 | --dry-run Print actions without copying |
| 404 | -h, --help This help |
| 405 | |
| 406 | Examples: |
| 407 | npx @cobusgreyling/loop-init . --pattern daily-triage --tool grok |
| 408 | npx @cobusgreyling/loop-init . -p pr-babysitter -t claude |
| 409 | npx @cobusgreyling/loop-init . -p daily-triage -t opencode |
| 410 | `); |
| 411 | process.exit(0); |
| 412 | } |
| 413 | |
| 414 | const { pattern, tool, target, dryRun } = args; |
| 415 | |
| 416 | const validPatterns = Object.keys(PATTERN_STARTERS) as Pattern[]; |
| 417 | const validTools = Object.keys(TOOL_SUFFIX) as Tool[]; |
| 418 | if (!validPatterns.includes(pattern)) { |
| 419 | console.error(`Unknown pattern: ${pattern}. Valid: ${validPatterns.join(', ')}`); |
| 420 | process.exit(1); |
| 421 | } |
| 422 | if (!validTools.includes(tool)) { |
| 423 | console.error(`Unknown tool: ${tool}. Valid: ${validTools.join(', ')}`); |
| 424 | process.exit(1); |
| 425 | } |
| 426 | |
| 427 | const targetDir = path.resolve(target); |
| 428 | const baseStarter = PATTERN_STARTERS[pattern]; |
| 429 | const suffix = TOOL_SUFFIX[tool]; |
| 430 | const starterName = pattern === 'daily-triage' ? `minimal-loop${suffix}` : baseStarter; |
| 431 | const startersRoot = await resolveBundledOrMonorepo('starters'); |
| 432 | const templatesRoot = await resolveBundledOrMonorepo('templates'); |
| 433 | const starterRoot = path.join(startersRoot, starterName); |
| 434 | |
| 435 | if (!(await exists(starterRoot))) { |
| 436 | const fallback = path.join(startersRoot, baseStarter); |
| 437 | if (!(await exists(fallback))) { |
| 438 | console.error(`Starter not found: ${starterRoot}`); |
| 439 | process.exit(1); |
no test coverage detected