opencodekit 0.6.6 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/index.js +656 -651
  2. package/dist/template/.opencode/AGENTS.md +56 -11
  3. package/dist/template/.opencode/README.md +18 -16
  4. package/dist/template/.opencode/command/accessibility-check.md +1 -1
  5. package/dist/template/.opencode/command/analyze-mockup.md +1 -1
  6. package/dist/template/.opencode/command/analyze-project.md +2 -0
  7. package/dist/template/.opencode/command/brainstorm.md +1 -1
  8. package/dist/template/.opencode/command/commit.md +1 -1
  9. package/dist/template/.opencode/command/create.md +9 -0
  10. package/dist/template/.opencode/command/design-audit.md +1 -1
  11. package/dist/template/.opencode/command/design.md +1 -1
  12. package/dist/template/.opencode/command/finish.md +17 -0
  13. package/dist/template/.opencode/command/fix-ci.md +4 -0
  14. package/dist/template/.opencode/command/fix-types.md +2 -0
  15. package/dist/template/.opencode/command/fix-ui.md +1 -1
  16. package/dist/template/.opencode/command/fix.md +1 -1
  17. package/dist/template/.opencode/command/handoff.md +2 -0
  18. package/dist/template/.opencode/command/implement.md +31 -1
  19. package/dist/template/.opencode/command/import-plan.md +2 -0
  20. package/dist/template/.opencode/command/integration-test.md +6 -2
  21. package/dist/template/.opencode/command/new-feature.md +2 -0
  22. package/dist/template/.opencode/command/plan.md +2 -0
  23. package/dist/template/.opencode/command/pr.md +2 -0
  24. package/dist/template/.opencode/command/research-and-implement.md +1 -1
  25. package/dist/template/.opencode/command/research-ui.md +1 -1
  26. package/dist/template/.opencode/command/resume.md +2 -0
  27. package/dist/template/.opencode/command/revert-feature.md +2 -0
  28. package/dist/template/.opencode/command/review-codebase.md +1 -1
  29. package/dist/template/.opencode/command/skill-create.md +4 -4
  30. package/dist/template/.opencode/command/skill-optimize.md +4 -4
  31. package/dist/template/.opencode/command/ui-review.md +2 -2
  32. package/dist/template/.opencode/opencode.json +490 -535
  33. package/dist/template/.opencode/package.json +20 -20
  34. package/dist/template/.opencode/skill/brainstorming/SKILL.md +2 -2
  35. package/dist/template/.opencode/skill/executing-plans/SKILL.md +1 -1
  36. package/dist/template/.opencode/skill/sharing-skills/SKILL.md +13 -4
  37. package/dist/template/.opencode/skill/subagent-driven-development/SKILL.md +1 -1
  38. package/dist/template/.opencode/skill/systematic-debugging/SKILL.md +2 -2
  39. package/dist/template/.opencode/skill/using-git-worktrees/SKILL.md +27 -18
  40. package/dist/template/.opencode/skill/{using-superpowers → using-skills}/SKILL.md +6 -3
  41. package/dist/template/.opencode/skill/writing-plans/SKILL.md +3 -3
  42. package/dist/template/.opencode/skill/writing-skills/SKILL.md +2 -2
  43. package/package.json +2 -1
  44. package/dist/template/.opencode/memory/handoffs/2025-12-27T103000Z.md +0 -76
  45. package/dist/template/.opencode/plugin/skill.ts +0 -275
  46. package/dist/template/.opencode/skill/systematic-debugging/CREATION-LOG.md +0 -119
  47. package/dist/template/.opencode/skill/systematic-debugging/test-academic.md +0 -14
  48. package/dist/template/.opencode/skill/systematic-debugging/test-pressure-1.md +0 -58
  49. package/dist/template/.opencode/skill/systematic-debugging/test-pressure-2.md +0 -68
  50. package/dist/template/.opencode/skill/systematic-debugging/test-pressure-3.md +0 -69
  51. package/dist/template/.opencode/skill/testing-skills-with-subagents/examples/CLAUDE_MD_TESTING.md +0 -189
package/dist/index.js CHANGED
@@ -750,7 +750,7 @@ var cac = (name = "") => new CAC(name);
750
750
  // package.json
