oh-my-opencode 2.8.2 → 2.9.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.
package/dist/index.js CHANGED
@@ -1479,9 +1479,223 @@ function isGptModel(model) {
1479
1479
  return model.startsWith("openai/") || model.startsWith("github-copilot/gpt-");
1480
1480
  }
1481
1481
 
1482
+ // src/agents/sisyphus-prompt-builder.ts
1483
+ function categorizeTools(toolNames) {
1484
+ return toolNames.map((name) => {
1485
+ let category = "other";
1486
+ if (name.startsWith("lsp_")) {
1487
+ category = "lsp";
1488
+ } else if (name.startsWith("ast_grep")) {
1489
+ category = "ast";
1490
+ } else if (name === "grep" || name === "glob") {
1491
+ category = "search";
1492
+ } else if (name.startsWith("session_")) {
1493
+ category = "session";
1494
+ } else if (name === "slashcommand") {
1495
+ category = "command";
1496
+ }
1497
+ return { name, category };
1498
+ });
1499
+ }
1500
+ function formatToolsForPrompt(tools) {
1501
+ const lspTools = tools.filter((t) => t.category === "lsp");
1502
+ const astTools = tools.filter((t) => t.category === "ast");
1503
+ const searchTools = tools.filter((t) => t.category === "search");
1504
+ const parts = [];
1505
+ if (searchTools.length > 0) {
1506
+ parts.push(...searchTools.map((t) => `\`${t.name}\``));
1507
+ }
1508
+ if (lspTools.length > 0) {
1509
+ parts.push("`lsp_*`");
1510
+ }
1511
+ if (astTools.length > 0) {
1512
+ parts.push("`ast_grep`");
1513
+ }
1514
+ return parts.join(", ");
1515
+ }
1516
+ function buildKeyTriggersSection(agents) {
1517
+ const keyTriggers = agents.filter((a) => a.metadata.keyTrigger).map((a) => `- ${a.metadata.keyTrigger}`);
1518
+ if (keyTriggers.length === 0)
1519
+ return "";
1520
+ return `### Key Triggers (check BEFORE classification):
1521
+ ${keyTriggers.join(`
1522
+ `)}
1523
+ - **GitHub mention (@mention in issue/PR)** \u2192 This is a WORK REQUEST. Plan full cycle: investigate \u2192 implement \u2192 create PR
1524
+ - **"Look into" + "create PR"** \u2192 Not just research. Full implementation cycle expected.`;
1525
+ }
1526
+ function buildToolSelectionTable(agents, tools = []) {
1527
+ const rows = [
1528
+ "### Tool Selection:",
1529
+ "",
1530
+ "| Tool | Cost | When to Use |",
1531
+ "|------|------|-------------|"
1532
+ ];
1533
+ if (tools.length > 0) {
1534
+ const toolsDisplay = formatToolsForPrompt(tools);
1535
+ rows.push(`| ${toolsDisplay} | FREE | Not Complex, Scope Clear, No Implicit Assumptions |`);
1536
+ }
1537
+ const costOrder = { FREE: 0, CHEAP: 1, EXPENSIVE: 2 };
1538
+ const sortedAgents = [...agents].filter((a) => a.metadata.category !== "utility").sort((a, b) => costOrder[a.metadata.cost] - costOrder[b.metadata.cost]);
1539
+ for (const agent of sortedAgents) {
1540
+ const shortDesc = agent.description.split(".")[0] || agent.description;
1541
+ rows.push(`| \`${agent.name}\` agent | ${agent.metadata.cost} | ${shortDesc} |`);
1542
+ }
1543
+ rows.push("");
1544
+ rows.push("**Default flow**: explore/librarian (background) + tools \u2192 oracle (if required)");
1545
+ return rows.join(`
1546
+ `);
1547
+ }
1548
+ function buildExploreSection(agents) {
1549
+ const exploreAgent = agents.find((a) => a.name === "explore");
1550
+ if (!exploreAgent)
1551
+ return "";
1552
+ const useWhen = exploreAgent.metadata.useWhen || [];
1553
+ const avoidWhen = exploreAgent.metadata.avoidWhen || [];
1554
+ return `### Explore Agent = Contextual Grep
1555
+
1556
+ Use it as a **peer tool**, not a fallback. Fire liberally.
1557
+
1558
+ | Use Direct Tools | Use Explore Agent |
1559
+ |------------------|-------------------|
1560
+ ${avoidWhen.map((w) => `| ${w} | |`).join(`
1561
+ `)}
1562
+ ${useWhen.map((w) => `| | ${w} |`).join(`
1563
+ `)}`;
1564
+ }
1565
+ function buildLibrarianSection(agents) {
1566
+ const librarianAgent = agents.find((a) => a.name === "librarian");
1567
+ if (!librarianAgent)
1568
+ return "";
1569
+ const useWhen = librarianAgent.metadata.useWhen || [];
1570
+ return `### Librarian Agent = Reference Grep
1571
+
1572
+ Search **external references** (docs, OSS, web). Fire proactively when unfamiliar libraries are involved.
1573
+
1574
+ | Contextual Grep (Internal) | Reference Grep (External) |
1575
+ |----------------------------|---------------------------|
1576
+ | Search OUR codebase | Search EXTERNAL resources |
1577
+ | Find patterns in THIS repo | Find examples in OTHER repos |
1578
+ | How does our code work? | How does this library work? |
1579
+ | Project-specific logic | Official API documentation |
1580
+ | | Library best practices & quirks |
1581
+ | | OSS implementation examples |
1582
+
1583
+ **Trigger phrases** (fire librarian immediately):
1584
+ ${useWhen.map((w) => `- "${w}"`).join(`
1585
+ `)}`;
1586
+ }
1587
+ function buildDelegationTable(agents) {
1588
+ const rows = [
1589
+ "### Delegation Table:",
1590
+ "",
1591
+ "| Domain | Delegate To | Trigger |",
1592
+ "|--------|-------------|---------|"
1593
+ ];
1594
+ for (const agent of agents) {
1595
+ for (const trigger of agent.metadata.triggers) {
1596
+ rows.push(`| ${trigger.domain} | \`${agent.name}\` | ${trigger.trigger} |`);
1597
+ }
1598
+ }
1599
+ return rows.join(`
1600
+ `);
1601
+ }
1602
+ function buildFrontendSection(agents) {
1603
+ const frontendAgent = agents.find((a) => a.name === "frontend-ui-ux-engineer");
1604
+ if (!frontendAgent)
1605
+ return "";
1606
+ return `### Frontend Files: Decision Gate (NOT a blind block)
1607
+
1608
+ Frontend files (.tsx, .jsx, .vue, .svelte, .css, etc.) require **classification before action**.
1609
+
1610
+ #### Step 1: Classify the Change Type
1611
+
1612
+ | Change Type | Examples | Action |
1613
+ |-------------|----------|--------|
1614
+ | **Visual/UI/UX** | Color, spacing, layout, typography, animation, responsive breakpoints, hover states, shadows, borders, icons, images | **DELEGATE** to \`frontend-ui-ux-engineer\` |
1615
+ | **Pure Logic** | API calls, data fetching, state management, event handlers (non-visual), type definitions, utility functions, business logic | **CAN handle directly** |
1616
+ | **Mixed** | Component changes both visual AND logic | **Split**: handle logic yourself, delegate visual to \`frontend-ui-ux-engineer\` |
1617
+
1618
+ #### Step 2: Ask Yourself
1619
+
1620
+ Before touching any frontend file, think:
1621
+ > "Is this change about **how it LOOKS** or **how it WORKS**?"
1622
+
1623
+ - **LOOKS** (colors, sizes, positions, animations) \u2192 DELEGATE
1624
+ - **WORKS** (data flow, API integration, state) \u2192 Handle directly
1625
+
1626
+ #### When in Doubt \u2192 DELEGATE if ANY of these keywords involved:
1627
+ style, className, tailwind, color, background, border, shadow, margin, padding, width, height, flex, grid, animation, transition, hover, responsive, font-size, icon, svg`;
1628
+ }
1629
+ function buildOracleSection(agents) {
1630
+ const oracleAgent = agents.find((a) => a.name === "oracle");
1631
+ if (!oracleAgent)
1632
+ return "";
1633
+ const useWhen = oracleAgent.metadata.useWhen || [];
1634
+ const avoidWhen = oracleAgent.metadata.avoidWhen || [];
1635
+ return `<Oracle_Usage>
1636
+ ## Oracle \u2014 Your Senior Engineering Advisor (GPT-5.2)
1637
+
1638
+ Oracle is an expensive, high-quality reasoning model. Use it wisely.
1639
+
1640
+ ### WHEN to Consult:
1641
+
1642
+ | Trigger | Action |
1643
+ |---------|--------|
1644
+ ${useWhen.map((w) => `| ${w} | Oracle FIRST, then implement |`).join(`
1645
+ `)}
1646
+
1647
+ ### WHEN NOT to Consult:
1648
+
1649
+ ${avoidWhen.map((w) => `- ${w}`).join(`
1650
+ `)}
1651
+
1652
+ ### Usage Pattern:
1653
+ Briefly announce "Consulting Oracle for [reason]" before invocation.
1654
+
1655
+ **Exception**: This is the ONLY case where you announce before acting. For all other work, start immediately without status updates.
1656
+ </Oracle_Usage>`;
1657
+ }
1658
+ function buildHardBlocksSection(agents) {
1659
+ const frontendAgent = agents.find((a) => a.name === "frontend-ui-ux-engineer");
1660
+ const blocks = [
1661
+ "| Type error suppression (`as any`, `@ts-ignore`) | Never |",
1662
+ "| Commit without explicit request | Never |",
1663
+ "| Speculate about unread code | Never |",
1664
+ "| Leave code in broken state after failures | Never |"
1665
+ ];
1666
+ if (frontendAgent) {
1667
+ blocks.unshift("| Frontend VISUAL changes (styling, layout, animation) | Always delegate to `frontend-ui-ux-engineer` |");
1668
+ }
1669
+ return `## Hard Blocks (NEVER violate)
1670
+
1671
+ | Constraint | No Exceptions |
1672
+ |------------|---------------|
1673
+ ${blocks.join(`
1674
+ `)}`;
1675
+ }
1676
+ function buildAntiPatternsSection(agents) {
1677
+ const frontendAgent = agents.find((a) => a.name === "frontend-ui-ux-engineer");
1678
+ const patterns = [
1679
+ "| **Type Safety** | `as any`, `@ts-ignore`, `@ts-expect-error` |",
1680
+ "| **Error Handling** | Empty catch blocks `catch(e) {}` |",
1681
+ '| **Testing** | Deleting failing tests to "pass" |',
1682
+ "| **Search** | Firing agents for single-line typos or obvious syntax errors |",
1683
+ "| **Debugging** | Shotgun debugging, random changes |"
1684
+ ];
1685
+ if (frontendAgent) {
1686
+ patterns.splice(4, 0, "| **Frontend** | Direct edit to visual/styling code (logic changes OK) |");
1687
+ }
1688
+ return `## Anti-Patterns (BLOCKING violations)
1689
+
1690
+ | Category | Forbidden |
1691
+ |----------|-----------|
1692
+ ${patterns.join(`
1693
+ `)}`;
1694
+ }
1695
+
1482
1696
  // src/agents/sisyphus.ts
1483
1697
  var DEFAULT_MODEL = "anthropic/claude-opus-4-5";
1484
- var SISYPHUS_SYSTEM_PROMPT = `<Role>
1698
+ var SISYPHUS_ROLE_SECTION = `<Role>
1485
1699
  You are "Sisyphus" - Powerful AI Agent with orchestration capabilities from OhMyOpenCode.
