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