751
751
  var package_default = {
752
752
  name: "opencodekit",
753
- version: "0.6.6",
753
+ version: "0.7.0",
754
754
  description: "CLI tool for bootstrapping and managing OpenCodeKit projects",
755
755
  type: "module",
756
756
  repository: {
@@ -785,6 +785,7 @@ var package_default = {
785
785
  dependencies: {
786
786
  "@clack/prompts": "^0.7.0",
787
787
  "@opencode-ai/plugin": "^1.0.141",
788
+ "beads-village": "^1.3.3",
788
789
  cac: "^6.7.14",
789
790
  "cli-table3": "^0.6.5",
790
791
  ora: "^9.0.0",
@@ -801,16 +802,16 @@ var package_default = {
801
802
  trustedDependencies: ["@beads/bd"]
802
803
  };
803
804
 
804
- // src/commands/init.ts
805
+ // src/commands/agent.ts
805
806
  import {
806
807
  existsSync,
808
+ lstatSync,
807
809
  mkdirSync,
808
810
  readFileSync,
809
- writeFileSync,
810
- readdirSync
811
+ readdirSync,
812
+ writeFileSync
811
813
  } from "node:fs";
812
- import { join, dirname, basename } from "node:path";
813
- import { fileURLToPath } from "node:url";
814
+ import { join } from "node:path";
814
815
 
815
816
  // node_modules/@clack/core/dist/index.mjs
816
817
  var import_sisteransi = __toESM(require_src(), 1);
@@ -1404,149 +1405,16 @@ function me() {
1404
1405
  return new RegExp(r2, "g");
1405
1406
  }
1406
1407
 
1407
- // src/commands/init.ts
1408
- var import_picocolors3 = __toESM(require_picocolors(), 1);
1409
- var EXCLUDED_DIRS = [
1410
- "node_modules",
1411
- ".git",
1412
- "dist",
1413
- ".DS_Store",
1414
- "coverage",
1415
- ".next",
1416
- ".turbo"
1417
- ];
1418
- var EXCLUDED_FILES = [
1419
- "bun.lock",
1420
- "package-lock.json",
1421
- "yarn.lock",
1422
- "pnpm-lock.yaml"
1423
- ];
1424
- function detectMode(targetDir) {
1425
- const opencodeDir = join(targetDir, ".opencode");
1426
- if (existsSync(opencodeDir)) {
1427
- return "already-initialized";
1428
- }
1429
- if (existsSync(targetDir)) {
1430
- const entries = readdirSync(targetDir);
1431
- const hasCode = entries.some((e2) => !e2.startsWith(".") && !EXCLUDED_DIRS.includes(e2) && e2 !== "node_modules");
1432
- if (hasCode) {
1433
- return "add-config";
1434
- }
1435
- }
1436
- return "scaffold";
1437
- }
1438
- function getTemplateRoot() {
1439
- const __filename2 = fileURLToPath(import.meta.url);
1440
- const __dirname2 = dirname(__filename2);
1441
- const possiblePaths = [
1442
- join(__dirname2, "template"),
1443
- join(__dirname2, "..", "..", ".opencode")
1444
- ];
1445
- for (const path of possiblePaths) {
1446
- const opencodeDir = join(path, ".opencode");
1447
- if (existsSync(opencodeDir)) {
1448
- return path;
1449
- }
1450
- }
1451
- return null;
1452
- }
1453
- async function copyDir(src, dest) {
1454
- const { mkdir, readdir } = await import("node:fs/promises");
1455
- await mkdir(dest, { recursive: true });
1456
- for (const entry of await readdir(src, { withFileTypes: true })) {
1457
- if (EXCLUDED_DIRS.includes(entry.name))
1458
- continue;
1459
- if (!entry.isDirectory() && EXCLUDED_FILES.includes(entry.name))
1460
- continue;
1461
- const srcPath = join(src, entry.name);
1462
- const destPath = join(dest, entry.name);
1463
- if (entry.isSymbolicLink()) {
1464
- continue;
1465
- } else if (entry.isDirectory()) {
1466
- await copyDir(srcPath, destPath);
1467
- } else {
1468
- const content = readFileSync(srcPath, "utf-8");
1469
- writeFileSync(destPath, content);
1470
- }
1471
- }
1472
- }
1473
- async function copyOpenCodeOnly(templateRoot, targetDir) {
1474
- const opencodeSrc = join(templateRoot, ".opencode");
1475
- const opencodeDest = join(targetDir, ".opencode");
1476
- if (!existsSync(opencodeSrc)) {
1477
- return false;
1478
- }
1479
- await copyDir(opencodeSrc, opencodeDest);
1480
- return true;
1481
- }
1482
- async function initCommand(options = {}) {
1483
- const targetDir = process.cwd();
1484
- const mode = detectMode(targetDir);
1485
- oe(import_picocolors3.default.bgCyan(import_picocolors3.default.black(" OpenCodeKit ")));
1486
- if (mode === "already-initialized" && !options.force) {
1487
- f2.warn("Already initialized (.opencode/ exists)");
1488
- f2.info(`Use ${import_picocolors3.default.cyan("--force")} to reinitialize`);
1489
- $e("Nothing to do");
1490
- return;
1491
- }
1492
- const templateRoot = getTemplateRoot();
1493
- if (!templateRoot) {
1494
- f2.error("Template not found. Please reinstall opencodekit.");
1495
- $e(import_picocolors3.default.red("Failed"));
1496
- process.exit(1);
1497
- }
1498
- let projectName = basename(targetDir);
1499
- if (mode === "scaffold") {
1500
- const name = await te({
1501
- message: "Project name",
1502
- placeholder: projectName,
1503
- defaultValue: projectName
1504
- });
1505
- if (lD(name)) {
1506
- ue("Cancelled");
1507
- process.exit(0);
1508
- }
1509
- projectName = name || projectName;
1510
- }
1511
- const s = de();
1512
- if (mode === "scaffold") {
1513
- s.start("Scaffolding project");
1514
- mkdirSync(targetDir, { recursive: true });
1515
- } else if (mode === "add-config") {
1516
- s.start("Adding OpenCodeKit");
1517
- } else {
1518
- s.start("Reinitializing");
1519
- }
1520
- const success = await copyOpenCodeOnly(templateRoot, targetDir);
1521
- if (!success) {
1522
- s.stop("Failed");
1523
- $e(import_picocolors3.default.red("Template copy failed"));
1524
- process.exit(1);
1525
- }
1526
- s.stop("Done");
1527
- le(`cd .opencode && bun install`, "Next steps");
1528
- $e(import_picocolors3.default.green("Ready to code!"));
1529
- }
1530
-
1531
1408
  // src/commands/agent.ts
1532
- import {
1533
- existsSync as existsSync2,
1534
- lstatSync,
1535
- mkdirSync as mkdirSync2,
1536
- readFileSync as readFileSync2,
1537
- readdirSync as readdirSync2,
1538
- writeFileSync as writeFileSync2
1539
- } from "node:fs";
1540
- import { join as join2 } from "node:path";
1541
- var import_picocolors5 = __toESM(require_picocolors(), 1);
1409
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
1542
1410
 
1543
1411
  // src/utils/errors.ts
1544
- var import_picocolors4 = __toESM(require_picocolors(), 1);
1412
+ var import_picocolors3 = __toESM(require_picocolors(), 1);
1545
1413
  function showError(message, fix) {
1546
1414
  console.log();
1547
- f2.error(import_picocolors4.default.red("✗") + " " + message);
1415
+ f2.error(import_picocolors3.default.red("✗") + " " + message);
1548
1416
  if (fix) {
1549
- f2.info(" " + import_picocolors4.default.dim("→ " + fix));
1417
+ f2.info(" " + import_picocolors3.default.dim("→ " + fix));
1550
1418
  }
1551
1419
  console.log();
1552
1420
  }
@@ -1561,18 +1429,18 @@ function alreadyExists(resource, name) {
1561
1429
  showError(`${resource} "${name}" already exists`);
1562
1430
  }
1563
1431
  function unknownAction(action, available) {
1564
- showError(`Unknown action: ${action}`, `Available: ${available.map((a3) => import_picocolors4.default.cyan(a3)).join(", ")}`);
1432
+ showError(`Unknown action: ${action}`, `Available: ${available.map((a3) => import_picocolors3.default.cyan(a3)).join(", ")}`);
1565
1433
  }
1566
1434
  function showWarning(message, suggestion) {
1567
- f2.warn(import_picocolors4.default.yellow("!") + " " + message);
1435
+ f2.warn(import_picocolors3.default.yellow("!") + " " + message);
1568
1436
  if (suggestion) {
1569
- f2.info(" " + import_picocolors4.default.dim("→ " + suggestion));
1437
+ f2.info(" " + import_picocolors3.default.dim("→ " + suggestion));
1570
1438
  }
1571
1439
  }
1572
1440
  function showEmpty(resource, createCmd) {
1573
- f2.info(import_picocolors4.default.dim(`No ${resource} found`));
1441
+ f2.info(import_picocolors3.default.dim(`No ${resource} found`));
1574
1442
  if (createCmd) {
1575
- f2.info(import_picocolors4.default.dim(`→ Run: ${import_picocolors4.default.cyan(createCmd)}`));
1443
+ f2.info(import_picocolors3.default.dim(`→ Run: ${import_picocolors3.default.cyan(createCmd)}`));
1576
1444
  }
1577
1445
  }
1578
1446
 
@@ -1590,12 +1458,12 @@ Describe what this agent does.
1590
1458
  Provide specific instructions for this agent.
1591
1459
  `;
1592
1460
  async function agentCommand(action) {
1593
- const opencodePath = join2(process.cwd(), ".opencode");
1594
- if (!existsSync2(opencodePath)) {
1461
+ const opencodePath = join(process.cwd(), ".opencode");
1462
+ if (!existsSync(opencodePath)) {
1595
1463
  notInitialized();
1596
1464
  return;
1597
1465
  }
1598
- const agentPath = join2(opencodePath, "agent");
1466
+ const agentPath = join(opencodePath, "agent");
1599
1467
  switch (action) {
1600
1468
  case "list":
1601
1469
  await listAgents(agentPath);
@@ -1613,37 +1481,37 @@ async function agentCommand(action) {
1613
1481
  }
1614
1482
  }
1615
1483
  async function listAgents(agentPath) {
1616
- if (!existsSync2(agentPath)) {
1484
+ if (!existsSync(agentPath)) {
1617
1485
  showEmpty("agents", "ock agent add");
1618
1486
  return;
1619
1487
  }
1620
- const opencodePath = join2(process.cwd(), ".opencode");
1621
- const configPath = join2(opencodePath, "opencode.json");
1488
+ const opencodePath = join(process.cwd(), ".opencode");
1489
+ const configPath = join(opencodePath, "opencode.json");
1622
1490
  let agentConfigs = {};
1623
- if (existsSync2(configPath)) {
1491
+ if (existsSync(configPath)) {
1624
1492
  try {
1625
- const configContent = readFileSync2(configPath, "utf-8");
1493
+ const configContent = readFileSync(configPath, "utf-8");
1626
1494
  const config = JSON.parse(configContent);
1627
1495
  agentConfigs = config.agent || {};
1628
1496
  } catch {}
1629
1497
  }
1630
- const entries = readdirSync2(agentPath);
1498
+ const entries = readdirSync(agentPath);
1631
1499
  const agents = entries.filter((entry) => {
1632
- const entryPath = join2(agentPath, entry);
1500
+ const entryPath = join(agentPath, entry);
1633
1501
  return lstatSync(entryPath).isFile() && entry.endsWith(".md");
1634
1502
  }).map((file) => file.replace(".md", ""));
1635
1503
  if (agents.length === 0) {
1636
1504
  showEmpty("agents", "ock agent add");
1637
1505
  return;
1638
1506
  }
1639
- f2.info(import_picocolors5.default.bold("Agents"));
1507
+ f2.info(import_picocolors4.default.bold("Agents"));
1640
1508
  for (const agent of agents) {
1641
1509
  let model = agentConfigs[agent]?.model;
1642
1510
  const disabled = agentConfigs[agent]?.disable;
1643
1511
  if (!model) {
1644
- const agentFile = join2(agentPath, `${agent}.md`);
1512
+ const agentFile = join(agentPath, `${agent}.md`);
1645
1513
  try {
1646
- const content = readFileSync2(agentFile, "utf-8");
1514
+ const content = readFileSync(agentFile, "utf-8");
1647
1515
  const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
1648
1516
  if (frontmatterMatch) {
1649
1517
  const modelMatch = frontmatterMatch[1].match(/^model:\s*(.+)$/m);
@@ -1653,13 +1521,13 @@ async function listAgents(agentPath) {
1653
1521
  }
1654
1522
  } catch {}
1655
1523
  }
1656
- const modelDisplay = model ? import_picocolors5.default.dim(` → ${model}`) : import_picocolors5.default.dim(" → (default)");
1657
- const disabledDisplay = disabled ? import_picocolors5.default.red(" [disabled]") : "";
1658
- console.log(` ${import_picocolors5.default.cyan("•")} ${agent}${modelDisplay}${disabledDisplay}`);
1524
+ const modelDisplay = model ? import_picocolors4.default.dim(` → ${model}`) : import_picocolors4.default.dim(" → (default)");
1525
+ const disabledDisplay = disabled ? import_picocolors4.default.red(" [disabled]") : "";
1526
+ console.log(` ${import_picocolors4.default.cyan("•")} ${agent}${modelDisplay}${disabledDisplay}`);
1659
1527
  }
1660
1528
  }
1661
1529
  async function addAgent(agentPath) {
1662
- oe(import_picocolors5.default.bgMagenta(import_picocolors5.default.black(" Add Agent ")));
1530
+ oe(import_picocolors4.default.bgMagenta(import_picocolors4.default.black(" Add Agent ")));
1663
1531
  const name = await te({
1664
1532
  message: "Agent name",
1665
1533
  placeholder: "e.g. reviewer, planner, researcher",
@@ -1686,18 +1554,18 @@ async function addAgent(agentPath) {
1686
1554
  ue("Cancelled");
1687
1555
  return;
1688
1556
  }
1689
- if (!existsSync2(agentPath)) {
1690
- mkdirSync2(agentPath, { recursive: true });
1557
+ if (!existsSync(agentPath)) {
1558
+ mkdirSync(agentPath, { recursive: true });
1691
1559
  }
1692
- const agentFile = join2(agentPath, `${name}.md`);
1693
- if (existsSync2(agentFile)) {
1560
+ const agentFile = join(agentPath, `${name}.md`);
1561
+ if (existsSync(agentFile)) {
1694
1562
  alreadyExists("Agent", String(name));
1695
- $e(import_picocolors5.default.red("Failed"));
1563
+ $e(import_picocolors4.default.red("Failed"));
1696
1564
  return;
1697
1565
  }
1698
1566
  const content = AGENT_TEMPLATE.replace("{{NAME}}", String(name).charAt(0).toUpperCase() + String(name).slice(1));
1699
- writeFileSync2(agentFile, content);
1700
- f2.success(`Created ${import_picocolors5.default.cyan(`.opencode/agent/${name}.md`)}`);
1567
+ writeFileSync(agentFile, content);
1568
+ f2.success(`Created ${import_picocolors4.default.cyan(`.opencode/agent/${name}.md`)}`);
1701
1569
  if (agentType === "primary") {
1702
1570
  le(`Add to opencode.json:
1703
1571
 
@@ -1708,17 +1576,17 @@ async function addAgent(agentPath) {
1708
1576
  }
1709
1577
  }`, "Next step");
1710
1578
  }
1711
- $e(import_picocolors5.default.green("Done! Edit the file to customize."));
1579
+ $e(import_picocolors4.default.green("Done! Edit the file to customize."));
1712
1580
  }
1713
1581
  async function viewAgent(agentPath, agentName) {
1714
1582
  if (!agentName) {
1715
- if (!existsSync2(agentPath)) {
1583
+ if (!existsSync(agentPath)) {
1716
1584
  showEmpty("agents", "ock agent add");
1717
1585
  return;
1718
1586
  }
1719
- const entries = readdirSync2(agentPath);
1587
+ const entries = readdirSync(agentPath);
1720
1588
  const agents = entries.filter((entry) => {
1721
- const entryPath = join2(agentPath, entry);
1589
+ const entryPath = join(agentPath, entry);
1722
1590
  return lstatSync(entryPath).isFile() && entry.endsWith(".md");
1723
1591
  }).map((file) => file.replace(".md", ""));
1724
1592
  if (agents.length === 0) {
@@ -1734,181 +1602,214 @@ async function viewAgent(agentPath, agentName) {
1734
1602
  }
1735
1603
  agentName = selected;
1736
1604
  }
1737
- const agentFile = join2(agentPath, `${agentName}.md`);
1738
- if (!existsSync2(agentFile)) {
1605
+ const agentFile = join(agentPath, `${agentName}.md`);
1606
+ if (!existsSync(agentFile)) {
1739
1607
  notFound("Agent", agentName);
1740
1608
  return;
1741
1609
  }
1742
- const content = readFileSync2(agentFile, "utf-8");
1610
+ const content = readFileSync(agentFile, "utf-8");
1743
1611
  console.log();
1744
- console.log(import_picocolors5.default.dim("─".repeat(40)));
1612
+ console.log(import_picocolors4.default.dim("─".repeat(40)));
1745
1613
  console.log(content);
1746
- console.log(import_picocolors5.default.dim("─".repeat(40)));
1614
+ console.log(import_picocolors4.default.dim("─".repeat(40)));
1747
1615
  }
1748
1616
 
1749
- // src/commands/skill.ts
1750
- import { join as join3 } from "node:path";
1751
- import { existsSync as existsSync3, readdirSync as readdirSync3, readFileSync as readFileSync3, lstatSync as lstatSync2 } from "node:fs";
1752
- var import_picocolors6 = __toESM(require_picocolors(), 1);
1753
- async function skillCommand(action) {
1754
- const opencodePath = join3(process.cwd(), ".opencode");
1755
- if (!existsSync3(opencodePath)) {
1756
- notInitialized();
1757
- return;
1758
- }
1759
- switch (action) {
1760
- case "list":
1761
- await listSkills(opencodePath);
1762
- break;
1763
- case "add":
1764
- await addSkill(opencodePath);
1765
- break;
1766
- case "view": {
1767
- const skillName = process.argv[4];
1768
- await viewSkill(opencodePath, skillName);
1769
- break;
1770
- }
1771
- default:
1772
- unknownAction(action, ["list", "add", "view"]);
1773
- }
1774
- }
1775
- function collectSkills(basePath) {
1776
- const skills = [];
1777
- if (!existsSync3(basePath))
1778
- return skills;
1779
- const tiers = ["core", "stack", "specialized"];
1780
- let hasTiers = false;
1781
- for (const tier of tiers) {
1782
- const tierPath = join3(basePath, tier);
1783
- if (existsSync3(tierPath)) {
1784
- hasTiers = true;
1785
- const entries = readdirSync3(tierPath);
1786
- for (const entry of entries) {
1787
- const entryPath = join3(tierPath, entry);
1788
- if (lstatSync2(entryPath).isDirectory()) {
1789
- skills.push({ name: entry, path: entryPath, tier });
1790
- }
1791
- }
1792
- }
1793
- }
1794
- if (!hasTiers) {
1795
- const entries = readdirSync3(basePath);
1796
- for (const entry of entries) {
1797
- const entryPath = join3(basePath, entry);
1798
- if (lstatSync2(entryPath).isDirectory()) {
1799
- skills.push({ name: entry, path: entryPath });
1800
- }
1801
- }
1802
- }
1803
- return skills;
1804
- }
1805
- async function listSkills(opencodePath) {
1806
- const locations = [
1807
- { path: join3(opencodePath, "superpowers", "skills"), name: "Superpowers" },
1808
- { path: join3(opencodePath, "skills"), name: "Project" }
1809
- ];
1810
- let totalSkills = 0;
1811
- for (const loc of locations) {
1812
- const skills = collectSkills(loc.path);
1813
- if (skills.length > 0) {
1814
- f2.info(import_picocolors6.default.bold(loc.name));
1815
- for (const skill of skills) {
1816
- const label = skill.tier ? `${skill.tier}/${skill.name}` : skill.name;
1817
- console.log(` ${import_picocolors6.default.cyan("•")} ${label}`);
1818
- }
1819
- totalSkills += skills.length;
1820
- }
1821
- }
1822
- if (totalSkills === 0) {
1823
- showEmpty("skills", "ock skill add");
1824
- }
1617
+ // src/commands/completion.ts
1618
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
1619
+ var BASH_COMPLETION = `# ock bash completion
1620
+ _ock_completion() {
1621
+ local cur prev commands
1622
+ COMPREPLY=()
1623
+ cur="\${COMP_WORDS[COMP_CWORD]}"
1624
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
1625
+
1626
+ commands="init config upgrade agent skill doctor status help"
1627
+
1628
+ case "\${prev}" in
1629
+ ock)
1630
+ COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
1631
+ return 0
1632
+ ;;
1633
+ agent)
1634
+ COMPREPLY=( $(compgen -W "list add view" -- "\${cur}") )
1635
+ return 0
1636
+ ;;
1637
+ skill)
1638
+ COMPREPLY=( $(compgen -W "list add view" -- "\${cur}") )
1639
+ return 0
1640
+ ;;
1641
+ config)
1642
+ COMPREPLY=( $(compgen -W "model mcp permission keybinds show" -- "\${cur}") )
1643
+ return 0
1644
+ ;;
1645
+ init)
1646
+ COMPREPLY=( $(compgen -W "--force" -- "\${cur}") )
1647
+ return 0
1648
+ ;;
1649
+ upgrade)
1650
+ COMPREPLY=( $(compgen -W "--force --check" -- "\${cur}") )
1651
+ return 0
1652
+ ;;
1653
+ *)
1654
+ ;;
1655
+ esac
1825
1656
  }