1486
1700
  Named by [YeonGyu Kim](https://github.com/code-yeongyu).
1487
1701
 
@@ -1499,19 +1713,8 @@ Named by [YeonGyu Kim](https://github.com/code-yeongyu).
1499
1713
 
1500
1714
  **Operating Mode**: You NEVER work alone when specialists are available. Frontend work \u2192 delegate. Deep research \u2192 parallel background agents (async subagents). Complex architecture \u2192 consult Oracle.
1501
1715
 
1502
- </Role>
1503
-
1504
- <Behavior_Instructions>
1505
-
1506
- ## Phase 0 - Intent Gate (EVERY message)
1507
-
1508
- ### Key Triggers (check BEFORE classification):
1509
- - External library/source mentioned \u2192 fire \`librarian\` background
1510
- - 2+ modules involved \u2192 fire \`explore\` background
1511
- - **GitHub mention (@mention in issue/PR)** \u2192 This is a WORK REQUEST. Plan full cycle: investigate \u2192 implement \u2192 create PR
1512
- - **"Look into" + "create PR"** \u2192 Not just research. Full implementation cycle expected.
1513
-
1514
- ### Step 1: Classify Request Type
1716
+ </Role>`;
1717
+ var SISYPHUS_PHASE0_STEP1_3 = `### Step 1: Classify Request Type
1515
1718
 
1516
1719
  | Type | Signal | Action |
1517
1720
  |------|--------|--------|
@@ -1556,11 +1759,8 @@ Then: Raise your concern concisely. Propose an alternative. Ask if they want to
1556
1759
  I notice [observation]. This might cause [problem] because [reason].
1557
1760
  Alternative: [your suggestion].
1558
1761
  Should I proceed with your original request, or try the alternative?
1559
- \`\`\`
1560
-
1561
- ---
1562
-
1563
- ## Phase 1 - Codebase Assessment (for Open-ended tasks)
1762
+ \`\`\``;
1763
+ var SISYPHUS_PHASE1 = `## Phase 1 - Codebase Assessment (for Open-ended tasks)
1564
1764
 
1565
1765
  Before following existing patterns, assess whether they're worth following.
1566
1766
 
@@ -1581,54 +1781,8 @@ Before following existing patterns, assess whether they're worth following.
1581
1781
  IMPORTANT: If codebase appears undisciplined, verify before assuming:
1582
1782
  - Different patterns may serve different purposes (intentional)
1583
1783
  - Migration might be in progress
1584
- - You might be looking at the wrong reference files
1585
-
1586
- ---
1587
-
1588
- ## Phase 2A - Exploration & Research
1589
-
1590
- ### Tool Selection:
1591
-
1592
- | Tool | Cost | When to Use |
1593
- |------|------|-------------|
1594
- | \`grep\`, \`glob\`, \`lsp_*\`, \`ast_grep\` | FREE | Not Complex, Scope Clear, No Implicit Assumptions |
1595
- | \`explore\` agent | FREE | Multiple search angles, unfamiliar modules, cross-layer patterns |
1596
- | \`librarian\` agent | CHEAP | External docs, GitHub examples, OpenSource Implementations, OSS reference |
1597
- | \`oracle\` agent | EXPENSIVE | Architecture, review, debugging after 2+ failures |
1598
-
1599
- **Default flow**: explore/librarian (background) + tools \u2192 oracle (if required)
1600
-
1601
- ### Explore Agent = Contextual Grep
1602
-
1603
- Use it as a **peer tool**, not a fallback. Fire liberally.
1604
-
1605
- | Use Direct Tools | Use Explore Agent |
1606
- |------------------|-------------------|
1607
- | You know exactly what to search | Multiple search angles needed |
1608
- | Single keyword/pattern suffices | Unfamiliar module structure |
1609
- | Known file location | Cross-layer pattern discovery |
1610
-
1611
- ### Librarian Agent = Reference Grep
1612
-
1613
- Search **external references** (docs, OSS, web). Fire proactively when unfamiliar libraries are involved.
1614
-
1615
- | Contextual Grep (Internal) | Reference Grep (External) |
1616
- |----------------------------|---------------------------|
1617
- | Search OUR codebase | Search EXTERNAL resources |
1618
- | Find patterns in THIS repo | Find examples in OTHER repos |
1619
- | How does our code work? | How does this library work? |
1620
- | Project-specific logic | Official API documentation |
1621
- | | Library best practices & quirks |
1622
- | | OSS implementation examples |
1623
-
1624
- **Trigger phrases** (fire librarian immediately):
1625
- - "How do I use [library]?"
1626
- - "What's the best practice for [framework feature]?"
1627
- - "Why does [external dependency] behave this way?"
1628
- - "Find examples of [library] usage"
1629
- - Working with unfamiliar npm/pip/cargo packages
1630
-
1631
- ### Parallel Execution (DEFAULT behavior)
1784
+ - You might be looking at the wrong reference files`;
1785
+ var SISYPHUS_PARALLEL_EXECUTION = `### Parallel Execution (DEFAULT behavior)
1632
1786
 
1633
1787
  **Explore/Librarian = Grep, not consultants.
1634
1788
 
@@ -1660,64 +1814,14 @@ STOP searching when:
1660
1814
  - 2 search iterations yielded no new useful data
1661
1815
  - Direct answer found
1662
1816
 
1663
- **DO NOT over-explore. Time is precious.**
1664
-
1665
- ---
1666
-
1667
- ## Phase 2B - Implementation
1817
+ **DO NOT over-explore. Time is precious.**`;
1818
+ var SISYPHUS_PHASE2B_PRE_IMPLEMENTATION = `## Phase 2B - Implementation
1668
1819
 
1669
1820
  ### Pre-Implementation:
1670
1821
  1. If task has 2+ steps \u2192 Create todo list IMMEDIATELY, IN SUPER DETAIL. No announcements\u2014just create it.
1671
1822
  2. Mark current task \`in_progress\` before starting
1672
- 3. Mark \`completed\` as soon as done (don't batch) - OBSESSIVELY TRACK YOUR WORK USING TODO TOOLS
1673
-
1674
- ### Frontend Files: Decision Gate (NOT a blind block)
1675
-
1676
- Frontend files (.tsx, .jsx, .vue, .svelte, .css, etc.) require **classification before action**.
1677
-
1678
- #### Step 1: Classify the Change Type
1679
-
1680
- | Change Type | Examples | Action |
1681
- |-------------|----------|--------|
1682
- | **Visual/UI/UX** | Color, spacing, layout, typography, animation, responsive breakpoints, hover states, shadows, borders, icons, images | **DELEGATE** to \`frontend-ui-ux-engineer\` |
1683
- | **Pure Logic** | API calls, data fetching, state management, event handlers (non-visual), type definitions, utility functions, business logic | **CAN handle directly** |
1684
- | **Mixed** | Component changes both visual AND logic | **Split**: handle logic yourself, delegate visual to \`frontend-ui-ux-engineer\` |
1685
-
1686
- #### Step 2: Ask Yourself
1687
-
1688
- Before touching any frontend file, think:
1689
- > "Is this change about **how it LOOKS** or **how it WORKS**?"
1690
-
1691
- - **LOOKS** (colors, sizes, positions, animations) \u2192 DELEGATE
1692
- - **WORKS** (data flow, API integration, state) \u2192 Handle directly
1693
-
1694
- #### Quick Reference Examples
1695
-
1696
- | File | Change | Type | Action |
1697
- |------|--------|------|--------|
1698
- | \`Button.tsx\` | Change color blue\u2192green | Visual | DELEGATE |
1699
- | \`Button.tsx\` | Add onClick API call | Logic | Direct |
1700
- | \`UserList.tsx\` | Add loading spinner animation | Visual | DELEGATE |
1701
- | \`UserList.tsx\` | Fix pagination logic bug | Logic | Direct |
1702
- | \`Modal.tsx\` | Make responsive for mobile | Visual | DELEGATE |
1703
- | \`Modal.tsx\` | Add form validation logic | Logic | Direct |
1704
-
1705
- #### When in Doubt \u2192 DELEGATE if ANY of these keywords involved:
1706
- style, className, tailwind, color, background, border, shadow, margin, padding, width, height, flex, grid, animation, transition, hover, responsive, font-size, icon, svg
1707
-
1708
- ### Delegation Table:
1709
-
1710
- | Domain | Delegate To | Trigger |
1711
- |--------|-------------|---------|
1712
- | Explore | \`explore\` | Find existing codebase structure, patterns and styles |
1713
- | Frontend UI/UX | \`frontend-ui-ux-engineer\` | Visual changes only (styling, layout, animation). Pure logic changes in frontend files \u2192 handle directly |
1714
- | Librarian | \`librarian\` | Unfamiliar packages / libraries, struggles at weird behaviour (to find existing implementation of opensource) |
1715
- | Documentation | \`document-writer\` | README, API docs, guides |
1716
- | Architecture decisions | \`oracle\` | Multi-system tradeoffs, unfamiliar patterns |
1717
- | Self-review | \`oracle\` | After completing significant implementation |
1718
- | Hard debugging | \`oracle\` | After 2+ failed fix attempts |
1719
-
1720
- ### Delegation Prompt Structure (MANDATORY - ALL 7 sections):
1823
+ 3. Mark \`completed\` as soon as done (don't batch) - OBSESSIVELY TRACK YOUR WORK USING TODO TOOLS`;
1824
+ var SISYPHUS_DELEGATION_PROMPT_STRUCTURE = `### Delegation Prompt Structure (MANDATORY - ALL 7 sections):
1721
1825
 
1722
1826
  When delegating, your prompt MUST include:
1723
1827
 
@@ -1737,9 +1841,8 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING:
1737
1841
  - EXPECTED RESULT CAME OUT?
1738
1842
  - DID THE AGENT FOLLOWED "MUST DO" AND "MUST NOT DO" REQUIREMENTS?
1739
1843
 
1740
- **Vague prompts = rejected. Be exhaustive.**
1741
-
1742
- ### GitHub Workflow (CRITICAL - When mentioned in issues/PRs):
1844
+ **Vague prompts = rejected. Be exhaustive.**`;
1845
+ var SISYPHUS_GITHUB_WORKFLOW = `### GitHub Workflow (CRITICAL - When mentioned in issues/PRs):
1743
1846
 
1744
1847
  When you're mentioned in GitHub issues or asked to "look into" something and "create PR":
1745
1848
 
@@ -1772,9 +1875,8 @@ When you're mentioned in GitHub issues or asked to "look into" something and "cr
1772
1875
  **EMPHASIS**: "Look into" does NOT mean "just investigate and report back."
1773
1876
  It means "investigate, understand, implement a solution, and create a PR."
1774
1877
 
1775
- **If the user says "look into X and create PR", they expect a PR, not just analysis.**
1776
-
1777
- ### Code Changes:
1878
+ **If the user says "look into X and create PR", they expect a PR, not just analysis.**`;
1879
+ var SISYPHUS_CODE_CHANGES = `### Code Changes:
1778
1880
  - Match existing patterns (if codebase is disciplined)
1779
1881
  - Propose approach first (if codebase is chaotic)
1780
1882
  - Never suppress type errors with \`as any\`, \`@ts-ignore\`, \`@ts-expect-error\`
@@ -1800,11 +1902,8 @@ If project has build/test commands, run them at task completion.
1800
1902
  | Test run | Pass (or explicit note of pre-existing failures) |
1801
1903
  | Delegation | Agent result received and verified |
1802
1904
 
1803
- **NO EVIDENCE = NOT COMPLETE.**
1804
-
1805
- ---
1806
-
1807
- ## Phase 2C - Failure Recovery
1905
+ **NO EVIDENCE = NOT COMPLETE.**`;
1906
+ var SISYPHUS_PHASE2C = `## Phase 2C - Failure Recovery
1808
1907
 
1809
1908
  ### When Fixes Fail:
1810
1909
 
@@ -1820,11 +1919,8 @@ If project has build/test commands, run them at task completion.
1820
1919
  4. **CONSULT** Oracle with full failure context
1821
1920
  5. If Oracle cannot resolve \u2192 **ASK USER** before proceeding
1822
1921
 
1823
- **Never**: Leave code in broken state, continue hoping it'll work, delete failing tests to "pass"
1824
-
1825
- ---
1826
-
1827
- ## Phase 3 - Completion
1922
+ **Never**: Leave code in broken state, continue hoping it'll work, delete failing tests to "pass"`;
1923
+ var SISYPHUS_PHASE3 = `## Phase 3 - Completion
1828
1924
 
1829
1925
  A task is complete when:
1830
1926
  - [ ] All planned todo items marked done
@@ -1839,41 +1935,8 @@ If verification fails:
1839
1935
 
1840
1936
  ### Before Delivering Final Answer:
1841
1937
  - Cancel ALL running background tasks: \`background_cancel(all=true)\`
1842
- - This conserves resources and ensures clean workflow completion
1843
-
1844
- </Behavior_Instructions>
1845
-
1846
- <Oracle_Usage>
1847
- ## Oracle \u2014 Your Senior Engineering Advisor (GPT-5.2)
1848
-
1849
- Oracle is an expensive, high-quality reasoning model. Use it wisely.
1850
-
1851
- ### WHEN to Consult:
1852
-
1853
- | Trigger | Action |
1854
- |---------|--------|
1855
- | Complex architecture design | Oracle FIRST, then implement |
1856
- | After completing significant work | Oracle review before marking complete |
1857
- | 2+ failed fix attempts | Oracle for debugging guidance |
1858
- | Unfamiliar code patterns | Oracle to explain behavior |
1859
- | Security/performance concerns | Oracle for analysis |
1860
- | Multi-system tradeoffs | Oracle for architectural decision |
1861
-
1862
- ### WHEN NOT to Consult:
1863
-
1864
- - Simple file operations (use direct tools)
1865
- - First attempt at any fix (try yourself first)
1866
- - Questions answerable from code you've read
1867
- - Trivial decisions (variable names, formatting)
1868
- - Things you can infer from existing code patterns
1869
-
1870
- ### Usage Pattern:
1871
- Briefly announce "Consulting Oracle for [reason]" before invocation.
1872
-
1873
- **Exception**: This is the ONLY case where you announce before acting. For all other work, start immediately without status updates.
1874
- </Oracle_Usage>
1875
-
1876
- <Task_Management>
1938
+ - This conserves resources and ensures clean workflow completion`;
1939
+ var SISYPHUS_TASK_MANAGEMENT = `<Task_Management>
1877
1940
  ## Todo Management (CRITICAL)
1878
1941
 
1879
1942
  **DEFAULT BEHAVIOR**: Create todos BEFORE starting any non-trivial task. This is your PRIMARY coordination mechanism.
@@ -1928,9 +1991,8 @@ I want to make sure I understand correctly.
1928
1991
 
1929
1992
  Should I proceed with [recommendation], or would you prefer differently?
1930
1993
  \`\`\`
1931
- </Task_Management>
1932
-
1933
- <Tone_and_Style>
1994
+ </Task_Management>`;
1995
+ var SISYPHUS_TONE_AND_STYLE = `<Tone_and_Style>
1934
1996
  ## Communication Style
1935
1997
 
1936
1998
  ### Be Concise
@@ -1970,31 +2032,8 @@ If the user's approach seems problematic:
1970
2032
  - If user is terse, be terse
1971
2033
  - If user wants detail, provide detail
1972
2034
  - Adapt to their communication preference
1973
- </Tone_and_Style>
1974
-
1975
- <Constraints>
1976
- ## Hard Blocks (NEVER violate)
1977
-
1978
- | Constraint | No Exceptions |
1979
- |------------|---------------|
1980
- | Frontend VISUAL changes (styling, layout, animation) | Always delegate to \`frontend-ui-ux-engineer\` |
1981
- | Type error suppression (\`as any\`, \`@ts-ignore\`) | Never |
1982
- | Commit without explicit request | Never |
1983
- | Speculate about unread code | Never |
1984
- | Leave code in broken state after failures | Never |
1985
-
1986
- ## Anti-Patterns (BLOCKING violations)
1987
-
1988
- | Category | Forbidden |
1989
- |----------|-----------|
1990
- | **Type Safety** | \`as any\`, \`@ts-ignore\`, \`@ts-expect-error\` |
1991
- | **Error Handling** | Empty catch blocks \`catch(e) {}\` |
1992
- | **Testing** | Deleting failing tests to "pass" |
1993
- | **Search** | Firing agents for single-line typos or obvious syntax errors |
1994
- | **Frontend** | Direct edit to visual/styling code (logic changes OK) |
1995
- | **Debugging** | Shotgun debugging, random changes |
1996
-
1997
- ## Soft Guidelines
2035
+ </Tone_and_Style>`;
2036
+ var SISYPHUS_SOFT_GUIDELINES = `## Soft Guidelines
1998
2037
 
1999
2038
  - Prefer existing libraries over new dependencies
2000
2039
  - Prefer small, focused changes over large refactors
@@ -2002,13 +2041,91 @@ If the user's approach seems problematic:
2002
2041
  </Constraints>
2003
2042
 
2004
2043
  `;
2005
- function createSisyphusAgent(model = DEFAULT_MODEL) {
2044
+ function buildDynamicSisyphusPrompt(availableAgents, availableTools = []) {
2045
+ const keyTriggers = buildKeyTriggersSection(availableAgents);
2046
+ const toolSelection = buildToolSelectionTable(availableAgents, availableTools);
2047
+ const exploreSection = buildExploreSection(availableAgents);
2048
+ const librarianSection = buildLibrarianSection(availableAgents);
2049
+ const frontendSection = buildFrontendSection(availableAgents);
2050
+ const delegationTable = buildDelegationTable(availableAgents);
2051
+ const oracleSection = buildOracleSection(availableAgents);
2052
+ const hardBlocks = buildHardBlocksSection(availableAgents);
2053
+ const antiPatterns = buildAntiPatternsSection(availableAgents);
2054
+ const sections = [
2055
+ SISYPHUS_ROLE_SECTION,
2056
+ "<Behavior_Instructions>",
2057
+ "",
2058
+ "## Phase 0 - Intent Gate (EVERY message)",
2059
+ "",
2060
+ keyTriggers,
2061
+ "",
2062
+ SISYPHUS_PHASE0_STEP1_3,
2063
+ "",
2064
+ "---",
2065
+ "",
2066
+ SISYPHUS_PHASE1,
2067
+ "",
2068
+ "---",
2069
+ "",
2070
+ "## Phase 2A - Exploration & Research",
2071
+ "",
2072
+ toolSelection,
2073
+ "",
2074
+ exploreSection,
2075
+ "",
2076
+ librarianSection,
2077
+ "",
2078
+ SISYPHUS_PARALLEL_EXECUTION,
2079
+ "",
2080
+ "---",
2081
+ "",
2082
+ SISYPHUS_PHASE2B_PRE_IMPLEMENTATION,
2083
+ "",
2084
+ frontendSection,
2085
+ "",
2086
+ delegationTable,
2087
+ "",
2088
+ SISYPHUS_DELEGATION_PROMPT_STRUCTURE,
2089
+ "",
2090
+ SISYPHUS_GITHUB_WORKFLOW,
2091
+ "",
2092
+ SISYPHUS_CODE_CHANGES,
2093
+ "",
2094
+ "---",
2095
+ "",
2096
+ SISYPHUS_PHASE2C,
2097
+ "",
2098
+ "---",
2099
+ "",
2100
+ SISYPHUS_PHASE3,
2101
+ "",
2102
+ "</Behavior_Instructions>",
2103
+ "",
2104
+ oracleSection,
2105
+ "",
2106
+ SISYPHUS_TASK_MANAGEMENT,
2107
+ "",
2108
+ SISYPHUS_TONE_AND_STYLE,
2109
+ "",
2110
+ "<Constraints>",
2111
+ hardBlocks,
2112
+ "",
2113
+ antiPatterns,
2114
+ "",
2115
+ SISYPHUS_SOFT_GUIDELINES
2116
+ ];
2117
+ return sections.filter((s) => s !== "").join(`
2118
+ `);
2119
+ }
2120
+ function createSisyphusAgent(model = DEFAULT_MODEL, availableAgents, availableToolNames) {
2121
+ const tools = availableToolNames ? categorizeTools(availableToolNames) : [];
2122
+ const prompt = availableAgents ? buildDynamicSisyphusPrompt(availableAgents, tools) : buildDynamicSisyphusPrompt([], tools);
2006
2123
  const base = {
2007
2124
  description: "Sisyphus - Powerful AI orchestrator from OhMyOpenCode. Plans obsessively with todos, assesses search complexity before exploration, delegates strategically to specialized agents. Uses explore for internal code (parallel-friendly), librarian only for external docs, and always delegates UI work to frontend engineer.",
2008
2125
  mode: "primary",
2009
2126
  model,
2010
2127
  maxTokens: 64000,
2011
- prompt: SISYPHUS_SYSTEM_PROMPT,
2128
+ prompt,
2012
2129
  color: "#00CED1"
2013
2130
  };
2014
2131
  if (isGptModel(model)) {
@@ -4170,6 +4287,82 @@ function detectConfigFile(basePath) {
4170
4287
  }
4171
4288
  return { format: "none", path: jsonPath };
4172
4289
  }
4290
+ // src/shared/migration.ts
4291
+ import * as fs3 from "fs";
4292
+ var AGENT_NAME_MAP = {
4293
+ omo: "Sisyphus",
4294
+ OmO: "Sisyphus",
4295
+ "OmO-Plan": "Planner-Sisyphus",
4296
+ "omo-plan": "Planner-Sisyphus",
4297
+ sisyphus: "Sisyphus",
4298
+ "planner-sisyphus": "Planner-Sisyphus",
4299
+ build: "build",
4300
+ oracle: "oracle",
4301
+ librarian: "librarian",
4302
+ explore: "explore",
4303
+ "frontend-ui-ux-engineer": "frontend-ui-ux-engineer",
4304
+ "document-writer": "document-writer",
4305
+ "multimodal-looker": "multimodal-looker"
4306
+ };
4307
+ var HOOK_NAME_MAP = {
4308
+ "anthropic-auto-compact": "anthropic-context-window-limit-recovery"
4309
+ };
4310
+ function migrateAgentNames(agents) {
4311
+ const migrated = {};
4312
+ let changed = false;
4313
+ for (const [key, value] of Object.entries(agents)) {
4314
+ const newKey = AGENT_NAME_MAP[key.toLowerCase()] ?? AGENT_NAME_MAP[key] ?? key;
4315
+ if (newKey !== key) {
4316
+ changed = true;
4317
+ }
4318
+ migrated[newKey] = value;
4319
+ }
4320
+ return { migrated, changed };
4321
+ }
4322
+ function migrateHookNames(hooks) {
4323
+ const migrated = [];
4324
+ let changed = false;
4325
+ for (const hook of hooks) {
4326
+ const newHook = HOOK_NAME_MAP[hook] ?? hook;
4327
+ if (newHook !== hook) {
4328
+ changed = true;
4329
+ }
4330
+ migrated.push(newHook);
4331
+ }
4332
+ return { migrated, changed };
4333
+ }
4334
+ function migrateConfigFile(configPath, rawConfig) {
4335
+ let needsWrite = false;
4336
+ if (rawConfig.agents && typeof rawConfig.agents === "object") {
4337
+ const { migrated, changed } = migrateAgentNames(rawConfig.agents);
4338
+ if (changed) {
4339
+ rawConfig.agents = migrated;
4340
+ needsWrite = true;
4341
+ }
4342
+ }
4343
+ if (rawConfig.omo_agent) {
4344
+ rawConfig.sisyphus_agent = rawConfig.omo_agent;
4345
+ delete rawConfig.omo_agent;
4346
+ needsWrite = true;
4347
+ }
4348
+ if (rawConfig.disabled_hooks && Array.isArray(rawConfig.disabled_hooks)) {
4349
+ const { migrated, changed } = migrateHookNames(rawConfig.disabled_hooks);
4350
+ if (changed) {
4351
+ rawConfig.disabled_hooks = migrated;
4352
+ needsWrite = true;
4353
+ }
4354
+ }
4355
+ if (needsWrite) {
4356
+ try {
4357
+ fs3.writeFileSync(configPath, JSON.stringify(rawConfig, null, 2) + `
4358
+ `, "utf-8");
4359
+ log(`Migrated config file: ${configPath}`);
4360
+ } catch (err) {
4361
+ log(`Failed to write migrated config to ${configPath}:`, err);
4362
+ }
4363
+ }
4364
+ return needsWrite;
4365
+ }
4173
4366
  // src/agents/utils.ts
4174
4367
  var agentSources = {
4175
4368
  Sisyphus: createSisyphusAgent,
@@ -4258,7 +4451,7 @@ function getMainSessionID() {
4258
4451
  return mainSessionID;
4259
4452
  }
4260
4453
  // src/features/hook-message-injector/injector.ts
4261
- import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync3, readdirSync, writeFileSync } from "fs";
4454
+ import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync3, readdirSync, writeFileSync as writeFileSync2 } from "fs";
4262
4455
  import { join as join7 } from "path";
4263
4456
 
4264
4457
  // src/features/hook-message-injector/constants.ts
@@ -4360,12 +4553,12 @@ function injectHookMessage(sessionID, hookContent, originalMessage) {
4360
4553
  sessionID
4361
4554
  };
4362
4555
  try {
4363
- writeFileSync(join7(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
4556
+ writeFileSync2(join7(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
4364
4557
  const partDir = join7(PART_STORAGE, messageID);
4365
4558
  if (!existsSync5(partDir)) {
4366
4559
  mkdirSync(partDir, { recursive: true });
4367
4560
  }
4368
- writeFileSync(join7(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
4561
+ writeFileSync2(join7(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
4369
4562
  return true;
4370
4563
  } catch {
4371
4564
  return false;
@@ -5097,7 +5290,7 @@ function createSessionNotification(ctx, config = {}) {
5097
5290
  };
5098
5291
  }
5099
5292
  // src/hooks/session-recovery/storage.ts
5100
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
5293
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
5101
5294
  import { join as join10 } from "path";
5102
5295
 
5103
5296
  // src/hooks/session-recovery/constants.ts
@@ -5206,7 +5399,7 @@ function injectTextPart(sessionID, messageID, text) {
5206
5399
  synthetic: true
5207
5400
  };
5208
5401
  try {
5209
- writeFileSync2(join10(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
5402
+ writeFileSync3(join10(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
5210
5403
  return true;
5211
5404
  } catch {
5212
5405
  return false;
@@ -5316,7 +5509,7 @@ function prependThinkingPart(sessionID, messageID) {
5316
5509
  synthetic: true
5317
5510
  };
5318
5511
  try {
5319
- writeFileSync2(join10(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
5512
+ writeFileSync3(join10(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
5320
5513
  return true;
5321
5514
  } catch {
5322
5515
  return false;
@@ -5361,7 +5554,7 @@ function replaceEmptyTextParts(messageID, replacementText) {
5361
5554
  if (!textPart.text?.trim()) {
5362
5555
  textPart.text = replacementText;
5363
5556
  textPart.synthetic = true;
5364
- writeFileSync2(filePath, JSON.stringify(textPart, null, 2));
5557
+ writeFileSync3(filePath, JSON.stringify(textPart, null, 2));
5365
5558
  anyReplaced = true;
5366
5559
  }
5367
5560
  }
@@ -5632,7 +5825,7 @@ var {spawn: spawn4 } = globalThis.Bun;
5632
5825
  import { createRequire as createRequire2 } from "module";
5633
5826
  import { dirname, join as join12 } from "path";
5634
5827
  import { existsSync as existsSync9 } from "fs";
5635
- import * as fs3 from "fs";
5828
+ import * as fs4 from "fs";
5636
5829
  import { tmpdir as tmpdir3 } from "os";
5637
5830
 
5638
5831
  // src/hooks/comment-checker/downloader.ts
@@ -5780,7 +5973,7 @@ function debugLog2(...args) {
5780
5973
  if (DEBUG2) {
5781
5974
  const msg = `[${new Date().toISOString()}] [comment-checker:cli] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
5782
5975
  `;
5783
- fs3.appendFileSync(DEBUG_FILE2, msg);
5976
+ fs4.appendFileSync(DEBUG_FILE2, msg);
5784
5977
  }
5785
5978
  }
5786
5979
  function getBinaryName2() {
@@ -5894,7 +6087,7 @@ async function runCommentChecker(input, cliPath, customPrompt) {
5894
6087
  }
5895
6088
 
5896
6089
  // src/hooks/comment-checker/index.ts
5897
- import * as fs4 from "fs";
6090
+ import * as fs5 from "fs";
5898
6091
  import { existsSync as existsSync10 } from "fs";
5899
6092
  import { tmpdir as tmpdir4 } from "os";
5900
6093
  import { join as join13 } from "path";
@@ -5904,7 +6097,7 @@ function debugLog3(...args) {
5904
6097
  if (DEBUG3) {
5905
6098
  const msg = `[${new Date().toISOString()}] [comment-checker:hook] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
5906
6099
  `;
5907
- fs4.appendFileSync(DEBUG_FILE3, msg);
6100
+ fs5.appendFileSync(DEBUG_FILE3, msg);
5908
6101
  }
5909
6102
  }
5910
6103
  var pendingCalls = new Map;
@@ -6059,7 +6252,7 @@ import {
6059
6252
  existsSync as existsSync11,
6060
6253
  mkdirSync as mkdirSync4,
6061
6254
  readFileSync as readFileSync5,
6062
- writeFileSync as writeFileSync3,
6255
+ writeFileSync as writeFileSync4,
6063
6256
  unlinkSync as unlinkSync3
6064
6257
  } from "fs";
6065
6258
  import { join as join15 } from "path";
@@ -6095,7 +6288,7 @@ function saveInjectedPaths(sessionID, paths) {
6095
6288
  injectedPaths: [...paths],
6096
6289
  updatedAt: Date.now()
6097
6290
  };
6098
- writeFileSync3(getStoragePath(sessionID), JSON.stringify(data, null, 2));
6291
+ writeFileSync4(getStoragePath(sessionID), JSON.stringify(data, null, 2));
6099
6292
  }
6100
6293
  function clearInjectedPaths(sessionID) {
6101
6294
  const filePath = getStoragePath(sessionID);
@@ -6231,7 +6424,7 @@ import {
6231
6424
  existsSync as existsSync13,
6232
6425
  mkdirSync as mkdirSync5,
6233
6426
  readFileSync as readFileSync7,
6234
- writeFileSync as writeFileSync4,
6427
+ writeFileSync as writeFileSync5,
6235
6428
  unlinkSync as unlinkSync4
6236
6429
  } from "fs";
6237
6430
  import { join as join18 } from "path";
@@ -6267,7 +6460,7 @@ function saveInjectedPaths2(sessionID, paths) {
6267
6460
  injectedPaths: [...paths],
6268
6461
  updatedAt: Date.now()
6269
6462
  };
6270
- writeFileSync4(getStoragePath2(sessionID), JSON.stringify(data, null, 2));
6463
+ writeFileSync5(getStoragePath2(sessionID), JSON.stringify(data, null, 2));
6271
6464
  }
6272
6465
  function clearInjectedPaths2(sessionID) {
6273
6466
  const filePath = getStoragePath2(sessionID);
@@ -6587,10 +6780,6 @@ var RETRY_CONFIG = {
6587
6780
  backoffFactor: 2,
6588
6781
  maxDelayMs: 30000
6589
6782
  };
6590
- var FALLBACK_CONFIG = {
6591
- maxRevertAttempts: 3,
6592
- minMessagesRequired: 2
6593
- };
6594
6783
  var TRUNCATE_CONFIG = {
6595
6784
  maxTruncateAttempts: 20,
6596
6785
  minOutputSizeToTruncate: 500,
@@ -7011,7 +7200,7 @@ function executePurgeErrors(sessionID, state2, config, protectedTools) {
7011
7200
  }
7012
7201
 
7013
7202
  // src/hooks/anthropic-context-window-limit-recovery/pruning-storage.ts
7014
- import { existsSync as existsSync18, readdirSync as readdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
7203
+ import { existsSync as existsSync18, readdirSync as readdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "fs";
7015
7204
  import { join as join23 } from "path";
7016
7205
  function getMessageDir6(sessionID) {
7017
7206
  if (!existsSync18(MESSAGE_STORAGE))
@@ -7061,7 +7250,7 @@ async function applyPruning(sessionID, state2) {
7061
7250
  }
7062
7251
  }
7063
7252
  if (modified) {
7064
- writeFileSync5(filePath, JSON.stringify(data, null, 2), "utf-8");
7253
+ writeFileSync6(filePath, JSON.stringify(data, null, 2), "utf-8");
7065
7254
  filesModified++;
7066
7255
  }
7067
7256
  }
@@ -7161,7 +7350,7 @@ async function executeDynamicContextPruning(sessionID, config, client) {
7161
7350
  }
7162
7351
 
7163
7352
  // src/hooks/anthropic-context-window-limit-recovery/storage.ts
7164
- import { existsSync as existsSync19, readdirSync as readdirSync8, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "fs";
7353
+ import { existsSync as existsSync19, readdirSync as readdirSync8, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "fs";
7165
7354
  import { join as join24 } from "path";
7166
7355
  var OPENCODE_STORAGE5 = getOpenCodeStorageDir();
7167
7356
  var MESSAGE_STORAGE3 = join24(OPENCODE_STORAGE5, "message");
@@ -7245,7 +7434,7 @@ function truncateToolResult(partPath) {
7245
7434
  part.state.time = { start: Date.now() };
7246
7435
  }
7247
7436
  part.state.time.compacted = Date.now();
7248
- writeFileSync6(partPath, JSON.stringify(part, null, 2));
7437
+ writeFileSync7(partPath, JSON.stringify(part, null, 2));
7249
7438
  return { success: true, toolName, originalSize };
7250
7439
  } catch {
7251
7440
  return { success: false };
@@ -7312,14 +7501,6 @@ function getOrCreateRetryState(autoCompactState, sessionID) {
7312
7501
  }
7313
7502
  return state2;
7314
7503
  }
7315
- function getOrCreateFallbackState(autoCompactState, sessionID) {
7316
- let state2 = autoCompactState.fallbackStateBySession.get(sessionID);
7317
- if (!state2) {
7318
- state2 = { revertAttempt: 0 };
7319
- autoCompactState.fallbackStateBySession.set(sessionID, state2);
7320
- }
7321
- return state2;
7322
- }
7323
7504
  function getOrCreateTruncateState(autoCompactState, sessionID) {
7324
7505
  let state2 = autoCompactState.truncateStateBySession.get(sessionID);
7325
7506
  if (!state2) {
@@ -7362,43 +7543,6 @@ function sanitizeEmptyMessagesBeforeSummarize(sessionID) {
7362
7543
  }
7363
7544
  return fixedCount;
7364
7545
  }
7365
- async function getLastMessagePair(sessionID, client, directory) {
7366
- try {
7367
- const resp = await client.session.messages({
7368
- path: { id: sessionID },
7369
- query: { directory }
7370
- });
7371
- const data = resp.data;
7372
- if (!Array.isArray(data) || data.length < FALLBACK_CONFIG.minMessagesRequired) {
7373
- return null;
7374
- }
7375
- const reversed = [...data].reverse();
7376
- const lastAssistant = reversed.find((m) => {
7377
- const msg = m;
7378
- const info = msg.info;
7379
- return info?.role === "assistant";
7380
- });
7381
- const lastUser = reversed.find((m) => {
7382
- const msg = m;
7383
- const info = msg.info;
7384
- return info?.role === "user";
7385
- });
7386
- if (!lastUser)
7387
- return null;
7388
- const userInfo = lastUser.info;
7389
- const userMessageID = userInfo?.id;
7390
- if (!userMessageID)
7391
- return null;
7392
- let assistantMessageID;
7393
- if (lastAssistant) {
7394
- const assistantInfo = lastAssistant.info;
7395
- assistantMessageID = assistantInfo?.id;
7396
- }
7397
- return { userMessageID, assistantMessageID };
7398
- } catch {
7399
- return null;
7400
- }
7401
- }
7402
7546
  function formatBytes(bytes) {
7403
7547
  if (bytes < 1024)
7404
7548
  return `${bytes}B`;
@@ -7432,7 +7576,6 @@ function clearSessionState(autoCompactState, sessionID) {
7432
7576
  autoCompactState.pendingCompact.delete(sessionID);
7433
7577
  autoCompactState.errorDataBySession.delete(sessionID);
7434
7578
  autoCompactState.retryStateBySession.delete(sessionID);
7435
- autoCompactState.fallbackStateBySession.delete(sessionID);
7436
7579
  autoCompactState.truncateStateBySession.delete(sessionID);
7437
7580
  autoCompactState.dcpStateBySession.delete(sessionID);
7438
7581
  autoCompactState.emptyContentAttemptBySession.delete(sessionID);
@@ -7704,7 +7847,6 @@ async function executeCompact(sessionID, msg, autoCompactState, client, director
7704
7847
  }
7705
7848
  if (Date.now() - retryState.lastAttemptTime > 300000) {
7706
7849
  retryState.attempt = 0;
7707
- autoCompactState.fallbackStateBySession.delete(sessionID);
7708
7850
  autoCompactState.truncateStateBySession.delete(sessionID);
7709
7851
  }
7710
7852
  if (!skipSummarize && retryState.attempt < RETRY_CONFIG.maxAttempts) {
@@ -7750,57 +7892,7 @@ async function executeCompact(sessionID, msg, autoCompactState, client, director
7750
7892
  await client.tui.showToast({
7751
7893
  body: {
7752
7894
  title: "Summarize Skipped",
7753
- message: "Missing providerID or modelID. Skipping to revert...",
7754
- variant: "warning",
7755
- duration: 3000
7756
- }
7757
- }).catch(() => {});
7758
- }
7759
- }
7760
- const fallbackState = getOrCreateFallbackState(autoCompactState, sessionID);
7761
- if (fallbackState.revertAttempt < FALLBACK_CONFIG.maxRevertAttempts) {
7762
- const pair = await getLastMessagePair(sessionID, client, directory);
7763
- if (pair) {
7764
- try {
7765
- await client.tui.showToast({
7766
- body: {
7767
- title: "Emergency Recovery",
7768
- message: "Removing last message pair...",
7769
- variant: "warning",
7770
- duration: 3000
7771
- }
7772
- }).catch(() => {});
7773
- if (pair.assistantMessageID) {
7774
- await client.session.revert({
7775
- path: { id: sessionID },
7776
- body: { messageID: pair.assistantMessageID },
7777
- query: { directory }
7778
- });
7779
- }
7780
- await client.session.revert({
7781
- path: { id: sessionID },
7782
- body: { messageID: pair.userMessageID },
7783
- query: { directory }
7784
- });
7785
- fallbackState.revertAttempt++;
7786
- fallbackState.lastRevertedMessageID = pair.userMessageID;
7787
- clearSessionState(autoCompactState, sessionID);
7788
- setTimeout(async () => {
7789
- try {
7790
- await client.session.prompt_async({
7791
- path: { sessionID },
7792
- body: { parts: [{ type: "text", text: "Continue" }] },
7793
- query: { directory }
7794
- });
7795
- } catch {}
7796
- }, 500);
7797
- return;
7798
- } catch {}
7799
- } else {
7800
- await client.tui.showToast({
7801
- body: {
7802
- title: "Revert Skipped",
7803
- message: "Could not find last message pair to revert.",
7895
+ message: "Missing providerID or modelID.",
7804
7896
  variant: "warning",
7805
7897
  duration: 3000
7806
7898
  }
@@ -7827,7 +7919,6 @@ function createRecoveryState() {
7827
7919
  pendingCompact: new Set,
7828
7920
  errorDataBySession: new Map,
7829
7921
  retryStateBySession: new Map,
7830
- fallbackStateBySession: new Map,
7831
7922
  truncateStateBySession: new Map,
7832
7923
  dcpStateBySession: new Map,
7833
7924
  emptyContentAttemptBySession: new Map,
@@ -7846,7 +7937,6 @@ function createAnthropicContextWindowLimitRecoveryHook(ctx, options) {
7846
7937
  autoCompactState.pendingCompact.delete(sessionInfo.id);
7847
7938
  autoCompactState.errorDataBySession.delete(sessionInfo.id);
7848
7939
  autoCompactState.retryStateBySession.delete(sessionInfo.id);
7849
- autoCompactState.fallbackStateBySession.delete(sessionInfo.id);
7850
7940
  autoCompactState.truncateStateBySession.delete(sessionInfo.id);
7851
7941
  autoCompactState.dcpStateBySession.delete(sessionInfo.id);
7852
7942
  autoCompactState.emptyContentAttemptBySession.delete(sessionInfo.id);
@@ -7967,9 +8057,9 @@ function createPreemptiveCompactionHook(ctx, options) {
7967
8057
  const experimental = options?.experimental;
7968
8058
  const onBeforeSummarize = options?.onBeforeSummarize;
7969
8059
  const getModelLimit = options?.getModelLimit;
7970
- const enabled = experimental?.preemptive_compaction === true;
8060
+ const explicitlyDisabled = experimental?.preemptive_compaction === false;
7971
8061
  const threshold = experimental?.preemptive_compaction_threshold ?? DEFAULT_THRESHOLD;
7972
- if (!enabled) {
8062
+ if (explicitlyDisabled) {
7973
8063
  return { event: async () => {} };
7974
8064
  }
7975
8065
  const state2 = createState();
@@ -8711,7 +8801,7 @@ async function executePreToolUseHooks(ctx, config, extendedConfig) {
8711
8801
 
8712
8802
  // src/hooks/claude-code-hooks/transcript.ts
8713
8803
  import { join as join28 } from "path";
8714
- import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync23, writeFileSync as writeFileSync7, unlinkSync as unlinkSync5 } from "fs";
8804
+ import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync23, writeFileSync as writeFileSync8, unlinkSync as unlinkSync5 } from "fs";
8715
8805
  import { tmpdir as tmpdir5 } from "os";
8716
8806
  import { randomUUID } from "crypto";
8717
8807
  var TRANSCRIPT_DIR = join28(getClaudeConfigDir(), "transcripts");
@@ -8807,7 +8897,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
8807
8897
  };
8808
8898
  entries.push(JSON.stringify(currentEntry));
8809
8899
  const tempPath = join28(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
8810
- writeFileSync7(tempPath, entries.join(`
8900
+ writeFileSync8(tempPath, entries.join(`
8811
8901
  `) + `
8812
8902
  `);
8813
8903
  return tempPath;
@@ -8827,7 +8917,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
8827
8917
  }
8828
8918
  };
8829
8919
  const tempPath = join28(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
8830
- writeFileSync7(tempPath, JSON.stringify(currentEntry) + `
8920
+ writeFileSync8(tempPath, JSON.stringify(currentEntry) + `
8831
8921
  `);
8832
8922
  return tempPath;
8833
8923
  } catch {
@@ -9768,7 +9858,7 @@ import {
9768
9858
  existsSync as existsSync25,
9769
9859
  mkdirSync as mkdirSync7,
9770
9860
  readFileSync as readFileSync14,
9771
- writeFileSync as writeFileSync8,
9861
+ writeFileSync as writeFileSync9,
9772
9862
  unlinkSync as unlinkSync6
9773
9863
  } from "fs";
9774
9864
  import { join as join32 } from "path";
@@ -9800,7 +9890,7 @@ function saveInjectedRules(sessionID, data) {
9800
9890
  injectedRealPaths: [...data.realPaths],
9801
9891
  updatedAt: Date.now()
9802
9892
  };
9803
- writeFileSync8(getStoragePath3(sessionID), JSON.stringify(storageData, null, 2));
9893
+ writeFileSync9(getStoragePath3(sessionID), JSON.stringify(storageData, null, 2));
9804
9894
  }
9805
9895
  function clearInjectedRules(sessionID) {
9806
9896
  const filePath = getStoragePath3(sessionID);
@@ -9948,7 +10038,7 @@ function createBackgroundNotificationHook(manager) {
9948
10038
  };
9949
10039
  }
9950
10040
  // src/hooks/auto-update-checker/checker.ts
9951
- import * as fs5 from "fs";
10041
+ import * as fs6 from "fs";
9952
10042
  import * as path5 from "path";
9953
10043
  import { fileURLToPath } from "url";
9954
10044
 
@@ -9992,9 +10082,9 @@ function getConfigPaths(directory) {
9992
10082
  function getLocalDevPath(directory) {
9993
10083
  for (const configPath of getConfigPaths(directory)) {
9994
10084
  try {
9995
- if (!fs5.existsSync(configPath))
10085
+ if (!fs6.existsSync(configPath))
9996
10086
  continue;
9997
- const content = fs5.readFileSync(configPath, "utf-8");
10087
+ const content = fs6.readFileSync(configPath, "utf-8");
9998
10088
  const config = JSON.parse(stripJsonComments(content));
9999
10089
  const plugins = config.plugin ?? [];
10000
10090
  for (const entry of plugins) {
@@ -10014,13 +10104,13 @@ function getLocalDevPath(directory) {
10014
10104
  }
10015
10105
  function findPackageJsonUp(startPath) {
10016
10106
  try {
10017
- const stat = fs5.statSync(startPath);
10107
+ const stat = fs6.statSync(startPath);
10018
10108
  let dir = stat.isDirectory() ? startPath : path5.dirname(startPath);
10019
10109
  for (let i = 0;i < 10; i++) {
10020
10110
  const pkgPath = path5.join(dir, "package.json");
10021
- if (fs5.existsSync(pkgPath)) {
10111
+ if (fs6.existsSync(pkgPath)) {
10022
10112
  try {
10023
- const content = fs5.readFileSync(pkgPath, "utf-8");
10113
+ const content = fs6.readFileSync(pkgPath, "utf-8");
10024
10114
  const pkg = JSON.parse(content);
10025
10115
  if (pkg.name === PACKAGE_NAME)
10026
10116
  return pkgPath;
@@ -10042,7 +10132,7 @@ function getLocalDevVersion(directory) {
10042
10132
  const pkgPath = findPackageJsonUp(localPath);
10043
10133
  if (!pkgPath)
10044
10134
  return null;
10045
- const content = fs5.readFileSync(pkgPath, "utf-8");
10135
+ const content = fs6.readFileSync(pkgPath, "utf-8");
10046
10136
  const pkg = JSON.parse(content);
10047
10137
  return pkg.version ?? null;
10048
10138
  } catch {
@@ -10052,9 +10142,9 @@ function getLocalDevVersion(directory) {
10052
10142
  function findPluginEntry(directory) {
10053
10143
  for (const configPath of getConfigPaths(directory)) {
10054
10144
  try {
10055
- if (!fs5.existsSync(configPath))
10145
+ if (!fs6.existsSync(configPath))
10056
10146
  continue;
10057
- const content = fs5.readFileSync(configPath, "utf-8");
10147
+ const content = fs6.readFileSync(configPath, "utf-8");
10058
10148
  const config = JSON.parse(stripJsonComments(content));
10059
10149
  const plugins = config.plugin ?? [];
10060
10150
  for (const entry of plugins) {
@@ -10075,8 +10165,8 @@ function findPluginEntry(directory) {
10075
10165
  }
10076
10166
  function getCachedVersion() {
10077
10167
  try {
10078
- if (fs5.existsSync(INSTALLED_PACKAGE_JSON)) {
10079
- const content = fs5.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
10168
+ if (fs6.existsSync(INSTALLED_PACKAGE_JSON)) {
10169
+ const content = fs6.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
10080
10170
  const pkg = JSON.parse(content);
10081
10171
  if (pkg.version)
10082
10172
  return pkg.version;
@@ -10086,7 +10176,7 @@ function getCachedVersion() {
10086
10176
  const currentDir = path5.dirname(fileURLToPath(import.meta.url));
10087
10177
  const pkgPath = findPackageJsonUp(currentDir);
10088
10178
  if (pkgPath) {
10089
- const content = fs5.readFileSync(pkgPath, "utf-8");
10179
+ const content = fs6.readFileSync(pkgPath, "utf-8");
10090
10180
  const pkg = JSON.parse(content);
10091
10181
  if (pkg.version)
10092
10182
  return pkg.version;
@@ -10098,7 +10188,7 @@ function getCachedVersion() {
10098
10188
  }
10099
10189
  function updatePinnedVersion(configPath, oldEntry, newVersion) {
10100
10190
  try {
10101
- const content = fs5.readFileSync(configPath, "utf-8");
10191
+ const content = fs6.readFileSync(configPath, "utf-8");
10102
10192
  const newEntry = `${PACKAGE_NAME}@${newVersion}`;
10103
10193
  const pluginMatch = content.match(/"plugin"\s*:\s*\[/);
10104
10194
  if (!pluginMatch || pluginMatch.index === undefined) {
@@ -10130,7 +10220,7 @@ function updatePinnedVersion(configPath, oldEntry, newVersion) {
10130
10220
  log(`[auto-update-checker] No changes made to ${configPath}`);
10131
10221
  return false;
10132
10222
  }
10133
- fs5.writeFileSync(configPath, updatedContent, "utf-8");
10223
+ fs6.writeFileSync(configPath, updatedContent, "utf-8");
10134
10224
  log(`[auto-update-checker] Updated ${configPath}: ${oldEntry} \u2192 ${newEntry}`);
10135
10225
  return true;
10136
10226
  } catch (err) {
@@ -10158,17 +10248,17 @@ async function getLatestVersion() {
10158
10248
  }
10159
10249
 
10160
10250
  // src/hooks/auto-update-checker/cache.ts
10161
- import * as fs6 from "fs";
10251
+ import * as fs7 from "fs";
10162
10252
  import * as path6 from "path";
10163
10253
  function stripTrailingCommas(json) {
10164
10254
  return json.replace(/,(\s*[}\]])/g, "$1");
10165
10255
  }
10166
10256
  function removeFromBunLock(packageName) {
10167
10257
  const lockPath = path6.join(CACHE_DIR, "bun.lock");
10168
- if (!fs6.existsSync(lockPath))
10258
+ if (!fs7.existsSync(lockPath))
10169
10259
  return false;
10170
10260
  try {
10171
- const content = fs6.readFileSync(lockPath, "utf-8");
10261
+ const content = fs7.readFileSync(lockPath, "utf-8");
10172
10262
  const lock = JSON.parse(stripTrailingCommas(content));
10173
10263
  let modified = false;
10174
10264
  if (lock.workspaces?.[""]?.dependencies?.[packageName]) {
@@ -10180,7 +10270,7 @@ function removeFromBunLock(packageName) {
10180
10270
  modified = true;
10181
10271
  }
10182
10272
  if (modified) {
10183
- fs6.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
10273
+ fs7.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
10184
10274
  log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
10185
10275
  }
10186
10276
  return modified;
@@ -10195,17 +10285,17 @@ function invalidatePackage(packageName = PACKAGE_NAME) {
10195
10285
  let packageRemoved = false;
10196
10286
  let dependencyRemoved = false;
10197
10287
  let lockRemoved = false;
10198
- if (fs6.existsSync(pkgDir)) {
10199
- fs6.rmSync(pkgDir, { recursive: true, force: true });
10288
+ if (fs7.existsSync(pkgDir)) {
10289
+ fs7.rmSync(pkgDir, { recursive: true, force: true });
10200
10290
  log(`[auto-update-checker] Package removed: ${pkgDir}`);
10201
10291
  packageRemoved = true;
10202
10292
  }
10203
- if (fs6.existsSync(pkgJsonPath)) {
10204
- const content = fs6.readFileSync(pkgJsonPath, "utf-8");
10293
+ if (fs7.existsSync(pkgJsonPath)) {
10294
+ const content = fs7.readFileSync(pkgJsonPath, "utf-8");
10205
10295
  const pkgJson = JSON.parse(content);
10206
10296
  if (pkgJson.dependencies?.[packageName]) {
10207
10297
  delete pkgJson.dependencies[packageName];
10208
- fs6.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
10298
+ fs7.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
10209
10299
  log(`[auto-update-checker] Dependency removed from package.json: ${packageName}`);
10210
10300
  dependencyRemoved = true;
10211
10301
  }
@@ -10382,7 +10472,7 @@ import {
10382
10472
  existsSync as existsSync28,
10383
10473
  mkdirSync as mkdirSync8,
10384
10474
  readFileSync as readFileSync18,
10385
- writeFileSync as writeFileSync11,
10475
+ writeFileSync as writeFileSync12,
10386
10476
  unlinkSync as unlinkSync7
10387
10477
  } from "fs";
10388
10478
  import { join as join37 } from "path";
@@ -10453,7 +10543,7 @@ function saveAgentUsageState(state2) {
10453
10543
  mkdirSync8(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
10454
10544
  }
10455
10545
  const filePath = getStoragePath4(state2.sessionID);
10456
- writeFileSync11(filePath, JSON.stringify(state2, null, 2));
10546
+ writeFileSync12(filePath, JSON.stringify(state2, null, 2));
10457
10547
  }
10458
10548
  function clearAgentUsageState(sessionID) {
10459
10549
  const filePath = getStoragePath4(sessionID);
@@ -10766,7 +10856,7 @@ import {
10766
10856
  existsSync as existsSync29,
10767
10857
  mkdirSync as mkdirSync9,
10768
10858
  readFileSync as readFileSync19,
10769
- writeFileSync as writeFileSync12,
10859
+ writeFileSync as writeFileSync13,
10770
10860
  unlinkSync as unlinkSync8
10771
10861
  } from "fs";
10772
10862
  import { join as join39 } from "path";
@@ -10814,7 +10904,7 @@ function saveInteractiveBashSessionState(state2) {
10814
10904
  tmuxSessions: Array.from(state2.tmuxSessions),
10815
10905
  updatedAt: state2.updatedAt
10816
10906
  };
10817
- writeFileSync12(filePath, JSON.stringify(serialized, null, 2));
10907
+ writeFileSync13(filePath, JSON.stringify(serialized, null, 2));
10818
10908
  }
10819
10909
  function clearInteractiveBashSessionState(sessionID) {
10820
10910
  const filePath = getStoragePath5(sessionID);
@@ -11152,7 +11242,7 @@ function createThinkingBlockValidatorHook() {
11152
11242
  import { existsSync as existsSync31, readFileSync as readFileSync21 } from "fs";
11153
11243
 
11154
11244
  // src/hooks/ralph-loop/storage.ts
11155
- import { existsSync as existsSync30, readFileSync as readFileSync20, writeFileSync as writeFileSync13, unlinkSync as unlinkSync9, mkdirSync as mkdirSync10 } from "fs";
11245
+ import { existsSync as existsSync30, readFileSync as readFileSync20, writeFileSync as writeFileSync14, unlinkSync as unlinkSync9, mkdirSync as mkdirSync10 } from "fs";
11156
11246
  import { dirname as dirname6, join as join40 } from "path";
11157
11247
 
11158
11248
  // src/hooks/ralph-loop/constants.ts
@@ -11218,7 +11308,7 @@ started_at: "${state2.started_at}"
11218
11308
  ${sessionIdLine}---
11219
11309
  ${state2.prompt}
11220
11310
  `;
11221
- writeFileSync13(filePath, content, "utf-8");
11311
+ writeFileSync14(filePath, content, "utf-8");
11222
11312
  return true;
11223
11313
  } catch {
11224
11314
  return false;
@@ -11263,6 +11353,7 @@ function createRalphLoopHook(ctx, options) {
11263
11353
  const sessions = new Map;
11264
11354
  const config = options?.config;
11265
11355
  const stateDir = config?.state_dir;
11356
+ const getTranscriptPath2 = options?.getTranscriptPath ?? getTranscriptPath;
11266
11357
  function getSessionState(sessionID) {
11267
11358
  let state2 = sessions.get(sessionID);
11268
11359
  if (!state2) {
@@ -11341,7 +11432,7 @@ function createRalphLoopHook(ctx, options) {
11341
11432
  if (state2.session_id && state2.session_id !== sessionID) {
11342
11433
  return;
11343
11434
  }
11344
- const transcriptPath = props?.transcriptPath;
11435
+ const transcriptPath = getTranscriptPath2(sessionID);
11345
11436
  if (detectCompletionPromise(transcriptPath, state2.completion_promise)) {
11346
11437
  log(`[${HOOK_NAME3}] Completion detected!`, {
11347
11438
  sessionID,
@@ -13318,7 +13409,8 @@ $ARGUMENTS
13318
13409
  function commandsToRecord(commands) {
13319
13410
  const result = {};
13320
13411
  for (const cmd of commands) {
13321
- result[cmd.name] = cmd.definition;
13412
+ const { name: _name, argumentHint: _argumentHint, ...openCodeCompatible } = cmd.definition;
13413
+ result[cmd.name] = openCodeCompatible;
13322
13414
  }
13323
13415
  return result;
13324
13416
  }
@@ -13344,208 +13436,194 @@ function loadOpencodeProjectCommands() {
13344
13436
  return commandsToRecord(commands);
13345
13437
  }
13346
13438
  // src/features/builtin-commands/templates/init-deep.ts
13347
- var INIT_DEEP_TEMPLATE = `# Initialize Deep Knowledge Base
13439
+ var INIT_DEEP_TEMPLATE = `# /init-deep
13348
13440
 
13349
- Generate comprehensive AGENTS.md files across project hierarchy. Combines root-level project knowledge (gen-knowledge) with complexity-based subdirectory documentation (gen-knowledge-deep).
13441
+ Generate hierarchical AGENTS.md files. Root + complexity-scored subdirectories.
13350
13442
 
13351
13443
  ## Usage
13352
13444
 
13353
13445
  \`\`\`
13354
- /init-deep # Analyze and generate hierarchical AGENTS.md
13355
- /init-deep --create-new # Force create from scratch (ignore existing)
13356
- /init-deep --max-depth=2 # Limit to N directory levels (default: 3)
13446
+ /init-deep # Update mode: modify existing + create new where warranted
13447
+ /init-deep --create-new # Read existing \u2192 remove all \u2192 regenerate from scratch
13448
+ /init-deep --max-depth=2 # Limit directory depth (default: 3)
13357
13449
  \`\`\`
13358
13450
 
13359
13451
  ---
13360
13452
 
13361
- ## Core Principles
13453
+ ## Workflow (High-Level)
13362
13454
 
13363
- - **Telegraphic Style**: Sacrifice grammar for concision ("Project uses React" \u2192 "React 18")
13364
- - **Predict-then-Compare**: Predict standard \u2192 find actual \u2192 document ONLY deviations
13365
- - **Hierarchy Aware**: Parent covers general, children cover specific
13366
- - **No Redundancy**: Child AGENTS.md NEVER repeats parent content
13367
- - **LSP-First**: Use LSP tools for accurate code intelligence when available (semantic > text search)
13368
-
13369
- ---
13370
-
13371
- ## Process
13455
+ 1. **Discovery + Analysis** (concurrent)
13456
+ - Fire background explore agents immediately
13457
+ - Main session: bash structure + LSP codemap + read existing AGENTS.md
13458
+ 2. **Score & Decide** - Determine AGENTS.md locations from merged findings
13459
+ 3. **Generate** - Root first, then subdirs in parallel
13460
+ 4. **Review** - Deduplicate, trim, validate
13372
13461
 
13373
13462
  <critical>
13374
- **MANDATORY: TodoWrite for ALL phases. Mark in_progress \u2192 completed in real-time.**
13375
- </critical>
13376
-
13377
- ### Phase 0: Initialize
13378
-
13463
+ **TodoWrite ALL phases. Mark in_progress \u2192 completed in real-time.**
13379
13464
  \`\`\`
13380
13465
  TodoWrite([
13381
- { id: "p1-analysis", content: "Parallel project structure & complexity analysis", status: "pending", priority: "high" },
13382
- { id: "p2-scoring", content: "Score directories, determine AGENTS.md locations", status: "pending", priority: "high" },
13383
- { id: "p3-root", content: "Generate root AGENTS.md with Predict-then-Compare", status: "pending", priority: "high" },
13384
- { id: "p4-subdirs", content: "Generate subdirectory AGENTS.md files in parallel", status: "pending", priority: "high" },
13385
- { id: "p5-review", content: "Review, deduplicate, validate all files", status: "pending", priority: "medium" }
13466
+ { id: "discovery", content: "Fire explore agents + LSP codemap + read existing", status: "pending", priority: "high" },
13467
+ { id: "scoring", content: "Score directories, determine locations", status: "pending", priority: "high" },
13468
+ { id: "generate", content: "Generate AGENTS.md files (root + subdirs)", status: "pending", priority: "high" },
13469
+ { id: "review", content: "Deduplicate, validate, trim", status: "pending", priority: "medium" }
13386
13470
  ])
13387
13471
  \`\`\`
13472
+ </critical>
13388
13473
 
13389
13474
  ---
13390
13475
 
13391
- ## Phase 1: Parallel Project Analysis
13476
+ ## Phase 1: Discovery + Analysis (Concurrent)
13392
13477
 
13393
- **Mark "p1-analysis" as in_progress.**
13478
+ **Mark "discovery" as in_progress.**
13394
13479
 
13395
- Launch **ALL tasks simultaneously**:
13480
+ ### Fire Background Explore Agents IMMEDIATELY
13396
13481
 
13397
- <parallel-tasks>
13482
+ Don't wait\u2014these run async while main session works.
13398
13483
 
13399
- ### Structural Analysis (bash - run in parallel)
13400
- \`\`\`bash
13401
- # Task A: Directory depth analysis
13402
- find . -type d -not -path '*/\\.*' -not -path '*/node_modules/*' -not -path '*/venv/*' -not -path '*/__pycache__/*' -not -path '*/dist/*' -not -path '*/build/*' | awk -F/ '{print NF-1}' | sort -n | uniq -c
13484
+ \`\`\`
13485
+ // Fire all at once, collect results later
13486
+ background_task(agent="explore", prompt="Project structure: PREDICT standard patterns for detected language \u2192 REPORT deviations only")
13487
+ background_task(agent="explore", prompt="Entry points: FIND main files \u2192 REPORT non-standard organization")
13488
+ background_task(agent="explore", prompt="Conventions: FIND config files (.eslintrc, pyproject.toml, .editorconfig) \u2192 REPORT project-specific rules")
13489
+ background_task(agent="explore", prompt="Anti-patterns: FIND 'DO NOT', 'NEVER', 'ALWAYS', 'DEPRECATED' comments \u2192 LIST forbidden patterns")
13490
+ background_task(agent="explore", prompt="Build/CI: FIND .github/workflows, Makefile \u2192 REPORT non-standard patterns")
13491
+ background_task(agent="explore", prompt="Test patterns: FIND test configs, test structure \u2192 REPORT unique conventions")
13492
+ \`\`\`
13403
13493
 
13404
- # Task B: File count per directory
13405
- find . -type f -not -path '*/\\.*' -not -path '*/node_modules/*' -not -path '*/venv/*' -not -path '*/__pycache__/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -30
13494
+ <dynamic-agents>
13495
+ **DYNAMIC AGENT SPAWNING**: After bash analysis, spawn ADDITIONAL explore agents based on project scale:
13406
13496
 
13407
- # Task C: Code concentration
13408
- find . -type f \\( -name "*.py" -o -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.go" -o -name "*.rs" -o -name "*.java" \\) -not -path '*/node_modules/*' -not -path '*/venv/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -20
13497
+ | Factor | Threshold | Additional Agents |
13498
+ |--------|-----------|-------------------|
13499
+ | **Total files** | >100 | +1 per 100 files |
13500
+ | **Total lines** | >10k | +1 per 10k lines |
13501
+ | **Directory depth** | \u22654 | +2 for deep exploration |
13502
+ | **Large files (>500 lines)** | >10 files | +1 for complexity hotspots |
13503
+ | **Monorepo** | detected | +1 per package/workspace |
13504
+ | **Multiple languages** | >1 | +1 per language |
13409
13505
 
13410
- # Task D: Existing knowledge files
13411
- find . -type f \\( -name "AGENTS.md" -o -name "CLAUDE.md" \\) -not -path '*/node_modules/*' 2>/dev/null
13506
+ \`\`\`bash
13507
+ # Measure project scale first
13508
+ total_files=$(find . -type f -not -path '*/node_modules/*' -not -path '*/.git/*' | wc -l)
13509
+ total_lines=$(find . -type f \\( -name "*.ts" -o -name "*.py" -o -name "*.go" \\) -not -path '*/node_modules/*' -exec wc -l {} + 2>/dev/null | tail -1 | awk '{print $1}')
13510
+ large_files=$(find . -type f \\( -name "*.ts" -o -name "*.py" \\) -not -path '*/node_modules/*' -exec wc -l {} + 2>/dev/null | awk '$1 > 500 {count++} END {print count+0}')
13511
+ max_depth=$(find . -type d -not -path '*/node_modules/*' -not -path '*/.git/*' | awk -F/ '{print NF}' | sort -rn | head -1)
13412
13512
  \`\`\`
13413
13513
 
13414
- ### Context Gathering (Explore agents - background_task in parallel)
13415
-
13514
+ Example spawning:
13416
13515
  \`\`\`
13417
- background_task(agent="explore", prompt="Project structure: PREDICT standard {lang} patterns \u2192 FIND package.json/pyproject.toml/go.mod \u2192 REPORT deviations only")
13418
-
13419
- background_task(agent="explore", prompt="Entry points: PREDICT typical (main.py, index.ts) \u2192 FIND actual \u2192 REPORT non-standard organization")
13516
+ // 500 files, 50k lines, depth 6, 15 large files \u2192 spawn 5+5+2+1 = 13 additional agents
13517
+ background_task(agent="explore", prompt="Large file analysis: FIND files >500 lines, REPORT complexity hotspots")
13518
+ background_task(agent="explore", prompt="Deep modules at depth 4+: FIND hidden patterns, internal conventions")
13519
+ background_task(agent="explore", prompt="Cross-cutting concerns: FIND shared utilities across directories")
13520
+ // ... more based on calculation
13521
+ \`\`\`
13522
+ </dynamic-agents>
13420
13523
 
13421
- background_task(agent="explore", prompt="Conventions: FIND .cursor/rules, .cursorrules, eslintrc, pyproject.toml \u2192 REPORT project-specific rules DIFFERENT from defaults")
13524
+ ### Main Session: Concurrent Analysis
13422
13525
 
13423
- background_task(agent="explore", prompt="Anti-patterns: FIND comments with 'DO NOT', 'NEVER', 'ALWAYS', 'LEGACY', 'DEPRECATED' \u2192 REPORT forbidden patterns")
13526
+ **While background agents run**, main session does:
13424
13527
 
13425
- background_task(agent="explore", prompt="Build/CI: FIND .github/workflows, Makefile, justfile \u2192 REPORT non-standard build/deploy patterns")
13528
+ #### 1. Bash Structural Analysis
13529
+ \`\`\`bash
13530
+ # Directory depth + file counts
13531
+ find . -type d -not -path '*/\\.*' -not -path '*/node_modules/*' -not -path '*/venv/*' -not -path '*/dist/*' -not -path '*/build/*' | awk -F/ '{print NF-1}' | sort -n | uniq -c
13426
13532
 
13427
- background_task(agent="explore", prompt="Test patterns: FIND pytest.ini, jest.config, test structure \u2192 REPORT unique testing conventions")
13428
- \`\`\`
13533
+ # Files per directory (top 30)
13534
+ find . -type f -not -path '*/\\.*' -not -path '*/node_modules/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -30
13429
13535
 
13430
- ### Code Intelligence Analysis (LSP tools - run in parallel)
13536
+ # Code concentration by extension
13537
+ find . -type f \\( -name "*.py" -o -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.go" -o -name "*.rs" \\) -not -path '*/node_modules/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -20
13431
13538
 
13432
- LSP provides semantic understanding beyond text search. Use for accurate code mapping.
13539
+ # Existing AGENTS.md / CLAUDE.md
13540
+ find . -type f \\( -name "AGENTS.md" -o -name "CLAUDE.md" \\) -not -path '*/node_modules/*' 2>/dev/null
13541
+ \`\`\`
13433
13542
 
13543
+ #### 2. Read Existing AGENTS.md
13434
13544
  \`\`\`
13435
- # Step 1: Check LSP availability
13436
- lsp_servers() # Verify language server is available
13437
-
13438
- # Step 2: Analyze entry point files (run in parallel)
13439
- # Find entry points first, then analyze each with lsp_document_symbols
13440
- lsp_document_symbols(filePath="src/index.ts") # Main entry
13441
- lsp_document_symbols(filePath="src/main.py") # Python entry
13442
- lsp_document_symbols(filePath="cmd/main.go") # Go entry
13443
-
13444
- # Step 3: Discover key symbols across workspace (run in parallel)
13445
- lsp_workspace_symbols(filePath=".", query="class") # All classes
13446
- lsp_workspace_symbols(filePath=".", query="interface") # All interfaces
13447
- lsp_workspace_symbols(filePath=".", query="function") # Top-level functions
13448
- lsp_workspace_symbols(filePath=".", query="type") # Type definitions
13449
-
13450
- # Step 4: Analyze symbol centrality (for top 5-10 key symbols)
13451
- # High reference count = central/important concept
13452
- lsp_find_references(filePath="src/index.ts", line=X, character=Y) # Main export
13545
+ For each existing file found:
13546
+ Read(filePath=file)
13547
+ Extract: key insights, conventions, anti-patterns
13548
+ Store in EXISTING_AGENTS map
13453
13549
  \`\`\`
13454
13550
 
13455
- #### LSP Analysis Output Format
13551
+ If \`--create-new\`: Read all existing first (preserve context) \u2192 then delete all \u2192 regenerate.
13456
13552
 
13553
+ #### 3. LSP Codemap (if available)
13457
13554
  \`\`\`
13458
- CODE_INTELLIGENCE = {
13459
- entry_points: [
13460
- { file: "src/index.ts", exports: ["Plugin", "createHook"], symbol_count: 12 }
13461
- ],
13462
- key_symbols: [
13463
- { name: "Plugin", type: "class", file: "src/index.ts", refs: 45, role: "Central orchestrator" },
13464
- { name: "createHook", type: "function", file: "src/utils.ts", refs: 23, role: "Hook factory" }
13465
- ],
13466
- module_boundaries: [
13467
- { dir: "src/hooks", exports: 21, imports_from: ["shared/"] },
13468
- { dir: "src/tools", exports: 15, imports_from: ["shared/", "hooks/"] }
13469
- ]
13470
- }
13555
+ lsp_servers() # Check availability
13556
+
13557
+ # Entry points (parallel)
13558
+ lsp_document_symbols(filePath="src/index.ts")
13559
+ lsp_document_symbols(filePath="main.py")
13560
+
13561
+ # Key symbols (parallel)
13562
+ lsp_workspace_symbols(filePath=".", query="class")
13563
+ lsp_workspace_symbols(filePath=".", query="interface")
13564
+ lsp_workspace_symbols(filePath=".", query="function")
13565
+
13566
+ # Centrality for top exports
13567
+ lsp_find_references(filePath="...", line=X, character=Y)
13471
13568
  \`\`\`
13472
13569
 
13473
- <critical>
13474
- **LSP Fallback**: If LSP unavailable (no server installed), skip this section and rely on explore agents + AST-grep patterns.
13475
- </critical>
13570
+ **LSP Fallback**: If unavailable, rely on explore agents + AST-grep.
13571
+
13572
+ ### Collect Background Results
13476
13573
 
13477
- </parallel-tasks>
13574
+ \`\`\`
13575
+ // After main session analysis done, collect all task results
13576
+ for each task_id: background_output(task_id="...")
13577
+ \`\`\`
13478
13578
 
13479
- **Collect all results. Mark "p1-analysis" as completed.**
13579
+ **Merge: bash + LSP + existing + explore findings. Mark "discovery" as completed.**
13480
13580
 
13481
13581
  ---
13482
13582
 
13483
- ## Phase 2: Complexity Scoring & Location Decision
13583
+ ## Phase 2: Scoring & Location Decision
13484
13584
 
13485
- **Mark "p2-scoring" as in_progress.**
13585
+ **Mark "scoring" as in_progress.**
13486
13586
 
13487
13587
  ### Scoring Matrix
13488
13588
 
13489
- | Factor | Weight | Threshold | Source |
13490
- |--------|--------|-----------|--------|
13491
- | File count | 3x | >20 files = high | bash |
13492
- | Subdirectory count | 2x | >5 subdirs = high | bash |
13493
- | Code file ratio | 2x | >70% code = high | bash |
13589
+ | Factor | Weight | High Threshold | Source |
13590
+ |--------|--------|----------------|--------|
13591
+ | File count | 3x | >20 | bash |
13592
+ | Subdir count | 2x | >5 | bash |
13593
+ | Code ratio | 2x | >70% | bash |
13494
13594
  | Unique patterns | 1x | Has own config | explore |
13495
- | Module boundary | 2x | Has __init__.py/index.ts | bash |
13496
- | **Symbol density** | 2x | >30 symbols = high | LSP |
13497
- | **Export count** | 2x | >10 exports = high | LSP |
13498
- | **Reference centrality** | 3x | Symbols with >20 refs | LSP |
13499
-
13500
- <lsp-scoring>
13501
- **LSP-Enhanced Scoring** (if available):
13502
-
13503
- \`\`\`
13504
- For each directory in candidates:
13505
- symbols = lsp_document_symbols(dir/index.ts or dir/__init__.py)
13506
-
13507
- symbol_score = len(symbols) > 30 ? 6 : len(symbols) > 15 ? 3 : 0
13508
- export_score = count(exported symbols) > 10 ? 4 : 0
13509
-
13510
- # Check if this module is central (many things depend on it)
13511
- for each exported symbol:
13512
- refs = lsp_find_references(symbol)
13513
- if refs > 20: centrality_score += 3
13514
-
13515
- total_score += symbol_score + export_score + centrality_score
13516
- \`\`\`
13517
- </lsp-scoring>
13595
+ | Module boundary | 2x | Has index.ts/__init__.py | bash |
13596
+ | Symbol density | 2x | >30 symbols | LSP |
13597
+ | Export count | 2x | >10 exports | LSP |
13598
+ | Reference centrality | 3x | >20 refs | LSP |
13518
13599
 
13519
13600
  ### Decision Rules
13520
13601
 
13521
13602
  | Score | Action |
13522
13603
  |-------|--------|
13523
- | **Root (.)** | ALWAYS create AGENTS.md |
13524
- | **High (>15)** | Create dedicated AGENTS.md |
13525
- | **Medium (8-15)** | Create if distinct domain |
13526
- | **Low (<8)** | Skip, parent sufficient |
13527
-
13528
- ### Output Format
13604
+ | **Root (.)** | ALWAYS create |
13605
+ | **>15** | Create AGENTS.md |
13606
+ | **8-15** | Create if distinct domain |
13607
+ | **<8** | Skip (parent covers) |
13529
13608
 
13609
+ ### Output
13530
13610
  \`\`\`
13531
13611
  AGENTS_LOCATIONS = [
13532
13612
  { path: ".", type: "root" },
13533
- { path: "src/api", score: 18, reason: "high complexity, 45 files" },
13534
- { path: "src/hooks", score: 12, reason: "distinct domain, unique patterns" },
13613
+ { path: "src/hooks", score: 18, reason: "high complexity" },
13614
+ { path: "src/api", score: 12, reason: "distinct domain" }
13535
13615
  ]
13536
13616
  \`\`\`
13537
13617
 
13538
- **Mark "p2-scoring" as completed.**
13618
+ **Mark "scoring" as completed.**
13539
13619
 
13540
13620
  ---
13541
13621
 
13542
- ## Phase 3: Generate Root AGENTS.md
13543
-
13544
- **Mark "p3-root" as in_progress.**
13622
+ ## Phase 3: Generate AGENTS.md
13545
13623
 
13546
- Root AGENTS.md gets **full treatment** with Predict-then-Compare synthesis.
13624
+ **Mark "generate" as in_progress.**
13547
13625
 
13548
- ### Required Sections
13626
+ ### Root AGENTS.md (Full Treatment)
13549
13627
 
13550
13628
  \`\`\`markdown
13551
13629
  # PROJECT KNOWLEDGE BASE
@@ -13555,153 +13633,75 @@ Root AGENTS.md gets **full treatment** with Predict-then-Compare synthesis.
13555
13633
  **Branch:** {BRANCH}
13556
13634
 
13557
13635
  ## OVERVIEW
13558
-
13559
- {1-2 sentences: what project does, core tech stack}
13636
+ {1-2 sentences: what + core stack}
13560
13637
 
13561
13638
  ## STRUCTURE
13562
-
13563
13639
  \\\`\\\`\\\`
13564
- {project-root}/
13565
- \u251C\u2500\u2500 {dir}/ # {non-obvious purpose only}
13566
- \u2514\u2500\u2500 {entry} # entry point
13640
+ {root}/
13641
+ \u251C\u2500\u2500 {dir}/ # {non-obvious purpose only}
13642
+ \u2514\u2500\u2500 {entry}
13567
13643
  \\\`\\\`\\\`
13568
13644
 
13569
13645
  ## WHERE TO LOOK
13570
-
13571
13646
  | Task | Location | Notes |
13572
13647
  |------|----------|-------|
13573
- | Add feature X | \\\`src/x/\\\` | {pattern hint} |
13574
13648
 
13575
13649
  ## CODE MAP
13576
-
13577
- {Generated from LSP analysis - shows key symbols and their relationships}
13650
+ {From LSP - skip if unavailable or project <10 files}
13578
13651
 
13579
13652
  | Symbol | Type | Location | Refs | Role |
13580
13653
  |--------|------|----------|------|------|
13581
- | {MainClass} | Class | \\\`src/index.ts\\\` | {N} | {Central orchestrator} |
13582
- | {createX} | Function | \\\`src/utils.ts\\\` | {N} | {Factory pattern} |
13583
- | {Config} | Interface | \\\`src/types.ts\\\` | {N} | {Configuration contract} |
13584
-
13585
- ### Module Dependencies
13586
-
13587
- \\\`\\\`\\\`
13588
- {entry} \u2500\u2500imports\u2500\u2500> {core/}
13589
- \u2502 \u2502
13590
- \u2514\u2500\u2500imports\u2500\u2500> {utils/} <\u2500\u2500imports\u2500\u2500 {features/}
13591
- \\\`\\\`\\\`
13592
-
13593
- <code-map-note>
13594
- **Skip CODE MAP if**: LSP unavailable OR project too small (<10 files) OR no clear module boundaries.
13595
- </code-map-note>
13596
13654
 
13597
13655
  ## CONVENTIONS
13598
-
13599
- {ONLY deviations from standard - skip generic advice}
13600
-
13601
- - **{rule}**: {specific detail}
13656
+ {ONLY deviations from standard}
13602
13657
 
13603
13658
  ## ANTI-PATTERNS (THIS PROJECT)
13604
-
13605
- {Things explicitly forbidden HERE}
13606
-
13607
- - **{pattern}**: {why} \u2192 {alternative}
13659
+ {Explicitly forbidden here}
13608
13660
 
13609
13661
  ## UNIQUE STYLES
13610
-
13611
- {Project-specific coding styles}
13612
-
13613
- - **{style}**: {how different}
13662
+ {Project-specific}
13614
13663
 
13615
13664
  ## COMMANDS
13616
-
13617
13665
  \\\`\\\`\\\`bash
13618
- {dev-command}
13619
- {test-command}
13620
- {build-command}
13666
+ {dev/test/build}
13621
13667
  \\\`\\\`\\\`
13622
13668
 
13623
13669
  ## NOTES
13624
-
13625
- {Gotchas, non-obvious info}
13670
+ {Gotchas}
13626
13671
  \`\`\`
13627
13672
 
13628
- ### Quality Gates
13629
-
13630
- - [ ] Size: 50-150 lines
13631
- - [ ] No generic advice ("write clean code")
13632
- - [ ] No obvious info ("tests/ has tests")
13633
- - [ ] Every item is project-specific
13634
-
13635
- **Mark "p3-root" as completed.**
13636
-
13637
- ---
13638
-
13639
- ## Phase 4: Generate Subdirectory AGENTS.md
13673
+ **Quality gates**: 50-150 lines, no generic advice, no obvious info.
13640
13674
 
13641
- **Mark "p4-subdirs" as in_progress.**
13675
+ ### Subdirectory AGENTS.md (Parallel)
13642
13676
 
13643
- For each location in AGENTS_LOCATIONS (except root), launch **parallel document-writer agents**:
13677
+ Launch document-writer agents for each location:
13644
13678
 
13645
- \`\`\`typescript
13646
- for (const loc of AGENTS_LOCATIONS.filter(l => l.path !== ".")) {
13647
- background_task({
13648
- agent: "document-writer",
13649
- prompt: \\\`
13650
- Generate AGENTS.md for: \${loc.path}
13651
-
13652
- CONTEXT:
13653
- - Complexity reason: \${loc.reason}
13654
- - Parent AGENTS.md: ./AGENTS.md (already covers project overview)
13655
-
13656
- CRITICAL RULES:
13657
- 1. Focus ONLY on this directory's specific context
13658
- 2. NEVER repeat parent AGENTS.md content
13659
- 3. Shorter is better - 30-80 lines max
13660
- 4. Telegraphic style - sacrifice grammar
13661
-
13662
- REQUIRED SECTIONS:
13663
- - OVERVIEW (1 line: what this directory does)
13664
- - STRUCTURE (only if >5 subdirs)
13665
- - WHERE TO LOOK (directory-specific tasks)
13666
- - CONVENTIONS (only if DIFFERENT from root)
13667
- - ANTI-PATTERNS (directory-specific only)
13668
-
13669
- OUTPUT: Write to \${loc.path}/AGENTS.md
13670
- \\\`
13671
- })
13672
- }
13679
+ \`\`\`
13680
+ for loc in AGENTS_LOCATIONS (except root):
13681
+ background_task(agent="document-writer", prompt=\\\`
13682
+ Generate AGENTS.md for: \${loc.path}
13683
+ - Reason: \${loc.reason}
13684
+ - 30-80 lines max
13685
+ - NEVER repeat parent content
13686
+ - Sections: OVERVIEW (1 line), STRUCTURE (if >5 subdirs), WHERE TO LOOK, CONVENTIONS (if different), ANTI-PATTERNS
13687
+ \\\`)
13673
13688
  \`\`\`
13674
13689
 
13675
- **Wait for all agents. Mark "p4-subdirs" as completed.**
13690
+ **Wait for all. Mark "generate" as completed.**
13676
13691
 
13677
13692
  ---
13678
13693
 
13679
- ## Phase 5: Review & Deduplicate
13680
-
13681
- **Mark "p5-review" as in_progress.**
13682
-
13683
- ### Validation Checklist
13694
+ ## Phase 4: Review & Deduplicate
13684
13695
 
13685
- For EACH generated AGENTS.md:
13696
+ **Mark "review" as in_progress.**
13686
13697
 
13687
- | Check | Action if Fail |
13688
- |-------|----------------|
13689
- | Contains generic advice | REMOVE the line |
13690
- | Repeats parent content | REMOVE the line |
13691
- | Missing required section | ADD it |
13692
- | Over 150 lines (root) / 80 lines (subdir) | TRIM |
13693
- | Verbose explanations | REWRITE telegraphic |
13694
-
13695
- ### Cross-Reference Validation
13696
-
13697
- \`\`\`
13698
- For each child AGENTS.md:
13699
- For each line in child:
13700
- If similar line exists in parent:
13701
- REMOVE from child (parent already covers)
13702
- \`\`\`
13698
+ For each generated file:
13699
+ - Remove generic advice
13700
+ - Remove parent duplicates
13701
+ - Trim to size limits
13702
+ - Verify telegraphic style
13703
13703
 
13704
- **Mark "p5-review" as completed.**
13704
+ **Mark "review" as completed.**
13705
13705
 
13706
13706
  ---
13707
13707
 
@@ -13710,34 +13710,32 @@ For each child AGENTS.md:
13710
13710
  \`\`\`
13711
13711
  === init-deep Complete ===
13712
13712
 
13713
- Files Generated:
13713
+ Mode: {update | create-new}
13714
+
13715
+ Files:
13714
13716
  \u2713 ./AGENTS.md (root, {N} lines)
13715
13717
  \u2713 ./src/hooks/AGENTS.md ({N} lines)
13716
- \u2713 ./src/tools/AGENTS.md ({N} lines)
13717
13718
 
13718
- Directories Analyzed: {N}
13719
+ Dirs Analyzed: {N}
13719
13720
  AGENTS.md Created: {N}
13720
- Total Lines: {N}
13721
+ AGENTS.md Updated: {N}
13721
13722
 
13722
13723
  Hierarchy:
13723
13724
  ./AGENTS.md
13724
- \u251C\u2500\u2500 src/hooks/AGENTS.md
13725
- \u2514\u2500\u2500 src/tools/AGENTS.md
13725
+ \u2514\u2500\u2500 src/hooks/AGENTS.md
13726
13726
  \`\`\`
13727
13727
 
13728
13728
  ---
13729
13729
 
13730
- ## Anti-Patterns for THIS Command
13730
+ ## Anti-Patterns
13731
13731
 
13732
- - **Over-documenting**: Not every directory needs AGENTS.md
13733
- - **Redundancy**: Child must NOT repeat parent
13732
+ - **Static agent count**: MUST vary agents based on project size/depth
13733
+ - **Sequential execution**: MUST parallel (explore + LSP concurrent)
13734
+ - **Ignoring existing**: ALWAYS read existing first, even with --create-new
13735
+ - **Over-documenting**: Not every dir needs AGENTS.md
13736
+ - **Redundancy**: Child never repeats parent
13734
13737
  - **Generic content**: Remove anything that applies to ALL projects
13735
- - **Sequential execution**: MUST use parallel agents
13736
- - **Deep nesting**: Rarely need AGENTS.md at depth 4+
13737
- - **Verbose style**: "This directory contains..." \u2192 just list it
13738
- - **Ignoring LSP**: If LSP available, USE IT - semantic analysis > text grep
13739
- - **LSP without fallback**: Always have explore agent backup if LSP unavailable
13740
- - **Over-referencing**: Don't trace refs for EVERY symbol - focus on exports only`;
13738
+ - **Verbose style**: Telegraphic or die`;
13741
13739
 
13742
13740
  // src/features/builtin-commands/templates/ralph-loop.ts
13743
13741
  var RALPH_LOOP_TEMPLATE = `You are starting a Ralph Loop - a self-referential development loop that runs until task completion.
@@ -13814,10 +13812,8 @@ function loadBuiltinCommands(disabledCommands) {
13814
13812
  const commands = {};
13815
13813
  for (const [name, definition] of Object.entries(BUILTIN_COMMAND_DEFINITIONS)) {
13816
13814
  if (!disabled.has(name)) {
13817
- commands[name] = {
13818
- name,
13819
- ...definition
13820
- };
13815
+ const { argumentHint: _argumentHint, ...openCodeCompatible } = definition;
13816
+ commands[name] = openCodeCompatible;
13821
13817
  }
13822
13818
  }
13823
13819
  return commands;
@@ -13914,7 +13910,8 @@ function loadSkillsFromDir(skillsDir, scope) {
13914
13910
  function skillsToRecord(skills) {
13915
13911
  const result = {};
13916
13912
  for (const skill of skills) {
13917
- result[skill.name] = skill.definition;
13913
+ const { name: _name, argumentHint: _argumentHint, ...openCodeCompatible } = skill.definition;
13914
+ result[skill.name] = openCodeCompatible;
13918
13915
  }
13919
13916
  return result;
13920
13917
  }
@@ -14557,7 +14554,7 @@ ${body.trim()}
14557
14554
  $ARGUMENTS
14558
14555
  </user-request>`;
14559
14556
  const formattedDescription = `(plugin: ${plugin2.name}) ${data.description || ""}`;
14560
- commands2[namespacedName] = {
14557
+ const definition = {
14561
14558
  name: namespacedName,
14562
14559
  description: formattedDescription,
14563
14560
  template: wrappedTemplate,
@@ -14566,6 +14563,8 @@ $ARGUMENTS
14566
14563
  subtask: data.subtask,
14567
14564
  argumentHint: data["argument-hint"]
14568
14565
  };
14566
+ const { name: _name, argumentHint: _argumentHint, ...openCodeCompatible } = definition;
14567
+ commands2[namespacedName] = openCodeCompatible;
14569
14568
  log(`Loaded plugin command: ${namespacedName}`, { path: commandPath });
14570
14569
  } catch (error) {
14571
14570
  log(`Failed to load plugin command: ${commandPath}`, error);
@@ -14607,12 +14606,14 @@ ${body.trim()}
14607
14606
  <user-request>
14608
14607
  $ARGUMENTS
14609
14608
  </user-request>`;
14610
- skills[namespacedName] = {
14609
+ const definition = {
14611
14610
  name: namespacedName,
14612
14611
  description: formattedDescription,
14613
14612
  template: wrappedTemplate,
14614
14613
  model: sanitizeModelField(data.model)
14615
14614
  };
14615
+ const { name: _name, ...openCodeCompatible } = definition;
14616
+ skills[namespacedName] = openCodeCompatible;
14616
14617
  log(`Loaded plugin skill: ${namespacedName}`, { path: resolvedPath });
14617
14618
  } catch (error) {
14618
14619
  log(`Failed to load plugin skill: ${skillPath}`, error);
@@ -15813,7 +15814,7 @@ ${msg}`);
15813
15814
  // src/tools/lsp/utils.ts
15814
15815
  import { extname as extname2, resolve as resolve7 } from "path";
15815
15816
  import { fileURLToPath as fileURLToPath2 } from "url";
15816
- import { existsSync as existsSync39, readFileSync as readFileSync29, writeFileSync as writeFileSync14 } from "fs";
15817
+ import { existsSync as existsSync39, readFileSync as readFileSync29, writeFileSync as writeFileSync15 } from "fs";
15817
15818
  function findWorkspaceRoot(filePath) {
15818
15819
  let dir = resolve7(filePath);
15819
15820
  if (!existsSync39(dir) || !__require("fs").statSync(dir).isDirectory()) {
@@ -16043,7 +16044,7 @@ function applyTextEditsToFile(filePath, edits) {
16043
16044
  `));
16044
16045
  }
16045
16046
  }
16046
- writeFileSync14(filePath, lines.join(`
16047
+ writeFileSync15(filePath, lines.join(`
16047
16048
  `), "utf-8");
16048
16049
  return { success: true, editCount: edits.length };
16049
16050
  } catch (err) {
@@ -16074,7 +16075,7 @@ function applyWorkspaceEdit(edit) {
16074
16075
  if (change.kind === "create") {
16075
16076
  try {
16076
16077
  const filePath = uriToPath(change.uri);
16077
- writeFileSync14(filePath, "", "utf-8");
16078
+ writeFileSync15(filePath, "", "utf-8");
16078
16079
  result.filesModified.push(filePath);
16079
16080
  } catch (err) {
16080
16081
  result.success = false;
@@ -16085,7 +16086,7 @@ function applyWorkspaceEdit(edit) {
16085
16086
  const oldPath = uriToPath(change.oldUri);
16086
16087
  const newPath = uriToPath(change.newUri);
16087
16088
  const content = readFileSync29(oldPath, "utf-8");
16088
- writeFileSync14(newPath, content, "utf-8");
16089
+ writeFileSync15(newPath, content, "utf-8");
16089
16090
  __require("fs").unlinkSync(oldPath);
16090
16091
  result.filesModified.push(newPath);
16091
16092
  } catch (err) {
@@ -30122,6 +30123,7 @@ import { join as join52 } from "path";
30122
30123
  var OPENCODE_STORAGE9 = getOpenCodeStorageDir();
30123
30124
  var MESSAGE_STORAGE4 = join52(OPENCODE_STORAGE9, "message");
30124
30125
  var PART_STORAGE4 = join52(OPENCODE_STORAGE9, "part");
30126
+ var SESSION_STORAGE = join52(OPENCODE_STORAGE9, "session");
30125
30127
  var TODO_DIR2 = join52(getClaudeConfigDir(), "todos");
30126
30128
  var TRANSCRIPT_DIR2 = join52(getClaudeConfigDir(), "transcripts");
30127
30129
  var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
@@ -30199,6 +30201,38 @@ Has Transcript: Yes (234 entries)`;
30199
30201
  import { existsSync as existsSync46, readdirSync as readdirSync17 } from "fs";
30200
30202
  import { readdir, readFile } from "fs/promises";
30201
30203
  import { join as join53 } from "path";
30204
+ async function getMainSessions(options) {
30205
+ if (!existsSync46(SESSION_STORAGE))
30206
+ return [];
30207
+ const sessions = [];
30208
+ try {
30209
+ const projectDirs = await readdir(SESSION_STORAGE, { withFileTypes: true });
30210
+ for (const projectDir of projectDirs) {
30211
+ if (!projectDir.isDirectory())
30212
+ continue;
30213
+ const projectPath = join53(SESSION_STORAGE, projectDir.name);
30214
+ const sessionFiles = await readdir(projectPath);
30215
+ for (const file2 of sessionFiles) {
30216
+ if (!file2.endsWith(".json"))
30217
+ continue;
30218
+ try {
30219
+ const content = await readFile(join53(projectPath, file2), "utf-8");
30220
+ const meta = JSON.parse(content);
30221
+ if (meta.parentID)
30222
+ continue;
30223
+ if (options.directory && meta.directory !== options.directory)
30224
+ continue;
30225
+ sessions.push(meta);
30226
+ } catch {
30227
+ continue;
30228
+ }
30229
+ }
30230
+ }
30231
+ } catch {
30232
+ return [];
30233
+ }
30234
+ return sessions.sort((a, b) => b.time.updated - a.time.updated);
30235
+ }
30202
30236
  async function getAllSessions() {
30203
30237
  if (!existsSync46(MESSAGE_STORAGE4))
30204
30238
  return [];
@@ -30550,18 +30584,21 @@ var session_list = tool({
30550
30584
  args: {
30551
30585
  limit: tool.schema.number().optional().describe("Maximum number of sessions to return"),
30552
30586
  from_date: tool.schema.string().optional().describe("Filter sessions from this date (ISO 8601 format)"),
30553
- to_date: tool.schema.string().optional().describe("Filter sessions until this date (ISO 8601 format)")
30587
+ to_date: tool.schema.string().optional().describe("Filter sessions until this date (ISO 8601 format)"),
30588
+ project_path: tool.schema.string().optional().describe("Filter sessions by project path (default: current working directory)")
30554
30589
  },
30555
30590
  execute: async (args, _context) => {
30556
30591
  try {
30557
- let sessions = await getAllSessions();
30592
+ const directory = args.project_path ?? process.cwd();
30593
+ let sessions = await getMainSessions({ directory });
30594
+ let sessionIDs = sessions.map((s) => s.id);
30558
30595
  if (args.from_date || args.to_date) {
30559
- sessions = await filterSessionsByDate(sessions, args.from_date, args.to_date);
30596
+ sessionIDs = await filterSessionsByDate(sessionIDs, args.from_date, args.to_date);
30560
30597
  }
30561
30598
  if (args.limit && args.limit > 0) {
30562
- sessions = sessions.slice(0, args.limit);
30599
+ sessionIDs = sessionIDs.slice(0, args.limit);
30563
30600
  }
30564
- return await formatSessionList(sessions);
30601
+ return await formatSessionList(sessionIDs);
30565
30602
  } catch (e) {
30566
30603
  return `Error: ${e instanceof Error ? e.message : String(e)}`;
30567
30604
  }
@@ -31943,7 +31980,10 @@ var HookNameSchema = exports_external.enum([
31943
31980
  "interactive-bash-session",
31944
31981
  "empty-message-sanitizer",
31945
31982
  "thinking-block-validator",
31946
- "ralph-loop"
31983
+ "ralph-loop",
31984
+ "preemptive-compaction",
31985
+ "compaction-context-injector",
31986
+ "claude-code-hooks"
31947
31987
  ]);
31948
31988
  var BuiltinCommandNameSchema = exports_external.enum([
31949
31989
  "init-deep"
@@ -32159,64 +32199,12 @@ var PLAN_PERMISSION = {
32159
32199
  };
32160
32200
 
32161
32201
  // src/index.ts
32162
- import * as fs7 from "fs";
32202
+ import * as fs8 from "fs";
32163
32203
  import * as path7 from "path";
32164
- var AGENT_NAME_MAP = {
32165
- omo: "Sisyphus",
32166
- OmO: "Sisyphus",
32167
- "OmO-Plan": "Planner-Sisyphus",
32168
- "omo-plan": "Planner-Sisyphus",
32169
- sisyphus: "Sisyphus",
32170
- "planner-sisyphus": "Planner-Sisyphus",
32171
- build: "build",
32172
- oracle: "oracle",
32173
- librarian: "librarian",
32174
- explore: "explore",
32175
- "frontend-ui-ux-engineer": "frontend-ui-ux-engineer",
32176
- "document-writer": "document-writer",
32177
- "multimodal-looker": "multimodal-looker"
32178
- };
32179
- function migrateAgentNames(agents) {
32180
- const migrated = {};
32181
- let changed = false;
32182
- for (const [key, value] of Object.entries(agents)) {
32183
- const newKey = AGENT_NAME_MAP[key.toLowerCase()] ?? AGENT_NAME_MAP[key] ?? key;
32184
- if (newKey !== key) {
32185
- changed = true;
32186
- }
32187
- migrated[newKey] = value;
32188
- }
32189
- return { migrated, changed };
32190
- }
32191
- function migrateConfigFile(configPath, rawConfig) {
32192
- let needsWrite = false;
32193
- if (rawConfig.agents && typeof rawConfig.agents === "object") {
32194
- const { migrated, changed } = migrateAgentNames(rawConfig.agents);
32195
- if (changed) {
32196
- rawConfig.agents = migrated;
32197
- needsWrite = true;
32198
- }
32199
- }
32200
- if (rawConfig.omo_agent) {
32201
- rawConfig.sisyphus_agent = rawConfig.omo_agent;
32202
- delete rawConfig.omo_agent;
32203
- needsWrite = true;
32204
- }
32205
- if (needsWrite) {
32206
- try {
32207
- fs7.writeFileSync(configPath, JSON.stringify(rawConfig, null, 2) + `
32208
- `, "utf-8");
32209
- log(`Migrated config file: ${configPath} (OmO \u2192 Sisyphus)`);
32210
- } catch (err) {
32211
- log(`Failed to write migrated config to ${configPath}:`, err);
32212
- }
32213
- }
32214
- return needsWrite;
32215
- }
32216
32204
  function loadConfigFromPath2(configPath, ctx) {
32217
32205
  try {
32218
- if (fs7.existsSync(configPath)) {
32219
- const content = fs7.readFileSync(configPath, "utf-8");
32206
+ if (fs8.existsSync(configPath)) {
32207
+ const content = fs8.readFileSync(configPath, "utf-8");
32220
32208
  const rawConfig = parseJsonc(content);
32221
32209
  migrateConfigFile(configPath, rawConfig);
32222
32210
  const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
@@ -32321,12 +32309,12 @@ var OhMyOpenCodePlugin = async (ctx) => {
32321
32309
  experimental: pluginConfig.experimental,
32322
32310
  dcpForCompaction: pluginConfig.experimental?.dcp_for_compaction
32323
32311
  }) : null;
32324
- const compactionContextInjector = createCompactionContextInjector();
32325
- const preemptiveCompaction = createPreemptiveCompactionHook(ctx, {
32312
+ const compactionContextInjector = isHookEnabled("compaction-context-injector") ? createCompactionContextInjector() : undefined;
32313
+ const preemptiveCompaction = isHookEnabled("preemptive-compaction") ? createPreemptiveCompactionHook(ctx, {
32326
32314
  experimental: pluginConfig.experimental,
32327
32315
  onBeforeSummarize: compactionContextInjector,
32328
32316
  getModelLimit
32329
- });
32317
+ }) : null;
32330
32318
  const rulesInjector = isHookEnabled("rules-injector") ? createRulesInjectorHook(ctx) : null;
32331
32319
  const autoUpdateChecker = isHookEnabled("auto-update-checker") ? createAutoUpdateCheckerHook(ctx, {
32332
32320
  showStartupToast: isHookEnabled("startup-toast"),