oh-my-opencode 2.8.3 → 2.9.1
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/README.ja.md +20 -5
- package/README.ko.md +17 -6
- package/README.md +20 -6
- package/README.zh-cn.md +20 -5
- package/dist/agents/document-writer.d.ts +2 -0
- package/dist/agents/explore.d.ts +2 -0
- package/dist/agents/frontend-ui-ux-engineer.d.ts +2 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/librarian.d.ts +2 -0
- package/dist/agents/multimodal-looker.d.ts +2 -0
- package/dist/agents/oracle.d.ts +2 -0
- package/dist/agents/sisyphus-prompt-builder.d.ts +25 -0
- package/dist/agents/sisyphus.d.ts +2 -1
- package/dist/agents/types.d.ts +39 -0
- package/dist/cli/index.js +31 -65
- package/dist/config/schema.d.ts +9 -3
- package/dist/features/builtin-commands/templates/init-deep.d.ts +1 -1
- package/dist/hooks/anthropic-context-window-limit-recovery/index.d.ts +1 -1
- package/dist/hooks/anthropic-context-window-limit-recovery/types.d.ts +0 -9
- package/dist/index.js +724 -688
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/migration.d.ts +11 -0
- package/dist/shared/migration.test.d.ts +1 -0
- package/dist/tools/session-manager/constants.d.ts +1 -0
- package/dist/tools/session-manager/storage.d.ts +5 -1
- package/dist/tools/session-manager/types.d.ts +18 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1479,9 +1479,256 @@ 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, skills = []) {
|
|
1517
|
+
const keyTriggers = agents.filter((a) => a.metadata.keyTrigger).map((a) => `- ${a.metadata.keyTrigger}`);
|
|
1518
|
+
const skillTriggers = skills.filter((s) => s.description).map((s) => `- **Skill \`${s.name}\`**: ${extractTriggerFromDescription(s.description)}`);
|
|
1519
|
+
const allTriggers = [...keyTriggers, ...skillTriggers];
|
|
1520
|
+
if (allTriggers.length === 0)
|
|
1521
|
+
return "";
|
|
1522
|
+
return `### Key Triggers (check BEFORE classification):
|
|
1523
|
+
|
|
1524
|
+
**BLOCKING: Check skills FIRST before any action.**
|
|
1525
|
+
If a skill matches, invoke it IMMEDIATELY via \`skill\` tool.
|
|
1526
|
+
|
|
1527
|
+
${allTriggers.join(`
|
|
1528
|
+
`)}
|
|
1529
|
+
- **GitHub mention (@mention in issue/PR)** \u2192 This is a WORK REQUEST. Plan full cycle: investigate \u2192 implement \u2192 create PR
|
|
1530
|
+
- **"Look into" + "create PR"** \u2192 Not just research. Full implementation cycle expected.`;
|
|
1531
|
+
}
|
|
1532
|
+
function extractTriggerFromDescription(description) {
|
|
1533
|
+
const triggerMatch = description.match(/Trigger[s]?[:\s]+([^.]+)/i);
|
|
1534
|
+
if (triggerMatch)
|
|
1535
|
+
return triggerMatch[1].trim();
|
|
1536
|
+
const activateMatch = description.match(/Activate when[:\s]+([^.]+)/i);
|
|
1537
|
+
if (activateMatch)
|
|
1538
|
+
return activateMatch[1].trim();
|
|
1539
|
+
const useWhenMatch = description.match(/Use (?:this )?when[:\s]+([^.]+)/i);
|
|
1540
|
+
if (useWhenMatch)
|
|
1541
|
+
return useWhenMatch[1].trim();
|
|
1542
|
+
return description.split(".")[0] || description;
|
|
1543
|
+
}
|
|
1544
|
+
function buildToolSelectionTable(agents, tools = [], skills = []) {
|
|
1545
|
+
const rows = [
|
|
1546
|
+
"### Tool & Skill Selection:",
|
|
1547
|
+
"",
|
|
1548
|
+
"**Priority Order**: Skills \u2192 Direct Tools \u2192 Agents",
|
|
1549
|
+
""
|
|
1550
|
+
];
|
|
1551
|
+
if (skills.length > 0) {
|
|
1552
|
+
rows.push("#### Skills (INVOKE FIRST if matching)");
|
|
1553
|
+
rows.push("");
|
|
1554
|
+
rows.push("| Skill | When to Use |");
|
|
1555
|
+
rows.push("|-------|-------------|");
|
|
1556
|
+
for (const skill of skills) {
|
|
1557
|
+
const shortDesc = extractTriggerFromDescription(skill.description);
|
|
1558
|
+
rows.push(`| \`${skill.name}\` | ${shortDesc} |`);
|
|
1559
|
+
}
|
|
1560
|
+
rows.push("");
|
|
1561
|
+
}
|
|
1562
|
+
rows.push("#### Tools & Agents");
|
|
1563
|
+
rows.push("");
|
|
1564
|
+
rows.push("| Resource | Cost | When to Use |");
|
|
1565
|
+
rows.push("|----------|------|-------------|");
|
|
1566
|
+
if (tools.length > 0) {
|
|
1567
|
+
const toolsDisplay = formatToolsForPrompt(tools);
|
|
1568
|
+
rows.push(`| ${toolsDisplay} | FREE | Not Complex, Scope Clear, No Implicit Assumptions |`);
|
|
1569
|
+
}
|
|
1570
|
+
const costOrder = { FREE: 0, CHEAP: 1, EXPENSIVE: 2 };
|
|
1571
|
+
const sortedAgents = [...agents].filter((a) => a.metadata.category !== "utility").sort((a, b) => costOrder[a.metadata.cost] - costOrder[b.metadata.cost]);
|
|
1572
|
+
for (const agent of sortedAgents) {
|
|
1573
|
+
const shortDesc = agent.description.split(".")[0] || agent.description;
|
|
1574
|
+
rows.push(`| \`${agent.name}\` agent | ${agent.metadata.cost} | ${shortDesc} |`);
|
|
1575
|
+
}
|
|
1576
|
+
rows.push("");
|
|
1577
|
+
rows.push("**Default flow**: skill (if match) \u2192 explore/librarian (background) + tools \u2192 oracle (if required)");
|
|
1578
|
+
return rows.join(`
|
|
1579
|
+
`);
|
|
1580
|
+
}
|
|
1581
|
+
function buildExploreSection(agents) {
|
|
1582
|
+
const exploreAgent = agents.find((a) => a.name === "explore");
|
|
1583
|
+
if (!exploreAgent)
|
|
1584
|
+
return "";
|
|
1585
|
+
const useWhen = exploreAgent.metadata.useWhen || [];
|
|
1586
|
+
const avoidWhen = exploreAgent.metadata.avoidWhen || [];
|
|
1587
|
+
return `### Explore Agent = Contextual Grep
|
|
1588
|
+
|
|
1589
|
+
Use it as a **peer tool**, not a fallback. Fire liberally.
|
|
1590
|
+
|
|
1591
|
+
| Use Direct Tools | Use Explore Agent |
|
|
1592
|
+
|------------------|-------------------|
|
|
1593
|
+
${avoidWhen.map((w) => `| ${w} | |`).join(`
|
|
1594
|
+
`)}
|
|
1595
|
+
${useWhen.map((w) => `| | ${w} |`).join(`
|
|
1596
|
+
`)}`;
|
|
1597
|
+
}
|
|
1598
|
+
function buildLibrarianSection(agents) {
|
|
1599
|
+
const librarianAgent = agents.find((a) => a.name === "librarian");
|
|
1600
|
+
if (!librarianAgent)
|
|
1601
|
+
return "";
|
|
1602
|
+
const useWhen = librarianAgent.metadata.useWhen || [];
|
|
1603
|
+
return `### Librarian Agent = Reference Grep
|
|
1604
|
+
|
|
1605
|
+
Search **external references** (docs, OSS, web). Fire proactively when unfamiliar libraries are involved.
|
|
1606
|
+
|
|
1607
|
+
| Contextual Grep (Internal) | Reference Grep (External) |
|
|
1608
|
+
|----------------------------|---------------------------|
|
|
1609
|
+
| Search OUR codebase | Search EXTERNAL resources |
|
|
1610
|
+
| Find patterns in THIS repo | Find examples in OTHER repos |
|
|
1611
|
+
| How does our code work? | How does this library work? |
|
|
1612
|
+
| Project-specific logic | Official API documentation |
|
|
1613
|
+
| | Library best practices & quirks |
|
|
1614
|
+
| | OSS implementation examples |
|
|
1615
|
+
|
|
1616
|
+
**Trigger phrases** (fire librarian immediately):
|
|
1617
|
+
${useWhen.map((w) => `- "${w}"`).join(`
|
|
1618
|
+
`)}`;
|
|
1619
|
+
}
|
|
1620
|
+
function buildDelegationTable(agents) {
|
|
1621
|
+
const rows = [
|
|
1622
|
+
"### Delegation Table:",
|
|
1623
|
+
"",
|
|
1624
|
+
"| Domain | Delegate To | Trigger |",
|
|
1625
|
+
"|--------|-------------|---------|"
|
|
1626
|
+
];
|
|
1627
|
+
for (const agent of agents) {
|
|
1628
|
+
for (const trigger of agent.metadata.triggers) {
|
|
1629
|
+
rows.push(`| ${trigger.domain} | \`${agent.name}\` | ${trigger.trigger} |`);
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
return rows.join(`
|
|
1633
|
+
`);
|
|
1634
|
+
}
|
|
1635
|
+
function buildFrontendSection(agents) {
|
|
1636
|
+
const frontendAgent = agents.find((a) => a.name === "frontend-ui-ux-engineer");
|
|
1637
|
+
if (!frontendAgent)
|
|
1638
|
+
return "";
|
|
1639
|
+
return `### Frontend Files: Decision Gate (NOT a blind block)
|
|
1640
|
+
|
|
1641
|
+
Frontend files (.tsx, .jsx, .vue, .svelte, .css, etc.) require **classification before action**.
|
|
1642
|
+
|
|
1643
|
+
#### Step 1: Classify the Change Type
|
|
1644
|
+
|
|
1645
|
+
| Change Type | Examples | Action |
|
|
1646
|
+
|-------------|----------|--------|
|
|
1647
|
+
| **Visual/UI/UX** | Color, spacing, layout, typography, animation, responsive breakpoints, hover states, shadows, borders, icons, images | **DELEGATE** to \`frontend-ui-ux-engineer\` |
|
|
1648
|
+
| **Pure Logic** | API calls, data fetching, state management, event handlers (non-visual), type definitions, utility functions, business logic | **CAN handle directly** |
|
|
1649
|
+
| **Mixed** | Component changes both visual AND logic | **Split**: handle logic yourself, delegate visual to \`frontend-ui-ux-engineer\` |
|
|
1650
|
+
|
|
1651
|
+
#### Step 2: Ask Yourself
|
|
1652
|
+
|
|
1653
|
+
Before touching any frontend file, think:
|
|
1654
|
+
> "Is this change about **how it LOOKS** or **how it WORKS**?"
|
|
1655
|
+
|
|
1656
|
+
- **LOOKS** (colors, sizes, positions, animations) \u2192 DELEGATE
|
|
1657
|
+
- **WORKS** (data flow, API integration, state) \u2192 Handle directly
|
|
1658
|
+
|
|
1659
|
+
#### When in Doubt \u2192 DELEGATE if ANY of these keywords involved:
|
|
1660
|
+
style, className, tailwind, color, background, border, shadow, margin, padding, width, height, flex, grid, animation, transition, hover, responsive, font-size, icon, svg`;
|
|
1661
|
+
}
|
|
1662
|
+
function buildOracleSection(agents) {
|
|
1663
|
+
const oracleAgent = agents.find((a) => a.name === "oracle");
|
|
1664
|
+
if (!oracleAgent)
|
|
1665
|
+
return "";
|
|
1666
|
+
const useWhen = oracleAgent.metadata.useWhen || [];
|
|
1667
|
+
const avoidWhen = oracleAgent.metadata.avoidWhen || [];
|
|
1668
|
+
return `<Oracle_Usage>
|
|
1669
|
+
## Oracle \u2014 Your Senior Engineering Advisor (GPT-5.2)
|
|
1670
|
+
|
|
1671
|
+
Oracle is an expensive, high-quality reasoning model. Use it wisely.
|
|
1672
|
+
|
|
1673
|
+
### WHEN to Consult:
|
|
1674
|
+
|
|
1675
|
+
| Trigger | Action |
|
|
1676
|
+
|---------|--------|
|
|
1677
|
+
${useWhen.map((w) => `| ${w} | Oracle FIRST, then implement |`).join(`
|
|
1678
|
+
`)}
|
|
1679
|
+
|
|
1680
|
+
### WHEN NOT to Consult:
|
|
1681
|
+
|
|
1682
|
+
${avoidWhen.map((w) => `- ${w}`).join(`
|
|
1683
|
+
`)}
|
|
1684
|
+
|
|
1685
|
+
### Usage Pattern:
|
|
1686
|
+
Briefly announce "Consulting Oracle for [reason]" before invocation.
|
|
1687
|
+
|
|
1688
|
+
**Exception**: This is the ONLY case where you announce before acting. For all other work, start immediately without status updates.
|
|
1689
|
+
</Oracle_Usage>`;
|
|
1690
|
+
}
|
|
1691
|
+
function buildHardBlocksSection(agents) {
|
|
1692
|
+
const frontendAgent = agents.find((a) => a.name === "frontend-ui-ux-engineer");
|
|
1693
|
+
const blocks = [
|
|
1694
|
+
"| Type error suppression (`as any`, `@ts-ignore`) | Never |",
|
|
1695
|
+
"| Commit without explicit request | Never |",
|
|
1696
|
+
"| Speculate about unread code | Never |",
|
|
1697
|
+
"| Leave code in broken state after failures | Never |"
|
|
1698
|
+
];
|
|
1699
|
+
if (frontendAgent) {
|
|
1700
|
+
blocks.unshift("| Frontend VISUAL changes (styling, layout, animation) | Always delegate to `frontend-ui-ux-engineer` |");
|
|
1701
|
+
}
|
|
1702
|
+
return `## Hard Blocks (NEVER violate)
|
|
1703
|
+
|
|
1704
|
+
| Constraint | No Exceptions |
|
|
1705
|
+
|------------|---------------|
|
|
1706
|
+
${blocks.join(`
|
|
1707
|
+
`)}`;
|
|
1708
|
+
}
|
|
1709
|
+
function buildAntiPatternsSection(agents) {
|
|
1710
|
+
const frontendAgent = agents.find((a) => a.name === "frontend-ui-ux-engineer");
|
|
1711
|
+
const patterns = [
|
|
1712
|
+
"| **Type Safety** | `as any`, `@ts-ignore`, `@ts-expect-error` |",
|
|
1713
|
+
"| **Error Handling** | Empty catch blocks `catch(e) {}` |",
|
|
1714
|
+
'| **Testing** | Deleting failing tests to "pass" |',
|
|
1715
|
+
"| **Search** | Firing agents for single-line typos or obvious syntax errors |",
|
|
1716
|
+
"| **Debugging** | Shotgun debugging, random changes |"
|
|
1717
|
+
];
|
|
1718
|
+
if (frontendAgent) {
|
|
1719
|
+
patterns.splice(4, 0, "| **Frontend** | Direct edit to visual/styling code (logic changes OK) |");
|
|
1720
|
+
}
|
|
1721
|
+
return `## Anti-Patterns (BLOCKING violations)
|
|
1722
|
+
|
|
1723
|
+
| Category | Forbidden |
|
|
1724
|
+
|----------|-----------|
|
|
1725
|
+
${patterns.join(`
|
|
1726
|
+
`)}`;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1482
1729
|
// src/agents/sisyphus.ts
|
|
1483
1730
|
var DEFAULT_MODEL = "anthropic/claude-opus-4-5";
|
|
1484
|
-
var
|
|
1731
|
+
var SISYPHUS_ROLE_SECTION = `<Role>
|
|
1485
1732
|
You are "Sisyphus" - Powerful AI Agent with orchestration capabilities from OhMyOpenCode.
|
|
1486
1733
|
Named by [YeonGyu Kim](https://github.com/code-yeongyu).
|
|
1487
1734
|
|
|
@@ -1499,22 +1746,26 @@ Named by [YeonGyu Kim](https://github.com/code-yeongyu).
|
|
|
1499
1746
|
|
|
1500
1747
|
**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
1748
|
|
|
1502
|
-
</Role
|
|
1749
|
+
</Role>`;
|
|
1750
|
+
var SISYPHUS_PHASE0_STEP1_3 = `### Step 0: Check Skills FIRST (BLOCKING)
|
|
1503
1751
|
|
|
1504
|
-
|
|
1752
|
+
**Before ANY classification or action, scan for matching skills.**
|
|
1505
1753
|
|
|
1506
|
-
|
|
1754
|
+
\`\`\`
|
|
1755
|
+
IF request matches a skill trigger:
|
|
1756
|
+
\u2192 INVOKE skill tool IMMEDIATELY
|
|
1757
|
+
\u2192 Do NOT proceed to Step 1 until skill is invoked
|
|
1758
|
+
\`\`\`
|
|
1507
1759
|
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
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.
|
|
1760
|
+
Skills are specialized workflows. When relevant, they handle the task better than manual orchestration.
|
|
1761
|
+
|
|
1762
|
+
---
|
|
1513
1763
|
|
|
1514
1764
|
### Step 1: Classify Request Type
|
|
1515
1765
|
|
|
1516
1766
|
| Type | Signal | Action |
|
|
1517
1767
|
|------|--------|--------|
|
|
1768
|
+
| **Skill Match** | Matches skill trigger phrase | **INVOKE skill FIRST** via \`skill\` tool |
|
|
1518
1769
|
| **Trivial** | Single file, known location, direct answer | Direct tools only (UNLESS Key Trigger applies) |
|
|
1519
1770
|
| **Explicit** | Specific file/line, clear command | Execute directly |
|
|
1520
1771
|
| **Exploratory** | "How does X work?", "Find Y" | Fire explore (1-3) + tools in parallel |
|
|
@@ -1556,11 +1807,8 @@ Then: Raise your concern concisely. Propose an alternative. Ask if they want to
|
|
|
1556
1807
|
I notice [observation]. This might cause [problem] because [reason].
|
|
1557
1808
|
Alternative: [your suggestion].
|
|
1558
1809
|
Should I proceed with your original request, or try the alternative?
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
---
|
|
1562
|
-
|
|
1563
|
-
## Phase 1 - Codebase Assessment (for Open-ended tasks)
|
|
1810
|
+
\`\`\``;
|
|
1811
|
+
var SISYPHUS_PHASE1 = `## Phase 1 - Codebase Assessment (for Open-ended tasks)
|
|
1564
1812
|
|
|
1565
1813
|
Before following existing patterns, assess whether they're worth following.
|
|
1566
1814
|
|
|
@@ -1581,54 +1829,8 @@ Before following existing patterns, assess whether they're worth following.
|
|
|
1581
1829
|
IMPORTANT: If codebase appears undisciplined, verify before assuming:
|
|
1582
1830
|
- Different patterns may serve different purposes (intentional)
|
|
1583
1831
|
- 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)
|
|
1832
|
+
- You might be looking at the wrong reference files`;
|
|
1833
|
+
var SISYPHUS_PARALLEL_EXECUTION = `### Parallel Execution (DEFAULT behavior)
|
|
1632
1834
|
|
|
1633
1835
|
**Explore/Librarian = Grep, not consultants.
|
|
1634
1836
|
|
|
@@ -1660,64 +1862,14 @@ STOP searching when:
|
|
|
1660
1862
|
- 2 search iterations yielded no new useful data
|
|
1661
1863
|
- Direct answer found
|
|
1662
1864
|
|
|
1663
|
-
**DO NOT over-explore. Time is precious
|
|
1664
|
-
|
|
1665
|
-
---
|
|
1666
|
-
|
|
1667
|
-
## Phase 2B - Implementation
|
|
1865
|
+
**DO NOT over-explore. Time is precious.**`;
|
|
1866
|
+
var SISYPHUS_PHASE2B_PRE_IMPLEMENTATION = `## Phase 2B - Implementation
|
|
1668
1867
|
|
|
1669
1868
|
### Pre-Implementation:
|
|
1670
1869
|
1. If task has 2+ steps \u2192 Create todo list IMMEDIATELY, IN SUPER DETAIL. No announcements\u2014just create it.
|
|
1671
1870
|
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):
|
|
1871
|
+
3. Mark \`completed\` as soon as done (don't batch) - OBSESSIVELY TRACK YOUR WORK USING TODO TOOLS`;
|
|
1872
|
+
var SISYPHUS_DELEGATION_PROMPT_STRUCTURE = `### Delegation Prompt Structure (MANDATORY - ALL 7 sections):
|
|
1721
1873
|
|
|
1722
1874
|
When delegating, your prompt MUST include:
|
|
1723
1875
|
|
|
@@ -1737,9 +1889,8 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING:
|
|
|
1737
1889
|
- EXPECTED RESULT CAME OUT?
|
|
1738
1890
|
- DID THE AGENT FOLLOWED "MUST DO" AND "MUST NOT DO" REQUIREMENTS?
|
|
1739
1891
|
|
|
1740
|
-
**Vague prompts = rejected. Be exhaustive
|
|
1741
|
-
|
|
1742
|
-
### GitHub Workflow (CRITICAL - When mentioned in issues/PRs):
|
|
1892
|
+
**Vague prompts = rejected. Be exhaustive.**`;
|
|
1893
|
+
var SISYPHUS_GITHUB_WORKFLOW = `### GitHub Workflow (CRITICAL - When mentioned in issues/PRs):
|
|
1743
1894
|
|
|
1744
1895
|
When you're mentioned in GitHub issues or asked to "look into" something and "create PR":
|
|
1745
1896
|
|
|
@@ -1772,9 +1923,8 @@ When you're mentioned in GitHub issues or asked to "look into" something and "cr
|
|
|
1772
1923
|
**EMPHASIS**: "Look into" does NOT mean "just investigate and report back."
|
|
1773
1924
|
It means "investigate, understand, implement a solution, and create a PR."
|
|
1774
1925
|
|
|
1775
|
-
**If the user says "look into X and create PR", they expect a PR, not just analysis
|
|
1776
|
-
|
|
1777
|
-
### Code Changes:
|
|
1926
|
+
**If the user says "look into X and create PR", they expect a PR, not just analysis.**`;
|
|
1927
|
+
var SISYPHUS_CODE_CHANGES = `### Code Changes:
|
|
1778
1928
|
- Match existing patterns (if codebase is disciplined)
|
|
1779
1929
|
- Propose approach first (if codebase is chaotic)
|
|
1780
1930
|
- Never suppress type errors with \`as any\`, \`@ts-ignore\`, \`@ts-expect-error\`
|
|
@@ -1800,11 +1950,8 @@ If project has build/test commands, run them at task completion.
|
|
|
1800
1950
|
| Test run | Pass (or explicit note of pre-existing failures) |
|
|
1801
1951
|
| Delegation | Agent result received and verified |
|
|
1802
1952
|
|
|
1803
|
-
**NO EVIDENCE = NOT COMPLETE
|
|
1804
|
-
|
|
1805
|
-
---
|
|
1806
|
-
|
|
1807
|
-
## Phase 2C - Failure Recovery
|
|
1953
|
+
**NO EVIDENCE = NOT COMPLETE.**`;
|
|
1954
|
+
var SISYPHUS_PHASE2C = `## Phase 2C - Failure Recovery
|
|
1808
1955
|
|
|
1809
1956
|
### When Fixes Fail:
|
|
1810
1957
|
|
|
@@ -1820,11 +1967,8 @@ If project has build/test commands, run them at task completion.
|
|
|
1820
1967
|
4. **CONSULT** Oracle with full failure context
|
|
1821
1968
|
5. If Oracle cannot resolve \u2192 **ASK USER** before proceeding
|
|
1822
1969
|
|
|
1823
|
-
**Never**: Leave code in broken state, continue hoping it'll work, delete failing tests to "pass"
|
|
1824
|
-
|
|
1825
|
-
---
|
|
1826
|
-
|
|
1827
|
-
## Phase 3 - Completion
|
|
1970
|
+
**Never**: Leave code in broken state, continue hoping it'll work, delete failing tests to "pass"`;
|
|
1971
|
+
var SISYPHUS_PHASE3 = `## Phase 3 - Completion
|
|
1828
1972
|
|
|
1829
1973
|
A task is complete when:
|
|
1830
1974
|
- [ ] All planned todo items marked done
|
|
@@ -1839,41 +1983,8 @@ If verification fails:
|
|
|
1839
1983
|
|
|
1840
1984
|
### Before Delivering Final Answer:
|
|
1841
1985
|
- 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>
|
|
1986
|
+
- This conserves resources and ensures clean workflow completion`;
|
|
1987
|
+
var SISYPHUS_TASK_MANAGEMENT = `<Task_Management>
|
|
1877
1988
|
## Todo Management (CRITICAL)
|
|
1878
1989
|
|
|
1879
1990
|
**DEFAULT BEHAVIOR**: Create todos BEFORE starting any non-trivial task. This is your PRIMARY coordination mechanism.
|
|
@@ -1928,9 +2039,8 @@ I want to make sure I understand correctly.
|
|
|
1928
2039
|
|
|
1929
2040
|
Should I proceed with [recommendation], or would you prefer differently?
|
|
1930
2041
|
\`\`\`
|
|
1931
|
-
</Task_Management
|
|
1932
|
-
|
|
1933
|
-
<Tone_and_Style>
|
|
2042
|
+
</Task_Management>`;
|
|
2043
|
+
var SISYPHUS_TONE_AND_STYLE = `<Tone_and_Style>
|
|
1934
2044
|
## Communication Style
|
|
1935
2045
|
|
|
1936
2046
|
### Be Concise
|
|
@@ -1970,31 +2080,8 @@ If the user's approach seems problematic:
|
|
|
1970
2080
|
- If user is terse, be terse
|
|
1971
2081
|
- If user wants detail, provide detail
|
|
1972
2082
|
- 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
|
|
2083
|
+
</Tone_and_Style>`;
|
|
2084
|
+
var SISYPHUS_SOFT_GUIDELINES = `## Soft Guidelines
|
|
1998
2085
|
|
|
1999
2086
|
- Prefer existing libraries over new dependencies
|
|
2000
2087
|
- Prefer small, focused changes over large refactors
|
|
@@ -2002,13 +2089,92 @@ If the user's approach seems problematic:
|
|
|
2002
2089
|
</Constraints>
|
|
2003
2090
|
|
|
2004
2091
|
`;
|
|
2005
|
-
function
|
|
2092
|
+
function buildDynamicSisyphusPrompt(availableAgents, availableTools = [], availableSkills = []) {
|
|
2093
|
+
const keyTriggers = buildKeyTriggersSection(availableAgents, availableSkills);
|
|
2094
|
+
const toolSelection = buildToolSelectionTable(availableAgents, availableTools, availableSkills);
|
|
2095
|
+
const exploreSection = buildExploreSection(availableAgents);
|
|
2096
|
+
const librarianSection = buildLibrarianSection(availableAgents);
|
|
2097
|
+
const frontendSection = buildFrontendSection(availableAgents);
|
|
2098
|
+
const delegationTable = buildDelegationTable(availableAgents);
|
|
2099
|
+
const oracleSection = buildOracleSection(availableAgents);
|
|
2100
|
+
const hardBlocks = buildHardBlocksSection(availableAgents);
|
|
2101
|
+
const antiPatterns = buildAntiPatternsSection(availableAgents);
|
|
2102
|
+
const sections = [
|
|
2103
|
+
SISYPHUS_ROLE_SECTION,
|
|
2104
|
+
"<Behavior_Instructions>",
|
|
2105
|
+
"",
|
|
2106
|
+
"## Phase 0 - Intent Gate (EVERY message)",
|
|
2107
|
+
"",
|
|
2108
|
+
keyTriggers,
|
|
2109
|
+
"",
|
|
2110
|
+
SISYPHUS_PHASE0_STEP1_3,
|
|
2111
|
+
"",
|
|
2112
|
+
"---",
|
|
2113
|
+
"",
|
|
2114
|
+
SISYPHUS_PHASE1,
|
|
2115
|
+
"",
|
|
2116
|
+
"---",
|
|
2117
|
+
"",
|
|
2118
|
+
"## Phase 2A - Exploration & Research",
|
|
2119
|
+
"",
|
|
2120
|
+
toolSelection,
|
|
2121
|
+
"",
|
|
2122
|
+
exploreSection,
|
|
2123
|
+
"",
|
|
2124
|
+
librarianSection,
|
|
2125
|
+
"",
|
|
2126
|
+
SISYPHUS_PARALLEL_EXECUTION,
|
|
2127
|
+
"",
|
|
2128
|
+
"---",
|
|
2129
|
+
"",
|
|
2130
|
+
SISYPHUS_PHASE2B_PRE_IMPLEMENTATION,
|
|
2131
|
+
"",
|
|
2132
|
+
frontendSection,
|
|
2133
|
+
"",
|
|
2134
|
+
delegationTable,
|
|
2135
|
+
"",
|
|
2136
|
+
SISYPHUS_DELEGATION_PROMPT_STRUCTURE,
|
|
2137
|
+
"",
|
|
2138
|
+
SISYPHUS_GITHUB_WORKFLOW,
|
|
2139
|
+
"",
|
|
2140
|
+
SISYPHUS_CODE_CHANGES,
|
|
2141
|
+
"",
|
|
2142
|
+
"---",
|
|
2143
|
+
"",
|
|
2144
|
+
SISYPHUS_PHASE2C,
|
|
2145
|
+
"",
|
|
2146
|
+
"---",
|
|
2147
|
+
"",
|
|
2148
|
+
SISYPHUS_PHASE3,
|
|
2149
|
+
"",
|
|
2150
|
+
"</Behavior_Instructions>",
|
|
2151
|
+
"",
|
|
2152
|
+
oracleSection,
|
|
2153
|
+
"",
|
|
2154
|
+
SISYPHUS_TASK_MANAGEMENT,
|
|
2155
|
+
"",
|
|
2156
|
+
SISYPHUS_TONE_AND_STYLE,
|
|
2157
|
+
"",
|
|
2158
|
+
"<Constraints>",
|
|
2159
|
+
hardBlocks,
|
|
2160
|
+
"",
|
|
2161
|
+
antiPatterns,
|
|
2162
|
+
"",
|
|
2163
|
+
SISYPHUS_SOFT_GUIDELINES
|
|
2164
|
+
];
|
|
2165
|
+
return sections.filter((s) => s !== "").join(`
|
|
2166
|
+
`);
|
|
2167
|
+
}
|
|
2168
|
+
function createSisyphusAgent(model = DEFAULT_MODEL, availableAgents, availableToolNames, availableSkills) {
|
|
2169
|
+
const tools = availableToolNames ? categorizeTools(availableToolNames) : [];
|
|
2170
|
+
const skills = availableSkills ?? [];
|
|
2171
|
+
const prompt = availableAgents ? buildDynamicSisyphusPrompt(availableAgents, tools, skills) : buildDynamicSisyphusPrompt([], tools, skills);
|
|
2006
2172
|
const base = {
|
|
2007
2173
|
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
2174
|
mode: "primary",
|
|
2009
2175
|
model,
|
|
2010
2176
|
maxTokens: 64000,
|
|
2011
|
-
prompt
|
|
2177
|
+
prompt,
|
|
2012
2178
|
color: "#00CED1"
|
|
2013
2179
|
};
|
|
2014
2180
|
if (isGptModel(model)) {
|
|
@@ -4170,6 +4336,82 @@ function detectConfigFile(basePath) {
|
|
|
4170
4336
|
}
|
|
4171
4337
|
return { format: "none", path: jsonPath };
|
|
4172
4338
|
}
|
|
4339
|
+
// src/shared/migration.ts
|
|
4340
|
+
import * as fs3 from "fs";
|
|
4341
|
+
var AGENT_NAME_MAP = {
|
|
4342
|
+
omo: "Sisyphus",
|
|
4343
|
+
OmO: "Sisyphus",
|
|
4344
|
+
"OmO-Plan": "Planner-Sisyphus",
|
|
4345
|
+
"omo-plan": "Planner-Sisyphus",
|
|
4346
|
+
sisyphus: "Sisyphus",
|
|
4347
|
+
"planner-sisyphus": "Planner-Sisyphus",
|
|
4348
|
+
build: "build",
|
|
4349
|
+
oracle: "oracle",
|
|
4350
|
+
librarian: "librarian",
|
|
4351
|
+
explore: "explore",
|
|
4352
|
+
"frontend-ui-ux-engineer": "frontend-ui-ux-engineer",
|
|
4353
|
+
"document-writer": "document-writer",
|
|
4354
|
+
"multimodal-looker": "multimodal-looker"
|
|
4355
|
+
};
|
|
4356
|
+
var HOOK_NAME_MAP = {
|
|
4357
|
+
"anthropic-auto-compact": "anthropic-context-window-limit-recovery"
|
|
4358
|
+
};
|
|
4359
|
+
function migrateAgentNames(agents) {
|
|
4360
|
+
const migrated = {};
|
|
4361
|
+
let changed = false;
|
|
4362
|
+
for (const [key, value] of Object.entries(agents)) {
|
|
4363
|
+
const newKey = AGENT_NAME_MAP[key.toLowerCase()] ?? AGENT_NAME_MAP[key] ?? key;
|
|
4364
|
+
if (newKey !== key) {
|
|
4365
|
+
changed = true;
|
|
4366
|
+
}
|
|
4367
|
+
migrated[newKey] = value;
|
|
4368
|
+
}
|
|
4369
|
+
return { migrated, changed };
|
|
4370
|
+
}
|
|
4371
|
+
function migrateHookNames(hooks) {
|
|
4372
|
+
const migrated = [];
|
|
4373
|
+
let changed = false;
|
|
4374
|
+
for (const hook of hooks) {
|
|
4375
|
+
const newHook = HOOK_NAME_MAP[hook] ?? hook;
|
|
4376
|
+
if (newHook !== hook) {
|
|
4377
|
+
changed = true;
|
|
4378
|
+
}
|
|
4379
|
+
migrated.push(newHook);
|
|
4380
|
+
}
|
|
4381
|
+
return { migrated, changed };
|
|
4382
|
+
}
|
|
4383
|
+
function migrateConfigFile(configPath, rawConfig) {
|
|
4384
|
+
let needsWrite = false;
|
|
4385
|
+
if (rawConfig.agents && typeof rawConfig.agents === "object") {
|
|
4386
|
+
const { migrated, changed } = migrateAgentNames(rawConfig.agents);
|
|
4387
|
+
if (changed) {
|
|
4388
|
+
rawConfig.agents = migrated;
|
|
4389
|
+
needsWrite = true;
|
|
4390
|
+
}
|
|
4391
|
+
}
|
|
4392
|
+
if (rawConfig.omo_agent) {
|
|
4393
|
+
rawConfig.sisyphus_agent = rawConfig.omo_agent;
|
|
4394
|
+
delete rawConfig.omo_agent;
|
|
4395
|
+
needsWrite = true;
|
|
4396
|
+
}
|
|
4397
|
+
if (rawConfig.disabled_hooks && Array.isArray(rawConfig.disabled_hooks)) {
|
|
4398
|
+
const { migrated, changed } = migrateHookNames(rawConfig.disabled_hooks);
|
|
4399
|
+
if (changed) {
|
|
4400
|
+
rawConfig.disabled_hooks = migrated;
|
|
4401
|
+
needsWrite = true;
|
|
4402
|
+
}
|
|
4403
|
+
}
|
|
4404
|
+
if (needsWrite) {
|
|
4405
|
+
try {
|
|
4406
|
+
fs3.writeFileSync(configPath, JSON.stringify(rawConfig, null, 2) + `
|
|
4407
|
+
`, "utf-8");
|
|
4408
|
+
log(`Migrated config file: ${configPath}`);
|
|
4409
|
+
} catch (err) {
|
|
4410
|
+
log(`Failed to write migrated config to ${configPath}:`, err);
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4413
|
+
return needsWrite;
|
|
4414
|
+
}
|
|
4173
4415
|
// src/agents/utils.ts
|
|
4174
4416
|
var agentSources = {
|
|
4175
4417
|
Sisyphus: createSisyphusAgent,
|
|
@@ -4258,7 +4500,7 @@ function getMainSessionID() {
|
|
|
4258
4500
|
return mainSessionID;
|
|
4259
4501
|
}
|
|
4260
4502
|
// src/features/hook-message-injector/injector.ts
|
|
4261
|
-
import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync3, readdirSync, writeFileSync } from "fs";
|
|
4503
|
+
import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync3, readdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
4262
4504
|
import { join as join7 } from "path";
|
|
4263
4505
|
|
|
4264
4506
|
// src/features/hook-message-injector/constants.ts
|
|
@@ -4360,12 +4602,12 @@ function injectHookMessage(sessionID, hookContent, originalMessage) {
|
|
|
4360
4602
|
sessionID
|
|
4361
4603
|
};
|
|
4362
4604
|
try {
|
|
4363
|
-
|
|
4605
|
+
writeFileSync2(join7(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
|
|
4364
4606
|
const partDir = join7(PART_STORAGE, messageID);
|
|
4365
4607
|
if (!existsSync5(partDir)) {
|
|
4366
4608
|
mkdirSync(partDir, { recursive: true });
|
|
4367
4609
|
}
|
|
4368
|
-
|
|
4610
|
+
writeFileSync2(join7(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
|
|
4369
4611
|
return true;
|
|
4370
4612
|
} catch {
|
|
4371
4613
|
return false;
|
|
@@ -5097,7 +5339,7 @@ function createSessionNotification(ctx, config = {}) {
|
|
|
5097
5339
|
};
|
|
5098
5340
|
}
|
|
5099
5341
|
// src/hooks/session-recovery/storage.ts
|
|
5100
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as
|
|
5342
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
5101
5343
|
import { join as join10 } from "path";
|
|
5102
5344
|
|
|
5103
5345
|
// src/hooks/session-recovery/constants.ts
|
|
@@ -5206,7 +5448,7 @@ function injectTextPart(sessionID, messageID, text) {
|
|
|
5206
5448
|
synthetic: true
|
|
5207
5449
|
};
|
|
5208
5450
|
try {
|
|
5209
|
-
|
|
5451
|
+
writeFileSync3(join10(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
|
|
5210
5452
|
return true;
|
|
5211
5453
|
} catch {
|
|
5212
5454
|
return false;
|
|
@@ -5316,7 +5558,7 @@ function prependThinkingPart(sessionID, messageID) {
|
|
|
5316
5558
|
synthetic: true
|
|
5317
5559
|
};
|
|
5318
5560
|
try {
|
|
5319
|
-
|
|
5561
|
+
writeFileSync3(join10(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
|
|
5320
5562
|
return true;
|
|
5321
5563
|
} catch {
|
|
5322
5564
|
return false;
|
|
@@ -5361,7 +5603,7 @@ function replaceEmptyTextParts(messageID, replacementText) {
|
|
|
5361
5603
|
if (!textPart.text?.trim()) {
|
|
5362
5604
|
textPart.text = replacementText;
|
|
5363
5605
|
textPart.synthetic = true;
|
|
5364
|
-
|
|
5606
|
+
writeFileSync3(filePath, JSON.stringify(textPart, null, 2));
|
|
5365
5607
|
anyReplaced = true;
|
|
5366
5608
|
}
|
|
5367
5609
|
}
|
|
@@ -5632,7 +5874,7 @@ var {spawn: spawn4 } = globalThis.Bun;
|
|
|
5632
5874
|
import { createRequire as createRequire2 } from "module";
|
|
5633
5875
|
import { dirname, join as join12 } from "path";
|
|
5634
5876
|
import { existsSync as existsSync9 } from "fs";
|
|
5635
|
-
import * as
|
|
5877
|
+
import * as fs4 from "fs";
|
|
5636
5878
|
import { tmpdir as tmpdir3 } from "os";
|
|
5637
5879
|
|
|
5638
5880
|
// src/hooks/comment-checker/downloader.ts
|
|
@@ -5780,7 +6022,7 @@ function debugLog2(...args) {
|
|
|
5780
6022
|
if (DEBUG2) {
|
|
5781
6023
|
const msg = `[${new Date().toISOString()}] [comment-checker:cli] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
|
|
5782
6024
|
`;
|
|
5783
|
-
|
|
6025
|
+
fs4.appendFileSync(DEBUG_FILE2, msg);
|
|
5784
6026
|
}
|
|
5785
6027
|
}
|
|
5786
6028
|
function getBinaryName2() {
|
|
@@ -5894,7 +6136,7 @@ async function runCommentChecker(input, cliPath, customPrompt) {
|
|
|
5894
6136
|
}
|
|
5895
6137
|
|
|
5896
6138
|
// src/hooks/comment-checker/index.ts
|
|
5897
|
-
import * as
|
|
6139
|
+
import * as fs5 from "fs";
|
|
5898
6140
|
import { existsSync as existsSync10 } from "fs";
|
|
5899
6141
|
import { tmpdir as tmpdir4 } from "os";
|
|
5900
6142
|
import { join as join13 } from "path";
|
|
@@ -5904,7 +6146,7 @@ function debugLog3(...args) {
|
|
|
5904
6146
|
if (DEBUG3) {
|
|
5905
6147
|
const msg = `[${new Date().toISOString()}] [comment-checker:hook] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
|
|
5906
6148
|
`;
|
|
5907
|
-
|
|
6149
|
+
fs5.appendFileSync(DEBUG_FILE3, msg);
|
|
5908
6150
|
}
|
|
5909
6151
|
}
|
|
5910
6152
|
var pendingCalls = new Map;
|
|
@@ -6059,7 +6301,7 @@ import {
|
|
|
6059
6301
|
existsSync as existsSync11,
|
|
6060
6302
|
mkdirSync as mkdirSync4,
|
|
6061
6303
|
readFileSync as readFileSync5,
|
|
6062
|
-
writeFileSync as
|
|
6304
|
+
writeFileSync as writeFileSync4,
|
|
6063
6305
|
unlinkSync as unlinkSync3
|
|
6064
6306
|
} from "fs";
|
|
6065
6307
|
import { join as join15 } from "path";
|
|
@@ -6095,7 +6337,7 @@ function saveInjectedPaths(sessionID, paths) {
|
|
|
6095
6337
|
injectedPaths: [...paths],
|
|
6096
6338
|
updatedAt: Date.now()
|
|
6097
6339
|
};
|
|
6098
|
-
|
|
6340
|
+
writeFileSync4(getStoragePath(sessionID), JSON.stringify(data, null, 2));
|
|
6099
6341
|
}
|
|
6100
6342
|
function clearInjectedPaths(sessionID) {
|
|
6101
6343
|
const filePath = getStoragePath(sessionID);
|
|
@@ -6231,7 +6473,7 @@ import {
|
|
|
6231
6473
|
existsSync as existsSync13,
|
|
6232
6474
|
mkdirSync as mkdirSync5,
|
|
6233
6475
|
readFileSync as readFileSync7,
|
|
6234
|
-
writeFileSync as
|
|
6476
|
+
writeFileSync as writeFileSync5,
|
|
6235
6477
|
unlinkSync as unlinkSync4
|
|
6236
6478
|
} from "fs";
|
|
6237
6479
|
import { join as join18 } from "path";
|
|
@@ -6267,7 +6509,7 @@ function saveInjectedPaths2(sessionID, paths) {
|
|
|
6267
6509
|
injectedPaths: [...paths],
|
|
6268
6510
|
updatedAt: Date.now()
|
|
6269
6511
|
};
|
|
6270
|
-
|
|
6512
|
+
writeFileSync5(getStoragePath2(sessionID), JSON.stringify(data, null, 2));
|
|
6271
6513
|
}
|
|
6272
6514
|
function clearInjectedPaths2(sessionID) {
|
|
6273
6515
|
const filePath = getStoragePath2(sessionID);
|
|
@@ -6587,10 +6829,6 @@ var RETRY_CONFIG = {
|
|
|
6587
6829
|
backoffFactor: 2,
|
|
6588
6830
|
maxDelayMs: 30000
|
|
6589
6831
|
};
|
|
6590
|
-
var FALLBACK_CONFIG = {
|
|
6591
|
-
maxRevertAttempts: 3,
|
|
6592
|
-
minMessagesRequired: 2
|
|
6593
|
-
};
|
|
6594
6832
|
var TRUNCATE_CONFIG = {
|
|
6595
6833
|
maxTruncateAttempts: 20,
|
|
6596
6834
|
minOutputSizeToTruncate: 500,
|
|
@@ -7011,7 +7249,7 @@ function executePurgeErrors(sessionID, state2, config, protectedTools) {
|
|
|
7011
7249
|
}
|
|
7012
7250
|
|
|
7013
7251
|
// src/hooks/anthropic-context-window-limit-recovery/pruning-storage.ts
|
|
7014
|
-
import { existsSync as existsSync18, readdirSync as readdirSync7, readFileSync as readFileSync12, writeFileSync as
|
|
7252
|
+
import { existsSync as existsSync18, readdirSync as readdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "fs";
|
|
7015
7253
|
import { join as join23 } from "path";
|
|
7016
7254
|
function getMessageDir6(sessionID) {
|
|
7017
7255
|
if (!existsSync18(MESSAGE_STORAGE))
|
|
@@ -7061,7 +7299,7 @@ async function applyPruning(sessionID, state2) {
|
|
|
7061
7299
|
}
|
|
7062
7300
|
}
|
|
7063
7301
|
if (modified) {
|
|
7064
|
-
|
|
7302
|
+
writeFileSync6(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
7065
7303
|
filesModified++;
|
|
7066
7304
|
}
|
|
7067
7305
|
}
|
|
@@ -7161,7 +7399,7 @@ async function executeDynamicContextPruning(sessionID, config, client) {
|
|
|
7161
7399
|
}
|
|
7162
7400
|
|
|
7163
7401
|
// src/hooks/anthropic-context-window-limit-recovery/storage.ts
|
|
7164
|
-
import { existsSync as existsSync19, readdirSync as readdirSync8, readFileSync as readFileSync13, writeFileSync as
|
|
7402
|
+
import { existsSync as existsSync19, readdirSync as readdirSync8, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "fs";
|
|
7165
7403
|
import { join as join24 } from "path";
|
|
7166
7404
|
var OPENCODE_STORAGE5 = getOpenCodeStorageDir();
|
|
7167
7405
|
var MESSAGE_STORAGE3 = join24(OPENCODE_STORAGE5, "message");
|
|
@@ -7245,7 +7483,7 @@ function truncateToolResult(partPath) {
|
|
|
7245
7483
|
part.state.time = { start: Date.now() };
|
|
7246
7484
|
}
|
|
7247
7485
|
part.state.time.compacted = Date.now();
|
|
7248
|
-
|
|
7486
|
+
writeFileSync7(partPath, JSON.stringify(part, null, 2));
|
|
7249
7487
|
return { success: true, toolName, originalSize };
|
|
7250
7488
|
} catch {
|
|
7251
7489
|
return { success: false };
|
|
@@ -7312,14 +7550,6 @@ function getOrCreateRetryState(autoCompactState, sessionID) {
|
|
|
7312
7550
|
}
|
|
7313
7551
|
return state2;
|
|
7314
7552
|
}
|
|
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
7553
|
function getOrCreateTruncateState(autoCompactState, sessionID) {
|
|
7324
7554
|
let state2 = autoCompactState.truncateStateBySession.get(sessionID);
|
|
7325
7555
|
if (!state2) {
|
|
@@ -7362,43 +7592,6 @@ function sanitizeEmptyMessagesBeforeSummarize(sessionID) {
|
|
|
7362
7592
|
}
|
|
7363
7593
|
return fixedCount;
|
|
7364
7594
|
}
|
|
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
7595
|
function formatBytes(bytes) {
|
|
7403
7596
|
if (bytes < 1024)
|
|
7404
7597
|
return `${bytes}B`;
|
|
@@ -7432,7 +7625,6 @@ function clearSessionState(autoCompactState, sessionID) {
|
|
|
7432
7625
|
autoCompactState.pendingCompact.delete(sessionID);
|
|
7433
7626
|
autoCompactState.errorDataBySession.delete(sessionID);
|
|
7434
7627
|
autoCompactState.retryStateBySession.delete(sessionID);
|
|
7435
|
-
autoCompactState.fallbackStateBySession.delete(sessionID);
|
|
7436
7628
|
autoCompactState.truncateStateBySession.delete(sessionID);
|
|
7437
7629
|
autoCompactState.dcpStateBySession.delete(sessionID);
|
|
7438
7630
|
autoCompactState.emptyContentAttemptBySession.delete(sessionID);
|
|
@@ -7704,7 +7896,6 @@ async function executeCompact(sessionID, msg, autoCompactState, client, director
|
|
|
7704
7896
|
}
|
|
7705
7897
|
if (Date.now() - retryState.lastAttemptTime > 300000) {
|
|
7706
7898
|
retryState.attempt = 0;
|
|
7707
|
-
autoCompactState.fallbackStateBySession.delete(sessionID);
|
|
7708
7899
|
autoCompactState.truncateStateBySession.delete(sessionID);
|
|
7709
7900
|
}
|
|
7710
7901
|
if (!skipSummarize && retryState.attempt < RETRY_CONFIG.maxAttempts) {
|
|
@@ -7750,57 +7941,7 @@ async function executeCompact(sessionID, msg, autoCompactState, client, director
|
|
|
7750
7941
|
await client.tui.showToast({
|
|
7751
7942
|
body: {
|
|
7752
7943
|
title: "Summarize Skipped",
|
|
7753
|
-
message: "Missing providerID or modelID.
|
|
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.",
|
|
7944
|
+
message: "Missing providerID or modelID.",
|
|
7804
7945
|
variant: "warning",
|
|
7805
7946
|
duration: 3000
|
|
7806
7947
|
}
|
|
@@ -7827,7 +7968,6 @@ function createRecoveryState() {
|
|
|
7827
7968
|
pendingCompact: new Set,
|
|
7828
7969
|
errorDataBySession: new Map,
|
|
7829
7970
|
retryStateBySession: new Map,
|
|
7830
|
-
fallbackStateBySession: new Map,
|
|
7831
7971
|
truncateStateBySession: new Map,
|
|
7832
7972
|
dcpStateBySession: new Map,
|
|
7833
7973
|
emptyContentAttemptBySession: new Map,
|
|
@@ -7846,7 +7986,6 @@ function createAnthropicContextWindowLimitRecoveryHook(ctx, options) {
|
|
|
7846
7986
|
autoCompactState.pendingCompact.delete(sessionInfo.id);
|
|
7847
7987
|
autoCompactState.errorDataBySession.delete(sessionInfo.id);
|
|
7848
7988
|
autoCompactState.retryStateBySession.delete(sessionInfo.id);
|
|
7849
|
-
autoCompactState.fallbackStateBySession.delete(sessionInfo.id);
|
|
7850
7989
|
autoCompactState.truncateStateBySession.delete(sessionInfo.id);
|
|
7851
7990
|
autoCompactState.dcpStateBySession.delete(sessionInfo.id);
|
|
7852
7991
|
autoCompactState.emptyContentAttemptBySession.delete(sessionInfo.id);
|
|
@@ -7967,9 +8106,9 @@ function createPreemptiveCompactionHook(ctx, options) {
|
|
|
7967
8106
|
const experimental = options?.experimental;
|
|
7968
8107
|
const onBeforeSummarize = options?.onBeforeSummarize;
|
|
7969
8108
|
const getModelLimit = options?.getModelLimit;
|
|
7970
|
-
const
|
|
8109
|
+
const explicitlyDisabled = experimental?.preemptive_compaction === false;
|
|
7971
8110
|
const threshold = experimental?.preemptive_compaction_threshold ?? DEFAULT_THRESHOLD;
|
|
7972
|
-
if (
|
|
8111
|
+
if (explicitlyDisabled) {
|
|
7973
8112
|
return { event: async () => {} };
|
|
7974
8113
|
}
|
|
7975
8114
|
const state2 = createState();
|
|
@@ -8711,7 +8850,7 @@ async function executePreToolUseHooks(ctx, config, extendedConfig) {
|
|
|
8711
8850
|
|
|
8712
8851
|
// src/hooks/claude-code-hooks/transcript.ts
|
|
8713
8852
|
import { join as join28 } from "path";
|
|
8714
|
-
import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync23, writeFileSync as
|
|
8853
|
+
import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync23, writeFileSync as writeFileSync8, unlinkSync as unlinkSync5 } from "fs";
|
|
8715
8854
|
import { tmpdir as tmpdir5 } from "os";
|
|
8716
8855
|
import { randomUUID } from "crypto";
|
|
8717
8856
|
var TRANSCRIPT_DIR = join28(getClaudeConfigDir(), "transcripts");
|
|
@@ -8807,7 +8946,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
|
|
|
8807
8946
|
};
|
|
8808
8947
|
entries.push(JSON.stringify(currentEntry));
|
|
8809
8948
|
const tempPath = join28(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
|
|
8810
|
-
|
|
8949
|
+
writeFileSync8(tempPath, entries.join(`
|
|
8811
8950
|
`) + `
|
|
8812
8951
|
`);
|
|
8813
8952
|
return tempPath;
|
|
@@ -8827,7 +8966,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
|
|
|
8827
8966
|
}
|
|
8828
8967
|
};
|
|
8829
8968
|
const tempPath = join28(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
|
|
8830
|
-
|
|
8969
|
+
writeFileSync8(tempPath, JSON.stringify(currentEntry) + `
|
|
8831
8970
|
`);
|
|
8832
8971
|
return tempPath;
|
|
8833
8972
|
} catch {
|
|
@@ -9768,7 +9907,7 @@ import {
|
|
|
9768
9907
|
existsSync as existsSync25,
|
|
9769
9908
|
mkdirSync as mkdirSync7,
|
|
9770
9909
|
readFileSync as readFileSync14,
|
|
9771
|
-
writeFileSync as
|
|
9910
|
+
writeFileSync as writeFileSync9,
|
|
9772
9911
|
unlinkSync as unlinkSync6
|
|
9773
9912
|
} from "fs";
|
|
9774
9913
|
import { join as join32 } from "path";
|
|
@@ -9800,7 +9939,7 @@ function saveInjectedRules(sessionID, data) {
|
|
|
9800
9939
|
injectedRealPaths: [...data.realPaths],
|
|
9801
9940
|
updatedAt: Date.now()
|
|
9802
9941
|
};
|
|
9803
|
-
|
|
9942
|
+
writeFileSync9(getStoragePath3(sessionID), JSON.stringify(storageData, null, 2));
|
|
9804
9943
|
}
|
|
9805
9944
|
function clearInjectedRules(sessionID) {
|
|
9806
9945
|
const filePath = getStoragePath3(sessionID);
|
|
@@ -9948,7 +10087,7 @@ function createBackgroundNotificationHook(manager) {
|
|
|
9948
10087
|
};
|
|
9949
10088
|
}
|
|
9950
10089
|
// src/hooks/auto-update-checker/checker.ts
|
|
9951
|
-
import * as
|
|
10090
|
+
import * as fs6 from "fs";
|
|
9952
10091
|
import * as path5 from "path";
|
|
9953
10092
|
import { fileURLToPath } from "url";
|
|
9954
10093
|
|
|
@@ -9992,9 +10131,9 @@ function getConfigPaths(directory) {
|
|
|
9992
10131
|
function getLocalDevPath(directory) {
|
|
9993
10132
|
for (const configPath of getConfigPaths(directory)) {
|
|
9994
10133
|
try {
|
|
9995
|
-
if (!
|
|
10134
|
+
if (!fs6.existsSync(configPath))
|
|
9996
10135
|
continue;
|
|
9997
|
-
const content =
|
|
10136
|
+
const content = fs6.readFileSync(configPath, "utf-8");
|
|
9998
10137
|
const config = JSON.parse(stripJsonComments(content));
|
|
9999
10138
|
const plugins = config.plugin ?? [];
|
|
10000
10139
|
for (const entry of plugins) {
|
|
@@ -10014,13 +10153,13 @@ function getLocalDevPath(directory) {
|
|
|
10014
10153
|
}
|
|
10015
10154
|
function findPackageJsonUp(startPath) {
|
|
10016
10155
|
try {
|
|
10017
|
-
const stat =
|
|
10156
|
+
const stat = fs6.statSync(startPath);
|
|
10018
10157
|
let dir = stat.isDirectory() ? startPath : path5.dirname(startPath);
|
|
10019
10158
|
for (let i = 0;i < 10; i++) {
|
|
10020
10159
|
const pkgPath = path5.join(dir, "package.json");
|
|
10021
|
-
if (
|
|
10160
|
+
if (fs6.existsSync(pkgPath)) {
|
|
10022
10161
|
try {
|
|
10023
|
-
const content =
|
|
10162
|
+
const content = fs6.readFileSync(pkgPath, "utf-8");
|
|
10024
10163
|
const pkg = JSON.parse(content);
|
|
10025
10164
|
if (pkg.name === PACKAGE_NAME)
|
|
10026
10165
|
return pkgPath;
|
|
@@ -10042,7 +10181,7 @@ function getLocalDevVersion(directory) {
|
|
|
10042
10181
|
const pkgPath = findPackageJsonUp(localPath);
|
|
10043
10182
|
if (!pkgPath)
|
|
10044
10183
|
return null;
|
|
10045
|
-
const content =
|
|
10184
|
+
const content = fs6.readFileSync(pkgPath, "utf-8");
|
|
10046
10185
|
const pkg = JSON.parse(content);
|
|
10047
10186
|
return pkg.version ?? null;
|
|
10048
10187
|
} catch {
|
|
@@ -10052,9 +10191,9 @@ function getLocalDevVersion(directory) {
|
|
|
10052
10191
|
function findPluginEntry(directory) {
|
|
10053
10192
|
for (const configPath of getConfigPaths(directory)) {
|
|
10054
10193
|
try {
|
|
10055
|
-
if (!
|
|
10194
|
+
if (!fs6.existsSync(configPath))
|
|
10056
10195
|
continue;
|
|
10057
|
-
const content =
|
|
10196
|
+
const content = fs6.readFileSync(configPath, "utf-8");
|
|
10058
10197
|
const config = JSON.parse(stripJsonComments(content));
|
|
10059
10198
|
const plugins = config.plugin ?? [];
|
|
10060
10199
|
for (const entry of plugins) {
|
|
@@ -10075,8 +10214,8 @@ function findPluginEntry(directory) {
|
|
|
10075
10214
|
}
|
|
10076
10215
|
function getCachedVersion() {
|
|
10077
10216
|
try {
|
|
10078
|
-
if (
|
|
10079
|
-
const content =
|
|
10217
|
+
if (fs6.existsSync(INSTALLED_PACKAGE_JSON)) {
|
|
10218
|
+
const content = fs6.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
|
|
10080
10219
|
const pkg = JSON.parse(content);
|
|
10081
10220
|
if (pkg.version)
|
|
10082
10221
|
return pkg.version;
|
|
@@ -10086,7 +10225,7 @@ function getCachedVersion() {
|
|
|
10086
10225
|
const currentDir = path5.dirname(fileURLToPath(import.meta.url));
|
|
10087
10226
|
const pkgPath = findPackageJsonUp(currentDir);
|
|
10088
10227
|
if (pkgPath) {
|
|
10089
|
-
const content =
|
|
10228
|
+
const content = fs6.readFileSync(pkgPath, "utf-8");
|
|
10090
10229
|
const pkg = JSON.parse(content);
|
|
10091
10230
|
if (pkg.version)
|
|
10092
10231
|
return pkg.version;
|
|
@@ -10098,7 +10237,7 @@ function getCachedVersion() {
|
|
|
10098
10237
|
}
|
|
10099
10238
|
function updatePinnedVersion(configPath, oldEntry, newVersion) {
|
|
10100
10239
|
try {
|
|
10101
|
-
const content =
|
|
10240
|
+
const content = fs6.readFileSync(configPath, "utf-8");
|
|
10102
10241
|
const newEntry = `${PACKAGE_NAME}@${newVersion}`;
|
|
10103
10242
|
const pluginMatch = content.match(/"plugin"\s*:\s*\[/);
|
|
10104
10243
|
if (!pluginMatch || pluginMatch.index === undefined) {
|
|
@@ -10130,7 +10269,7 @@ function updatePinnedVersion(configPath, oldEntry, newVersion) {
|
|
|
10130
10269
|
log(`[auto-update-checker] No changes made to ${configPath}`);
|
|
10131
10270
|
return false;
|
|
10132
10271
|
}
|
|
10133
|
-
|
|
10272
|
+
fs6.writeFileSync(configPath, updatedContent, "utf-8");
|
|
10134
10273
|
log(`[auto-update-checker] Updated ${configPath}: ${oldEntry} \u2192 ${newEntry}`);
|
|
10135
10274
|
return true;
|
|
10136
10275
|
} catch (err) {
|
|
@@ -10158,17 +10297,17 @@ async function getLatestVersion() {
|
|
|
10158
10297
|
}
|
|
10159
10298
|
|
|
10160
10299
|
// src/hooks/auto-update-checker/cache.ts
|
|
10161
|
-
import * as
|
|
10300
|
+
import * as fs7 from "fs";
|
|
10162
10301
|
import * as path6 from "path";
|
|
10163
10302
|
function stripTrailingCommas(json) {
|
|
10164
10303
|
return json.replace(/,(\s*[}\]])/g, "$1");
|
|
10165
10304
|
}
|
|
10166
10305
|
function removeFromBunLock(packageName) {
|
|
10167
10306
|
const lockPath = path6.join(CACHE_DIR, "bun.lock");
|
|
10168
|
-
if (!
|
|
10307
|
+
if (!fs7.existsSync(lockPath))
|
|
10169
10308
|
return false;
|
|
10170
10309
|
try {
|
|
10171
|
-
const content =
|
|
10310
|
+
const content = fs7.readFileSync(lockPath, "utf-8");
|
|
10172
10311
|
const lock = JSON.parse(stripTrailingCommas(content));
|
|
10173
10312
|
let modified = false;
|
|
10174
10313
|
if (lock.workspaces?.[""]?.dependencies?.[packageName]) {
|
|
@@ -10180,7 +10319,7 @@ function removeFromBunLock(packageName) {
|
|
|
10180
10319
|
modified = true;
|
|
10181
10320
|
}
|
|
10182
10321
|
if (modified) {
|
|
10183
|
-
|
|
10322
|
+
fs7.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
|
|
10184
10323
|
log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
|
|
10185
10324
|
}
|
|
10186
10325
|
return modified;
|
|
@@ -10195,17 +10334,17 @@ function invalidatePackage(packageName = PACKAGE_NAME) {
|
|
|
10195
10334
|
let packageRemoved = false;
|
|
10196
10335
|
let dependencyRemoved = false;
|
|
10197
10336
|
let lockRemoved = false;
|
|
10198
|
-
if (
|
|
10199
|
-
|
|
10337
|
+
if (fs7.existsSync(pkgDir)) {
|
|
10338
|
+
fs7.rmSync(pkgDir, { recursive: true, force: true });
|
|
10200
10339
|
log(`[auto-update-checker] Package removed: ${pkgDir}`);
|
|
10201
10340
|
packageRemoved = true;
|
|
10202
10341
|
}
|
|
10203
|
-
if (
|
|
10204
|
-
const content =
|
|
10342
|
+
if (fs7.existsSync(pkgJsonPath)) {
|
|
10343
|
+
const content = fs7.readFileSync(pkgJsonPath, "utf-8");
|
|
10205
10344
|
const pkgJson = JSON.parse(content);
|
|
10206
10345
|
if (pkgJson.dependencies?.[packageName]) {
|
|
10207
10346
|
delete pkgJson.dependencies[packageName];
|
|
10208
|
-
|
|
10347
|
+
fs7.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
|
|
10209
10348
|
log(`[auto-update-checker] Dependency removed from package.json: ${packageName}`);
|
|
10210
10349
|
dependencyRemoved = true;
|
|
10211
10350
|
}
|
|
@@ -10382,7 +10521,7 @@ import {
|
|
|
10382
10521
|
existsSync as existsSync28,
|
|
10383
10522
|
mkdirSync as mkdirSync8,
|
|
10384
10523
|
readFileSync as readFileSync18,
|
|
10385
|
-
writeFileSync as
|
|
10524
|
+
writeFileSync as writeFileSync12,
|
|
10386
10525
|
unlinkSync as unlinkSync7
|
|
10387
10526
|
} from "fs";
|
|
10388
10527
|
import { join as join37 } from "path";
|
|
@@ -10453,7 +10592,7 @@ function saveAgentUsageState(state2) {
|
|
|
10453
10592
|
mkdirSync8(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
|
|
10454
10593
|
}
|
|
10455
10594
|
const filePath = getStoragePath4(state2.sessionID);
|
|
10456
|
-
|
|
10595
|
+
writeFileSync12(filePath, JSON.stringify(state2, null, 2));
|
|
10457
10596
|
}
|
|
10458
10597
|
function clearAgentUsageState(sessionID) {
|
|
10459
10598
|
const filePath = getStoragePath4(sessionID);
|
|
@@ -10766,7 +10905,7 @@ import {
|
|
|
10766
10905
|
existsSync as existsSync29,
|
|
10767
10906
|
mkdirSync as mkdirSync9,
|
|
10768
10907
|
readFileSync as readFileSync19,
|
|
10769
|
-
writeFileSync as
|
|
10908
|
+
writeFileSync as writeFileSync13,
|
|
10770
10909
|
unlinkSync as unlinkSync8
|
|
10771
10910
|
} from "fs";
|
|
10772
10911
|
import { join as join39 } from "path";
|
|
@@ -10814,7 +10953,7 @@ function saveInteractiveBashSessionState(state2) {
|
|
|
10814
10953
|
tmuxSessions: Array.from(state2.tmuxSessions),
|
|
10815
10954
|
updatedAt: state2.updatedAt
|
|
10816
10955
|
};
|
|
10817
|
-
|
|
10956
|
+
writeFileSync13(filePath, JSON.stringify(serialized, null, 2));
|
|
10818
10957
|
}
|
|
10819
10958
|
function clearInteractiveBashSessionState(sessionID) {
|
|
10820
10959
|
const filePath = getStoragePath5(sessionID);
|
|
@@ -11152,7 +11291,7 @@ function createThinkingBlockValidatorHook() {
|
|
|
11152
11291
|
import { existsSync as existsSync31, readFileSync as readFileSync21 } from "fs";
|
|
11153
11292
|
|
|
11154
11293
|
// src/hooks/ralph-loop/storage.ts
|
|
11155
|
-
import { existsSync as existsSync30, readFileSync as readFileSync20, writeFileSync as
|
|
11294
|
+
import { existsSync as existsSync30, readFileSync as readFileSync20, writeFileSync as writeFileSync14, unlinkSync as unlinkSync9, mkdirSync as mkdirSync10 } from "fs";
|
|
11156
11295
|
import { dirname as dirname6, join as join40 } from "path";
|
|
11157
11296
|
|
|
11158
11297
|
// src/hooks/ralph-loop/constants.ts
|
|
@@ -11218,7 +11357,7 @@ started_at: "${state2.started_at}"
|
|
|
11218
11357
|
${sessionIdLine}---
|
|
11219
11358
|
${state2.prompt}
|
|
11220
11359
|
`;
|
|
11221
|
-
|
|
11360
|
+
writeFileSync14(filePath, content, "utf-8");
|
|
11222
11361
|
return true;
|
|
11223
11362
|
} catch {
|
|
11224
11363
|
return false;
|
|
@@ -13319,7 +13458,8 @@ $ARGUMENTS
|
|
|
13319
13458
|
function commandsToRecord(commands) {
|
|
13320
13459
|
const result = {};
|
|
13321
13460
|
for (const cmd of commands) {
|
|
13322
|
-
|
|
13461
|
+
const { name: _name, argumentHint: _argumentHint, ...openCodeCompatible } = cmd.definition;
|
|
13462
|
+
result[cmd.name] = openCodeCompatible;
|
|
13323
13463
|
}
|
|
13324
13464
|
return result;
|
|
13325
13465
|
}
|
|
@@ -13345,208 +13485,194 @@ function loadOpencodeProjectCommands() {
|
|
|
13345
13485
|
return commandsToRecord(commands);
|
|
13346
13486
|
}
|
|
13347
13487
|
// src/features/builtin-commands/templates/init-deep.ts
|
|
13348
|
-
var INIT_DEEP_TEMPLATE = `#
|
|
13488
|
+
var INIT_DEEP_TEMPLATE = `# /init-deep
|
|
13349
13489
|
|
|
13350
|
-
Generate
|
|
13490
|
+
Generate hierarchical AGENTS.md files. Root + complexity-scored subdirectories.
|
|
13351
13491
|
|
|
13352
13492
|
## Usage
|
|
13353
13493
|
|
|
13354
13494
|
\`\`\`
|
|
13355
|
-
/init-deep #
|
|
13356
|
-
/init-deep --create-new #
|
|
13357
|
-
/init-deep --max-depth=2 # Limit
|
|
13495
|
+
/init-deep # Update mode: modify existing + create new where warranted
|
|
13496
|
+
/init-deep --create-new # Read existing \u2192 remove all \u2192 regenerate from scratch
|
|
13497
|
+
/init-deep --max-depth=2 # Limit directory depth (default: 3)
|
|
13358
13498
|
\`\`\`
|
|
13359
13499
|
|
|
13360
13500
|
---
|
|
13361
13501
|
|
|
13362
|
-
##
|
|
13363
|
-
|
|
13364
|
-
- **Telegraphic Style**: Sacrifice grammar for concision ("Project uses React" \u2192 "React 18")
|
|
13365
|
-
- **Predict-then-Compare**: Predict standard \u2192 find actual \u2192 document ONLY deviations
|
|
13366
|
-
- **Hierarchy Aware**: Parent covers general, children cover specific
|
|
13367
|
-
- **No Redundancy**: Child AGENTS.md NEVER repeats parent content
|
|
13368
|
-
- **LSP-First**: Use LSP tools for accurate code intelligence when available (semantic > text search)
|
|
13369
|
-
|
|
13370
|
-
---
|
|
13502
|
+
## Workflow (High-Level)
|
|
13371
13503
|
|
|
13372
|
-
|
|
13504
|
+
1. **Discovery + Analysis** (concurrent)
|
|
13505
|
+
- Fire background explore agents immediately
|
|
13506
|
+
- Main session: bash structure + LSP codemap + read existing AGENTS.md
|
|
13507
|
+
2. **Score & Decide** - Determine AGENTS.md locations from merged findings
|
|
13508
|
+
3. **Generate** - Root first, then subdirs in parallel
|
|
13509
|
+
4. **Review** - Deduplicate, trim, validate
|
|
13373
13510
|
|
|
13374
13511
|
<critical>
|
|
13375
|
-
**
|
|
13376
|
-
</critical>
|
|
13377
|
-
|
|
13378
|
-
### Phase 0: Initialize
|
|
13379
|
-
|
|
13512
|
+
**TodoWrite ALL phases. Mark in_progress \u2192 completed in real-time.**
|
|
13380
13513
|
\`\`\`
|
|
13381
13514
|
TodoWrite([
|
|
13382
|
-
{ id: "
|
|
13383
|
-
{ id: "
|
|
13384
|
-
{ id: "
|
|
13385
|
-
{ id: "
|
|
13386
|
-
{ id: "p5-review", content: "Review, deduplicate, validate all files", status: "pending", priority: "medium" }
|
|
13515
|
+
{ id: "discovery", content: "Fire explore agents + LSP codemap + read existing", status: "pending", priority: "high" },
|
|
13516
|
+
{ id: "scoring", content: "Score directories, determine locations", status: "pending", priority: "high" },
|
|
13517
|
+
{ id: "generate", content: "Generate AGENTS.md files (root + subdirs)", status: "pending", priority: "high" },
|
|
13518
|
+
{ id: "review", content: "Deduplicate, validate, trim", status: "pending", priority: "medium" }
|
|
13387
13519
|
])
|
|
13388
13520
|
\`\`\`
|
|
13521
|
+
</critical>
|
|
13389
13522
|
|
|
13390
13523
|
---
|
|
13391
13524
|
|
|
13392
|
-
## Phase 1:
|
|
13525
|
+
## Phase 1: Discovery + Analysis (Concurrent)
|
|
13393
13526
|
|
|
13394
|
-
**Mark "
|
|
13527
|
+
**Mark "discovery" as in_progress.**
|
|
13395
13528
|
|
|
13396
|
-
|
|
13529
|
+
### Fire Background Explore Agents IMMEDIATELY
|
|
13397
13530
|
|
|
13398
|
-
|
|
13531
|
+
Don't wait\u2014these run async while main session works.
|
|
13399
13532
|
|
|
13400
|
-
|
|
13401
|
-
|
|
13402
|
-
|
|
13403
|
-
|
|
13533
|
+
\`\`\`
|
|
13534
|
+
// Fire all at once, collect results later
|
|
13535
|
+
background_task(agent="explore", prompt="Project structure: PREDICT standard patterns for detected language \u2192 REPORT deviations only")
|
|
13536
|
+
background_task(agent="explore", prompt="Entry points: FIND main files \u2192 REPORT non-standard organization")
|
|
13537
|
+
background_task(agent="explore", prompt="Conventions: FIND config files (.eslintrc, pyproject.toml, .editorconfig) \u2192 REPORT project-specific rules")
|
|
13538
|
+
background_task(agent="explore", prompt="Anti-patterns: FIND 'DO NOT', 'NEVER', 'ALWAYS', 'DEPRECATED' comments \u2192 LIST forbidden patterns")
|
|
13539
|
+
background_task(agent="explore", prompt="Build/CI: FIND .github/workflows, Makefile \u2192 REPORT non-standard patterns")
|
|
13540
|
+
background_task(agent="explore", prompt="Test patterns: FIND test configs, test structure \u2192 REPORT unique conventions")
|
|
13541
|
+
\`\`\`
|
|
13404
13542
|
|
|
13405
|
-
|
|
13406
|
-
|
|
13543
|
+
<dynamic-agents>
|
|
13544
|
+
**DYNAMIC AGENT SPAWNING**: After bash analysis, spawn ADDITIONAL explore agents based on project scale:
|
|
13407
13545
|
|
|
13408
|
-
|
|
13409
|
-
|
|
13546
|
+
| Factor | Threshold | Additional Agents |
|
|
13547
|
+
|--------|-----------|-------------------|
|
|
13548
|
+
| **Total files** | >100 | +1 per 100 files |
|
|
13549
|
+
| **Total lines** | >10k | +1 per 10k lines |
|
|
13550
|
+
| **Directory depth** | \u22654 | +2 for deep exploration |
|
|
13551
|
+
| **Large files (>500 lines)** | >10 files | +1 for complexity hotspots |
|
|
13552
|
+
| **Monorepo** | detected | +1 per package/workspace |
|
|
13553
|
+
| **Multiple languages** | >1 | +1 per language |
|
|
13410
13554
|
|
|
13411
|
-
|
|
13412
|
-
|
|
13555
|
+
\`\`\`bash
|
|
13556
|
+
# Measure project scale first
|
|
13557
|
+
total_files=$(find . -type f -not -path '*/node_modules/*' -not -path '*/.git/*' | wc -l)
|
|
13558
|
+
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}')
|
|
13559
|
+
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}')
|
|
13560
|
+
max_depth=$(find . -type d -not -path '*/node_modules/*' -not -path '*/.git/*' | awk -F/ '{print NF}' | sort -rn | head -1)
|
|
13413
13561
|
\`\`\`
|
|
13414
13562
|
|
|
13415
|
-
|
|
13416
|
-
|
|
13563
|
+
Example spawning:
|
|
13417
13564
|
\`\`\`
|
|
13418
|
-
|
|
13419
|
-
|
|
13420
|
-
background_task(agent="explore", prompt="
|
|
13565
|
+
// 500 files, 50k lines, depth 6, 15 large files \u2192 spawn 5+5+2+1 = 13 additional agents
|
|
13566
|
+
background_task(agent="explore", prompt="Large file analysis: FIND files >500 lines, REPORT complexity hotspots")
|
|
13567
|
+
background_task(agent="explore", prompt="Deep modules at depth 4+: FIND hidden patterns, internal conventions")
|
|
13568
|
+
background_task(agent="explore", prompt="Cross-cutting concerns: FIND shared utilities across directories")
|
|
13569
|
+
// ... more based on calculation
|
|
13570
|
+
\`\`\`
|
|
13571
|
+
</dynamic-agents>
|
|
13421
13572
|
|
|
13422
|
-
|
|
13573
|
+
### Main Session: Concurrent Analysis
|
|
13423
13574
|
|
|
13424
|
-
|
|
13575
|
+
**While background agents run**, main session does:
|
|
13425
13576
|
|
|
13426
|
-
|
|
13577
|
+
#### 1. Bash Structural Analysis
|
|
13578
|
+
\`\`\`bash
|
|
13579
|
+
# Directory depth + file counts
|
|
13580
|
+
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
|
|
13427
13581
|
|
|
13428
|
-
|
|
13429
|
-
|
|
13582
|
+
# Files per directory (top 30)
|
|
13583
|
+
find . -type f -not -path '*/\\.*' -not -path '*/node_modules/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -30
|
|
13430
13584
|
|
|
13431
|
-
|
|
13585
|
+
# Code concentration by extension
|
|
13586
|
+
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
|
|
13432
13587
|
|
|
13433
|
-
|
|
13588
|
+
# Existing AGENTS.md / CLAUDE.md
|
|
13589
|
+
find . -type f \\( -name "AGENTS.md" -o -name "CLAUDE.md" \\) -not -path '*/node_modules/*' 2>/dev/null
|
|
13590
|
+
\`\`\`
|
|
13434
13591
|
|
|
13592
|
+
#### 2. Read Existing AGENTS.md
|
|
13435
13593
|
\`\`\`
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
# Find entry points first, then analyze each with lsp_document_symbols
|
|
13441
|
-
lsp_document_symbols(filePath="src/index.ts") # Main entry
|
|
13442
|
-
lsp_document_symbols(filePath="src/main.py") # Python entry
|
|
13443
|
-
lsp_document_symbols(filePath="cmd/main.go") # Go entry
|
|
13444
|
-
|
|
13445
|
-
# Step 3: Discover key symbols across workspace (run in parallel)
|
|
13446
|
-
lsp_workspace_symbols(filePath=".", query="class") # All classes
|
|
13447
|
-
lsp_workspace_symbols(filePath=".", query="interface") # All interfaces
|
|
13448
|
-
lsp_workspace_symbols(filePath=".", query="function") # Top-level functions
|
|
13449
|
-
lsp_workspace_symbols(filePath=".", query="type") # Type definitions
|
|
13450
|
-
|
|
13451
|
-
# Step 4: Analyze symbol centrality (for top 5-10 key symbols)
|
|
13452
|
-
# High reference count = central/important concept
|
|
13453
|
-
lsp_find_references(filePath="src/index.ts", line=X, character=Y) # Main export
|
|
13594
|
+
For each existing file found:
|
|
13595
|
+
Read(filePath=file)
|
|
13596
|
+
Extract: key insights, conventions, anti-patterns
|
|
13597
|
+
Store in EXISTING_AGENTS map
|
|
13454
13598
|
\`\`\`
|
|
13455
13599
|
|
|
13456
|
-
|
|
13600
|
+
If \`--create-new\`: Read all existing first (preserve context) \u2192 then delete all \u2192 regenerate.
|
|
13457
13601
|
|
|
13602
|
+
#### 3. LSP Codemap (if available)
|
|
13458
13603
|
\`\`\`
|
|
13459
|
-
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13467
|
-
|
|
13468
|
-
|
|
13469
|
-
|
|
13470
|
-
|
|
13471
|
-
|
|
13604
|
+
lsp_servers() # Check availability
|
|
13605
|
+
|
|
13606
|
+
# Entry points (parallel)
|
|
13607
|
+
lsp_document_symbols(filePath="src/index.ts")
|
|
13608
|
+
lsp_document_symbols(filePath="main.py")
|
|
13609
|
+
|
|
13610
|
+
# Key symbols (parallel)
|
|
13611
|
+
lsp_workspace_symbols(filePath=".", query="class")
|
|
13612
|
+
lsp_workspace_symbols(filePath=".", query="interface")
|
|
13613
|
+
lsp_workspace_symbols(filePath=".", query="function")
|
|
13614
|
+
|
|
13615
|
+
# Centrality for top exports
|
|
13616
|
+
lsp_find_references(filePath="...", line=X, character=Y)
|
|
13472
13617
|
\`\`\`
|
|
13473
13618
|
|
|
13474
|
-
|
|
13475
|
-
**LSP Fallback**: If LSP unavailable (no server installed), skip this section and rely on explore agents + AST-grep patterns.
|
|
13476
|
-
</critical>
|
|
13619
|
+
**LSP Fallback**: If unavailable, rely on explore agents + AST-grep.
|
|
13477
13620
|
|
|
13478
|
-
|
|
13621
|
+
### Collect Background Results
|
|
13479
13622
|
|
|
13480
|
-
|
|
13623
|
+
\`\`\`
|
|
13624
|
+
// After main session analysis done, collect all task results
|
|
13625
|
+
for each task_id: background_output(task_id="...")
|
|
13626
|
+
\`\`\`
|
|
13627
|
+
|
|
13628
|
+
**Merge: bash + LSP + existing + explore findings. Mark "discovery" as completed.**
|
|
13481
13629
|
|
|
13482
13630
|
---
|
|
13483
13631
|
|
|
13484
|
-
## Phase 2:
|
|
13632
|
+
## Phase 2: Scoring & Location Decision
|
|
13485
13633
|
|
|
13486
|
-
**Mark "
|
|
13634
|
+
**Mark "scoring" as in_progress.**
|
|
13487
13635
|
|
|
13488
13636
|
### Scoring Matrix
|
|
13489
13637
|
|
|
13490
|
-
| Factor | Weight | Threshold | Source |
|
|
13491
|
-
|
|
13492
|
-
| File count | 3x | >20
|
|
13493
|
-
|
|
|
13494
|
-
| Code
|
|
13638
|
+
| Factor | Weight | High Threshold | Source |
|
|
13639
|
+
|--------|--------|----------------|--------|
|
|
13640
|
+
| File count | 3x | >20 | bash |
|
|
13641
|
+
| Subdir count | 2x | >5 | bash |
|
|
13642
|
+
| Code ratio | 2x | >70% | bash |
|
|
13495
13643
|
| Unique patterns | 1x | Has own config | explore |
|
|
13496
|
-
| Module boundary | 2x | Has __init__.py
|
|
13497
|
-
|
|
|
13498
|
-
|
|
|
13499
|
-
|
|
|
13500
|
-
|
|
13501
|
-
<lsp-scoring>
|
|
13502
|
-
**LSP-Enhanced Scoring** (if available):
|
|
13503
|
-
|
|
13504
|
-
\`\`\`
|
|
13505
|
-
For each directory in candidates:
|
|
13506
|
-
symbols = lsp_document_symbols(dir/index.ts or dir/__init__.py)
|
|
13507
|
-
|
|
13508
|
-
symbol_score = len(symbols) > 30 ? 6 : len(symbols) > 15 ? 3 : 0
|
|
13509
|
-
export_score = count(exported symbols) > 10 ? 4 : 0
|
|
13510
|
-
|
|
13511
|
-
# Check if this module is central (many things depend on it)
|
|
13512
|
-
for each exported symbol:
|
|
13513
|
-
refs = lsp_find_references(symbol)
|
|
13514
|
-
if refs > 20: centrality_score += 3
|
|
13515
|
-
|
|
13516
|
-
total_score += symbol_score + export_score + centrality_score
|
|
13517
|
-
\`\`\`
|
|
13518
|
-
</lsp-scoring>
|
|
13644
|
+
| Module boundary | 2x | Has index.ts/__init__.py | bash |
|
|
13645
|
+
| Symbol density | 2x | >30 symbols | LSP |
|
|
13646
|
+
| Export count | 2x | >10 exports | LSP |
|
|
13647
|
+
| Reference centrality | 3x | >20 refs | LSP |
|
|
13519
13648
|
|
|
13520
13649
|
### Decision Rules
|
|
13521
13650
|
|
|
13522
13651
|
| Score | Action |
|
|
13523
13652
|
|-------|--------|
|
|
13524
|
-
| **Root (.)** | ALWAYS create
|
|
13525
|
-
|
|
|
13526
|
-
| **
|
|
13527
|
-
|
|
|
13528
|
-
|
|
13529
|
-
### Output Format
|
|
13653
|
+
| **Root (.)** | ALWAYS create |
|
|
13654
|
+
| **>15** | Create AGENTS.md |
|
|
13655
|
+
| **8-15** | Create if distinct domain |
|
|
13656
|
+
| **<8** | Skip (parent covers) |
|
|
13530
13657
|
|
|
13658
|
+
### Output
|
|
13531
13659
|
\`\`\`
|
|
13532
13660
|
AGENTS_LOCATIONS = [
|
|
13533
13661
|
{ path: ".", type: "root" },
|
|
13534
|
-
{ path: "src/
|
|
13535
|
-
{ path: "src/
|
|
13662
|
+
{ path: "src/hooks", score: 18, reason: "high complexity" },
|
|
13663
|
+
{ path: "src/api", score: 12, reason: "distinct domain" }
|
|
13536
13664
|
]
|
|
13537
13665
|
\`\`\`
|
|
13538
13666
|
|
|
13539
|
-
**Mark "
|
|
13667
|
+
**Mark "scoring" as completed.**
|
|
13540
13668
|
|
|
13541
13669
|
---
|
|
13542
13670
|
|
|
13543
|
-
## Phase 3: Generate
|
|
13544
|
-
|
|
13545
|
-
**Mark "p3-root" as in_progress.**
|
|
13671
|
+
## Phase 3: Generate AGENTS.md
|
|
13546
13672
|
|
|
13547
|
-
|
|
13673
|
+
**Mark "generate" as in_progress.**
|
|
13548
13674
|
|
|
13549
|
-
###
|
|
13675
|
+
### Root AGENTS.md (Full Treatment)
|
|
13550
13676
|
|
|
13551
13677
|
\`\`\`markdown
|
|
13552
13678
|
# PROJECT KNOWLEDGE BASE
|
|
@@ -13556,153 +13682,75 @@ Root AGENTS.md gets **full treatment** with Predict-then-Compare synthesis.
|
|
|
13556
13682
|
**Branch:** {BRANCH}
|
|
13557
13683
|
|
|
13558
13684
|
## OVERVIEW
|
|
13559
|
-
|
|
13560
|
-
{1-2 sentences: what project does, core tech stack}
|
|
13685
|
+
{1-2 sentences: what + core stack}
|
|
13561
13686
|
|
|
13562
13687
|
## STRUCTURE
|
|
13563
|
-
|
|
13564
13688
|
\\\`\\\`\\\`
|
|
13565
|
-
{
|
|
13566
|
-
\u251C\u2500\u2500 {dir}/
|
|
13567
|
-
\u2514\u2500\u2500 {entry}
|
|
13689
|
+
{root}/
|
|
13690
|
+
\u251C\u2500\u2500 {dir}/ # {non-obvious purpose only}
|
|
13691
|
+
\u2514\u2500\u2500 {entry}
|
|
13568
13692
|
\\\`\\\`\\\`
|
|
13569
13693
|
|
|
13570
13694
|
## WHERE TO LOOK
|
|
13571
|
-
|
|
13572
13695
|
| Task | Location | Notes |
|
|
13573
13696
|
|------|----------|-------|
|
|
13574
|
-
| Add feature X | \\\`src/x/\\\` | {pattern hint} |
|
|
13575
13697
|
|
|
13576
13698
|
## CODE MAP
|
|
13577
|
-
|
|
13578
|
-
{Generated from LSP analysis - shows key symbols and their relationships}
|
|
13699
|
+
{From LSP - skip if unavailable or project <10 files}
|
|
13579
13700
|
|
|
13580
13701
|
| Symbol | Type | Location | Refs | Role |
|
|
13581
13702
|
|--------|------|----------|------|------|
|
|
13582
|
-
| {MainClass} | Class | \\\`src/index.ts\\\` | {N} | {Central orchestrator} |
|
|
13583
|
-
| {createX} | Function | \\\`src/utils.ts\\\` | {N} | {Factory pattern} |
|
|
13584
|
-
| {Config} | Interface | \\\`src/types.ts\\\` | {N} | {Configuration contract} |
|
|
13585
|
-
|
|
13586
|
-
### Module Dependencies
|
|
13587
|
-
|
|
13588
|
-
\\\`\\\`\\\`
|
|
13589
|
-
{entry} \u2500\u2500imports\u2500\u2500> {core/}
|
|
13590
|
-
\u2502 \u2502
|
|
13591
|
-
\u2514\u2500\u2500imports\u2500\u2500> {utils/} <\u2500\u2500imports\u2500\u2500 {features/}
|
|
13592
|
-
\\\`\\\`\\\`
|
|
13593
|
-
|
|
13594
|
-
<code-map-note>
|
|
13595
|
-
**Skip CODE MAP if**: LSP unavailable OR project too small (<10 files) OR no clear module boundaries.
|
|
13596
|
-
</code-map-note>
|
|
13597
13703
|
|
|
13598
13704
|
## CONVENTIONS
|
|
13599
|
-
|
|
13600
|
-
{ONLY deviations from standard - skip generic advice}
|
|
13601
|
-
|
|
13602
|
-
- **{rule}**: {specific detail}
|
|
13705
|
+
{ONLY deviations from standard}
|
|
13603
13706
|
|
|
13604
13707
|
## ANTI-PATTERNS (THIS PROJECT)
|
|
13605
|
-
|
|
13606
|
-
{Things explicitly forbidden HERE}
|
|
13607
|
-
|
|
13608
|
-
- **{pattern}**: {why} \u2192 {alternative}
|
|
13708
|
+
{Explicitly forbidden here}
|
|
13609
13709
|
|
|
13610
13710
|
## UNIQUE STYLES
|
|
13611
|
-
|
|
13612
|
-
{Project-specific coding styles}
|
|
13613
|
-
|
|
13614
|
-
- **{style}**: {how different}
|
|
13711
|
+
{Project-specific}
|
|
13615
13712
|
|
|
13616
13713
|
## COMMANDS
|
|
13617
|
-
|
|
13618
13714
|
\\\`\\\`\\\`bash
|
|
13619
|
-
{dev
|
|
13620
|
-
{test-command}
|
|
13621
|
-
{build-command}
|
|
13715
|
+
{dev/test/build}
|
|
13622
13716
|
\\\`\\\`\\\`
|
|
13623
13717
|
|
|
13624
13718
|
## NOTES
|
|
13625
|
-
|
|
13626
|
-
{Gotchas, non-obvious info}
|
|
13719
|
+
{Gotchas}
|
|
13627
13720
|
\`\`\`
|
|
13628
13721
|
|
|
13629
|
-
|
|
13630
|
-
|
|
13631
|
-
- [ ] Size: 50-150 lines
|
|
13632
|
-
- [ ] No generic advice ("write clean code")
|
|
13633
|
-
- [ ] No obvious info ("tests/ has tests")
|
|
13634
|
-
- [ ] Every item is project-specific
|
|
13635
|
-
|
|
13636
|
-
**Mark "p3-root" as completed.**
|
|
13722
|
+
**Quality gates**: 50-150 lines, no generic advice, no obvious info.
|
|
13637
13723
|
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
## Phase 4: Generate Subdirectory AGENTS.md
|
|
13724
|
+
### Subdirectory AGENTS.md (Parallel)
|
|
13641
13725
|
|
|
13642
|
-
|
|
13726
|
+
Launch document-writer agents for each location:
|
|
13643
13727
|
|
|
13644
|
-
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
CONTEXT:
|
|
13654
|
-
- Complexity reason: \${loc.reason}
|
|
13655
|
-
- Parent AGENTS.md: ./AGENTS.md (already covers project overview)
|
|
13656
|
-
|
|
13657
|
-
CRITICAL RULES:
|
|
13658
|
-
1. Focus ONLY on this directory's specific context
|
|
13659
|
-
2. NEVER repeat parent AGENTS.md content
|
|
13660
|
-
3. Shorter is better - 30-80 lines max
|
|
13661
|
-
4. Telegraphic style - sacrifice grammar
|
|
13662
|
-
|
|
13663
|
-
REQUIRED SECTIONS:
|
|
13664
|
-
- OVERVIEW (1 line: what this directory does)
|
|
13665
|
-
- STRUCTURE (only if >5 subdirs)
|
|
13666
|
-
- WHERE TO LOOK (directory-specific tasks)
|
|
13667
|
-
- CONVENTIONS (only if DIFFERENT from root)
|
|
13668
|
-
- ANTI-PATTERNS (directory-specific only)
|
|
13669
|
-
|
|
13670
|
-
OUTPUT: Write to \${loc.path}/AGENTS.md
|
|
13671
|
-
\\\`
|
|
13672
|
-
})
|
|
13673
|
-
}
|
|
13728
|
+
\`\`\`
|
|
13729
|
+
for loc in AGENTS_LOCATIONS (except root):
|
|
13730
|
+
background_task(agent="document-writer", prompt=\\\`
|
|
13731
|
+
Generate AGENTS.md for: \${loc.path}
|
|
13732
|
+
- Reason: \${loc.reason}
|
|
13733
|
+
- 30-80 lines max
|
|
13734
|
+
- NEVER repeat parent content
|
|
13735
|
+
- Sections: OVERVIEW (1 line), STRUCTURE (if >5 subdirs), WHERE TO LOOK, CONVENTIONS (if different), ANTI-PATTERNS
|
|
13736
|
+
\\\`)
|
|
13674
13737
|
\`\`\`
|
|
13675
13738
|
|
|
13676
|
-
**Wait for all
|
|
13739
|
+
**Wait for all. Mark "generate" as completed.**
|
|
13677
13740
|
|
|
13678
13741
|
---
|
|
13679
13742
|
|
|
13680
|
-
## Phase
|
|
13681
|
-
|
|
13682
|
-
**Mark "p5-review" as in_progress.**
|
|
13683
|
-
|
|
13684
|
-
### Validation Checklist
|
|
13685
|
-
|
|
13686
|
-
For EACH generated AGENTS.md:
|
|
13687
|
-
|
|
13688
|
-
| Check | Action if Fail |
|
|
13689
|
-
|-------|----------------|
|
|
13690
|
-
| Contains generic advice | REMOVE the line |
|
|
13691
|
-
| Repeats parent content | REMOVE the line |
|
|
13692
|
-
| Missing required section | ADD it |
|
|
13693
|
-
| Over 150 lines (root) / 80 lines (subdir) | TRIM |
|
|
13694
|
-
| Verbose explanations | REWRITE telegraphic |
|
|
13743
|
+
## Phase 4: Review & Deduplicate
|
|
13695
13744
|
|
|
13696
|
-
|
|
13745
|
+
**Mark "review" as in_progress.**
|
|
13697
13746
|
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
\`\`\`
|
|
13747
|
+
For each generated file:
|
|
13748
|
+
- Remove generic advice
|
|
13749
|
+
- Remove parent duplicates
|
|
13750
|
+
- Trim to size limits
|
|
13751
|
+
- Verify telegraphic style
|
|
13704
13752
|
|
|
13705
|
-
**Mark "
|
|
13753
|
+
**Mark "review" as completed.**
|
|
13706
13754
|
|
|
13707
13755
|
---
|
|
13708
13756
|
|
|
@@ -13711,34 +13759,32 @@ For each child AGENTS.md:
|
|
|
13711
13759
|
\`\`\`
|
|
13712
13760
|
=== init-deep Complete ===
|
|
13713
13761
|
|
|
13714
|
-
|
|
13762
|
+
Mode: {update | create-new}
|
|
13763
|
+
|
|
13764
|
+
Files:
|
|
13715
13765
|
\u2713 ./AGENTS.md (root, {N} lines)
|
|
13716
13766
|
\u2713 ./src/hooks/AGENTS.md ({N} lines)
|
|
13717
|
-
\u2713 ./src/tools/AGENTS.md ({N} lines)
|
|
13718
13767
|
|
|
13719
|
-
|
|
13768
|
+
Dirs Analyzed: {N}
|
|
13720
13769
|
AGENTS.md Created: {N}
|
|
13721
|
-
|
|
13770
|
+
AGENTS.md Updated: {N}
|
|
13722
13771
|
|
|
13723
13772
|
Hierarchy:
|
|
13724
13773
|
./AGENTS.md
|
|
13725
|
-
\
|
|
13726
|
-
\u2514\u2500\u2500 src/tools/AGENTS.md
|
|
13774
|
+
\u2514\u2500\u2500 src/hooks/AGENTS.md
|
|
13727
13775
|
\`\`\`
|
|
13728
13776
|
|
|
13729
13777
|
---
|
|
13730
13778
|
|
|
13731
|
-
## Anti-Patterns
|
|
13779
|
+
## Anti-Patterns
|
|
13732
13780
|
|
|
13733
|
-
- **
|
|
13734
|
-
- **
|
|
13781
|
+
- **Static agent count**: MUST vary agents based on project size/depth
|
|
13782
|
+
- **Sequential execution**: MUST parallel (explore + LSP concurrent)
|
|
13783
|
+
- **Ignoring existing**: ALWAYS read existing first, even with --create-new
|
|
13784
|
+
- **Over-documenting**: Not every dir needs AGENTS.md
|
|
13785
|
+
- **Redundancy**: Child never repeats parent
|
|
13735
13786
|
- **Generic content**: Remove anything that applies to ALL projects
|
|
13736
|
-
- **
|
|
13737
|
-
- **Deep nesting**: Rarely need AGENTS.md at depth 4+
|
|
13738
|
-
- **Verbose style**: "This directory contains..." \u2192 just list it
|
|
13739
|
-
- **Ignoring LSP**: If LSP available, USE IT - semantic analysis > text grep
|
|
13740
|
-
- **LSP without fallback**: Always have explore agent backup if LSP unavailable
|
|
13741
|
-
- **Over-referencing**: Don't trace refs for EVERY symbol - focus on exports only`;
|
|
13787
|
+
- **Verbose style**: Telegraphic or die`;
|
|
13742
13788
|
|
|
13743
13789
|
// src/features/builtin-commands/templates/ralph-loop.ts
|
|
13744
13790
|
var RALPH_LOOP_TEMPLATE = `You are starting a Ralph Loop - a self-referential development loop that runs until task completion.
|
|
@@ -13815,10 +13861,8 @@ function loadBuiltinCommands(disabledCommands) {
|
|
|
13815
13861
|
const commands = {};
|
|
13816
13862
|
for (const [name, definition] of Object.entries(BUILTIN_COMMAND_DEFINITIONS)) {
|
|
13817
13863
|
if (!disabled.has(name)) {
|
|
13818
|
-
|
|
13819
|
-
|
|
13820
|
-
...definition
|
|
13821
|
-
};
|
|
13864
|
+
const { argumentHint: _argumentHint, ...openCodeCompatible } = definition;
|
|
13865
|
+
commands[name] = openCodeCompatible;
|
|
13822
13866
|
}
|
|
13823
13867
|
}
|
|
13824
13868
|
return commands;
|
|
@@ -13915,7 +13959,8 @@ function loadSkillsFromDir(skillsDir, scope) {
|
|
|
13915
13959
|
function skillsToRecord(skills) {
|
|
13916
13960
|
const result = {};
|
|
13917
13961
|
for (const skill of skills) {
|
|
13918
|
-
|
|
13962
|
+
const { name: _name, argumentHint: _argumentHint, ...openCodeCompatible } = skill.definition;
|
|
13963
|
+
result[skill.name] = openCodeCompatible;
|
|
13919
13964
|
}
|
|
13920
13965
|
return result;
|
|
13921
13966
|
}
|
|
@@ -14558,7 +14603,7 @@ ${body.trim()}
|
|
|
14558
14603
|
$ARGUMENTS
|
|
14559
14604
|
</user-request>`;
|
|
14560
14605
|
const formattedDescription = `(plugin: ${plugin2.name}) ${data.description || ""}`;
|
|
14561
|
-
|
|
14606
|
+
const definition = {
|
|
14562
14607
|
name: namespacedName,
|
|
14563
14608
|
description: formattedDescription,
|
|
14564
14609
|
template: wrappedTemplate,
|
|
@@ -14567,6 +14612,8 @@ $ARGUMENTS
|
|
|
14567
14612
|
subtask: data.subtask,
|
|
14568
14613
|
argumentHint: data["argument-hint"]
|
|
14569
14614
|
};
|
|
14615
|
+
const { name: _name, argumentHint: _argumentHint, ...openCodeCompatible } = definition;
|
|
14616
|
+
commands2[namespacedName] = openCodeCompatible;
|
|
14570
14617
|
log(`Loaded plugin command: ${namespacedName}`, { path: commandPath });
|
|
14571
14618
|
} catch (error) {
|
|
14572
14619
|
log(`Failed to load plugin command: ${commandPath}`, error);
|
|
@@ -14608,12 +14655,14 @@ ${body.trim()}
|
|
|
14608
14655
|
<user-request>
|
|
14609
14656
|
$ARGUMENTS
|
|
14610
14657
|
</user-request>`;
|
|
14611
|
-
|
|
14658
|
+
const definition = {
|
|
14612
14659
|
name: namespacedName,
|
|
14613
14660
|
description: formattedDescription,
|
|
14614
14661
|
template: wrappedTemplate,
|
|
14615
14662
|
model: sanitizeModelField(data.model)
|
|
14616
14663
|
};
|
|
14664
|
+
const { name: _name, ...openCodeCompatible } = definition;
|
|
14665
|
+
skills[namespacedName] = openCodeCompatible;
|
|
14617
14666
|
log(`Loaded plugin skill: ${namespacedName}`, { path: resolvedPath });
|
|
14618
14667
|
} catch (error) {
|
|
14619
14668
|
log(`Failed to load plugin skill: ${skillPath}`, error);
|
|
@@ -15814,7 +15863,7 @@ ${msg}`);
|
|
|
15814
15863
|
// src/tools/lsp/utils.ts
|
|
15815
15864
|
import { extname as extname2, resolve as resolve7 } from "path";
|
|
15816
15865
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
15817
|
-
import { existsSync as existsSync39, readFileSync as readFileSync29, writeFileSync as
|
|
15866
|
+
import { existsSync as existsSync39, readFileSync as readFileSync29, writeFileSync as writeFileSync15 } from "fs";
|
|
15818
15867
|
function findWorkspaceRoot(filePath) {
|
|
15819
15868
|
let dir = resolve7(filePath);
|
|
15820
15869
|
if (!existsSync39(dir) || !__require("fs").statSync(dir).isDirectory()) {
|
|
@@ -16044,7 +16093,7 @@ function applyTextEditsToFile(filePath, edits) {
|
|
|
16044
16093
|
`));
|
|
16045
16094
|
}
|
|
16046
16095
|
}
|
|
16047
|
-
|
|
16096
|
+
writeFileSync15(filePath, lines.join(`
|
|
16048
16097
|
`), "utf-8");
|
|
16049
16098
|
return { success: true, editCount: edits.length };
|
|
16050
16099
|
} catch (err) {
|
|
@@ -16075,7 +16124,7 @@ function applyWorkspaceEdit(edit) {
|
|
|
16075
16124
|
if (change.kind === "create") {
|
|
16076
16125
|
try {
|
|
16077
16126
|
const filePath = uriToPath(change.uri);
|
|
16078
|
-
|
|
16127
|
+
writeFileSync15(filePath, "", "utf-8");
|
|
16079
16128
|
result.filesModified.push(filePath);
|
|
16080
16129
|
} catch (err) {
|
|
16081
16130
|
result.success = false;
|
|
@@ -16086,7 +16135,7 @@ function applyWorkspaceEdit(edit) {
|
|
|
16086
16135
|
const oldPath = uriToPath(change.oldUri);
|
|
16087
16136
|
const newPath = uriToPath(change.newUri);
|
|
16088
16137
|
const content = readFileSync29(oldPath, "utf-8");
|
|
16089
|
-
|
|
16138
|
+
writeFileSync15(newPath, content, "utf-8");
|
|
16090
16139
|
__require("fs").unlinkSync(oldPath);
|
|
16091
16140
|
result.filesModified.push(newPath);
|
|
16092
16141
|
} catch (err) {
|
|
@@ -30123,6 +30172,7 @@ import { join as join52 } from "path";
|
|
|
30123
30172
|
var OPENCODE_STORAGE9 = getOpenCodeStorageDir();
|
|
30124
30173
|
var MESSAGE_STORAGE4 = join52(OPENCODE_STORAGE9, "message");
|
|
30125
30174
|
var PART_STORAGE4 = join52(OPENCODE_STORAGE9, "part");
|
|
30175
|
+
var SESSION_STORAGE = join52(OPENCODE_STORAGE9, "session");
|
|
30126
30176
|
var TODO_DIR2 = join52(getClaudeConfigDir(), "todos");
|
|
30127
30177
|
var TRANSCRIPT_DIR2 = join52(getClaudeConfigDir(), "transcripts");
|
|
30128
30178
|
var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
|
|
@@ -30200,6 +30250,38 @@ Has Transcript: Yes (234 entries)`;
|
|
|
30200
30250
|
import { existsSync as existsSync46, readdirSync as readdirSync17 } from "fs";
|
|
30201
30251
|
import { readdir, readFile } from "fs/promises";
|
|
30202
30252
|
import { join as join53 } from "path";
|
|
30253
|
+
async function getMainSessions(options) {
|
|
30254
|
+
if (!existsSync46(SESSION_STORAGE))
|
|
30255
|
+
return [];
|
|
30256
|
+
const sessions = [];
|
|
30257
|
+
try {
|
|
30258
|
+
const projectDirs = await readdir(SESSION_STORAGE, { withFileTypes: true });
|
|
30259
|
+
for (const projectDir of projectDirs) {
|
|
30260
|
+
if (!projectDir.isDirectory())
|
|
30261
|
+
continue;
|
|
30262
|
+
const projectPath = join53(SESSION_STORAGE, projectDir.name);
|
|
30263
|
+
const sessionFiles = await readdir(projectPath);
|
|
30264
|
+
for (const file2 of sessionFiles) {
|
|
30265
|
+
if (!file2.endsWith(".json"))
|
|
30266
|
+
continue;
|
|
30267
|
+
try {
|
|
30268
|
+
const content = await readFile(join53(projectPath, file2), "utf-8");
|
|
30269
|
+
const meta = JSON.parse(content);
|
|
30270
|
+
if (meta.parentID)
|
|
30271
|
+
continue;
|
|
30272
|
+
if (options.directory && meta.directory !== options.directory)
|
|
30273
|
+
continue;
|
|
30274
|
+
sessions.push(meta);
|
|
30275
|
+
} catch {
|
|
30276
|
+
continue;
|
|
30277
|
+
}
|
|
30278
|
+
}
|
|
30279
|
+
}
|
|
30280
|
+
} catch {
|
|
30281
|
+
return [];
|
|
30282
|
+
}
|
|
30283
|
+
return sessions.sort((a, b) => b.time.updated - a.time.updated);
|
|
30284
|
+
}
|
|
30203
30285
|
async function getAllSessions() {
|
|
30204
30286
|
if (!existsSync46(MESSAGE_STORAGE4))
|
|
30205
30287
|
return [];
|
|
@@ -30551,18 +30633,21 @@ var session_list = tool({
|
|
|
30551
30633
|
args: {
|
|
30552
30634
|
limit: tool.schema.number().optional().describe("Maximum number of sessions to return"),
|
|
30553
30635
|
from_date: tool.schema.string().optional().describe("Filter sessions from this date (ISO 8601 format)"),
|
|
30554
|
-
to_date: tool.schema.string().optional().describe("Filter sessions until this date (ISO 8601 format)")
|
|
30636
|
+
to_date: tool.schema.string().optional().describe("Filter sessions until this date (ISO 8601 format)"),
|
|
30637
|
+
project_path: tool.schema.string().optional().describe("Filter sessions by project path (default: current working directory)")
|
|
30555
30638
|
},
|
|
30556
30639
|
execute: async (args, _context) => {
|
|
30557
30640
|
try {
|
|
30558
|
-
|
|
30641
|
+
const directory = args.project_path ?? process.cwd();
|
|
30642
|
+
let sessions = await getMainSessions({ directory });
|
|
30643
|
+
let sessionIDs = sessions.map((s) => s.id);
|
|
30559
30644
|
if (args.from_date || args.to_date) {
|
|
30560
|
-
|
|
30645
|
+
sessionIDs = await filterSessionsByDate(sessionIDs, args.from_date, args.to_date);
|
|
30561
30646
|
}
|
|
30562
30647
|
if (args.limit && args.limit > 0) {
|
|
30563
|
-
|
|
30648
|
+
sessionIDs = sessionIDs.slice(0, args.limit);
|
|
30564
30649
|
}
|
|
30565
|
-
return await formatSessionList(
|
|
30650
|
+
return await formatSessionList(sessionIDs);
|
|
30566
30651
|
} catch (e) {
|
|
30567
30652
|
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
30568
30653
|
}
|
|
@@ -31944,7 +32029,10 @@ var HookNameSchema = exports_external.enum([
|
|
|
31944
32029
|
"interactive-bash-session",
|
|
31945
32030
|
"empty-message-sanitizer",
|
|
31946
32031
|
"thinking-block-validator",
|
|
31947
|
-
"ralph-loop"
|
|
32032
|
+
"ralph-loop",
|
|
32033
|
+
"preemptive-compaction",
|
|
32034
|
+
"compaction-context-injector",
|
|
32035
|
+
"claude-code-hooks"
|
|
31948
32036
|
]);
|
|
31949
32037
|
var BuiltinCommandNameSchema = exports_external.enum([
|
|
31950
32038
|
"init-deep"
|
|
@@ -32160,64 +32248,12 @@ var PLAN_PERMISSION = {
|
|
|
32160
32248
|
};
|
|
32161
32249
|
|
|
32162
32250
|
// src/index.ts
|
|
32163
|
-
import * as
|
|
32251
|
+
import * as fs8 from "fs";
|
|
32164
32252
|
import * as path7 from "path";
|
|
32165
|
-
var AGENT_NAME_MAP = {
|
|
32166
|
-
omo: "Sisyphus",
|
|
32167
|
-
OmO: "Sisyphus",
|
|
32168
|
-
"OmO-Plan": "Planner-Sisyphus",
|
|
32169
|
-
"omo-plan": "Planner-Sisyphus",
|
|
32170
|
-
sisyphus: "Sisyphus",
|
|
32171
|
-
"planner-sisyphus": "Planner-Sisyphus",
|
|
32172
|
-
build: "build",
|
|
32173
|
-
oracle: "oracle",
|
|
32174
|
-
librarian: "librarian",
|
|
32175
|
-
explore: "explore",
|
|
32176
|
-
"frontend-ui-ux-engineer": "frontend-ui-ux-engineer",
|
|
32177
|
-
"document-writer": "document-writer",
|
|
32178
|
-
"multimodal-looker": "multimodal-looker"
|
|
32179
|
-
};
|
|
32180
|
-
function migrateAgentNames(agents) {
|
|
32181
|
-
const migrated = {};
|
|
32182
|
-
let changed = false;
|
|
32183
|
-
for (const [key, value] of Object.entries(agents)) {
|
|
32184
|
-
const newKey = AGENT_NAME_MAP[key.toLowerCase()] ?? AGENT_NAME_MAP[key] ?? key;
|
|
32185
|
-
if (newKey !== key) {
|
|
32186
|
-
changed = true;
|
|
32187
|
-
}
|
|
32188
|
-
migrated[newKey] = value;
|
|
32189
|
-
}
|
|
32190
|
-
return { migrated, changed };
|
|
32191
|
-
}
|
|
32192
|
-
function migrateConfigFile(configPath, rawConfig) {
|
|
32193
|
-
let needsWrite = false;
|
|
32194
|
-
if (rawConfig.agents && typeof rawConfig.agents === "object") {
|
|
32195
|
-
const { migrated, changed } = migrateAgentNames(rawConfig.agents);
|
|
32196
|
-
if (changed) {
|
|
32197
|
-
rawConfig.agents = migrated;
|
|
32198
|
-
needsWrite = true;
|
|
32199
|
-
}
|
|
32200
|
-
}
|
|
32201
|
-
if (rawConfig.omo_agent) {
|
|
32202
|
-
rawConfig.sisyphus_agent = rawConfig.omo_agent;
|
|
32203
|
-
delete rawConfig.omo_agent;
|
|
32204
|
-
needsWrite = true;
|
|
32205
|
-
}
|
|
32206
|
-
if (needsWrite) {
|
|
32207
|
-
try {
|
|
32208
|
-
fs7.writeFileSync(configPath, JSON.stringify(rawConfig, null, 2) + `
|
|
32209
|
-
`, "utf-8");
|
|
32210
|
-
log(`Migrated config file: ${configPath} (OmO \u2192 Sisyphus)`);
|
|
32211
|
-
} catch (err) {
|
|
32212
|
-
log(`Failed to write migrated config to ${configPath}:`, err);
|
|
32213
|
-
}
|
|
32214
|
-
}
|
|
32215
|
-
return needsWrite;
|
|
32216
|
-
}
|
|
32217
32253
|
function loadConfigFromPath2(configPath, ctx) {
|
|
32218
32254
|
try {
|
|
32219
|
-
if (
|
|
32220
|
-
const content =
|
|
32255
|
+
if (fs8.existsSync(configPath)) {
|
|
32256
|
+
const content = fs8.readFileSync(configPath, "utf-8");
|
|
32221
32257
|
const rawConfig = parseJsonc(content);
|
|
32222
32258
|
migrateConfigFile(configPath, rawConfig);
|
|
32223
32259
|
const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
|
|
@@ -32322,12 +32358,12 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
32322
32358
|
experimental: pluginConfig.experimental,
|
|
32323
32359
|
dcpForCompaction: pluginConfig.experimental?.dcp_for_compaction
|
|
32324
32360
|
}) : null;
|
|
32325
|
-
const compactionContextInjector = createCompactionContextInjector();
|
|
32326
|
-
const preemptiveCompaction = createPreemptiveCompactionHook(ctx, {
|
|
32361
|
+
const compactionContextInjector = isHookEnabled("compaction-context-injector") ? createCompactionContextInjector() : undefined;
|
|
32362
|
+
const preemptiveCompaction = isHookEnabled("preemptive-compaction") ? createPreemptiveCompactionHook(ctx, {
|
|
32327
32363
|
experimental: pluginConfig.experimental,
|
|
32328
32364
|
onBeforeSummarize: compactionContextInjector,
|
|
32329
32365
|
getModelLimit
|
|
32330
|
-
});
|
|
32366
|
+
}) : null;
|
|
32331
32367
|
const rulesInjector = isHookEnabled("rules-injector") ? createRulesInjectorHook(ctx) : null;
|
|
32332
32368
|
const autoUpdateChecker = isHookEnabled("auto-update-checker") ? createAutoUpdateCheckerHook(ctx, {
|
|
32333
32369
|
showStartupToast: isHookEnabled("startup-toast"),
|