1826
- async function addSkill(opencodePath) {
1827
- oe(import_picocolors6.default.bgYellow(import_picocolors6.default.black(" Add Skill ")));
1828
- const superpowersPath = join3(opencodePath, "superpowers", "skills");
1829
- const skills = collectSkills(superpowersPath);
1830
- if (skills.length === 0) {
1831
- showEmpty("skills available to install");
1832
- $e("Done");
1833
- return;
1834
- }
1835
- const selected = await ie({
1836
- message: "Select skill to install",
1837
- options: skills.map((s) => ({
1838
- value: s.name,
1839
- label: s.tier ? `${s.name} (${s.tier})` : s.name
1840
- }))
1841
- });
1842
- if (lD(selected)) {
1843
- ue("Cancelled");
1844
- return;
1845
- }
1846
- const skill = skills.find((s) => s.name === selected);
1847
- if (!skill)
1848
- return;
1849
- const skillMdPath = join3(skill.path, "SKILL.md");
1850
- if (!existsSync3(skillMdPath)) {
1851
- notFound("SKILL.md in", skill.name);
1852
- $e(import_picocolors6.default.red("Failed"));
1853
- return;
1854
- }
1855
- const content = readFileSync3(skillMdPath, "utf-8");
1856
- const lines = content.split(`
1857
- `).slice(0, 10);
1858
- console.log();
1859
- console.log(import_picocolors6.default.dim("─".repeat(40)));
1860
- console.log(lines.join(`
1861
- `));
1862
- if (content.split(`
1863
- `).length > 10) {
1864
- console.log(import_picocolors6.default.dim("..."));
1865
- }
1866
- console.log(import_picocolors6.default.dim("─".repeat(40)));
1867
- console.log();
1868
- f2.success(`Skill "${skill.name}" is available at:`);
1869
- f2.info(import_picocolors6.default.cyan(skill.path));
1870
- le(`Skills in superpowers/ are auto-loaded.
1871
- Use ${import_picocolors6.default.cyan("find_skills")} + ${import_picocolors6.default.cyan("use_skill")} in opencode.`, "Usage");
1872
- $e(import_picocolors6.default.green("Done!"));
1657
+ complete -F _ock_completion ock
1658
+ `;
1659
+ var ZSH_COMPLETION = `#compdef ock
1660
+
1661
+ _ock() {
1662
+ local -a commands
1663
+ local -a agent_actions
1664
+ local -a skill_actions
1665
+ local -a config_actions
1666
+
1667
+ commands=(
1668
+ 'init:Initialize OpenCodeKit in current directory'
1669
+ 'config:Edit opencode.json'
1670
+ 'upgrade:Update templates to latest version'
1671
+ 'agent:Manage agents'
1672
+ 'skill:Manage skills'
1673
+ 'doctor:Check project health'
1674
+ 'status:Show project overview'
1675
+ 'help:Show help'
1676
+ )
1677
+
1678
+ agent_actions=(
1679
+ 'list:List all agents'
1680
+ 'add:Create a new agent'
1681
+ 'view:View agent details'
1682
+ )
1683
+
1684
+ skill_actions=(
1685
+ 'list:List all skills'
1686
+ 'add:Install a skill'
1687
+ 'view:View skill details'
1688
+ )
1689
+
1690
+ config_actions=(
1691
+ 'model:Change default model'
1692
+ 'mcp:Manage MCP servers'
1693
+ 'permission:Edit permissions'
1694
+ 'keybinds:Edit keyboard shortcuts'
1695
+ 'show:View current config'
1696
+ )
1697
+
1698
+ case "$words[2]" in
1699
+ agent)
1700
+ _describe -t actions 'agent action' agent_actions
1701
+ ;;
1702
+ skill)
1703
+ _describe -t actions 'skill action' skill_actions
1704
+ ;;
1705
+ config)
1706
+ _describe -t actions 'config action' config_actions
1707
+ ;;
1708
+ init)
1709
+ _arguments '--force[Reinitialize even if already exists]'
1710
+ ;;
1711
+ upgrade)
1712
+ _arguments \\
1713
+ '--force[Force upgrade even if up to date]' \\
1714
+ '--check[Check for updates only]'
1715
+ ;;
1716
+ *)
1717
+ _describe -t commands 'command' commands
1718
+ ;;
1719
+ esac
1873
1720
  }
1874
- async function viewSkill(opencodePath, skillName) {
1875
- const superpowersPath = join3(opencodePath, "superpowers", "skills");
1876
- const skills = collectSkills(superpowersPath);
1877
- if (skills.length === 0) {
1878
- showEmpty("skills");
1879
- return;
1880
- }
1881
- if (!skillName) {
1721
+
1722
+ _ock "$@"
1723
+ `;
1724
+ var FISH_COMPLETION = `# ock fish completion
1725
+ complete -c ock -n "__fish_use_subcommand" -a "init" -d "Initialize OpenCodeKit"
1726
+ complete -c ock -n "__fish_use_subcommand" -a "config" -d "Edit opencode.json"
1727
+ complete -c ock -n "__fish_use_subcommand" -a "upgrade" -d "Update templates"
1728
+ complete -c ock -n "__fish_use_subcommand" -a "agent" -d "Manage agents"
1729
+ complete -c ock -n "__fish_use_subcommand" -a "skill" -d "Manage skills"
1730
+ complete -c ock -n "__fish_use_subcommand" -a "doctor" -d "Check project health"
1731
+ complete -c ock -n "__fish_use_subcommand" -a "status" -d "Show project overview"
1732
+
1733
+ # agent subcommands
1734
+ complete -c ock -n "__fish_seen_subcommand_from agent" -a "list" -d "List agents"
1735
+ complete -c ock -n "__fish_seen_subcommand_from agent" -a "add" -d "Add agent"
1736
+ complete -c ock -n "__fish_seen_subcommand_from agent" -a "view" -d "View agent"
1737
+
1738
+ # skill subcommands
1739
+ complete -c ock -n "__fish_seen_subcommand_from skill" -a "list" -d "List skills"
1740
+ complete -c ock -n "__fish_seen_subcommand_from skill" -a "add" -d "Add skill"
1741
+ complete -c ock -n "__fish_seen_subcommand_from skill" -a "view" -d "View skill"
1742
+
1743
+ # config subcommands
1744
+ complete -c ock -n "__fish_seen_subcommand_from config" -a "model" -d "Change model"
1745
+ complete -c ock -n "__fish_seen_subcommand_from config" -a "mcp" -d "Manage MCP"
1746
+ complete -c ock -n "__fish_seen_subcommand_from config" -a "permission" -d "Edit permissions"
1747
+ complete -c ock -n "__fish_seen_subcommand_from config" -a "keybinds" -d "Edit keybinds"
1748
+ complete -c ock -n "__fish_seen_subcommand_from config" -a "show" -d "View config"
1749
+
1750
+ # init options
1751
+ complete -c ock -n "__fish_seen_subcommand_from init" -l force -d "Reinitialize"
1752
+
1753
+ # upgrade options
1754
+ complete -c ock -n "__fish_seen_subcommand_from upgrade" -l force -d "Force upgrade"
1755
+ complete -c ock -n "__fish_seen_subcommand_from upgrade" -l check -d "Check only"
1756
+ `;
1757
+ async function completionCommand(shell) {
1758
+ if (!shell) {
1759
+ oe(import_picocolors5.default.bgCyan(import_picocolors5.default.black(" Shell Completion ")));
1882
1760
  const selected = await ie({
1883
- message: "Select skill to view",
1884
- options: skills.map((s) => ({ value: s.name, label: s.name }))
1761
+ message: "Select your shell",
1762
+ options: [
1763
+ { value: "bash", label: "Bash" },
1764
+ { value: "zsh", label: "Zsh" },
1765
+ { value: "fish", label: "Fish" }
1766
+ ]
1885
1767
  });
1886
1768
  if (lD(selected)) {
1769
+ ue("Cancelled");
1887
1770
  return;
1888
1771
  }
1889
- skillName = selected;
1890
- }
1891
- const skill = skills.find((s) => s.name === skillName);
1892
- if (!skill) {
1893
- notFound("Skill", skillName);
1894
- return;
1772
+ shell = selected;
1895
1773
  }
1896
- const skillMdPath = join3(skill.path, "SKILL.md");
1897
- if (!existsSync3(skillMdPath)) {
1898
- notFound("SKILL.md");
1899
- return;
1774
+ let script;
1775
+ let setupInstructions;
1776
+ switch (shell) {
1777
+ case "bash":
1778
+ script = BASH_COMPLETION;
1779
+ setupInstructions = `Add to ~/.bashrc:
1780
+ source <(ock completion bash)
1781
+
1782
+ Or save to file:
1783
+ ock completion bash > ~/.local/share/bash-completion/completions/ock`;
1784
+ break;
1785
+ case "zsh":
1786
+ script = ZSH_COMPLETION;
1787
+ setupInstructions = `Add to ~/.zshrc (before compinit):
1788
+ source <(ock completion zsh)
1789
+
1790
+ Or save to fpath:
1791
+ ock completion zsh > ~/.zsh/completions/_ock
1792
+ # Then add to ~/.zshrc: fpath=(~/.zsh/completions $fpath)`;
1793
+ break;
1794
+ case "fish":
1795
+ script = FISH_COMPLETION;
1796
+ setupInstructions = `Save to fish completions:
1797
+ ock completion fish > ~/.config/fish/completions/ock.fish`;
1798
+ break;
1799
+ default:
1800
+ f2.error(`Unknown shell: ${shell}`);
1801
+ return;
1900
1802
  }
1901
- const content = readFileSync3(skillMdPath, "utf-8");
1902
- console.log();
1903
- console.log(import_picocolors6.default.dim("".repeat(40)));
1904
- console.log(content);
1905
- console.log(import_picocolors6.default.dim("─".repeat(40)));
1803
+ console.log(script);
1804
+ console.error();
1805
+ console.error(import_picocolors5.default.bold("Setup:"));
1806
+ console.error(import_picocolors5.default.dim(setupInstructions));
1906
1807
  }
1907
1808
 
1908
1809
  // src/commands/config.ts
1909
- import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
1910
- import { join as join4 } from "node:path";
1911
- var import_picocolors7 = __toESM(require_picocolors(), 1);
1810
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
1811
+ import { join as join2 } from "node:path";
1812
+ var import_picocolors6 = __toESM(require_picocolors(), 1);
1912
1813
  var DEFAULT_SERVER_PORT = 4096;
1913
1814
  var MODELS_DEV_URL = "https://models.dev/api.json";
1914
1815
  async function fetchFromServer(endpoint) {
@@ -1938,13 +1839,13 @@ async function getAgentsFromServer() {
1938
1839
  return fetchFromServer("/agent");
1939
1840
  }
1940
1841
  async function configCommand(action) {
1941
- const opencodePath = join4(process.cwd(), ".opencode");
1942
- const configPath = join4(opencodePath, "opencode.json");
1943
- if (!existsSync4(opencodePath)) {
1842
+ const opencodePath = join2(process.cwd(), ".opencode");
1843
+ const configPath = join2(opencodePath, "opencode.json");
1844
+ if (!existsSync2(opencodePath)) {
1944
1845
  notInitialized();
1945
1846
  return;
1946
1847
  }
1947
- if (!existsSync4(configPath)) {
1848
+ if (!existsSync2(configPath)) {
1948
1849
  showError("opencode.json not found", "ock init --force");
1949
1850
  return;
1950
1851
  }
@@ -1999,64 +1900,66 @@ async function configCommand(action) {
1999
1900
  }
2000
1901
  }
2001
1902
  function loadConfig(configPath) {
2002
- return JSON.parse(readFileSync4(configPath, "utf-8"));
1903
+ const content = readFileSync2(configPath, "utf-8");
1904
+ const jsonWithoutComments = content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
1905
+ return JSON.parse(jsonWithoutComments);
2003
1906
  }
2004
1907
  function saveConfig(configPath, config) {
2005
- writeFileSync3(configPath, JSON.stringify(config, null, 2) + `
1908
+ writeFileSync2(configPath, JSON.stringify(config, null, 2) + `
2006
1909
  `);
2007
1910
  }
2008
1911
  function showConfig(configPath) {
2009
1912
  const config = loadConfig(configPath);
2010
1913
  console.log();
2011
- console.log(import_picocolors7.default.bold(" Model"));
2012
- console.log(` ${import_picocolors7.default.cyan(config.model || "not set")}`);
1914
+ console.log(import_picocolors6.default.bold(" Model"));
1915
+ console.log(` ${import_picocolors6.default.cyan(config.model || "not set")}`);
2013
1916
  if (config.small_model) {
2014
- console.log(import_picocolors7.default.bold(" Small Model"));
2015
- console.log(` ${import_picocolors7.default.cyan(config.small_model)}`);
1917
+ console.log(import_picocolors6.default.bold(" Small Model"));
1918
+ console.log(` ${import_picocolors6.default.cyan(config.small_model)}`);
2016
1919
  }
2017
- console.log(import_picocolors7.default.bold(" Theme"));
2018
- console.log(` ${import_picocolors7.default.cyan(config.theme || "system")}`);
2019
- console.log(import_picocolors7.default.bold(" Share"));
2020
- console.log(` ${import_picocolors7.default.cyan(config.share || "manual")}`);
1920
+ console.log(import_picocolors6.default.bold(" Theme"));
1921
+ console.log(` ${import_picocolors6.default.cyan(config.theme || "system")}`);
1922
+ console.log(import_picocolors6.default.bold(" Share"));
1923
+ console.log(` ${import_picocolors6.default.cyan(config.share || "manual")}`);
2021
1924
  const autoupdateDisplay = config.autoupdate === "notify" ? "notify" : config.autoupdate === false ? "disabled" : "enabled";
2022
- console.log(import_picocolors7.default.bold(" Autoupdate"));
2023
- console.log(` ${import_picocolors7.default.cyan(autoupdateDisplay)}`);
1925
+ console.log(import_picocolors6.default.bold(" Autoupdate"));
1926
+ console.log(` ${import_picocolors6.default.cyan(autoupdateDisplay)}`);
2024
1927
  if (config.tui && Object.keys(config.tui).length > 0) {
2025
- console.log(import_picocolors7.default.bold(" TUI"));
1928
+ console.log(import_picocolors6.default.bold(" TUI"));
2026
1929
  if (config.tui.scroll_speed !== undefined) {
2027
- console.log(` scroll_speed: ${import_picocolors7.default.cyan(String(config.tui.scroll_speed))}`);
1930
+ console.log(` scroll_speed: ${import_picocolors6.default.cyan(String(config.tui.scroll_speed))}`);
2028
1931
  }
2029
1932
  if (config.tui.scroll_acceleration !== undefined) {
2030
- console.log(` scroll_acceleration: ${import_picocolors7.default.cyan(String(config.tui.scroll_acceleration))}`);
1933
+ console.log(` scroll_acceleration: ${import_picocolors6.default.cyan(String(config.tui.scroll_acceleration))}`);
2031
1934
  }
2032
1935
  if (config.tui.diff_style) {
2033
- console.log(` diff_style: ${import_picocolors7.default.cyan(config.tui.diff_style)}`);
1936
+ console.log(` diff_style: ${import_picocolors6.default.cyan(config.tui.diff_style)}`);
2034
1937
  }
2035
1938
  }
2036
1939
  if (config.mcp && Object.keys(config.mcp).length > 0) {
2037
- console.log(import_picocolors7.default.bold(" MCP Servers"));
1940
+ console.log(import_picocolors6.default.bold(" MCP Servers"));
2038
1941
  for (const [name, server] of Object.entries(config.mcp)) {
2039
- const status = server.enabled === false ? import_picocolors7.default.dim("off") : import_picocolors7.default.green("on");
1942
+ const status = server.enabled === false ? import_picocolors6.default.dim("off") : import_picocolors6.default.green("on");
2040
1943
  console.log(` ${status} ${name}`);
2041
1944
  }
2042
1945
  }
2043
1946
  if (config.tools && Object.keys(config.tools).length > 0) {
2044
- console.log(import_picocolors7.default.bold(" Tools"));
1947
+ console.log(import_picocolors6.default.bold(" Tools"));
2045
1948
  for (const [tool, enabled] of Object.entries(config.tools)) {
2046
- const status = enabled === false ? import_picocolors7.default.red("off") : import_picocolors7.default.green("on");
1949
+ const status = enabled === false ? import_picocolors6.default.red("off") : import_picocolors6.default.green("on");
2047
1950
  console.log(` ${status} ${tool}`);
2048
1951
  }
2049
1952
  }
2050
1953
  if (config.keybinds && Object.keys(config.keybinds).length > 0) {
2051
- console.log(import_picocolors7.default.bold(" Keybinds"));
1954
+ console.log(import_picocolors6.default.bold(" Keybinds"));
2052
1955
  for (const [action, key] of Object.entries(config.keybinds)) {
2053
- console.log(` ${import_picocolors7.default.dim(action)}: ${import_picocolors7.default.cyan(key)}`);
1956
+ console.log(` ${import_picocolors6.default.dim(action)}: ${import_picocolors6.default.cyan(key)}`);
2054
1957
  }
2055
1958
  }
2056
1959
  console.log();
2057
1960
  }
2058
1961
  async function configMenu(configPath) {
2059
- oe(import_picocolors7.default.bgCyan(import_picocolors7.default.black(" Configuration ")));
1962
+ oe(import_picocolors6.default.bgCyan(import_picocolors6.default.black(" Configuration ")));
2060
1963
  while (true) {
2061
1964
  const action = await ie({
2062
1965
  message: "What do you want to configure?",
@@ -2131,8 +2034,8 @@ async function editModel(configPath, modelType = "model") {
2131
2034
  const config = loadConfig(configPath);
2132
2035
  const currentModel = config[modelType] || "not set";
2133
2036
  const modelLabel = modelType === "small_model" ? "Small Model" : "Model";
2134
- f2.info(`Current ${modelLabel}: ${import_picocolors7.default.cyan(currentModel)}`);
2135
- f2.info(import_picocolors7.default.dim("Fetching models from models.dev..."));
2037
+ f2.info(`Current ${modelLabel}: ${import_picocolors6.default.cyan(currentModel)}`);
2038
+ f2.info(import_picocolors6.default.dim("Fetching models from models.dev..."));
2136
2039
  const modelsDevData = await fetchFromModelsDev();
2137
2040
  if (!modelsDevData || Object.keys(modelsDevData).length === 0) {
2138
2041
  f2.warn("models.dev unavailable - please enter manually");
@@ -2153,7 +2056,7 @@ async function editModel(configPath, modelType = "model") {
2153
2056
  }
2154
2057
  config[modelType] = newModel;
2155
2058
  saveConfig(configPath, config);
2156
- f2.success(`${modelLabel} set to ${import_picocolors7.default.cyan(newModel)}`);
2059
+ f2.success(`${modelLabel} set to ${import_picocolors6.default.cyan(newModel)}`);
2157
2060
  return;
2158
2061
  }
2159
2062
  f2.success("Fetched models from models.dev");
@@ -2216,7 +2119,7 @@ async function editModel(configPath, modelType = "model") {
2216
2119
  }
2217
2120
  config[modelType] = customModel;
2218
2121
  saveConfig(configPath, config);
2219
- f2.success(`${modelLabel} set to ${import_picocolors7.default.cyan(customModel)}`);
2122
+ f2.success(`${modelLabel} set to ${import_picocolors6.default.cyan(customModel)}`);
2220
2123
  return;
2221
2124
  }
2222
2125
  if (providerId === "__search__") {
@@ -2281,7 +2184,7 @@ async function editModel(configPath, modelType = "model") {
2281
2184
  const fullModelId = `${providerId}/${selectedModel}`;
2282
2185
  config[modelType] = fullModelId;
2283
2186
  saveConfig(configPath, config);
2284
- f2.success(`${modelLabel} set to ${import_picocolors7.default.cyan(fullModelId)}`);
2187
+ f2.success(`${modelLabel} set to ${import_picocolors6.default.cyan(fullModelId)}`);
2285
2188
  }
2286
2189
  function getModelsForProvider(provider) {
2287
2190
  const options = [];
@@ -2329,7 +2232,7 @@ async function editAgentModel(configPath) {
2329
2232
  let agentNames = [];
2330
2233
  const agentInfoMap = new Map;
2331
2234
  if (serverAgents && serverAgents.length > 0) {
2332
- f2.info(import_picocolors7.default.dim("Fetched agents from OpenCode server"));
2235
+ f2.info(import_picocolors6.default.dim("Fetched agents from OpenCode server"));
2333
2236
  for (const agent of serverAgents) {
2334
2237
  agentNames.push(agent.name);
2335
2238
  agentInfoMap.set(agent.name, {
@@ -2353,14 +2256,14 @@ async function editAgentModel(configPath) {
2353
2256
  return;
2354
2257
  }
2355
2258
  console.log();
2356
- console.log(import_picocolors7.default.bold(" Agent Models"));
2259
+ console.log(import_picocolors6.default.bold(" Agent Models"));
2357
2260
  for (const name of agentNames) {
2358
2261
  const info = agentInfoMap.get(name);
2359
- const model = info?.model || import_picocolors7.default.dim("(default)");
2360
- const builtIn = info?.builtIn ? import_picocolors7.default.dim(" [built-in]") : "";
2262
+ const model = info?.model || import_picocolors6.default.dim("(default)");
2263
+ const builtIn = info?.builtIn ? import_picocolors6.default.dim(" [built-in]") : "";
2361
2264
  const localConfig = config.agent[name];
2362
- const disabled = localConfig?.disable ? import_picocolors7.default.red(" [disabled]") : "";
2363
- console.log(` ${import_picocolors7.default.cyan(name)}: ${model}${builtIn}${disabled}`);
2265
+ const disabled = localConfig?.disable ? import_picocolors6.default.red(" [disabled]") : "";
2266
+ console.log(` ${import_picocolors6.default.cyan(name)}: ${model}${builtIn}${disabled}`);
2364
2267
  }
2365
2268
  console.log();
2366
2269
  const agentOptions = [
@@ -2408,7 +2311,7 @@ async function editAgentModel(configPath) {
2408
2311
  }
2409
2312
  config.agent[agentName].disable = !currentAgent.disable;
2410
2313
  saveConfig(configPath, config);
2411
- const status = config.agent[agentName].disable ? import_picocolors7.default.red("disabled") : import_picocolors7.default.green("enabled");
2314
+ const status = config.agent[agentName].disable ? import_picocolors6.default.red("disabled") : import_picocolors6.default.green("enabled");
2412
2315
  f2.success(`Agent ${agentName}: ${status}`);
2413
2316
  return;
2414
2317
  }
@@ -2429,8 +2332,8 @@ async function editAgentModel(configPath) {
2429
2332
  return;
2430
2333
  }
2431
2334
  const agentInfo = agentInfoMap.get(agentName);
2432
- f2.info(`Current model: ${import_picocolors7.default.cyan(agentInfo?.model || currentAgent.model || "(default)")}`);
2433
- f2.info(import_picocolors7.default.dim("Fetching models from models.dev..."));
2335
+ f2.info(`Current model: ${import_picocolors6.default.cyan(agentInfo?.model || currentAgent.model || "(default)")}`);
2336
+ f2.info(import_picocolors6.default.dim("Fetching models from models.dev..."));
2434
2337
  const modelsDevData = await fetchFromModelsDev();
2435
2338
  if (!modelsDevData || Object.keys(modelsDevData).length === 0) {
2436
2339
  f2.warn("models.dev unavailable - please enter manually");
@@ -2452,7 +2355,7 @@ async function editAgentModel(configPath) {
2452
2355
  }
2453
2356
  config.agent[agentName].model = newModel;
2454
2357
  saveConfig(configPath, config);
2455
- f2.success(`${agentName} model set to ${import_picocolors7.default.cyan(newModel)}`);
2358
+ f2.success(`${agentName} model set to ${import_picocolors6.default.cyan(newModel)}`);
2456
2359
  return;
2457
2360
  }
2458
2361
  const localProviders = config.provider || {};
@@ -2510,7 +2413,7 @@ async function editAgentModel(configPath) {
2510
2413
  agentConfig.model = undefined;
2511
2414
  }
2512
2415
  saveConfig(configPath, config);
2513
- f2.success(`${agentName} model set to ${import_picocolors7.default.cyan("(default)")}`);
2416
+ f2.success(`${agentName} model set to ${import_picocolors6.default.cyan("(default)")}`);
2514
2417
  return;
2515
2418
  }
2516
2419
  if (providerId === "__custom__") {
@@ -2532,7 +2435,7 @@ async function editAgentModel(configPath) {
2532
2435
  }
2533
2436
  config.agent[agentName].model = customModel;
2534
2437
  saveConfig(configPath, config);
2535
- f2.success(`${agentName} model set to ${import_picocolors7.default.cyan(customModel)}`);
2438
+ f2.success(`${agentName} model set to ${import_picocolors6.default.cyan(customModel)}`);
2536
2439
  return;
2537
2440
  }
2538
2441
  if (providerId === "__search__") {
@@ -2587,7 +2490,7 @@ async function editAgentModel(configPath) {
2587
2490
  }
2588
2491
  config.agent[agentName].model = fullModelId;
2589
2492
  saveConfig(configPath, config);
2590
- f2.success(`${agentName} model set to ${import_picocolors7.default.cyan(fullModelId)}`);
2493
+ f2.success(`${agentName} model set to ${import_picocolors6.default.cyan(fullModelId)}`);
2591
2494
  }
2592
2495
  async function editMCP(configPath) {
2593
2496
  const config = loadConfig(configPath);
@@ -2606,11 +2509,11 @@ async function editMCP(configPath) {
2606
2509
  return;
2607
2510
  }
2608
2511
  console.log();
2609
- console.log(import_picocolors7.default.bold(" MCP Servers"));
2512
+ console.log(import_picocolors6.default.bold(" MCP Servers"));
2610
2513
  for (const [name, server] of Object.entries(config.mcp)) {
2611
- const status = server.enabled === false ? import_picocolors7.default.red("off") : import_picocolors7.default.green("on");
2612
- const type = server.type === "remote" ? import_picocolors7.default.dim("remote") : import_picocolors7.default.dim("local");
2613
- const endpoint = server.type === "remote" ? import_picocolors7.default.dim(` → ${server.url}`) : import_picocolors7.default.dim(` → ${(server.command || []).join(" ")}`);
2514
+ const status = server.enabled === false ? import_picocolors6.default.red("off") : import_picocolors6.default.green("on");
2515
+ const type = server.type === "remote" ? import_picocolors6.default.dim("remote") : import_picocolors6.default.dim("local");
2516
+ const endpoint = server.type === "remote" ? import_picocolors6.default.dim(` → ${server.url}`) : import_picocolors6.default.dim(` → ${(server.command || []).join(" ")}`);
2614
2517
  console.log(` ${status} ${name} ${type}${endpoint}`);
2615
2518
  }
2616
2519
  console.log();
@@ -2656,7 +2559,7 @@ async function toggleMCP(configPath, config) {
2656
2559
  const wasEnabled = server.enabled !== false;
2657
2560
  server.enabled = !wasEnabled;
2658
2561
  saveConfig(configPath, config);
2659
- const status = server.enabled ? import_picocolors7.default.green("enabled") : import_picocolors7.default.dim("disabled");
2562
+ const status = server.enabled ? import_picocolors6.default.green("enabled") : import_picocolors6.default.dim("disabled");
2660
2563
  f2.success(`${serverName}: ${status}`);
2661
2564
  }
2662
2565
  async function addMCPServer(configPath, config) {
@@ -2722,7 +2625,7 @@ async function addMCPServer(configPath, config) {
2722
2625
  };
2723
2626
  }
2724
2627
  saveConfig(configPath, config);
2725
- f2.success(`Added MCP server: ${import_picocolors7.default.cyan(serverName)}`);
2628
+ f2.success(`Added MCP server: ${import_picocolors6.default.cyan(serverName)}`);
2726
2629
  }
2727
2630
  async function removeMCP(configPath, config) {
2728
2631
  const servers = Object.keys(config.mcp || {}).map((name) => ({
@@ -2753,13 +2656,13 @@ async function editPermissions(configPath) {
2753
2656
  config.permission = {};
2754
2657
  }
2755
2658
  console.log();
2756
- console.log(import_picocolors7.default.bold(" Current Permissions"));
2757
- console.log(` edit: ${import_picocolors7.default.cyan(config.permission.edit || "ask")}`);
2758
- console.log(` external_directory: ${import_picocolors7.default.cyan(config.permission.external_directory || "ask")}`);
2659
+ console.log(import_picocolors6.default.bold(" Current Permissions"));
2660
+ console.log(` edit: ${import_picocolors6.default.cyan(config.permission.edit || "ask")}`);
2661
+ console.log(` external_directory: ${import_picocolors6.default.cyan(config.permission.external_directory || "ask")}`);
2759
2662
  if (config.permission.bash) {
2760
- console.log(import_picocolors7.default.bold(" Bash"));
2663
+ console.log(import_picocolors6.default.bold(" Bash"));
2761
2664
  for (const [pattern, perm] of Object.entries(config.permission.bash)) {
2762
- console.log(` ${import_picocolors7.default.dim(pattern)}: ${import_picocolors7.default.cyan(perm)}`);
2665
+ console.log(` ${import_picocolors6.default.dim(pattern)}: ${import_picocolors6.default.cyan(perm)}`);
2763
2666
  }
2764
2667
  }
2765
2668
  console.log();
@@ -2821,9 +2724,9 @@ async function editKeybinds(configPath) {
2821
2724
  }
2822
2725
  if (Object.keys(config.keybinds).length > 0) {
2823
2726
  console.log();
2824
- console.log(import_picocolors7.default.bold(" Current Keybinds"));
2727
+ console.log(import_picocolors6.default.bold(" Current Keybinds"));
2825
2728
  for (const [action2, key] of Object.entries(config.keybinds)) {
2826
- console.log(` ${import_picocolors7.default.dim(action2)}: ${import_picocolors7.default.cyan(key)}`);
2729
+ console.log(` ${import_picocolors6.default.dim(action2)}: ${import_picocolors6.default.cyan(key)}`);
2827
2730
  }
2828
2731
  console.log();
2829
2732
  }
@@ -2876,7 +2779,7 @@ async function editKeybinds(configPath) {
2876
2779
  }
2877
2780
  config.keybinds[keybindName] = newKey;
2878
2781
  saveConfig(configPath, config);
2879
- f2.success(`${keybindName} → ${import_picocolors7.default.cyan(newKey)}`);
2782
+ f2.success(`${keybindName} → ${import_picocolors6.default.cyan(newKey)}`);
2880
2783
  }
2881
2784
  var OPENCODE_THEMES = [
2882
2785
  { value: "system", label: "System", hint: "follows OS preference" },
@@ -2916,7 +2819,7 @@ var OPENCODE_THEMES = [
2916
2819
  async function editTheme(configPath) {
2917
2820
  const config = loadConfig(configPath);
2918
2821
  const currentTheme = config.theme || "system";
2919
- f2.info(`Current theme: ${import_picocolors7.default.cyan(currentTheme)}`);
2822
+ f2.info(`Current theme: ${import_picocolors6.default.cyan(currentTheme)}`);
2920
2823
  const validTheme = OPENCODE_THEMES.some((t) => t.value === currentTheme) ? currentTheme : "system";
2921
2824
  const selectedTheme = await ie({
2922
2825
  message: "Select theme",
@@ -2933,7 +2836,7 @@ async function editTheme(configPath) {
2933
2836
  }
2934
2837
  config.theme = selectedTheme;
2935
2838
  saveConfig(configPath, config);
2936
- f2.success(`Theme set to ${import_picocolors7.default.cyan(selectedTheme)}`);
2839
+ f2.success(`Theme set to ${import_picocolors6.default.cyan(selectedTheme)}`);
2937
2840
  }
2938
2841
  async function editTui(configPath) {
2939
2842
  const config = loadConfig(configPath);
@@ -2981,7 +2884,7 @@ async function editTui(configPath) {
2981
2884
  }
2982
2885
  config.tui.diff_style = style;
2983
2886
  saveConfig(configPath, config);
2984
- f2.success(`Diff style set to ${import_picocolors7.default.cyan(style)}`);
2887
+ f2.success(`Diff style set to ${import_picocolors6.default.cyan(style)}`);
2985
2888
  } else {
2986
2889
  const settingKey = setting;
2987
2890
  const value = await te({
@@ -2998,7 +2901,7 @@ async function editTui(configPath) {
2998
2901
  }
2999
2902
  config.tui[settingKey] = value ? Number(value) : undefined;
3000
2903
  saveConfig(configPath, config);
3001
- f2.success(`${settingKey} set to ${import_picocolors7.default.cyan(value || "default")}`);
2904
+ f2.success(`${settingKey} set to ${import_picocolors6.default.cyan(value || "default")}`);
3002
2905
  }
3003
2906
  }
3004
2907
  async function editTools(configPath) {
@@ -3018,9 +2921,9 @@ async function editTools(configPath) {
3018
2921
  "todoread"
3019
2922
  ];
3020
2923
  console.log();
3021
- console.log(import_picocolors7.default.bold(" Tool Status"));
2924
+ console.log(import_picocolors6.default.bold(" Tool Status"));
3022
2925
  for (const tool of commonTools) {
3023
- const status = config.tools[tool] === false ? import_picocolors7.default.red("off") : import_picocolors7.default.green("on");
2926
+ const status = config.tools[tool] === false ? import_picocolors6.default.red("off") : import_picocolors6.default.green("on");
3024
2927
  console.log(` ${status} ${tool}`);
3025
2928
  }
3026
2929
  console.log();
@@ -3054,7 +2957,7 @@ async function editTools(configPath) {
3054
2957
  const wasEnabled = config.tools[toolName] !== false;
3055
2958
  config.tools[toolName] = !wasEnabled;
3056
2959
  saveConfig(configPath, config);
3057
- const status = config.tools[toolName] ? import_picocolors7.default.green("enabled") : import_picocolors7.default.red("disabled");
2960
+ const status = config.tools[toolName] ? import_picocolors6.default.green("enabled") : import_picocolors6.default.red("disabled");
3058
2961
  f2.success(`${toolName}: ${status}`);
3059
2962
  } else {
3060
2963
  const toolName = await te({
@@ -3077,13 +2980,13 @@ async function editTools(configPath) {
3077
2980
  }
3078
2981
  config.tools[toolName] = enabled;
3079
2982
  saveConfig(configPath, config);
3080
- f2.success(`Added ${toolName}: ${enabled ? import_picocolors7.default.green("on") : import_picocolors7.default.red("off")}`);
2983
+ f2.success(`Added ${toolName}: ${enabled ? import_picocolors6.default.green("on") : import_picocolors6.default.red("off")}`);
3081
2984
  }
3082
2985
  }
3083
2986
  async function editShare(configPath) {
3084
2987
  const config = loadConfig(configPath);
3085
2988
  const current = config.share || "manual";
3086
- f2.info(`Current share setting: ${import_picocolors7.default.cyan(current)}`);
2989
+ f2.info(`Current share setting: ${import_picocolors6.default.cyan(current)}`);
3087
2990
  const selected = await ie({
3088
2991
  message: "Share setting",
3089
2992
  options: [
@@ -3106,13 +3009,13 @@ async function editShare(configPath) {
3106
3009
  const shareValue = selected;
3107
3010
  config.share = shareValue;
3108
3011
  saveConfig(configPath, config);
3109
- f2.success(`Share set to ${import_picocolors7.default.cyan(shareValue)}`);
3012
+ f2.success(`Share set to ${import_picocolors6.default.cyan(shareValue)}`);
3110
3013
  }
3111
3014
  async function editAutoupdate(configPath) {
3112
3015
  const config = loadConfig(configPath);
3113
3016
  const current = config.autoupdate ?? true;
3114
3017
  const display = current === "notify" ? "notify" : current ? "enabled" : "disabled";
3115
- f2.info(`Current autoupdate: ${import_picocolors7.default.cyan(display)}`);
3018
+ f2.info(`Current autoupdate: ${import_picocolors6.default.cyan(display)}`);
3116
3019
  const selected = await ie({
3117
3020
  message: "Autoupdate behavior",
3118
3021
  options: [
@@ -3143,69 +3046,366 @@ async function editAutoupdate(configPath) {
3143
3046
  config.autoupdate = selectedValue === "true";
3144
3047
  }
3145
3048
  saveConfig(configPath, config);
3146
- f2.success(`Autoupdate set to ${import_picocolors7.default.cyan(selectedValue)}`);
3049
+ f2.success(`Autoupdate set to ${import_picocolors6.default.cyan(selectedValue)}`);
3147
3050
  }
3148
3051
 
3149
- // src/commands/upgrade.ts
3150
- import { join as join5, dirname as dirname2 } from "node:path";
3151
- import { fileURLToPath as fileURLToPath2 } from "node:url";
3052
+ // src/commands/init.ts
3152
3053
  import {
3153
- existsSync as existsSync5,
3154
- readFileSync as readFileSync5,
3155
- writeFileSync as writeFileSync4,
3156
- readdirSync as readdirSync4,
3157
- mkdirSync as mkdirSync3,
3158
- copyFileSync
3054
+ existsSync as existsSync3,
3055
+ mkdirSync as mkdirSync2,
3056
+ readFileSync as readFileSync3,
3057
+ writeFileSync as writeFileSync3,
3058
+ readdirSync as readdirSync2
3159
3059
  } from "node:fs";
3160
- var import_picocolors8 = __toESM(require_picocolors(), 1);
3161
- var PRESERVE_FILES = [
3162
- "opencode.json"
3060
+ import { join as join3, dirname, basename } from "node:path";
3061
+ import { fileURLToPath } from "node:url";
3062
+ var import_picocolors7 = __toESM(require_picocolors(), 1);
3063
+ var EXCLUDED_DIRS = [
3064
+ "node_modules",
3065
+ ".git",
3066
+ "dist",
3067
+ ".DS_Store",
3068
+ "coverage",
3069
+ ".next",
3070
+ ".turbo"
3163
3071
  ];
3164
- var PRESERVE_DIRS = [
3165
- "agent",
3166
- "command",
3167
- "memory"
3072
+ var EXCLUDED_FILES = [
3073
+ "bun.lock",
3074
+ "package-lock.json",
3075
+ "yarn.lock",
3076
+ "pnpm-lock.yaml"
3168
3077
  ];
3169
- var SKIP_DIRS = ["node_modules", ".git", "dist", "coverage"];
3170
- function getTemplateRoot2() {
3171
- const __filename2 = fileURLToPath2(import.meta.url);
3172
- const __dirname2 = dirname2(__filename2);
3078
+ function detectMode(targetDir) {
3079
+ const opencodeDir = join3(targetDir, ".opencode");
3080
+ if (existsSync3(opencodeDir)) {
3081
+ return "already-initialized";
3082
+ }
3083
+ if (existsSync3(targetDir)) {
3084
+ const entries = readdirSync2(targetDir);
3085
+ const hasCode = entries.some((e2) => !e2.startsWith(".") && !EXCLUDED_DIRS.includes(e2) && e2 !== "node_modules");
3086
+ if (hasCode) {
3087
+ return "add-config";
3088
+ }
3089
+ }
3090
+ return "scaffold";
3091
+ }
3092
+ function getTemplateRoot() {
3093
+ const __filename2 = fileURLToPath(import.meta.url);
3094
+ const __dirname2 = dirname(__filename2);
3173
3095
  const possiblePaths = [
3174
- join5(__dirname2, "template"),
3175
- join5(__dirname2, "..", "..", ".opencode")
3096
+ join3(__dirname2, "template"),
3097
+ join3(__dirname2, "..", "..", ".opencode")
3176
3098
  ];
3177
3099
  for (const path of possiblePaths) {
3178
- const opencodeDir = join5(path, ".opencode");
3179
- if (existsSync5(opencodeDir)) {
3100
+ const opencodeDir = join3(path, ".opencode");
3101
+ if (existsSync3(opencodeDir)) {
3180
3102
  return path;
3181
3103
  }
3182
3104
  }
3183
3105
  return null;
3184
3106
  }
3185
- function getCurrentVersion(opencodeDir) {
3186
- const versionFile = join5(opencodeDir, ".version");
3187
- if (existsSync5(versionFile)) {
3188
- return readFileSync5(versionFile, "utf-8").trim();
3189
- }
3190
- return null;
3191
- }
3192
- function getPackageVersion() {
3193
- const __filename2 = fileURLToPath2(import.meta.url);
3194
- const __dirname2 = dirname2(__filename2);
3195
- const pkgPaths = [
3196
- join5(__dirname2, "..", "..", "package.json"),
3197
- join5(__dirname2, "..", "package.json")
3198
- ];
3199
- for (const pkgPath of pkgPaths) {
3200
- if (existsSync5(pkgPath)) {
3201
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
3202
- return pkg.version;
3107
+ async function copyDir(src, dest) {
3108
+ const { mkdir, readdir } = await import("node:fs/promises");
3109
+ await mkdir(dest, { recursive: true });
3110
+ for (const entry of await readdir(src, { withFileTypes: true })) {
3111
+ if (EXCLUDED_DIRS.includes(entry.name))
3112
+ continue;
3113
+ if (!entry.isDirectory() && EXCLUDED_FILES.includes(entry.name))
3114
+ continue;
3115
+ const srcPath = join3(src, entry.name);
3116
+ const destPath = join3(dest, entry.name);
3117
+ if (entry.isSymbolicLink()) {
3118
+ continue;
3119
+ } else if (entry.isDirectory()) {
3120
+ await copyDir(srcPath, destPath);
3121
+ } else {
3122
+ const content = readFileSync3(srcPath, "utf-8");
3123
+ writeFileSync3(destPath, content);
3203
3124
  }
3204
3125
  }
3205
- return "unknown";
3206
3126
  }
3207
- async function checkVersion(opencodeDir) {
3208
- const current = getCurrentVersion(opencodeDir);
3127
+ async function copyOpenCodeOnly(templateRoot, targetDir) {
3128
+ const opencodeSrc = join3(templateRoot, ".opencode");
3129
+ const opencodeDest = join3(targetDir, ".opencode");
3130
+ if (!existsSync3(opencodeSrc)) {
3131
+ return false;
3132
+ }
3133
+ await copyDir(opencodeSrc, opencodeDest);
3134
+ return true;
3135
+ }
3136
+ async function initCommand(options = {}) {
3137
+ const targetDir = process.cwd();
3138
+ const mode = detectMode(targetDir);
3139
+ oe(import_picocolors7.default.bgCyan(import_picocolors7.default.black(" OpenCodeKit ")));
3140
+ if (mode === "already-initialized" && !options.force) {
3141
+ f2.warn("Already initialized (.opencode/ exists)");
3142
+ f2.info(`Use ${import_picocolors7.default.cyan("--force")} to reinitialize`);
3143
+ $e("Nothing to do");
3144
+ return;
3145
+ }
3146
+ const templateRoot = getTemplateRoot();
3147
+ if (!templateRoot) {
3148
+ f2.error("Template not found. Please reinstall opencodekit.");
3149
+ $e(import_picocolors7.default.red("Failed"));
3150
+ process.exit(1);
3151
+ }
3152
+ let projectName = basename(targetDir);
3153
+ if (mode === "scaffold") {
3154
+ const name = await te({
3155
+ message: "Project name",
3156
+ placeholder: projectName,
3157
+ defaultValue: projectName
3158
+ });
3159
+ if (lD(name)) {
3160
+ ue("Cancelled");
3161
+ process.exit(0);
3162
+ }
3163
+ projectName = name || projectName;
3164
+ }
3165
+ const s = de();
3166
+ if (mode === "scaffold") {
3167
+ s.start("Scaffolding project");
3168
+ mkdirSync2(targetDir, { recursive: true });
3169
+ } else if (mode === "add-config") {
3170
+ s.start("Adding OpenCodeKit");
3171
+ } else {
3172
+ s.start("Reinitializing");
3173
+ }
3174
+ const success = await copyOpenCodeOnly(templateRoot, targetDir);
3175
+ if (!success) {
3176
+ s.stop("Failed");
3177
+ $e(import_picocolors7.default.red("Template copy failed"));
3178
+ process.exit(1);
3179
+ }
3180
+ s.stop("Done");
3181
+ le(`cd .opencode && bun install`, "Next steps");
3182
+ $e(import_picocolors7.default.green("Ready to code!"));
3183
+ }
3184
+
3185
+ // src/commands/menu.ts
3186
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
3187
+ import { existsSync as existsSync6, readdirSync as readdirSync5, lstatSync as lstatSync3 } from "node:fs";
3188
+ import { join as join6, basename as basename2 } from "node:path";
3189
+
3190
+ // src/commands/skill.ts
3191
+ import { join as join4 } from "node:path";
3192
+ import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync4, lstatSync as lstatSync2 } from "node:fs";
3193
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
3194
+ async function skillCommand(action) {
3195
+ const opencodePath = join4(process.cwd(), ".opencode");
3196
+ if (!existsSync4(opencodePath)) {
3197
+ notInitialized();
3198
+ return;
3199
+ }
3200
+ switch (action) {
3201
+ case "list":
3202
+ await listSkills(opencodePath);
3203
+ break;
3204
+ case "add":
3205
+ await addSkill(opencodePath);
3206
+ break;
3207
+ case "view": {
3208
+ const skillName = process.argv[4];
3209
+ await viewSkill(opencodePath, skillName);
3210
+ break;
3211
+ }
3212
+ default:
3213
+ unknownAction(action, ["list", "add", "view"]);
3214
+ }
3215
+ }
3216
+ function collectSkills(basePath) {
3217
+ const skills = [];
3218
+ if (!existsSync4(basePath))
3219
+ return skills;
3220
+ const tiers = ["core", "stack", "specialized"];
3221
+ let hasTiers = false;
3222
+ for (const tier of tiers) {
3223
+ const tierPath = join4(basePath, tier);
3224
+ if (existsSync4(tierPath)) {
3225
+ hasTiers = true;
3226
+ const entries = readdirSync3(tierPath);
3227
+ for (const entry of entries) {
3228
+ const entryPath = join4(tierPath, entry);
3229
+ if (lstatSync2(entryPath).isDirectory()) {
3230
+ skills.push({ name: entry, path: entryPath, tier });
3231
+ }
3232
+ }
3233
+ }
3234
+ }
3235
+ if (!hasTiers) {
3236
+ const entries = readdirSync3(basePath);
3237
+ for (const entry of entries) {
3238
+ const entryPath = join4(basePath, entry);
3239
+ if (lstatSync2(entryPath).isDirectory()) {
3240
+ skills.push({ name: entry, path: entryPath });
3241
+ }
3242
+ }
3243
+ }
3244
+ return skills;
3245
+ }
3246
+ async function listSkills(opencodePath) {
3247
+ const locations = [
3248
+ { path: join4(opencodePath, "superpowers", "skills"), name: "Superpowers" },
3249
+ { path: join4(opencodePath, "skills"), name: "Project" }
3250
+ ];
3251
+ let totalSkills = 0;
3252
+ for (const loc of locations) {
3253
+ const skills = collectSkills(loc.path);
3254
+ if (skills.length > 0) {
3255
+ f2.info(import_picocolors8.default.bold(loc.name));
3256
+ for (const skill of skills) {
3257
+ const label = skill.tier ? `${skill.tier}/${skill.name}` : skill.name;
3258
+ console.log(` ${import_picocolors8.default.cyan("•")} ${label}`);
3259
+ }
3260
+ totalSkills += skills.length;
3261
+ }
3262
+ }
3263
+ if (totalSkills === 0) {
3264
+ showEmpty("skills", "ock skill add");
3265
+ }
3266
+ }
3267
+ async function addSkill(opencodePath) {
3268
+ oe(import_picocolors8.default.bgYellow(import_picocolors8.default.black(" Add Skill ")));
3269
+ const superpowersPath = join4(opencodePath, "superpowers", "skills");
3270
+ const skills = collectSkills(superpowersPath);
3271
+ if (skills.length === 0) {
3272
+ showEmpty("skills available to install");
3273
+ $e("Done");
3274
+ return;
3275
+ }
3276
+ const selected = await ie({
3277
+ message: "Select skill to install",
3278
+ options: skills.map((s) => ({
3279
+ value: s.name,
3280
+ label: s.tier ? `${s.name} (${s.tier})` : s.name
3281
+ }))
3282
+ });
3283
+ if (lD(selected)) {
3284
+ ue("Cancelled");
3285
+ return;
3286
+ }
3287
+ const skill = skills.find((s) => s.name === selected);
3288
+ if (!skill)
3289
+ return;
3290
+ const skillMdPath = join4(skill.path, "SKILL.md");
3291
+ if (!existsSync4(skillMdPath)) {
3292
+ notFound("SKILL.md in", skill.name);
3293
+ $e(import_picocolors8.default.red("Failed"));
3294
+ return;
3295
+ }
3296
+ const content = readFileSync4(skillMdPath, "utf-8");
3297
+ const lines = content.split(`
3298
+ `).slice(0, 10);
3299
+ console.log();
3300
+ console.log(import_picocolors8.default.dim("─".repeat(40)));
3301
+ console.log(lines.join(`
3302
+ `));
3303
+ if (content.split(`
3304
+ `).length > 10) {
3305
+ console.log(import_picocolors8.default.dim("..."));
3306
+ }
3307
+ console.log(import_picocolors8.default.dim("─".repeat(40)));
3308
+ console.log();
3309
+ f2.success(`Skill "${skill.name}" is available at:`);
3310
+ f2.info(import_picocolors8.default.cyan(skill.path));
3311
+ le(`Skills in superpowers/ are auto-loaded.
3312
+ Use ${import_picocolors8.default.cyan("find_skills")} + ${import_picocolors8.default.cyan("use_skill")} in opencode.`, "Usage");
3313
+ $e(import_picocolors8.default.green("Done!"));
3314
+ }
3315
+ async function viewSkill(opencodePath, skillName) {
3316
+ const superpowersPath = join4(opencodePath, "superpowers", "skills");
3317
+ const skills = collectSkills(superpowersPath);
3318
+ if (skills.length === 0) {
3319
+ showEmpty("skills");
3320
+ return;
3321
+ }
3322
+ if (!skillName) {
3323
+ const selected = await ie({
3324
+ message: "Select skill to view",
3325
+ options: skills.map((s) => ({ value: s.name, label: s.name }))
3326
+ });
3327
+ if (lD(selected)) {
3328
+ return;
3329
+ }
3330
+ skillName = selected;
3331
+ }
3332
+ const skill = skills.find((s) => s.name === skillName);
3333
+ if (!skill) {
3334
+ notFound("Skill", skillName);
3335
+ return;
3336
+ }
3337
+ const skillMdPath = join4(skill.path, "SKILL.md");
3338
+ if (!existsSync4(skillMdPath)) {
3339
+ notFound("SKILL.md");
3340
+ return;
3341
+ }
3342
+ const content = readFileSync4(skillMdPath, "utf-8");
3343
+ console.log();
3344
+ console.log(import_picocolors8.default.dim("─".repeat(40)));
3345
+ console.log(content);
3346
+ console.log(import_picocolors8.default.dim("─".repeat(40)));
3347
+ }
3348
+
3349
+ // src/commands/upgrade.ts
3350
+ import { join as join5, dirname as dirname2 } from "node:path";
3351
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
3352
+ import {
3353
+ existsSync as existsSync5,
3354
+ readFileSync as readFileSync5,
3355
+ writeFileSync as writeFileSync4,
3356
+ readdirSync as readdirSync4,
3357
+ mkdirSync as mkdirSync3,
3358
+ copyFileSync
3359
+ } from "node:fs";
3360
+ var import_picocolors9 = __toESM(require_picocolors(), 1);
3361
+ var PRESERVE_FILES = [
3362
+ "opencode.json"
3363
+ ];
3364
+ var PRESERVE_DIRS = [
3365
+ "agent",
3366
+ "command",
3367
+ "memory"
3368
+ ];
3369
+ var SKIP_DIRS = ["node_modules", ".git", "dist", "coverage"];
3370
+ function getTemplateRoot2() {
3371
+ const __filename2 = fileURLToPath2(import.meta.url);
3372
+ const __dirname2 = dirname2(__filename2);
3373
+ const possiblePaths = [
3374
+ join5(__dirname2, "template"),
3375
+ join5(__dirname2, "..", "..", ".opencode")
3376
+ ];
3377
+ for (const path of possiblePaths) {
3378
+ const opencodeDir = join5(path, ".opencode");
3379
+ if (existsSync5(opencodeDir)) {
3380
+ return path;
3381
+ }
3382
+ }
3383
+ return null;
3384
+ }
3385
+ function getCurrentVersion(opencodeDir) {
3386
+ const versionFile = join5(opencodeDir, ".version");
3387
+ if (existsSync5(versionFile)) {
3388
+ return readFileSync5(versionFile, "utf-8").trim();
3389
+ }
3390
+ return null;
3391
+ }
3392
+ function getPackageVersion() {
3393
+ const __filename2 = fileURLToPath2(import.meta.url);
3394
+ const __dirname2 = dirname2(__filename2);
3395
+ const pkgPaths = [
3396
+ join5(__dirname2, "..", "..", "package.json"),
3397
+ join5(__dirname2, "..", "package.json")
3398
+ ];
3399
+ for (const pkgPath of pkgPaths) {
3400
+ if (existsSync5(pkgPath)) {
3401
+ const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
3402
+ return pkg.version;
3403
+ }
3404
+ }
3405
+ return "unknown";
3406
+ }
3407
+ async function checkVersion(opencodeDir) {
3408
+ const current = getCurrentVersion(opencodeDir);
3209
3409
  const latest = getPackageVersion();
3210
3410
  return {
3211
3411
  current,
@@ -3281,23 +3481,23 @@ async function upgradeCommand(options = {}) {
3281
3481
  notInitialized();
3282
3482
  return;
3283
3483
  }
3284
- oe(import_picocolors8.default.bgCyan(import_picocolors8.default.black(" Upgrade ")));
3484
+ oe(import_picocolors9.default.bgCyan(import_picocolors9.default.black(" Upgrade ")));
3285
3485
  const versionInfo = await checkVersion(opencodeDir);
3286
3486
  console.log();
3287
- console.log(` ${import_picocolors8.default.bold("Installed")} ${import_picocolors8.default.cyan(versionInfo.current || "unknown")}`);
3288
- console.log(` ${import_picocolors8.default.bold("Latest")} ${import_picocolors8.default.cyan(versionInfo.latest || "unknown")}`);
3487
+ console.log(` ${import_picocolors9.default.bold("Installed")} ${import_picocolors9.default.cyan(versionInfo.current || "unknown")}`);
3488
+ console.log(` ${import_picocolors9.default.bold("Latest")} ${import_picocolors9.default.cyan(versionInfo.latest || "unknown")}`);
3289
3489
  console.log();
3290
3490
  if (options.check) {
3291
3491
  if (versionInfo.needsUpdate) {
3292
- f2.info(`Update available: ${import_picocolors8.default.cyan(versionInfo.latest)}`);
3293
- $e(`Run ${import_picocolors8.default.cyan("ock upgrade")} to update`);
3492
+ f2.info(`Update available: ${import_picocolors9.default.cyan(versionInfo.latest)}`);
3493
+ $e(`Run ${import_picocolors9.default.cyan("ock upgrade")} to update`);
3294
3494
  } else {
3295
- $e(import_picocolors8.default.green("Already up to date"));
3495
+ $e(import_picocolors9.default.green("Already up to date"));
3296
3496
  }
3297
3497
  return;
3298
3498
  }
3299
3499
  if (!versionInfo.needsUpdate && !options.force) {
3300
- $e(import_picocolors8.default.green("Already up to date"));
3500
+ $e(import_picocolors9.default.green("Already up to date"));
3301
3501
  return;
3302
3502
  }
3303
3503
  const templateRoot = getTemplateRoot2();
@@ -3333,205 +3533,10 @@ async function upgradeCommand(options = {}) {
3333
3533
  f2.info(`Preserved ${result.preserved.length} user files`);
3334
3534
  }
3335
3535
  le("cd .opencode && bun install", "Run if dependencies changed");
3336
- $e(import_picocolors8.default.green(`Upgraded to ${versionInfo.latest}`));
3337
- }
3338
-
3339
- // src/commands/completion.ts
3340
- var import_picocolors9 = __toESM(require_picocolors(), 1);
3341
- var BASH_COMPLETION = `# ock bash completion
3342
- _ock_completion() {
3343
- local cur prev commands
3344
- COMPREPLY=()
3345
- cur="\${COMP_WORDS[COMP_CWORD]}"
3346
- prev="\${COMP_WORDS[COMP_CWORD-1]}"
3347
-
3348
- commands="init config upgrade agent skill doctor status help"
3349
-
3350
- case "\${prev}" in
3351
- ock)
3352
- COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
3353
- return 0
3354
- ;;
3355
- agent)
3356
- COMPREPLY=( $(compgen -W "list add view" -- "\${cur}") )
3357
- return 0
3358
- ;;
3359
- skill)
3360
- COMPREPLY=( $(compgen -W "list add view" -- "\${cur}") )
3361
- return 0
3362
- ;;
3363
- config)
3364
- COMPREPLY=( $(compgen -W "model mcp permission keybinds show" -- "\${cur}") )
3365
- return 0
3366
- ;;
3367
- init)
3368
- COMPREPLY=( $(compgen -W "--force" -- "\${cur}") )
3369
- return 0
3370
- ;;
3371
- upgrade)
3372
- COMPREPLY=( $(compgen -W "--force --check" -- "\${cur}") )
3373
- return 0
3374
- ;;
3375
- *)
3376
- ;;
3377
- esac
3378
- }
3379
- complete -F _ock_completion ock
3380
- `;
3381
- var ZSH_COMPLETION = `#compdef ock
3382
-
3383
- _ock() {
3384
- local -a commands
3385
- local -a agent_actions
3386
- local -a skill_actions
3387
- local -a config_actions
3388
-
3389
- commands=(
3390
- 'init:Initialize OpenCodeKit in current directory'
3391
- 'config:Edit opencode.json'
3392
- 'upgrade:Update templates to latest version'
3393
- 'agent:Manage agents'
3394
- 'skill:Manage skills'
3395
- 'doctor:Check project health'
3396
- 'status:Show project overview'
3397
- 'help:Show help'
3398
- )
3399
-
3400
- agent_actions=(
3401
- 'list:List all agents'
3402
- 'add:Create a new agent'
3403
- 'view:View agent details'
3404
- )
3405
-
3406
- skill_actions=(
3407
- 'list:List all skills'
3408
- 'add:Install a skill'
3409
- 'view:View skill details'
3410
- )
3411
-
3412
- config_actions=(
3413
- 'model:Change default model'
3414
- 'mcp:Manage MCP servers'
3415
- 'permission:Edit permissions'
3416
- 'keybinds:Edit keyboard shortcuts'
3417
- 'show:View current config'
3418
- )
3419
-
3420
- case "$words[2]" in
3421
- agent)
3422
- _describe -t actions 'agent action' agent_actions
3423
- ;;
3424
- skill)
3425
- _describe -t actions 'skill action' skill_actions
3426
- ;;
3427
- config)
3428
- _describe -t actions 'config action' config_actions
3429
- ;;
3430
- init)
3431
- _arguments '--force[Reinitialize even if already exists]'
3432
- ;;
3433
- upgrade)
3434
- _arguments \\
3435
- '--force[Force upgrade even if up to date]' \\
3436
- '--check[Check for updates only]'
3437
- ;;
3438
- *)
3439
- _describe -t commands 'command' commands
3440
- ;;
3441
- esac
3442
- }
3443
-
3444
- _ock "$@"
3445
- `;
3446
- var FISH_COMPLETION = `# ock fish completion
3447
- complete -c ock -n "__fish_use_subcommand" -a "init" -d "Initialize OpenCodeKit"
3448
- complete -c ock -n "__fish_use_subcommand" -a "config" -d "Edit opencode.json"
3449
- complete -c ock -n "__fish_use_subcommand" -a "upgrade" -d "Update templates"
3450
- complete -c ock -n "__fish_use_subcommand" -a "agent" -d "Manage agents"
3451
- complete -c ock -n "__fish_use_subcommand" -a "skill" -d "Manage skills"
3452
- complete -c ock -n "__fish_use_subcommand" -a "doctor" -d "Check project health"
3453
- complete -c ock -n "__fish_use_subcommand" -a "status" -d "Show project overview"
3454
-
3455
- # agent subcommands
3456
- complete -c ock -n "__fish_seen_subcommand_from agent" -a "list" -d "List agents"
3457
- complete -c ock -n "__fish_seen_subcommand_from agent" -a "add" -d "Add agent"
3458
- complete -c ock -n "__fish_seen_subcommand_from agent" -a "view" -d "View agent"
3459
-
3460
- # skill subcommands
3461
- complete -c ock -n "__fish_seen_subcommand_from skill" -a "list" -d "List skills"
3462
- complete -c ock -n "__fish_seen_subcommand_from skill" -a "add" -d "Add skill"
3463
- complete -c ock -n "__fish_seen_subcommand_from skill" -a "view" -d "View skill"
3464
-
3465
- # config subcommands
3466
- complete -c ock -n "__fish_seen_subcommand_from config" -a "model" -d "Change model"
3467
- complete -c ock -n "__fish_seen_subcommand_from config" -a "mcp" -d "Manage MCP"
3468
- complete -c ock -n "__fish_seen_subcommand_from config" -a "permission" -d "Edit permissions"
3469
- complete -c ock -n "__fish_seen_subcommand_from config" -a "keybinds" -d "Edit keybinds"
3470
- complete -c ock -n "__fish_seen_subcommand_from config" -a "show" -d "View config"
3471
-
3472
- # init options
3473
- complete -c ock -n "__fish_seen_subcommand_from init" -l force -d "Reinitialize"
3474
-
3475
- # upgrade options
3476
- complete -c ock -n "__fish_seen_subcommand_from upgrade" -l force -d "Force upgrade"
3477
- complete -c ock -n "__fish_seen_subcommand_from upgrade" -l check -d "Check only"
3478
- `;
3479
- async function completionCommand(shell) {
3480
- if (!shell) {
3481
- oe(import_picocolors9.default.bgCyan(import_picocolors9.default.black(" Shell Completion ")));
3482
- const selected = await ie({
3483
- message: "Select your shell",
3484
- options: [
3485
- { value: "bash", label: "Bash" },
3486
- { value: "zsh", label: "Zsh" },
3487
- { value: "fish", label: "Fish" }
3488
- ]
3489
- });
3490
- if (lD(selected)) {
3491
- ue("Cancelled");
3492
- return;
3493
- }
3494
- shell = selected;
3495
- }
3496
- let script;
3497
- let setupInstructions;
3498
- switch (shell) {
3499
- case "bash":
3500
- script = BASH_COMPLETION;
3501
- setupInstructions = `Add to ~/.bashrc:
3502
- source <(ock completion bash)
3503
-
3504
- Or save to file:
3505
- ock completion bash > ~/.local/share/bash-completion/completions/ock`;
3506
- break;
3507
- case "zsh":
3508
- script = ZSH_COMPLETION;
3509
- setupInstructions = `Add to ~/.zshrc (before compinit):
3510
- source <(ock completion zsh)
3511
-
3512
- Or save to fpath:
3513
- ock completion zsh > ~/.zsh/completions/_ock
3514
- # Then add to ~/.zshrc: fpath=(~/.zsh/completions $fpath)`;
3515
- break;
3516
- case "fish":
3517
- script = FISH_COMPLETION;
3518
- setupInstructions = `Save to fish completions:
3519
- ock completion fish > ~/.config/fish/completions/ock.fish`;
3520
- break;
3521
- default:
3522
- f2.error(`Unknown shell: ${shell}`);
3523
- return;
3524
- }
3525
- console.log(script);
3526
- console.error();
3527
- console.error(import_picocolors9.default.bold("Setup:"));
3528
- console.error(import_picocolors9.default.dim(setupInstructions));
3536
+ $e(import_picocolors9.default.green(`Upgraded to ${versionInfo.latest}`));
3529
3537
  }
3530
3538
 
3531
3539
  // src/commands/menu.ts
3532
- var import_picocolors10 = __toESM(require_picocolors(), 1);
3533
- import { existsSync as existsSync6, readdirSync as readdirSync5, lstatSync as lstatSync3 } from "node:fs";
3534
- import { join as join6, basename as basename2 } from "node:path";
3535
3540
  async function interactiveMenu(version) {
3536
3541
  oe(import_picocolors10.default.bgCyan(import_picocolors10.default.black(` OpenCodeKit v${version} `)));
3537
3542
  const action = await ie({