@letta-ai/letta-code 0.13.7 → 0.13.9
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/letta.js
CHANGED
|
@@ -256,7 +256,7 @@ var init_values = __esm(() => {
|
|
|
256
256
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
257
257
|
|
|
258
258
|
// node_modules/@letta-ai/letta-client/version.mjs
|
|
259
|
-
var VERSION = "1.7.
|
|
259
|
+
var VERSION = "1.7.6";
|
|
260
260
|
|
|
261
261
|
// node_modules/@letta-ai/letta-client/internal/detect-platform.mjs
|
|
262
262
|
function getDetectedPlatform() {
|
|
@@ -1817,6 +1817,31 @@ var init_passages = __esm(() => {
|
|
|
1817
1817
|
};
|
|
1818
1818
|
});
|
|
1819
1819
|
|
|
1820
|
+
// node_modules/@letta-ai/letta-client/resources/agents/schedule.mjs
|
|
1821
|
+
var Schedule;
|
|
1822
|
+
var init_schedule = __esm(() => {
|
|
1823
|
+
init_path();
|
|
1824
|
+
Schedule = class Schedule extends APIResource {
|
|
1825
|
+
create(agentID, body, options) {
|
|
1826
|
+
return this._client.post(path`/v1/agents/${agentID}/schedule`, { body, ...options });
|
|
1827
|
+
}
|
|
1828
|
+
retrieve(scheduledMessageID, params, options) {
|
|
1829
|
+
const { agent_id } = params;
|
|
1830
|
+
return this._client.get(path`/v1/agents/${agent_id}/schedule/${scheduledMessageID}`, options);
|
|
1831
|
+
}
|
|
1832
|
+
list(agentID, query = {}, options) {
|
|
1833
|
+
return this._client.get(path`/v1/agents/${agentID}/schedule`, { query, ...options });
|
|
1834
|
+
}
|
|
1835
|
+
delete(scheduledMessageID, params, options) {
|
|
1836
|
+
const { agent_id, ...body } = params;
|
|
1837
|
+
return this._client.delete(path`/v1/agents/${agent_id}/schedule/${scheduledMessageID}`, {
|
|
1838
|
+
body,
|
|
1839
|
+
...options
|
|
1840
|
+
});
|
|
1841
|
+
}
|
|
1842
|
+
};
|
|
1843
|
+
});
|
|
1844
|
+
|
|
1820
1845
|
// node_modules/@letta-ai/letta-client/resources/agents/tools.mjs
|
|
1821
1846
|
var Tools;
|
|
1822
1847
|
var init_tools = __esm(() => {
|
|
@@ -1935,6 +1960,8 @@ var init_agents = __esm(() => {
|
|
|
1935
1960
|
init_messages();
|
|
1936
1961
|
init_passages();
|
|
1937
1962
|
init_passages();
|
|
1963
|
+
init_schedule();
|
|
1964
|
+
init_schedule();
|
|
1938
1965
|
init_tools();
|
|
1939
1966
|
init_tools();
|
|
1940
1967
|
init_pagination();
|
|
@@ -1945,6 +1972,7 @@ var init_agents = __esm(() => {
|
|
|
1945
1972
|
constructor() {
|
|
1946
1973
|
super(...arguments);
|
|
1947
1974
|
this.messages = new Messages(this._client);
|
|
1975
|
+
this.schedule = new Schedule(this._client);
|
|
1948
1976
|
this.blocks = new Blocks(this._client);
|
|
1949
1977
|
this.tools = new Tools(this._client);
|
|
1950
1978
|
this.folders = new Folders(this._client);
|
|
@@ -1986,6 +2014,7 @@ var init_agents = __esm(() => {
|
|
|
1986
2014
|
}
|
|
1987
2015
|
};
|
|
1988
2016
|
Agents.Messages = Messages;
|
|
2017
|
+
Agents.Schedule = Schedule;
|
|
1989
2018
|
Agents.Blocks = Blocks;
|
|
1990
2019
|
Agents.Tools = Tools;
|
|
1991
2020
|
Agents.Folders = Folders;
|
|
@@ -2011,6 +2040,9 @@ var init_passages2 = __esm(() => {
|
|
|
2011
2040
|
headers: buildHeaders([{ Accept: "*/*" }, options?.headers])
|
|
2012
2041
|
});
|
|
2013
2042
|
}
|
|
2043
|
+
createMany(archiveID, body, options) {
|
|
2044
|
+
return this._client.post(path`/v1/archives/${archiveID}/passages/batch`, { body, ...options });
|
|
2045
|
+
}
|
|
2014
2046
|
};
|
|
2015
2047
|
});
|
|
2016
2048
|
|
|
@@ -2111,6 +2143,9 @@ var init_messages2 = __esm(() => {
|
|
|
2111
2143
|
list(conversationID, query = {}, options) {
|
|
2112
2144
|
return this._client.getAPIList(path`/v1/conversations/${conversationID}/messages`, ArrayPage, { query, ...options });
|
|
2113
2145
|
}
|
|
2146
|
+
compact(conversationID, body = {}, options) {
|
|
2147
|
+
return this._client.post(path`/v1/conversations/${conversationID}/compact`, { body, ...options });
|
|
2148
|
+
}
|
|
2114
2149
|
stream(conversationID, body = {}, options) {
|
|
2115
2150
|
return this._client.post(path`/v1/conversations/${conversationID}/stream`, {
|
|
2116
2151
|
body,
|
|
@@ -3073,7 +3108,7 @@ var package_default;
|
|
|
3073
3108
|
var init_package = __esm(() => {
|
|
3074
3109
|
package_default = {
|
|
3075
3110
|
name: "@letta-ai/letta-code",
|
|
3076
|
-
version: "0.13.
|
|
3111
|
+
version: "0.13.9",
|
|
3077
3112
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
3078
3113
|
type: "module",
|
|
3079
3114
|
bin: {
|
|
@@ -3103,7 +3138,7 @@ var init_package = __esm(() => {
|
|
|
3103
3138
|
access: "public"
|
|
3104
3139
|
},
|
|
3105
3140
|
dependencies: {
|
|
3106
|
-
"@letta-ai/letta-client": "^1.7.
|
|
3141
|
+
"@letta-ai/letta-client": "^1.7.6",
|
|
3107
3142
|
glob: "^13.0.0",
|
|
3108
3143
|
"ink-link": "^5.0.0",
|
|
3109
3144
|
open: "^10.2.0",
|
|
@@ -5556,7 +5591,451 @@ var init_general_purpose = () => {};
|
|
|
5556
5591
|
// src/agent/subagents/builtin/memory.md
|
|
5557
5592
|
var memory_default = `---
|
|
5558
5593
|
name: memory
|
|
5559
|
-
description:
|
|
5594
|
+
description: Restructure memory blocks into focused, scannable, hierarchically-named blocks (use \`/\` naming)
|
|
5595
|
+
tools: Read, Edit, Write, Glob, Grep, Bash, conversation_search
|
|
5596
|
+
model: opus
|
|
5597
|
+
memoryBlocks: none
|
|
5598
|
+
mode: stateless
|
|
5599
|
+
permissionMode: bypassPermissions
|
|
5600
|
+
---
|
|
5601
|
+
|
|
5602
|
+
You are a memory subagent launched via the Task tool to create a better structure of the memories store in files.. You run autonomously and return a **single final report** when done. You **cannot ask questions** mid-execution.
|
|
5603
|
+
|
|
5604
|
+
## Goal
|
|
5605
|
+
|
|
5606
|
+
Your goal is to **explode** a few large memory blocks into a **deeply hierarchical structure of 15–25 small, focused files**.
|
|
5607
|
+
|
|
5608
|
+
You propose a new organization scheme that best captures the underlying memories, then implement it aggressively—creating new files, deleting old files, and renaming files until the directory is optimally structured.
|
|
5609
|
+
|
|
5610
|
+
### Target Output
|
|
5611
|
+
|
|
5612
|
+
| Metric | Target |
|
|
5613
|
+
|--------|--------|
|
|
5614
|
+
| **Total files** | 15–25 (aim for ~20) |
|
|
5615
|
+
| **Max lines per file** | ~40 lines (split if larger) |
|
|
5616
|
+
| **Hierarchy depth** | 2–3 levels using \`/\` naming (e.g., \`project/tooling/bun\`) |
|
|
5617
|
+
| **Nesting requirement** | Every new block MUST be nested under a parent using \`/\` |
|
|
5618
|
+
|
|
5619
|
+
**Anti-patterns to avoid:**
|
|
5620
|
+
- ❌ Ending with only 3–5 large files
|
|
5621
|
+
- ❌ Flat naming (all blocks at top level)
|
|
5622
|
+
- ❌ Mega-blocks with 10+ sections
|
|
5623
|
+
- ❌ Single-level hierarchy (only \`project.md\`, \`human.md\`)
|
|
5624
|
+
|
|
5625
|
+
## Scope and constraints (non-negotiable)
|
|
5626
|
+
|
|
5627
|
+
**The parent agent handles backup and creates memory files.** You only work inside \`.letta/backups/working/\`.
|
|
5628
|
+
|
|
5629
|
+
- ✅ Reorganize all the files in \`.letta/backups/working/\` so that they are hierarchical and well managed.
|
|
5630
|
+
- ✅ Rename/split/merge blocks when it improves structure
|
|
5631
|
+
- ✅ Delete blocks **only after** their content is fully consolidated elsewhere
|
|
5632
|
+
- ✅ Produce a detailed report with decisions and before/after examples
|
|
5633
|
+
- ❌ Do not run backup or restore scripts
|
|
5634
|
+
- ❌ Do not invent new facts; reorganize and clarify existing information only
|
|
5635
|
+
|
|
5636
|
+
## Guiding principles (use these to decide what to do)
|
|
5637
|
+
|
|
5638
|
+
1. **Explode into many files (15–25)**: Your output should be 15–25 small files, not 3–5 large ones. Split aggressively.
|
|
5639
|
+
2. **Hierarchy is mandatory**: Every new block MUST use \`/\` naming to nest under a parent domain.
|
|
5640
|
+
- ✅ Good: \`human/prefs/communication\`, \`project/tooling/bun\`, \`project/gotchas/testing\`
|
|
5641
|
+
- ❌ Bad: \`communication_prefs.md\`, \`bun_notes.md\` (flat names)
|
|
5642
|
+
3. **Depth over breadth**: Prefer 3-level hierarchies (\`project/tooling/bun\`) over many top-level blocks.
|
|
5643
|
+
4. **Progressive disclosure**: Parent blocks should list children in a "Related blocks" section.
|
|
5644
|
+
5. **One concept per file**: If a block has 2+ distinct topics, it should be 2+ files.
|
|
5645
|
+
6. **40-line max**: If a file exceeds ~40 lines, split it further.
|
|
5646
|
+
7. **Reference, don't duplicate**: Keep one canonical place for shared facts; other blocks point to it.
|
|
5647
|
+
8. **Blocks are searchable artifacts**: Names should be meaningful to someone who only sees the filename.
|
|
5648
|
+
9. **Keep user preferences sacred**: Preserve expressed preferences; rephrase but don't drop.
|
|
5649
|
+
10. **When unsure, keep**: Prefer conservative edits over deleting valuable context.
|
|
5650
|
+
|
|
5651
|
+
### Example Target Structure (what success looks like)
|
|
5652
|
+
|
|
5653
|
+
Starting from 3 files (\`project.md\`, \`human.md\`, \`persona.md\`), you should end with something like:
|
|
5654
|
+
|
|
5655
|
+
\`\`\`
|
|
5656
|
+
.letta/backups/working/
|
|
5657
|
+
├── human.md # Index: points to children
|
|
5658
|
+
├── human/
|
|
5659
|
+
│ ├── background.md # Who they are
|
|
5660
|
+
│ ├── prefs.md # Index for preferences
|
|
5661
|
+
│ ├── prefs/
|
|
5662
|
+
│ │ ├── communication.md # How they like to communicate
|
|
5663
|
+
│ │ ├── coding_style.md # Code formatting preferences
|
|
5664
|
+
│ │ └── review_style.md # PR/code review preferences
|
|
5665
|
+
│ └── context.md # Current project context
|
|
5666
|
+
├── project.md # Index: points to children
|
|
5667
|
+
├── project/
|
|
5668
|
+
│ ├── overview.md # What the project is
|
|
5669
|
+
│ ├── architecture.md # System design
|
|
5670
|
+
│ ├── tooling.md # Index for tooling
|
|
5671
|
+
│ ├── tooling/
|
|
5672
|
+
│ │ ├── bun.md # Bun-specific notes
|
|
5673
|
+
│ │ ├── testing.md # Test framework details
|
|
5674
|
+
│ │ └── linting.md # Linter configuration
|
|
5675
|
+
│ ├── conventions.md # Code conventions
|
|
5676
|
+
│ └── gotchas.md # Footguns and warnings
|
|
5677
|
+
├── persona.md # Index: points to children
|
|
5678
|
+
└── persona/
|
|
5679
|
+
├── role.md # Agent's role definition
|
|
5680
|
+
├── behavior.md # How to behave
|
|
5681
|
+
└── constraints.md # What not to do
|
|
5682
|
+
\`\`\`
|
|
5683
|
+
|
|
5684
|
+
This example has **~20 files** with **3 levels of hierarchy**. Your output should look similar.
|
|
5685
|
+
|
|
5686
|
+
## Actions available
|
|
5687
|
+
|
|
5688
|
+
- **KEEP + CLEAN**: Remove cruft, add structure, resolve contradictions.
|
|
5689
|
+
- **RENAME**: Change block name to match contents and improve searchability.
|
|
5690
|
+
- **SPLIT (DECOMPOSE)**: Extract distinct concepts into focused blocks (**prefer nested names**).
|
|
5691
|
+
- **MERGE**: Consolidate overlapping blocks into one canonical block, remove duplicates, then delete originals.
|
|
5692
|
+
- **DETACH**: Mark as detached when it’s not needed by default but should remain discoverable.
|
|
5693
|
+
|
|
5694
|
+
## Operating procedure
|
|
5695
|
+
|
|
5696
|
+
### Step 1: Read
|
|
5697
|
+
|
|
5698
|
+
The parent agent has already backed up memory files to \`.letta/backups/working/\`. Your job is to read and edit these files.
|
|
5699
|
+
|
|
5700
|
+
First, list what files are available:
|
|
5701
|
+
|
|
5702
|
+
\`\`\`bash
|
|
5703
|
+
ls .letta/backups/working/
|
|
5704
|
+
\`\`\`
|
|
5705
|
+
|
|
5706
|
+
Then read **all** relevant memory block files (examples):
|
|
5707
|
+
|
|
5708
|
+
\`\`\`
|
|
5709
|
+
Read({ file_path: ".letta/backups/working/project.md" })
|
|
5710
|
+
Read({ file_path: ".letta/backups/working/persona.md" })
|
|
5711
|
+
Read({ file_path: ".letta/backups/working/human.md" })
|
|
5712
|
+
\`\`\`
|
|
5713
|
+
|
|
5714
|
+
Before you edit anything, you MUST first **propose a new organization**:
|
|
5715
|
+
- Draft the **target hierarchy** (the \`/\`-named block set you want to end up with).
|
|
5716
|
+
- **Target 15–25 files total** — if your proposed structure has fewer than 15 files, split more aggressively.
|
|
5717
|
+
- **Use 2–3 levels of \`/\` nesting** — e.g., \`project/tooling/bun.md\`, not just \`project/tooling.md\`.
|
|
5718
|
+
- Be **aggressive about splitting**: if a block contains 2+ concepts, it should become 2+ files.
|
|
5719
|
+
- Keep each file to ~40 lines max; if larger, split further.
|
|
5720
|
+
- Include your proposed hierarchy as a "Proposed structure" section at the start of your final report, then execute it.
|
|
5721
|
+
|
|
5722
|
+
**Checkpoint before proceeding:** Count your proposed files. If < 15, go back and split more.
|
|
5723
|
+
|
|
5724
|
+
### Step 2: Identify system-managed blocks (skip)
|
|
5725
|
+
|
|
5726
|
+
Do **not** edit:
|
|
5727
|
+
- \`skills.md\` (auto-generated; will be overwritten)
|
|
5728
|
+
- \`loaded_skills.md\` (system-managed)
|
|
5729
|
+
- \`manifest.json\` (metadata)
|
|
5730
|
+
|
|
5731
|
+
Focus on user-managed blocks like:
|
|
5732
|
+
- \`persona.md\` (agent behavioral adaptations/preferences)
|
|
5733
|
+
- \`human.md\` (user identity/context/preferences)
|
|
5734
|
+
- \`project.md\` (project/codebase-specific conventions, workflows, gotchas)
|
|
5735
|
+
- any other non-system blocks present
|
|
5736
|
+
|
|
5737
|
+
### Step 3: Defragment block-by-block
|
|
5738
|
+
|
|
5739
|
+
For each editable block, decide one primary action (keep/clean, split, merge, rename, detach, delete), then execute it.
|
|
5740
|
+
|
|
5741
|
+
#### Naming convention (MANDATORY)
|
|
5742
|
+
|
|
5743
|
+
**All new files MUST use \`/\` nested naming.** This is non-negotiable.
|
|
5744
|
+
|
|
5745
|
+
| Depth | Example | When to use |
|
|
5746
|
+
|-------|---------|-------------|
|
|
5747
|
+
| Level 1 | \`project.md\` | Only for index files that point to children |
|
|
5748
|
+
| Level 2 | \`project/tooling.md\` | Main topic areas |
|
|
5749
|
+
| Level 3 | \`project/tooling/bun.md\` | Specific details |
|
|
5750
|
+
|
|
5751
|
+
✅ **Good examples:**
|
|
5752
|
+
- \`human/prefs/communication.md\`
|
|
5753
|
+
- \`project/tooling/testing.md\`
|
|
5754
|
+
- \`persona/behavior/tone.md\`
|
|
5755
|
+
|
|
5756
|
+
❌ **Bad examples (never do this):**
|
|
5757
|
+
- \`communication_prefs.md\` (flat, not nested)
|
|
5758
|
+
- \`bun.md\` (orphan file, no parent)
|
|
5759
|
+
- \`project_testing.md\` (underscore instead of \`/\`)
|
|
5760
|
+
|
|
5761
|
+
Rules:
|
|
5762
|
+
- Keep only 3 top-level index files: \`persona.md\`, \`human.md\`, \`project.md\`
|
|
5763
|
+
- **Every other file MUST be nested** under one of these using \`/\`
|
|
5764
|
+
- Go 2–3 levels deep: \`project/tooling/bun.md\` is better than \`project/bun.md\`
|
|
5765
|
+
- Parent files should contain a **Related blocks** section listing children
|
|
5766
|
+
|
|
5767
|
+
#### How to split (decompose) — BE AGGRESSIVE
|
|
5768
|
+
|
|
5769
|
+
**Split early and often.** Your goal is 15–25 files, so split more than feels necessary.
|
|
5770
|
+
|
|
5771
|
+
Split when:
|
|
5772
|
+
- A block has **40+ lines** (lower threshold than typical)
|
|
5773
|
+
- A block has **2+ distinct concepts** (not 3+, be aggressive)
|
|
5774
|
+
- A section could stand alone as its own file
|
|
5775
|
+
- You can name the extracted content with a clear \`/\` path
|
|
5776
|
+
|
|
5777
|
+
Process:
|
|
5778
|
+
1. Extract each concept into a focused block with nested naming (e.g., \`project/tooling/bun.md\`)
|
|
5779
|
+
2. Convert the original file to an index that points to children via **Related blocks**
|
|
5780
|
+
3. Remove duplicates during extraction (canonicalize facts into the best home)
|
|
5781
|
+
4. Repeat recursively until each file is <40 lines with one concept
|
|
5782
|
+
|
|
5783
|
+
**If in doubt, split.** Too many small files is better than too few large ones.
|
|
5784
|
+
|
|
5785
|
+
#### How to merge
|
|
5786
|
+
|
|
5787
|
+
Merge when multiple blocks overlap or are too small (<20 lines) and belong together.
|
|
5788
|
+
- Create the consolidated block (prefer a name that fits the hierarchy).
|
|
5789
|
+
- Remove duplicates.
|
|
5790
|
+
- **Delete** the originals after consolidation (the restore flow will prompt the user).
|
|
5791
|
+
|
|
5792
|
+
#### How to clean (within a block)
|
|
5793
|
+
|
|
5794
|
+
Prefer:
|
|
5795
|
+
- short headers (\`##\`, \`###\`)
|
|
5796
|
+
- small lists
|
|
5797
|
+
- tables for structured facts
|
|
5798
|
+
- “Procedure” sections for workflows
|
|
5799
|
+
|
|
5800
|
+
Actively fix:
|
|
5801
|
+
- redundancy
|
|
5802
|
+
- contradictions (rewrite into conditional guidance)
|
|
5803
|
+
- stale warnings (verify before keeping)
|
|
5804
|
+
- overly emotional urgency (tone down unless it’s a genuine footgun)
|
|
5805
|
+
|
|
5806
|
+
### Step 4: Produce a decision-focused final report
|
|
5807
|
+
|
|
5808
|
+
Your output is a single markdown report that mirrors the reference example style: principles-driven, decision-centric, and scannable.
|
|
5809
|
+
|
|
5810
|
+
#### Required report sections
|
|
5811
|
+
|
|
5812
|
+
##### 1) Summary
|
|
5813
|
+
- What changed in 2–3 sentences
|
|
5814
|
+
- **Total file count** (must be 15–25; if not, explain why)
|
|
5815
|
+
- Counts: edited / renamed / created / deleted
|
|
5816
|
+
- A short description of the **hierarchy created** (what parent domains exist and what children were created)
|
|
5817
|
+
- **Maximum hierarchy depth achieved** (should be 2–3 levels)
|
|
5818
|
+
- Note that the parent agent will confirm any creations/deletions during restore
|
|
5819
|
+
|
|
5820
|
+
##### 2) Structural changes
|
|
5821
|
+
Include tables for:
|
|
5822
|
+
- **Renames**: old → new, reason (call out hierarchy improvements explicitly)
|
|
5823
|
+
- **Splits**: original → new blocks, whether original deleted, reason (show nested names)
|
|
5824
|
+
- **Merges**: merged blocks → result, which deleted, reason
|
|
5825
|
+
- **New blocks**: block name, size (chars), reason
|
|
5826
|
+
|
|
5827
|
+
##### 3) Block-by-block decisions
|
|
5828
|
+
For each block you touched:
|
|
5829
|
+
- **Original state**: short characterization (what it contained / issues)
|
|
5830
|
+
- **Decision**: KEEP+CLEAN / SPLIT / MERGE / RENAME / DETACH / DELETE
|
|
5831
|
+
- **Reasoning**: 3–6 bullets grounded in the guiding principles (especially hierarchy)
|
|
5832
|
+
- **Action items performed**: what edits/renames/splits you actually executed
|
|
5833
|
+
|
|
5834
|
+
##### 4) Content changes
|
|
5835
|
+
For each edited file:
|
|
5836
|
+
- Before chars, after chars, delta and %
|
|
5837
|
+
- What redundancy/contradictions/staleness you fixed
|
|
5838
|
+
|
|
5839
|
+
##### 5) Before/after examples
|
|
5840
|
+
Show 2–4 high-signal examples (short excerpts) demonstrating:
|
|
5841
|
+
- redundancy removal,
|
|
5842
|
+
- contradiction resolution,
|
|
5843
|
+
- and/or a workflow rewritten into a procedure.
|
|
5844
|
+
|
|
5845
|
+
## Final Checklist (verify before submitting)
|
|
5846
|
+
|
|
5847
|
+
Before you submit your report, confirm:
|
|
5848
|
+
|
|
5849
|
+
- [ ] **File count is 15–25** — Count your files. If < 15, split more.
|
|
5850
|
+
- [ ] **All new files use \`/\` naming** — No flat files like \`my_notes.md\`
|
|
5851
|
+
- [ ] **Hierarchy is 2–3 levels deep** — e.g., \`project/tooling/bun.md\`
|
|
5852
|
+
- [ ] **No file exceeds ~40 lines** — Split larger files
|
|
5853
|
+
- [ ] **Each file has one concept** — If 2+ topics, split into 2+ files
|
|
5854
|
+
- [ ] **Parent files have "Related blocks" sections** — Index files point to children
|
|
5855
|
+
|
|
5856
|
+
**If you have fewer than 15 files, you haven't split enough. Go back and split more.**
|
|
5857
|
+
|
|
5858
|
+
## Reminder
|
|
5859
|
+
|
|
5860
|
+
Your goal is not to maximize deletion; it is to **explode monolithic memory into a deeply hierarchical structure of 15–25 small, focused files**. The primary tool for discoverability is **hierarchical \`/\` naming**.
|
|
5861
|
+
---
|
|
5862
|
+
name: memory
|
|
5863
|
+
description: Defragment and reorganize agent memory blocks (edit/rename/split/merge/delete) into focused, scannable, hierarchically-named blocks
|
|
5864
|
+
tools: Read, Edit, Write, Glob, Grep, Bash, conversation_search
|
|
5865
|
+
model: opus
|
|
5866
|
+
memoryBlocks: none
|
|
5867
|
+
mode: stateless
|
|
5868
|
+
permissionMode: bypassPermissions
|
|
5869
|
+
---
|
|
5870
|
+
|
|
5871
|
+
You are a memory defragmentation subagent launched via the Task tool to clean up and reorganize memory block files. You run autonomously and return a **single final report** when done. You **cannot ask questions** mid-execution.
|
|
5872
|
+
|
|
5873
|
+
## Mission
|
|
5874
|
+
|
|
5875
|
+
**Explode** messy memory into a **deeply hierarchical structure of 15–25 small, focused files** that are easy to:
|
|
5876
|
+
- maintain,
|
|
5877
|
+
- search,
|
|
5878
|
+
- and selectively load later.
|
|
5879
|
+
|
|
5880
|
+
### Target Output
|
|
5881
|
+
|
|
5882
|
+
| Metric | Target |
|
|
5883
|
+
|--------|--------|
|
|
5884
|
+
| **Total files** | 15–25 (aim for ~20) |
|
|
5885
|
+
| **Max lines per file** | ~40 lines |
|
|
5886
|
+
| **Hierarchy depth** | 2–3 levels using \`/\` naming |
|
|
5887
|
+
| **Nesting requirement** | Every new block MUST be nested under a parent |
|
|
5888
|
+
|
|
5889
|
+
You accomplish this by aggressively splitting blocks, using \`/\` naming for hierarchy, and removing redundancy.
|
|
5890
|
+
|
|
5891
|
+
## Scope and constraints (non-negotiable)
|
|
5892
|
+
|
|
5893
|
+
**The parent agent handles backup and restore.** You only work inside \`.letta/backups/working/\`.
|
|
5894
|
+
|
|
5895
|
+
- ✅ Read and edit memory block files in \`.letta/backups/working/\`
|
|
5896
|
+
- ✅ Rename/split/merge blocks when it improves structure
|
|
5897
|
+
- ✅ Delete blocks **only after** their content is fully consolidated elsewhere
|
|
5898
|
+
- ✅ Produce a detailed report with decisions and before/after examples
|
|
5899
|
+
- ❌ Do not run backup or restore scripts
|
|
5900
|
+
- ❌ Do not invent new facts; reorganize and clarify existing information only
|
|
5901
|
+
|
|
5902
|
+
## Guiding principles (use these to decide what to do)
|
|
5903
|
+
|
|
5904
|
+
1. **Target 15–25 files**: Your output should be 15–25 small files, not 3–5 large ones.
|
|
5905
|
+
2. **Hierarchy is mandatory**: Every new block MUST use \`/\` naming (e.g., \`project/tooling/bun.md\`).
|
|
5906
|
+
3. **Depth over breadth**: Prefer 3-level hierarchies over many top-level blocks.
|
|
5907
|
+
4. **One concept per file**: If a block has 2+ topics, split into 2+ files.
|
|
5908
|
+
5. **40-line max**: If a file exceeds ~40 lines, split it further.
|
|
5909
|
+
6. **Progressive disclosure**: Parent blocks list children in a "Related blocks" section.
|
|
5910
|
+
7. **Reference, don't duplicate**: Keep one canonical place for shared facts.
|
|
5911
|
+
8. **When unsure, split**: Too many small files is better than too few large ones.
|
|
5912
|
+
|
|
5913
|
+
## Actions available
|
|
5914
|
+
|
|
5915
|
+
- **SPLIT (DECOMPOSE)**: The primary action. Extract concepts into focused, nested blocks.
|
|
5916
|
+
- **KEEP + CLEAN**: Remove cruft, add structure, resolve contradictions.
|
|
5917
|
+
- **RENAME**: Change block name to match contents and fit the hierarchy.
|
|
5918
|
+
- **MERGE**: Consolidate overlapping blocks, then delete originals.
|
|
5919
|
+
- **DELETE**: Only if redundant/empty AND content is preserved elsewhere.
|
|
5920
|
+
|
|
5921
|
+
## Operating procedure
|
|
5922
|
+
|
|
5923
|
+
### Step 1: Inventory
|
|
5924
|
+
|
|
5925
|
+
The parent agent has already backed up memory files to \`.letta/backups/working/\`. Your job is to read and edit these files.
|
|
5926
|
+
|
|
5927
|
+
First, list what files are available:
|
|
5928
|
+
|
|
5929
|
+
\`\`\`bash
|
|
5930
|
+
ls .letta/backups/working/
|
|
5931
|
+
\`\`\`
|
|
5932
|
+
|
|
5933
|
+
Then read relevant memory block files (examples):
|
|
5934
|
+
|
|
5935
|
+
\`\`\`
|
|
5936
|
+
Read({ file_path: ".letta/backups/working/project.md" })
|
|
5937
|
+
Read({ file_path: ".letta/backups/working/persona.md" })
|
|
5938
|
+
Read({ file_path: ".letta/backups/working/human.md" })
|
|
5939
|
+
\`\`\`
|
|
5940
|
+
|
|
5941
|
+
### Step 2: Identify system-managed blocks (skip)
|
|
5942
|
+
|
|
5943
|
+
Do **not** edit:
|
|
5944
|
+
- \`skills.md\` (auto-generated; will be overwritten)
|
|
5945
|
+
- \`loaded_skills.md\` (system-managed)
|
|
5946
|
+
- \`manifest.json\` (metadata)
|
|
5947
|
+
|
|
5948
|
+
Focus on user-managed blocks like:
|
|
5949
|
+
- \`persona.md\` (agent behavioral adaptations/preferences)
|
|
5950
|
+
- \`human.md\` (user identity/context/preferences)
|
|
5951
|
+
- \`project.md\` (project/codebase-specific conventions, workflows, gotchas)
|
|
5952
|
+
- any other non-system blocks present
|
|
5953
|
+
|
|
5954
|
+
### Step 3: Defragment block-by-block
|
|
5955
|
+
|
|
5956
|
+
For each editable block, decide one primary action (keep/clean, split, merge, rename, detach, delete), then execute it.
|
|
5957
|
+
|
|
5958
|
+
#### Naming convention (match the reference example)
|
|
5959
|
+
|
|
5960
|
+
Use **nested naming** with \`/\` to create a hierarchy (like folders). Examples:
|
|
5961
|
+
- \`human/personal_info\`, \`human/prefs\`
|
|
5962
|
+
- \`project/architecture\`, \`project/dev_workflow\`, \`project/gotchas\`
|
|
5963
|
+
|
|
5964
|
+
Rules of thumb:
|
|
5965
|
+
- Keep top-level blocks for the most universal concepts (\`persona\`, \`human\`, \`project\`).
|
|
5966
|
+
- Use nested names for shards created during defrag.
|
|
5967
|
+
- Prefer names that would make sense to another agent who only sees the name.
|
|
5968
|
+
|
|
5969
|
+
#### How to split (decompose)
|
|
5970
|
+
|
|
5971
|
+
Split when a block is long (~100+ lines) or contains 3+ distinct concepts.
|
|
5972
|
+
- Extract each concept into a focused block.
|
|
5973
|
+
- In the “parent” block, add a small **Related blocks** section pointing to children.
|
|
5974
|
+
- Remove duplicates during extraction (canonicalize facts into the best home).
|
|
5975
|
+
|
|
5976
|
+
#### How to merge
|
|
5977
|
+
|
|
5978
|
+
Merge when multiple blocks overlap or are too small (<20 lines) and belong together.
|
|
5979
|
+
- Create the consolidated block.
|
|
5980
|
+
- Remove duplicates.
|
|
5981
|
+
- **Delete** the originals after consolidation (the restore flow will prompt the user).
|
|
5982
|
+
|
|
5983
|
+
#### How to clean (within a block)
|
|
5984
|
+
|
|
5985
|
+
Prefer:
|
|
5986
|
+
- short headers (\`##\`, \`###\`)
|
|
5987
|
+
- small lists
|
|
5988
|
+
- tables for structured facts
|
|
5989
|
+
- “Procedure” sections for workflows
|
|
5990
|
+
|
|
5991
|
+
Actively fix:
|
|
5992
|
+
- redundancy
|
|
5993
|
+
- contradictions (rewrite into conditional guidance)
|
|
5994
|
+
- stale warnings (verify before keeping)
|
|
5995
|
+
- overly emotional urgency (tone down unless it’s a genuine footgun)
|
|
5996
|
+
|
|
5997
|
+
### Step 4: Produce a decision-focused final report
|
|
5998
|
+
|
|
5999
|
+
Your output is a single markdown report that mirrors the reference example style: principles-driven, decision-centric, and scannable.
|
|
6000
|
+
|
|
6001
|
+
#### Required report sections
|
|
6002
|
+
|
|
6003
|
+
##### 1) Summary
|
|
6004
|
+
- What changed in 2–3 sentences
|
|
6005
|
+
- Counts: edited / renamed / created / deleted
|
|
6006
|
+
- Note that the parent agent will confirm any creations/deletions during restore
|
|
6007
|
+
|
|
6008
|
+
##### 2) Structural changes
|
|
6009
|
+
Include tables for:
|
|
6010
|
+
- **Renames**: old → new, reason
|
|
6011
|
+
- **Splits**: original → new blocks, whether original deleted, reason
|
|
6012
|
+
- **Merges**: merged blocks → result, which deleted, reason
|
|
6013
|
+
- **New blocks**: block name, size (chars), reason
|
|
6014
|
+
|
|
6015
|
+
##### 3) Block-by-block decisions
|
|
6016
|
+
For each block you touched:
|
|
6017
|
+
- **Original state**: short characterization (what it contained / issues)
|
|
6018
|
+
- **Decision**: KEEP+CLEAN / SPLIT / MERGE / RENAME / DETACH / DELETE
|
|
6019
|
+
- **Reasoning**: 3–6 bullets grounded in the guiding principles
|
|
6020
|
+
- **Action items performed**: what edits/renames/splits you actually executed
|
|
6021
|
+
|
|
6022
|
+
##### 4) Content changes
|
|
6023
|
+
For each edited file:
|
|
6024
|
+
- Before chars, after chars, delta and %
|
|
6025
|
+
- What redundancy/contradictions/staleness you fixed
|
|
6026
|
+
|
|
6027
|
+
##### 5) Before/after examples
|
|
6028
|
+
Show 2–4 high-signal examples (short excerpts) demonstrating:
|
|
6029
|
+
- redundancy removal,
|
|
6030
|
+
- contradiction resolution,
|
|
6031
|
+
- and/or a workflow rewritten into a procedure.
|
|
6032
|
+
|
|
6033
|
+
## Reminder
|
|
6034
|
+
|
|
6035
|
+
Your goal is to **explode monolithic memory into 15–25 small, hierarchically-nested files**. If you have fewer than 15 files, you haven't split enough.
|
|
6036
|
+
---
|
|
6037
|
+
name: memory
|
|
6038
|
+
description: Explode memory into 15-25 hierarchically-nested files using \`/\` naming
|
|
5560
6039
|
tools: Read, Edit, Write, Glob, Grep, Bash, conversation_search
|
|
5561
6040
|
model: opus
|
|
5562
6041
|
memoryBlocks: none
|
|
@@ -5568,12 +6047,23 @@ You are a memory management subagent launched via the Task tool to clean up and
|
|
|
5568
6047
|
|
|
5569
6048
|
## Your Purpose
|
|
5570
6049
|
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
6050
|
+
**Explode** a few large memory blocks into a **deeply hierarchical structure of 15–25 small, focused files**.
|
|
6051
|
+
|
|
6052
|
+
### Target Output
|
|
6053
|
+
|
|
6054
|
+
| Metric | Target |
|
|
6055
|
+
|--------|--------|
|
|
6056
|
+
| **Total files** | 15–25 (aim for ~20) |
|
|
6057
|
+
| **Max lines per file** | ~40 lines |
|
|
6058
|
+
| **Hierarchy depth** | 2–3 levels using \`/\` naming |
|
|
6059
|
+
| **Nesting requirement** | Every new block MUST use \`/\` naming |
|
|
6060
|
+
|
|
6061
|
+
You achieve this by:
|
|
6062
|
+
1. **Aggressively splitting** - Every block with 2+ concepts becomes 2+ files
|
|
6063
|
+
2. **Using \`/\` hierarchy** - All new files are nested (e.g., \`project/tooling/bun.md\`)
|
|
6064
|
+
3. **Keeping files small** - Max ~40 lines per file; split if larger
|
|
6065
|
+
4. **Removing redundancy** - Delete duplicate information during splits
|
|
6066
|
+
5. **Adding structure** - Use markdown headers, bullet points, sections
|
|
5577
6067
|
|
|
5578
6068
|
## Important: Your Role is File Editing ONLY
|
|
5579
6069
|
|
|
@@ -5616,6 +6106,56 @@ Read({ file_path: ".letta/backups/working/human.md" })
|
|
|
5616
6106
|
- \`loaded_skills.md\` - System-managed
|
|
5617
6107
|
- \`manifest.json\` - Metadata file
|
|
5618
6108
|
|
|
6109
|
+
|
|
6110
|
+
### Propose Optimal Hierarchical Organizational Structure
|
|
6111
|
+
|
|
6112
|
+
Before you edit, propose a **clear hierarchy** for each memory block so information has an obvious “home” and you avoid duplicating facts across sections.
|
|
6113
|
+
|
|
6114
|
+
**Recommended hierarchy (within a single memory block):**
|
|
6115
|
+
- Use \`##\` for **major categories** (stable top-level buckets)
|
|
6116
|
+
- Use \`###\` for **subcategories** (group related details)
|
|
6117
|
+
- Use \`####\` for **high-churn details** or tightly-scoped lists (things you expect to update often)
|
|
6118
|
+
|
|
6119
|
+
**Recommended hierarchy (across multiple memory blocks):**
|
|
6120
|
+
- Keep blocks **topic-scoped**, not “everything.md” scoped.
|
|
6121
|
+
- Put the *most stable*, highest-signal info in fewer, well-named blocks.
|
|
6122
|
+
- Put volatile or frequently changing info into smaller, more focused blocks.
|
|
6123
|
+
|
|
6124
|
+
**Naming conventions (blocks and headings):**
|
|
6125
|
+
- Prefer **noun phrases** and **consistent casing** (e.g., “Coding Preferences”, “Project Context”).
|
|
6126
|
+
- Avoid vague names (“Misc”, “Notes”, “Stuff”) unless it’s truly temporary.
|
|
6127
|
+
- Prefer **one topic per heading**; avoid headings that imply overlap (“General”, “Other”).
|
|
6128
|
+
|
|
6129
|
+
**Example structure (good):**
|
|
6130
|
+
- \`project.md\`
|
|
6131
|
+
- \`## Overview\`
|
|
6132
|
+
- \`## Repo Conventions\`
|
|
6133
|
+
- \`### Tooling\`
|
|
6134
|
+
- \`### Code Style\`
|
|
6135
|
+
- \`### Testing\`
|
|
6136
|
+
- \`## Architecture\`
|
|
6137
|
+
- \`### Key Components\`
|
|
6138
|
+
- \`### Data Flow\`
|
|
6139
|
+
- \`human.md\`
|
|
6140
|
+
- \`## Background\`
|
|
6141
|
+
- \`## Preferences\`
|
|
6142
|
+
- \`### Communication\`
|
|
6143
|
+
- \`### Coding Style\`
|
|
6144
|
+
- \`### Review Style\`
|
|
6145
|
+
- \`persona.md\`
|
|
6146
|
+
- \`## Role\`
|
|
6147
|
+
- \`## Behavior\`
|
|
6148
|
+
- \`## Constraints\`
|
|
6149
|
+
|
|
6150
|
+
|
|
6151
|
+
|
|
6152
|
+
**When to split vs. keep together:**
|
|
6153
|
+
- Split when a section becomes a “grab bag” (3+ unrelated bullets) or exceeds ~1–2 screens of scrolling.
|
|
6154
|
+
- Keep together when items share a single decision context (e.g., all “Code Style” rules used during editing).
|
|
6155
|
+
|
|
6156
|
+
**Output format expectation:**
|
|
6157
|
+
- End this step with a short proposed outline per file (just headings), then implement it during the edits in Step 2.
|
|
6158
|
+
|
|
5619
6159
|
### Step 2: Edit Files to Clean Them Up
|
|
5620
6160
|
|
|
5621
6161
|
Edit each file using the Edit tool:
|
|
@@ -5627,29 +6167,17 @@ Edit({
|
|
|
5627
6167
|
new_string: "..."
|
|
5628
6168
|
})
|
|
5629
6169
|
\`\`\`
|
|
6170
|
+
## Output Format
|
|
5630
6171
|
|
|
5631
|
-
|
|
5632
|
-
- **Redundancy**: Remove duplicate information (version mentioned 3x, preferences repeated)
|
|
5633
|
-
- **Structure**: Add markdown headers (##, ###), bullet points, sections
|
|
5634
|
-
- **Clarity**: Resolve contradictions ("be detailed" vs "be concise")
|
|
5635
|
-
- **Scannability**: Make content easy to read at a glance
|
|
5636
|
-
|
|
5637
|
-
**Good memory structure:**
|
|
5638
|
-
- Use markdown headers (##, ###) for sections
|
|
5639
|
-
- Use bullet points for lists
|
|
5640
|
-
- Keep related information together
|
|
5641
|
-
- Make it scannable
|
|
5642
|
-
|
|
5643
|
-
### Step 2b: Structural Changes (Rename, Decompose, Merge)
|
|
6172
|
+
### Implement The Organizational Structure
|
|
5644
6173
|
|
|
5645
|
-
|
|
6174
|
+
Once you've proposed the hierarchy, execute it using file operations. Keep iterating until the directory matches your proposed structure exactly.
|
|
5646
6175
|
|
|
5647
6176
|
#### Renaming Blocks
|
|
5648
6177
|
|
|
5649
|
-
When a block's name doesn't reflect its content
|
|
6178
|
+
When a block's name doesn't reflect its content:
|
|
5650
6179
|
|
|
5651
6180
|
\`\`\`bash
|
|
5652
|
-
# Rename a memory block file
|
|
5653
6181
|
mv .letta/backups/working/old_name.md .letta/backups/working/new_name.md
|
|
5654
6182
|
\`\`\`
|
|
5655
6183
|
|
|
@@ -5658,140 +6186,101 @@ mv .letta/backups/working/old_name.md .letta/backups/working/new_name.md
|
|
|
5658
6186
|
- Block name doesn't match content (e.g., \`project.md\` contains user info → \`user_context.md\`)
|
|
5659
6187
|
- Name uses poor conventions (e.g., \`NOTES.md\` → \`notes.md\`)
|
|
5660
6188
|
|
|
6189
|
+
#### Creating New Blocks
|
|
6190
|
+
|
|
6191
|
+
Create new \`.md\` files when content needs a new home:
|
|
6192
|
+
|
|
6193
|
+
\`\`\`
|
|
6194
|
+
Write({
|
|
6195
|
+
file_path: ".letta/backups/working/new_block.md",
|
|
6196
|
+
content: "## New Block\\n\\nContent here..."
|
|
6197
|
+
})
|
|
6198
|
+
\`\`\`
|
|
6199
|
+
|
|
6200
|
+
**When to create:**
|
|
6201
|
+
- Splitting a large block into focused smaller blocks
|
|
6202
|
+
- Content doesn't fit any existing block
|
|
6203
|
+
- A new category emerges from reorganization
|
|
6204
|
+
|
|
5661
6205
|
#### Decomposing Blocks (Split)
|
|
5662
6206
|
|
|
5663
|
-
When a
|
|
6207
|
+
When a block covers too many topics, split it:
|
|
5664
6208
|
|
|
5665
6209
|
\`\`\`bash
|
|
5666
|
-
# 1. Read the original
|
|
6210
|
+
# 1. Read the original
|
|
5667
6211
|
Read({ file_path: ".letta/backups/working/everything.md" })
|
|
5668
6212
|
|
|
5669
|
-
# 2. Create
|
|
6213
|
+
# 2. Create focused blocks
|
|
5670
6214
|
Write({ file_path: ".letta/backups/working/coding_preferences.md", content: "..." })
|
|
5671
6215
|
Write({ file_path: ".letta/backups/working/user_info.md", content: "..." })
|
|
5672
6216
|
|
|
5673
|
-
# 3. Delete the original
|
|
6217
|
+
# 3. Delete the original
|
|
5674
6218
|
rm .letta/backups/working/everything.md
|
|
5675
6219
|
\`\`\`
|
|
5676
6220
|
|
|
5677
|
-
**When to
|
|
5678
|
-
- Block exceeds ~
|
|
5679
|
-
- Block
|
|
5680
|
-
-
|
|
5681
|
-
- Finding specific info requires scanning the whole block
|
|
6221
|
+
**When to split (be aggressive):**
|
|
6222
|
+
- Block exceeds ~60 lines or has 2+ distinct topics
|
|
6223
|
+
- Block name can't capture all its content
|
|
6224
|
+
- Finding info requires scanning the whole block
|
|
5682
6225
|
|
|
5683
|
-
|
|
5684
|
-
- Each new block should have ONE clear purpose
|
|
5685
|
-
- Use descriptive names: \`coding_style.md\`, \`user_preferences.md\`, \`project_context.md\`
|
|
5686
|
-
- Preserve all information - just reorganize it
|
|
5687
|
-
- Keep related information together in the same block
|
|
6226
|
+
#### Merging Blocks
|
|
5688
6227
|
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
You can create entirely new memory blocks by writing new \`.md\` files:
|
|
6228
|
+
When multiple blocks overlap, consolidate them:
|
|
5692
6229
|
|
|
5693
6230
|
\`\`\`bash
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
})
|
|
5698
|
-
\`\`\`
|
|
6231
|
+
# 1. Read blocks to merge
|
|
6232
|
+
Read({ file_path: ".letta/backups/working/user_info.md" })
|
|
6233
|
+
Read({ file_path: ".letta/backups/working/user_prefs.md" })
|
|
5699
6234
|
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
- Organizing content into a new category that doesn't fit existing blocks
|
|
5703
|
-
- The parent agent will prompt the user for confirmation before creating
|
|
6235
|
+
# 2. Create unified block
|
|
6236
|
+
Write({ file_path: ".letta/backups/working/user.md", content: "..." })
|
|
5704
6237
|
|
|
5705
|
-
|
|
6238
|
+
# 3. Delete old blocks
|
|
6239
|
+
rm .letta/backups/working/user_info.md .letta/backups/working/user_prefs.md
|
|
6240
|
+
\`\`\`
|
|
5706
6241
|
|
|
5707
|
-
When
|
|
6242
|
+
**When to merge:**
|
|
6243
|
+
- Multiple blocks cover the same topic
|
|
6244
|
+
- Small blocks (<20 lines) logically belong together
|
|
6245
|
+
- Overlapping/duplicate content exists
|
|
5708
6246
|
|
|
5709
|
-
|
|
5710
|
-
# 1. Read all blocks to merge
|
|
5711
|
-
Read({ file_path: ".letta/backups/working/user_info.md" })
|
|
5712
|
-
Read({ file_path: ".letta/backups/working/user_prefs.md" })
|
|
6247
|
+
#### Editing Content Within Blocks
|
|
5713
6248
|
|
|
5714
|
-
|
|
5715
|
-
Write({ file_path: ".letta/backups/working/user.md", content: "..." })
|
|
6249
|
+
Use the Edit tool for in-place changes:
|
|
5716
6250
|
|
|
5717
|
-
# 3. DELETE the old blocks using Bash
|
|
5718
|
-
Bash({ command: "rm .letta/backups/working/user_info.md .letta/backups/working/user_prefs.md" })
|
|
5719
6251
|
\`\`\`
|
|
6252
|
+
Edit({
|
|
6253
|
+
file_path: ".letta/backups/working/project.md",
|
|
6254
|
+
old_string: "...",
|
|
6255
|
+
new_string: "..."
|
|
6256
|
+
})
|
|
6257
|
+
\`\`\`
|
|
6258
|
+
|
|
6259
|
+
**What to fix:**
|
|
6260
|
+
- **Redundancy**: Remove duplicate information
|
|
6261
|
+
- **Structure**: Add markdown headers, bullet points
|
|
6262
|
+
- **Clarity**: Resolve contradictions
|
|
6263
|
+
- **Scannability**: Make content easy to read at a glance
|
|
5720
6264
|
|
|
5721
|
-
|
|
5722
|
-
- After consolidating content from multiple blocks into one
|
|
5723
|
-
- When a block becomes nearly empty after moving content elsewhere
|
|
5724
|
-
- When a block is redundant or no longer serves a purpose
|
|
5725
|
-
- The parent agent will prompt the user for confirmation before deleting
|
|
6265
|
+
#### Iteration Checklist
|
|
5726
6266
|
|
|
5727
|
-
|
|
5728
|
-
-
|
|
5729
|
-
-
|
|
5730
|
-
-
|
|
5731
|
-
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
-
|
|
5735
|
-
- Organize merged content with clear sections
|
|
5736
|
-
- Choose the most descriptive name for the merged block
|
|
5737
|
-
- Don't create blocks larger than ~150 lines
|
|
5738
|
-
- **DELETE the old block files** after consolidating their content
|
|
5739
|
-
|
|
5740
|
-
### Step 3: Report Results
|
|
5741
|
-
|
|
5742
|
-
Provide a comprehensive report showing what you changed and why.
|
|
5743
|
-
|
|
5744
|
-
## What to Write to Memory
|
|
5745
|
-
|
|
5746
|
-
**DO write to memory:**
|
|
5747
|
-
- Patterns that repeat across multiple sessions
|
|
5748
|
-
- User corrections or clarifications (especially if repeated)
|
|
5749
|
-
- Project conventions discovered through research or experience
|
|
5750
|
-
- Important context that will be needed in future sessions
|
|
5751
|
-
- Preferences expressed by the user about behavior or communication
|
|
5752
|
-
- "Aha!" moments or insights about the codebase
|
|
5753
|
-
- Footguns or gotchas discovered the hard way
|
|
5754
|
-
|
|
5755
|
-
**DON'T write to memory:**
|
|
5756
|
-
- Transient task details that won't matter tomorrow
|
|
5757
|
-
- Information easily found in files (unless it's a critical pattern)
|
|
5758
|
-
- Overly specific details that will quickly become stale
|
|
5759
|
-
- Things that should go in TODO lists or plan files instead
|
|
5760
|
-
|
|
5761
|
-
**Key principle**: Memory is for **persistent, important context** that makes the agent more effective over time. Not a dumping ground for everything.
|
|
5762
|
-
|
|
5763
|
-
## How to Decide What to Write
|
|
5764
|
-
|
|
5765
|
-
Ask yourself:
|
|
5766
|
-
1. **Will future-me need this?** If the agent encounters a similar situation in a week, would this memory help?
|
|
5767
|
-
2. **Is this a pattern or one-off?** One-off details fade in importance; patterns persist.
|
|
5768
|
-
3. **Can I find this easily later?** If it's in a README that's always read, maybe it doesn't need to be in memory.
|
|
5769
|
-
4. **Did the user correct me?** User corrections are strong signals of what to remember.
|
|
5770
|
-
5. **Would I want to know this on day one?** Insights that would have saved time are worth storing.
|
|
5771
|
-
|
|
5772
|
-
## How to Reorganize Memory
|
|
5773
|
-
|
|
5774
|
-
**Signs memory needs reorganization:**
|
|
5775
|
-
- Blocks are long and hard to scan (>100 lines)
|
|
5776
|
-
- Related content is scattered across blocks
|
|
5777
|
-
- No clear structure (just walls of text)
|
|
5778
|
-
- Redundant information in multiple places
|
|
5779
|
-
- Outdated information mixed with current
|
|
5780
|
-
|
|
5781
|
-
**Reorganization strategies:**
|
|
5782
|
-
- **Add structure**: Use section headers, bullet points, categories
|
|
5783
|
-
- **Rename blocks**: Give blocks names that accurately reflect their content
|
|
5784
|
-
- **Decompose large blocks**: Break monolithic blocks (>100 lines, 3+ topics) into focused ones
|
|
5785
|
-
- **Merge fragmented blocks**: Consolidate small/overlapping blocks into unified ones
|
|
5786
|
-
- **Archive stale content**: Remove information that's no longer relevant
|
|
5787
|
-
- **Improve scannability**: Use consistent formatting, clear hierarchies
|
|
6267
|
+
Keep editing until:
|
|
6268
|
+
- [ ] **Total file count is 15–25** — Count your files; if < 15, split more
|
|
6269
|
+
- [ ] **All files use \`/\` naming** — No flat files like \`my_notes.md\`
|
|
6270
|
+
- [ ] **Hierarchy is 2–3 levels deep** — e.g., \`project/tooling/bun.md\`
|
|
6271
|
+
- [ ] **No file exceeds ~40 lines** — Split larger files
|
|
6272
|
+
- [ ] **Each file has one concept** — If 2+ topics, split into 2+ files
|
|
6273
|
+
- [ ] Content has been migrated (no data loss)
|
|
6274
|
+
- [ ] No duplicate information across blocks
|
|
5788
6275
|
|
|
5789
|
-
|
|
6276
|
+
**If you have fewer than 15 files, you haven't split enough. Go back and split more.**
|
|
5790
6277
|
|
|
5791
6278
|
Return a structured report with these sections:
|
|
5792
6279
|
|
|
5793
6280
|
### 1. Summary
|
|
5794
6281
|
- Brief overview of what you edited (2-3 sentences)
|
|
6282
|
+
- **Total file count** (must be 15–25)
|
|
6283
|
+
- **Maximum hierarchy depth achieved** (should be 2–3 levels)
|
|
5795
6284
|
- Number of files modified, renamed, created, or deleted
|
|
5796
6285
|
- The parent agent will prompt the user to confirm any creations or deletions
|
|
5797
6286
|
|
|
@@ -5804,15 +6293,16 @@ Report any renames, decompositions, or merges:
|
|
|
5804
6293
|
|----------|----------|--------|
|
|
5805
6294
|
| stuff.md | coding_preferences.md | Name now reflects content |
|
|
5806
6295
|
|
|
5807
|
-
**Decompositions (
|
|
6296
|
+
**Decompositions (using \`/\` hierarchy):**
|
|
5808
6297
|
| Original Block | New Blocks | Deleted | Reason |
|
|
5809
6298
|
|----------------|------------|---------|--------|
|
|
5810
|
-
|
|
|
6299
|
+
| project.md | project/overview.md, project/tooling/bun.md, project/tooling/testing.md, project/conventions.md, project/gotchas.md | ✅ content moved | Exploded into 5 nested files |
|
|
5811
6300
|
|
|
5812
|
-
**New Blocks (
|
|
6301
|
+
**New Blocks (all using \`/\` naming):**
|
|
5813
6302
|
| Block Name | Size | Reason |
|
|
5814
6303
|
|------------|------|--------|
|
|
5815
|
-
|
|
|
6304
|
+
| project/security/auth.md | 156 chars | Nested under project/security |
|
|
6305
|
+
| human/prefs/communication.md | 98 chars | Split from human.md |
|
|
5816
6306
|
|
|
5817
6307
|
**Merges:**
|
|
5818
6308
|
| Merged Blocks | Result | Deleted | Reason |
|
|
@@ -5901,13 +6391,13 @@ Why: Resolved contradictions by explaining when to use each approach.
|
|
|
5901
6391
|
|
|
5902
6392
|
## Critical Reminders
|
|
5903
6393
|
|
|
5904
|
-
1. **
|
|
5905
|
-
2. **
|
|
5906
|
-
3. **
|
|
5907
|
-
4. **
|
|
5908
|
-
5. **
|
|
6394
|
+
1. **Create new files** — Reorganize large blocks into 15–25 small, nested files
|
|
6395
|
+
2. **Remove old files** — After moving content to new nested files, delete the originals
|
|
6396
|
+
3. **Use \`/\` naming for ALL new files** — Every new file must be nested (e.g., \`project/tooling/bun.md\`)
|
|
6397
|
+
4. **Preserve user preferences** — Keep expressed preferences, just reorganize them into the right files
|
|
6398
|
+
5. **Don't invent information** — Only reorganize existing content into better structure
|
|
5909
6399
|
|
|
5910
|
-
Remember: Your goal is to
|
|
6400
|
+
Remember: Your goal is to **completely reorganize** memory into a deeply hierarchical structure of 15–25 small files. You're not tidying up — you're exploding monolithic blocks into a proper file tree.
|
|
5911
6401
|
`;
|
|
5912
6402
|
var init_memory = () => {};
|
|
5913
6403
|
|
|
@@ -8121,7 +8611,17 @@ function buildShellLaunchers(command) {
|
|
|
8121
8611
|
var SEP = "\x00";
|
|
8122
8612
|
|
|
8123
8613
|
// src/hooks/types.ts
|
|
8124
|
-
|
|
8614
|
+
function isToolEvent(event) {
|
|
8615
|
+
return TOOL_EVENTS.has(event);
|
|
8616
|
+
}
|
|
8617
|
+
var TOOL_EVENTS;
|
|
8618
|
+
var init_types = __esm(() => {
|
|
8619
|
+
TOOL_EVENTS = new Set([
|
|
8620
|
+
"PreToolUse",
|
|
8621
|
+
"PostToolUse",
|
|
8622
|
+
"PermissionRequest"
|
|
8623
|
+
]);
|
|
8624
|
+
});
|
|
8125
8625
|
|
|
8126
8626
|
// src/hooks/executor.ts
|
|
8127
8627
|
import { spawn } from "node:child_process";
|
|
@@ -8187,11 +8687,25 @@ function executeWithLauncher(launcher, inputJson, workingDirectory, input, timeo
|
|
|
8187
8687
|
if (!resolved) {
|
|
8188
8688
|
resolved = true;
|
|
8189
8689
|
const exitLabel = result.exitCode === 0 /* ALLOW */ ? "\x1B[32m✓ allowed\x1B[0m" : result.exitCode === 2 /* BLOCK */ ? "\x1B[31m✗ blocked\x1B[0m" : "\x1B[33m⚠ error\x1B[0m";
|
|
8190
|
-
console.log(`\x1B[90m[hook] ${
|
|
8690
|
+
console.log(`\x1B[90m[hook] ${command}\x1B[0m`);
|
|
8691
|
+
console.log(`\x1B[90m ⎿ ${exitLabel} (${result.durationMs}ms)\x1B[0m`);
|
|
8692
|
+
if (result.stdout) {
|
|
8693
|
+
console.log(`\x1B[90m ⎿ (stdout)\x1B[0m`);
|
|
8694
|
+
const indented = result.stdout.split(`
|
|
8695
|
+
`).map((line) => ` ${line}`).join(`
|
|
8696
|
+
`);
|
|
8697
|
+
console.log(`\x1B[90m${indented}\x1B[0m`);
|
|
8698
|
+
}
|
|
8699
|
+
if (result.stderr) {
|
|
8700
|
+
console.log(`\x1B[90m ⎿ (stderr)\x1B[0m`);
|
|
8701
|
+
const indented = result.stderr.split(`
|
|
8702
|
+
`).map((line) => ` ${line}`).join(`
|
|
8703
|
+
`);
|
|
8704
|
+
console.log(`\x1B[90m${indented}\x1B[0m`);
|
|
8705
|
+
}
|
|
8191
8706
|
resolve2(result);
|
|
8192
8707
|
}
|
|
8193
8708
|
};
|
|
8194
|
-
console.log(`\x1B[90m[hook] Running: ${command}\x1B[0m`);
|
|
8195
8709
|
let child;
|
|
8196
8710
|
try {
|
|
8197
8711
|
child = trySpawnWithLauncher(launcher, workingDirectory, input);
|
|
@@ -8369,14 +8883,27 @@ function mergeHooksConfigs(global2, project, projectLocal = {}) {
|
|
|
8369
8883
|
...Object.keys(projectLocal)
|
|
8370
8884
|
]);
|
|
8371
8885
|
for (const event of allEvents) {
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8886
|
+
if (isToolEvent(event)) {
|
|
8887
|
+
const toolEvent = event;
|
|
8888
|
+
const globalMatchers = global2[toolEvent] || [];
|
|
8889
|
+
const projectMatchers = project[toolEvent] || [];
|
|
8890
|
+
const projectLocalMatchers = projectLocal[toolEvent] || [];
|
|
8891
|
+
merged[toolEvent] = [
|
|
8892
|
+
...projectLocalMatchers,
|
|
8893
|
+
...projectMatchers,
|
|
8894
|
+
...globalMatchers
|
|
8895
|
+
];
|
|
8896
|
+
} else {
|
|
8897
|
+
const simpleEvent = event;
|
|
8898
|
+
const globalMatchers = global2[simpleEvent] || [];
|
|
8899
|
+
const projectMatchers = project[simpleEvent] || [];
|
|
8900
|
+
const projectLocalMatchers = projectLocal[simpleEvent] || [];
|
|
8901
|
+
merged[simpleEvent] = [
|
|
8902
|
+
...projectLocalMatchers,
|
|
8903
|
+
...projectMatchers,
|
|
8904
|
+
...globalMatchers
|
|
8905
|
+
];
|
|
8906
|
+
}
|
|
8380
8907
|
}
|
|
8381
8908
|
return merged;
|
|
8382
8909
|
}
|
|
@@ -8399,23 +8926,36 @@ function matchesTool(pattern, toolName) {
|
|
|
8399
8926
|
return pattern === toolName;
|
|
8400
8927
|
}
|
|
8401
8928
|
function getMatchingHooks(config, event, toolName) {
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8929
|
+
if (isToolEvent(event)) {
|
|
8930
|
+
const matchers = config[event];
|
|
8931
|
+
if (!matchers || matchers.length === 0) {
|
|
8932
|
+
return [];
|
|
8933
|
+
}
|
|
8934
|
+
const hooks = [];
|
|
8935
|
+
for (const matcher of matchers) {
|
|
8936
|
+
if (!toolName || matchesTool(matcher.matcher, toolName)) {
|
|
8937
|
+
hooks.push(...matcher.hooks);
|
|
8938
|
+
}
|
|
8939
|
+
}
|
|
8940
|
+
return hooks;
|
|
8941
|
+
} else {
|
|
8942
|
+
const matchers = config[event];
|
|
8943
|
+
if (!matchers || matchers.length === 0) {
|
|
8944
|
+
return [];
|
|
8945
|
+
}
|
|
8946
|
+
const hooks = [];
|
|
8947
|
+
for (const matcher of matchers) {
|
|
8409
8948
|
hooks.push(...matcher.hooks);
|
|
8410
8949
|
}
|
|
8950
|
+
return hooks;
|
|
8411
8951
|
}
|
|
8412
|
-
return hooks;
|
|
8413
8952
|
}
|
|
8414
8953
|
async function getHooksForEvent(event, toolName, workingDirectory = process.cwd()) {
|
|
8415
8954
|
const config = await loadHooks(workingDirectory);
|
|
8416
8955
|
return getMatchingHooks(config, event, toolName);
|
|
8417
8956
|
}
|
|
8418
8957
|
var init_loader = __esm(async () => {
|
|
8958
|
+
init_types();
|
|
8419
8959
|
await init_settings_manager();
|
|
8420
8960
|
});
|
|
8421
8961
|
|
|
@@ -59815,7 +60355,7 @@ async function sendMessageStream(conversationId, messages, opts = { streamTokens
|
|
|
59815
60355
|
} else {
|
|
59816
60356
|
stream2 = await client.conversations.messages.create(conversationId, {
|
|
59817
60357
|
messages,
|
|
59818
|
-
|
|
60358
|
+
stream: true,
|
|
59819
60359
|
stream_tokens: opts.streamTokens ?? true,
|
|
59820
60360
|
background: opts.background ?? true,
|
|
59821
60361
|
client_tools: getClientToolsFromRegistry()
|
|
@@ -61089,7 +61629,7 @@ function sortChronological2(messages) {
|
|
|
61089
61629
|
async function getResumeData2(client, agent, conversationId) {
|
|
61090
61630
|
try {
|
|
61091
61631
|
let inContextMessageIds;
|
|
61092
|
-
let messages;
|
|
61632
|
+
let messages = [];
|
|
61093
61633
|
const useConversationsApi = conversationId && conversationId !== "default";
|
|
61094
61634
|
if (process.env.DEBUG) {
|
|
61095
61635
|
console.log(`[DEBUG] getResumeData: conversationId=${conversationId}, useConversationsApi=${useConversationsApi}, agentId=${agent.id}`);
|
|
@@ -61100,12 +61640,16 @@ async function getResumeData2(client, agent, conversationId) {
|
|
|
61100
61640
|
if (!inContextMessageIds || inContextMessageIds.length === 0) {
|
|
61101
61641
|
debugWarn("check-approval", "No in-context messages - no pending approvals");
|
|
61102
61642
|
if (isBackfillEnabled2()) {
|
|
61103
|
-
|
|
61104
|
-
|
|
61105
|
-
|
|
61106
|
-
|
|
61107
|
-
|
|
61108
|
-
|
|
61643
|
+
try {
|
|
61644
|
+
const backfill = await client.conversations.messages.list(conversationId, { limit: MESSAGE_HISTORY_LIMIT2, order: "desc" });
|
|
61645
|
+
return {
|
|
61646
|
+
pendingApproval: null,
|
|
61647
|
+
pendingApprovals: [],
|
|
61648
|
+
messageHistory: sortChronological2(backfill.getPaginatedItems())
|
|
61649
|
+
};
|
|
61650
|
+
} catch (backfillError) {
|
|
61651
|
+
debugWarn("check-approval", `Failed to load message history: ${backfillError instanceof Error ? backfillError.message : String(backfillError)}`);
|
|
61652
|
+
}
|
|
61109
61653
|
}
|
|
61110
61654
|
return {
|
|
61111
61655
|
pendingApproval: null,
|
|
@@ -61118,11 +61662,17 @@ async function getResumeData2(client, agent, conversationId) {
|
|
|
61118
61662
|
throw new Error("Expected at least one in-context message");
|
|
61119
61663
|
}
|
|
61120
61664
|
const retrievedMessages = await client.messages.retrieve(lastInContextId);
|
|
61121
|
-
|
|
61122
|
-
|
|
61123
|
-
|
|
61124
|
-
|
|
61125
|
-
|
|
61665
|
+
if (isBackfillEnabled2()) {
|
|
61666
|
+
try {
|
|
61667
|
+
const backfillPage = await client.conversations.messages.list(conversationId, {
|
|
61668
|
+
limit: MESSAGE_HISTORY_LIMIT2,
|
|
61669
|
+
order: "desc"
|
|
61670
|
+
});
|
|
61671
|
+
messages = sortChronological2(backfillPage.getPaginatedItems());
|
|
61672
|
+
} catch (backfillError) {
|
|
61673
|
+
debugWarn("check-approval", `Failed to load message history: ${backfillError instanceof Error ? backfillError.message : String(backfillError)}`);
|
|
61674
|
+
}
|
|
61675
|
+
}
|
|
61126
61676
|
const messageToCheck = retrievedMessages.find((msg) => msg.message_type === "approval_request_message") ?? retrievedMessages[0];
|
|
61127
61677
|
if (messageToCheck) {
|
|
61128
61678
|
debugWarn("check-approval", `Found last in-context message: ${messageToCheck.id} (type: ${messageToCheck.message_type})` + (retrievedMessages.length > 1 ? ` - had ${retrievedMessages.length} variants` : ""));
|
|
@@ -61157,14 +61707,20 @@ async function getResumeData2(client, agent, conversationId) {
|
|
|
61157
61707
|
throw new Error("Expected at least one in-context message");
|
|
61158
61708
|
}
|
|
61159
61709
|
const retrievedMessages = await client.messages.retrieve(lastInContextId);
|
|
61160
|
-
|
|
61161
|
-
|
|
61162
|
-
|
|
61163
|
-
|
|
61164
|
-
|
|
61165
|
-
|
|
61166
|
-
|
|
61167
|
-
|
|
61710
|
+
if (isBackfillEnabled2()) {
|
|
61711
|
+
try {
|
|
61712
|
+
const messagesPage = await client.agents.messages.list(agent.id, {
|
|
61713
|
+
limit: MESSAGE_HISTORY_LIMIT2,
|
|
61714
|
+
order: "desc",
|
|
61715
|
+
conversation_id: "default"
|
|
61716
|
+
});
|
|
61717
|
+
messages = sortChronological2(messagesPage.items);
|
|
61718
|
+
if (process.env.DEBUG) {
|
|
61719
|
+
console.log(`[DEBUG] agents.messages.list(conversation_id=default) returned ${messagesPage.items.length} messages`);
|
|
61720
|
+
}
|
|
61721
|
+
} catch (backfillError) {
|
|
61722
|
+
debugWarn("check-approval", `Failed to load message history: ${backfillError instanceof Error ? backfillError.message : String(backfillError)}`);
|
|
61723
|
+
}
|
|
61168
61724
|
}
|
|
61169
61725
|
const messageToCheck = retrievedMessages.find((msg) => msg.message_type === "approval_request_message") ?? retrievedMessages[0];
|
|
61170
61726
|
if (messageToCheck) {
|
|
@@ -71670,24 +72226,61 @@ async function addHookMatcher(event, matcher, location, workingDirectory = proce
|
|
|
71670
72226
|
hooks[event] = [];
|
|
71671
72227
|
}
|
|
71672
72228
|
const eventMatchers = hooks[event];
|
|
71673
|
-
|
|
71674
|
-
eventMatchers.push(matcher);
|
|
71675
|
-
}
|
|
72229
|
+
eventMatchers.push(matcher);
|
|
71676
72230
|
await saveHooksToLocation(hooks, location, workingDirectory);
|
|
71677
72231
|
}
|
|
71678
|
-
async function
|
|
72232
|
+
async function addSimpleHookMatcher(event, matcher, location, workingDirectory = process.cwd()) {
|
|
71679
72233
|
const hooks = loadHooksFromLocation(location, workingDirectory);
|
|
71680
|
-
|
|
71681
|
-
|
|
71682
|
-
throw new Error(`Invalid matcher index ${matcherIndex} for event ${event}`);
|
|
72234
|
+
if (!hooks[event]) {
|
|
72235
|
+
hooks[event] = [];
|
|
71683
72236
|
}
|
|
71684
|
-
eventMatchers
|
|
71685
|
-
|
|
71686
|
-
|
|
72237
|
+
const eventMatchers = hooks[event];
|
|
72238
|
+
eventMatchers.push(matcher);
|
|
72239
|
+
await saveHooksToLocation(hooks, location, workingDirectory);
|
|
72240
|
+
}
|
|
72241
|
+
async function removeHook(event, index, location, workingDirectory = process.cwd()) {
|
|
72242
|
+
const hooks = loadHooksFromLocation(location, workingDirectory);
|
|
72243
|
+
if (isToolEvent(event)) {
|
|
72244
|
+
const eventMatchers = hooks[event];
|
|
72245
|
+
if (!eventMatchers || index < 0 || index >= eventMatchers.length) {
|
|
72246
|
+
throw new Error(`Invalid matcher index ${index} for event ${event}`);
|
|
72247
|
+
}
|
|
72248
|
+
eventMatchers.splice(index, 1);
|
|
72249
|
+
if (eventMatchers.length === 0) {
|
|
72250
|
+
delete hooks[event];
|
|
72251
|
+
}
|
|
72252
|
+
} else {
|
|
72253
|
+
const eventMatchers = hooks[event];
|
|
72254
|
+
if (!eventMatchers || index < 0 || index >= eventMatchers.length) {
|
|
72255
|
+
throw new Error(`Invalid matcher index ${index} for event ${event}`);
|
|
72256
|
+
}
|
|
72257
|
+
eventMatchers.splice(index, 1);
|
|
72258
|
+
if (eventMatchers.length === 0) {
|
|
72259
|
+
delete hooks[event];
|
|
72260
|
+
}
|
|
71687
72261
|
}
|
|
71688
72262
|
await saveHooksToLocation(hooks, location, workingDirectory);
|
|
71689
72263
|
}
|
|
71690
|
-
function
|
|
72264
|
+
function loadMatchersWithSource(event, workingDirectory = process.cwd()) {
|
|
72265
|
+
const result = [];
|
|
72266
|
+
const locations = ["project-local", "project", "user"];
|
|
72267
|
+
for (const location of locations) {
|
|
72268
|
+
const hooks = loadHooksFromLocation(location, workingDirectory);
|
|
72269
|
+
const matchers = hooks[event] || [];
|
|
72270
|
+
for (let i = 0;i < matchers.length; i++) {
|
|
72271
|
+
const matcher = matchers[i];
|
|
72272
|
+
if (matcher) {
|
|
72273
|
+
result.push({
|
|
72274
|
+
...matcher,
|
|
72275
|
+
source: location,
|
|
72276
|
+
sourceIndex: i
|
|
72277
|
+
});
|
|
72278
|
+
}
|
|
72279
|
+
}
|
|
72280
|
+
}
|
|
72281
|
+
return result;
|
|
72282
|
+
}
|
|
72283
|
+
function loadSimpleMatchersWithSource(event, workingDirectory = process.cwd()) {
|
|
71691
72284
|
const result = [];
|
|
71692
72285
|
const locations = ["project-local", "project", "user"];
|
|
71693
72286
|
for (const location of locations) {
|
|
@@ -71712,9 +72305,16 @@ function countTotalHooks(workingDirectory = process.cwd()) {
|
|
|
71712
72305
|
for (const location of locations) {
|
|
71713
72306
|
const hooks = loadHooksFromLocation(location, workingDirectory);
|
|
71714
72307
|
for (const event of Object.keys(hooks)) {
|
|
71715
|
-
|
|
71716
|
-
|
|
71717
|
-
|
|
72308
|
+
if (isToolEvent(event)) {
|
|
72309
|
+
const matchers = hooks[event] || [];
|
|
72310
|
+
for (const matcher of matchers) {
|
|
72311
|
+
count += matcher.hooks.length;
|
|
72312
|
+
}
|
|
72313
|
+
} else {
|
|
72314
|
+
const matchers = hooks[event] || [];
|
|
72315
|
+
for (const matcher of matchers) {
|
|
72316
|
+
count += matcher.hooks.length;
|
|
72317
|
+
}
|
|
71718
72318
|
}
|
|
71719
72319
|
}
|
|
71720
72320
|
}
|
|
@@ -71725,14 +72325,22 @@ function countHooksForEvent(event, workingDirectory = process.cwd()) {
|
|
|
71725
72325
|
const locations = ["project-local", "project", "user"];
|
|
71726
72326
|
for (const location of locations) {
|
|
71727
72327
|
const hooks = loadHooksFromLocation(location, workingDirectory);
|
|
71728
|
-
|
|
71729
|
-
|
|
71730
|
-
|
|
72328
|
+
if (isToolEvent(event)) {
|
|
72329
|
+
const matchers = hooks[event] || [];
|
|
72330
|
+
for (const matcher of matchers) {
|
|
72331
|
+
count += matcher.hooks.length;
|
|
72332
|
+
}
|
|
72333
|
+
} else {
|
|
72334
|
+
const matchers = hooks[event] || [];
|
|
72335
|
+
for (const matcher of matchers) {
|
|
72336
|
+
count += matcher.hooks.length;
|
|
72337
|
+
}
|
|
71731
72338
|
}
|
|
71732
72339
|
}
|
|
71733
72340
|
return count;
|
|
71734
72341
|
}
|
|
71735
72342
|
var init_writer = __esm(async () => {
|
|
72343
|
+
init_types();
|
|
71736
72344
|
await init_settings_manager();
|
|
71737
72345
|
});
|
|
71738
72346
|
|
|
@@ -71760,6 +72368,7 @@ function boxBottom(width) {
|
|
|
71760
72368
|
}
|
|
71761
72369
|
var import_react57, jsx_dev_runtime34, BOX_TOP_LEFT = "╭", BOX_TOP_RIGHT = "╮", BOX_BOTTOM_LEFT = "╰", BOX_BOTTOM_RIGHT = "╯", BOX_HORIZONTAL = "─", BOX_VERTICAL = "│", HOOK_EVENTS, TOOL_NAMES3, SAVE_LOCATIONS, HooksManager;
|
|
71762
72370
|
var init_HooksManager = __esm(async () => {
|
|
72371
|
+
init_types();
|
|
71763
72372
|
init_useTerminalWidth();
|
|
71764
72373
|
init_colors();
|
|
71765
72374
|
await __promiseAll([
|
|
@@ -71820,13 +72429,14 @@ var init_HooksManager = __esm(async () => {
|
|
|
71820
72429
|
const [screen, setScreen] = import_react57.useState("events");
|
|
71821
72430
|
const [selectedIndex, setSelectedIndex] = import_react57.useState(0);
|
|
71822
72431
|
const [selectedEvent, setSelectedEvent] = import_react57.useState(null);
|
|
71823
|
-
const [
|
|
72432
|
+
const [hooks, setHooks] = import_react57.useState([]);
|
|
71824
72433
|
const [totalHooks, setTotalHooks] = import_react57.useState(0);
|
|
71825
72434
|
const [newMatcher, setNewMatcher] = import_react57.useState("");
|
|
71826
72435
|
const [newCommand, setNewCommand] = import_react57.useState("");
|
|
71827
72436
|
const [selectedLocation, setSelectedLocation] = import_react57.useState(0);
|
|
71828
|
-
const [
|
|
72437
|
+
const [deleteHookIndex, setDeleteHookIndex] = import_react57.useState(-1);
|
|
71829
72438
|
const [deleteConfirmIndex, setDeleteConfirmIndex] = import_react57.useState(1);
|
|
72439
|
+
const isCurrentToolEvent = selectedEvent ? isToolEvent(selectedEvent) : false;
|
|
71830
72440
|
const refreshCounts = import_react57.useCallback(() => {
|
|
71831
72441
|
setTotalHooks(countTotalHooks());
|
|
71832
72442
|
}, []);
|
|
@@ -71835,9 +72445,12 @@ var init_HooksManager = __esm(async () => {
|
|
|
71835
72445
|
refreshCounts();
|
|
71836
72446
|
}
|
|
71837
72447
|
}, [screen, refreshCounts]);
|
|
71838
|
-
const
|
|
71839
|
-
|
|
71840
|
-
|
|
72448
|
+
const loadHooks2 = import_react57.useCallback((event) => {
|
|
72449
|
+
if (isToolEvent(event)) {
|
|
72450
|
+
setHooks(loadMatchersWithSource(event));
|
|
72451
|
+
} else {
|
|
72452
|
+
setHooks(loadSimpleMatchersWithSource(event));
|
|
72453
|
+
}
|
|
71841
72454
|
}, []);
|
|
71842
72455
|
const handleAddHook = import_react57.useCallback(async () => {
|
|
71843
72456
|
if (!selectedEvent || !newCommand.trim())
|
|
@@ -71845,45 +72458,46 @@ var init_HooksManager = __esm(async () => {
|
|
|
71845
72458
|
const location = SAVE_LOCATIONS[selectedLocation]?.location;
|
|
71846
72459
|
if (!location)
|
|
71847
72460
|
return;
|
|
71848
|
-
|
|
71849
|
-
matcher
|
|
71850
|
-
|
|
71851
|
-
|
|
71852
|
-
|
|
71853
|
-
|
|
72461
|
+
if (isToolEvent(selectedEvent)) {
|
|
72462
|
+
const matcher = {
|
|
72463
|
+
matcher: newMatcher.trim() || "*",
|
|
72464
|
+
hooks: [{ type: "command", command: newCommand.trim() }]
|
|
72465
|
+
};
|
|
72466
|
+
await addHookMatcher(selectedEvent, matcher, location);
|
|
72467
|
+
} else {
|
|
72468
|
+
const matcher = {
|
|
72469
|
+
hooks: [{ type: "command", command: newCommand.trim() }]
|
|
72470
|
+
};
|
|
72471
|
+
await addSimpleHookMatcher(selectedEvent, matcher, location);
|
|
72472
|
+
}
|
|
72473
|
+
loadHooks2(selectedEvent);
|
|
71854
72474
|
refreshCounts();
|
|
71855
72475
|
setNewMatcher("");
|
|
71856
72476
|
setNewCommand("");
|
|
71857
72477
|
setSelectedLocation(0);
|
|
71858
|
-
setScreen("
|
|
72478
|
+
setScreen("hooks-list");
|
|
71859
72479
|
setSelectedIndex(0);
|
|
71860
72480
|
}, [
|
|
71861
72481
|
selectedEvent,
|
|
71862
72482
|
newMatcher,
|
|
71863
72483
|
newCommand,
|
|
71864
72484
|
selectedLocation,
|
|
71865
|
-
|
|
72485
|
+
loadHooks2,
|
|
71866
72486
|
refreshCounts
|
|
71867
72487
|
]);
|
|
71868
72488
|
const handleDeleteHook = import_react57.useCallback(async () => {
|
|
71869
|
-
if (
|
|
72489
|
+
if (deleteHookIndex < 0 || !selectedEvent)
|
|
71870
72490
|
return;
|
|
71871
|
-
const
|
|
71872
|
-
if (!
|
|
72491
|
+
const hook = hooks[deleteHookIndex];
|
|
72492
|
+
if (!hook)
|
|
71873
72493
|
return;
|
|
71874
|
-
await
|
|
71875
|
-
|
|
72494
|
+
await removeHook(selectedEvent, hook.sourceIndex, hook.source);
|
|
72495
|
+
loadHooks2(selectedEvent);
|
|
71876
72496
|
refreshCounts();
|
|
71877
|
-
|
|
71878
|
-
setScreen("
|
|
72497
|
+
setDeleteHookIndex(-1);
|
|
72498
|
+
setScreen("hooks-list");
|
|
71879
72499
|
setSelectedIndex(0);
|
|
71880
|
-
}, [
|
|
71881
|
-
deleteMatcherIndex,
|
|
71882
|
-
selectedEvent,
|
|
71883
|
-
matchers,
|
|
71884
|
-
loadMatchers,
|
|
71885
|
-
refreshCounts
|
|
71886
|
-
]);
|
|
72500
|
+
}, [deleteHookIndex, selectedEvent, hooks, loadHooks2, refreshCounts]);
|
|
71887
72501
|
use_input_default((input, key) => {
|
|
71888
72502
|
if (key.ctrl && input === "c") {
|
|
71889
72503
|
onClose();
|
|
@@ -71898,26 +72512,31 @@ var init_HooksManager = __esm(async () => {
|
|
|
71898
72512
|
const selected = HOOK_EVENTS[selectedIndex];
|
|
71899
72513
|
if (selected) {
|
|
71900
72514
|
setSelectedEvent(selected.event);
|
|
71901
|
-
|
|
71902
|
-
setScreen("
|
|
72515
|
+
loadHooks2(selected.event);
|
|
72516
|
+
setScreen("hooks-list");
|
|
71903
72517
|
setSelectedIndex(0);
|
|
71904
72518
|
}
|
|
71905
72519
|
} else if (key.escape) {
|
|
71906
72520
|
onClose();
|
|
71907
72521
|
}
|
|
71908
|
-
} else if (screen === "
|
|
71909
|
-
const itemCount =
|
|
72522
|
+
} else if (screen === "hooks-list") {
|
|
72523
|
+
const itemCount = hooks.length + 1;
|
|
71910
72524
|
if (key.upArrow) {
|
|
71911
72525
|
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
71912
72526
|
} else if (key.downArrow) {
|
|
71913
72527
|
setSelectedIndex((prev) => Math.min(itemCount - 1, prev + 1));
|
|
71914
72528
|
} else if (key.return) {
|
|
71915
72529
|
if (selectedIndex === 0) {
|
|
71916
|
-
|
|
71917
|
-
|
|
72530
|
+
if (isCurrentToolEvent) {
|
|
72531
|
+
setScreen("add-matcher");
|
|
72532
|
+
setNewMatcher("");
|
|
72533
|
+
} else {
|
|
72534
|
+
setScreen("add-command");
|
|
72535
|
+
setNewCommand("");
|
|
72536
|
+
}
|
|
71918
72537
|
} else {}
|
|
71919
72538
|
} else if ((input === "d" || input === "D") && selectedIndex > 0) {
|
|
71920
|
-
|
|
72539
|
+
setDeleteHookIndex(selectedIndex - 1);
|
|
71921
72540
|
setDeleteConfirmIndex(1);
|
|
71922
72541
|
setScreen("delete-confirm");
|
|
71923
72542
|
} else if (key.escape) {
|
|
@@ -71930,7 +72549,7 @@ var init_HooksManager = __esm(async () => {
|
|
|
71930
72549
|
setScreen("add-command");
|
|
71931
72550
|
setNewCommand("");
|
|
71932
72551
|
} else if (key.escape) {
|
|
71933
|
-
setScreen("
|
|
72552
|
+
setScreen("hooks-list");
|
|
71934
72553
|
setSelectedIndex(0);
|
|
71935
72554
|
setNewMatcher("");
|
|
71936
72555
|
}
|
|
@@ -71939,7 +72558,12 @@ var init_HooksManager = __esm(async () => {
|
|
|
71939
72558
|
setScreen("save-location");
|
|
71940
72559
|
setSelectedLocation(0);
|
|
71941
72560
|
} else if (key.escape) {
|
|
71942
|
-
|
|
72561
|
+
if (isCurrentToolEvent) {
|
|
72562
|
+
setScreen("add-matcher");
|
|
72563
|
+
} else {
|
|
72564
|
+
setScreen("hooks-list");
|
|
72565
|
+
setSelectedIndex(0);
|
|
72566
|
+
}
|
|
71943
72567
|
}
|
|
71944
72568
|
} else if (screen === "save-location") {
|
|
71945
72569
|
if (key.upArrow) {
|
|
@@ -71958,10 +72582,10 @@ var init_HooksManager = __esm(async () => {
|
|
|
71958
72582
|
if (deleteConfirmIndex === 0) {
|
|
71959
72583
|
handleDeleteHook();
|
|
71960
72584
|
} else {
|
|
71961
|
-
setScreen("
|
|
72585
|
+
setScreen("hooks-list");
|
|
71962
72586
|
}
|
|
71963
72587
|
} else if (key.escape) {
|
|
71964
|
-
setScreen("
|
|
72588
|
+
setScreen("hooks-list");
|
|
71965
72589
|
}
|
|
71966
72590
|
}
|
|
71967
72591
|
});
|
|
@@ -72023,7 +72647,9 @@ var init_HooksManager = __esm(async () => {
|
|
|
72023
72647
|
]
|
|
72024
72648
|
}, undefined, true, undefined, this);
|
|
72025
72649
|
}
|
|
72026
|
-
if (screen === "
|
|
72650
|
+
if (screen === "hooks-list" && selectedEvent) {
|
|
72651
|
+
const title = isCurrentToolEvent ? ` ${selectedEvent} - Tool Matchers ` : ` ${selectedEvent} - Hooks `;
|
|
72652
|
+
const addLabel = isCurrentToolEvent ? "+ Add new matcher..." : "+ Add new hook...";
|
|
72027
72653
|
return /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Box_default, {
|
|
72028
72654
|
flexDirection: "column",
|
|
72029
72655
|
paddingX: 1,
|
|
@@ -72032,27 +72658,46 @@ var init_HooksManager = __esm(async () => {
|
|
|
72032
72658
|
children: boxTop(boxWidth)
|
|
72033
72659
|
}, undefined, false, undefined, this),
|
|
72034
72660
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72035
|
-
children: boxLine(
|
|
72661
|
+
children: boxLine(title, boxWidth)
|
|
72036
72662
|
}, undefined, false, undefined, this),
|
|
72037
72663
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72038
72664
|
children: boxBottom(boxWidth)
|
|
72039
72665
|
}, undefined, false, undefined, this),
|
|
72040
|
-
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(
|
|
72041
|
-
|
|
72042
|
-
|
|
72043
|
-
|
|
72044
|
-
|
|
72045
|
-
|
|
72046
|
-
|
|
72047
|
-
|
|
72048
|
-
|
|
72049
|
-
|
|
72050
|
-
|
|
72051
|
-
|
|
72052
|
-
|
|
72053
|
-
|
|
72054
|
-
|
|
72055
|
-
|
|
72666
|
+
isCurrentToolEvent ? /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(jsx_dev_runtime34.Fragment, {
|
|
72667
|
+
children: [
|
|
72668
|
+
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72669
|
+
dimColor: true,
|
|
72670
|
+
children: "Input to command is JSON of tool call arguments."
|
|
72671
|
+
}, undefined, false, undefined, this),
|
|
72672
|
+
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72673
|
+
dimColor: true,
|
|
72674
|
+
children: "Exit code 0 - stdout/stderr not shown"
|
|
72675
|
+
}, undefined, false, undefined, this),
|
|
72676
|
+
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72677
|
+
dimColor: true,
|
|
72678
|
+
children: "Exit code 2 - show stderr to model and block tool call"
|
|
72679
|
+
}, undefined, false, undefined, this),
|
|
72680
|
+
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72681
|
+
dimColor: true,
|
|
72682
|
+
children: "Other exit codes - show stderr to user only but continue"
|
|
72683
|
+
}, undefined, false, undefined, this)
|
|
72684
|
+
]
|
|
72685
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(jsx_dev_runtime34.Fragment, {
|
|
72686
|
+
children: [
|
|
72687
|
+
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72688
|
+
dimColor: true,
|
|
72689
|
+
children: "Exit code 0 - success, continue"
|
|
72690
|
+
}, undefined, false, undefined, this),
|
|
72691
|
+
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72692
|
+
dimColor: true,
|
|
72693
|
+
children: "Exit code 2 - show stderr to model and block"
|
|
72694
|
+
}, undefined, false, undefined, this),
|
|
72695
|
+
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72696
|
+
dimColor: true,
|
|
72697
|
+
children: "Other exit codes - show stderr to user only"
|
|
72698
|
+
}, undefined, false, undefined, this)
|
|
72699
|
+
]
|
|
72700
|
+
}, undefined, true, undefined, this),
|
|
72056
72701
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72057
72702
|
children: " "
|
|
72058
72703
|
}, undefined, false, undefined, this),
|
|
@@ -72068,16 +72713,17 @@ var init_HooksManager = __esm(async () => {
|
|
|
72068
72713
|
}, undefined, true, undefined, this),
|
|
72069
72714
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72070
72715
|
color: "green",
|
|
72071
|
-
children:
|
|
72716
|
+
children: addLabel
|
|
72072
72717
|
}, undefined, false, undefined, this)
|
|
72073
72718
|
]
|
|
72074
72719
|
}, undefined, true, undefined, this),
|
|
72075
|
-
|
|
72720
|
+
hooks.map((hook, index) => {
|
|
72076
72721
|
const isSelected = index + 1 === selectedIndex;
|
|
72077
72722
|
const prefix = isSelected ? "❯" : " ";
|
|
72078
|
-
const sourceLabel = `[${getSourceLabel(
|
|
72079
|
-
const
|
|
72080
|
-
const
|
|
72723
|
+
const sourceLabel = `[${getSourceLabel(hook.source)}]`;
|
|
72724
|
+
const isToolMatcher = "matcher" in hook;
|
|
72725
|
+
const matcherPattern = isToolMatcher ? hook.matcher || "*" : null;
|
|
72726
|
+
const command = "hooks" in hook ? hook.hooks[0]?.command || "" : "";
|
|
72081
72727
|
const truncatedCommand = command.length > 30 ? `${command.slice(0, 27)}...` : command;
|
|
72082
72728
|
return /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72083
72729
|
children: [
|
|
@@ -72095,7 +72741,7 @@ var init_HooksManager = __esm(async () => {
|
|
|
72095
72741
|
color: "cyan",
|
|
72096
72742
|
children: sourceLabel
|
|
72097
72743
|
}, undefined, false, undefined, this),
|
|
72098
|
-
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72744
|
+
matcherPattern !== null && /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72099
72745
|
children: [
|
|
72100
72746
|
" ",
|
|
72101
72747
|
matcherPattern.padEnd(12),
|
|
@@ -72107,7 +72753,7 @@ var init_HooksManager = __esm(async () => {
|
|
|
72107
72753
|
children: truncatedCommand
|
|
72108
72754
|
}, undefined, false, undefined, this)
|
|
72109
72755
|
]
|
|
72110
|
-
}, `${
|
|
72756
|
+
}, `${hook.source}-${index}`, true, undefined, this);
|
|
72111
72757
|
}),
|
|
72112
72758
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72113
72759
|
children: " "
|
|
@@ -72213,6 +72859,7 @@ var init_HooksManager = __esm(async () => {
|
|
|
72213
72859
|
}, undefined, true, undefined, this);
|
|
72214
72860
|
}
|
|
72215
72861
|
if (screen === "add-command" && selectedEvent) {
|
|
72862
|
+
const title = isCurrentToolEvent ? ` Add new matcher for ${selectedEvent} ` : ` Add new hook for ${selectedEvent} `;
|
|
72216
72863
|
return /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Box_default, {
|
|
72217
72864
|
flexDirection: "column",
|
|
72218
72865
|
paddingX: 1,
|
|
@@ -72221,18 +72868,18 @@ var init_HooksManager = __esm(async () => {
|
|
|
72221
72868
|
children: boxTop(boxWidth)
|
|
72222
72869
|
}, undefined, false, undefined, this),
|
|
72223
72870
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72224
|
-
children: boxLine(
|
|
72871
|
+
children: boxLine(title, boxWidth)
|
|
72225
72872
|
}, undefined, false, undefined, this),
|
|
72226
72873
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72227
72874
|
children: boxBottom(boxWidth)
|
|
72228
72875
|
}, undefined, false, undefined, this),
|
|
72229
|
-
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72876
|
+
isCurrentToolEvent && /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72230
72877
|
children: [
|
|
72231
72878
|
"Matcher: ",
|
|
72232
72879
|
newMatcher || "*"
|
|
72233
72880
|
]
|
|
72234
72881
|
}, undefined, true, undefined, this),
|
|
72235
|
-
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72882
|
+
isCurrentToolEvent && /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72236
72883
|
children: " "
|
|
72237
72884
|
}, undefined, false, undefined, this),
|
|
72238
72885
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
@@ -72292,7 +72939,7 @@ var init_HooksManager = __esm(async () => {
|
|
|
72292
72939
|
selectedEvent
|
|
72293
72940
|
]
|
|
72294
72941
|
}, undefined, true, undefined, this),
|
|
72295
|
-
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72942
|
+
isCurrentToolEvent && /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72296
72943
|
children: [
|
|
72297
72944
|
"Matcher: ",
|
|
72298
72945
|
newMatcher || "*"
|
|
@@ -72348,8 +72995,11 @@ var init_HooksManager = __esm(async () => {
|
|
|
72348
72995
|
]
|
|
72349
72996
|
}, undefined, true, undefined, this);
|
|
72350
72997
|
}
|
|
72351
|
-
if (screen === "delete-confirm" &&
|
|
72352
|
-
const
|
|
72998
|
+
if (screen === "delete-confirm" && deleteHookIndex >= 0) {
|
|
72999
|
+
const hook = hooks[deleteHookIndex];
|
|
73000
|
+
const isToolMatcher = hook && "matcher" in hook;
|
|
73001
|
+
const matcherPattern = isToolMatcher ? hook.matcher || "*" : null;
|
|
73002
|
+
const command = hook && "hooks" in hook ? hook.hooks[0]?.command : "";
|
|
72353
73003
|
return /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Box_default, {
|
|
72354
73004
|
flexDirection: "column",
|
|
72355
73005
|
paddingX: 1,
|
|
@@ -72366,22 +73016,22 @@ var init_HooksManager = __esm(async () => {
|
|
|
72366
73016
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72367
73017
|
children: " "
|
|
72368
73018
|
}, undefined, false, undefined, this),
|
|
72369
|
-
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
73019
|
+
matcherPattern !== null && /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72370
73020
|
children: [
|
|
72371
73021
|
"Matcher: ",
|
|
72372
|
-
|
|
73022
|
+
matcherPattern
|
|
72373
73023
|
]
|
|
72374
73024
|
}, undefined, true, undefined, this),
|
|
72375
73025
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72376
73026
|
children: [
|
|
72377
73027
|
"Command: ",
|
|
72378
|
-
|
|
73028
|
+
command
|
|
72379
73029
|
]
|
|
72380
73030
|
}, undefined, true, undefined, this),
|
|
72381
73031
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
72382
73032
|
children: [
|
|
72383
73033
|
"Source: ",
|
|
72384
|
-
|
|
73034
|
+
hook ? getSourceLabel(hook.source) : ""
|
|
72385
73035
|
]
|
|
72386
73036
|
}, undefined, true, undefined, this),
|
|
72387
73037
|
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
@@ -75371,18 +76021,46 @@ var init_AgentInfoBar = __esm(async () => {
|
|
|
75371
76021
|
color: "gray",
|
|
75372
76022
|
children: " (type /pin to pin agent)"
|
|
75373
76023
|
}, undefined, false, undefined, this),
|
|
75374
|
-
/* @__PURE__ */ jsx_dev_runtime35.jsxDEV(
|
|
76024
|
+
isCloudUser && adeUrl && !isTmux && /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(jsx_dev_runtime35.Fragment, {
|
|
76025
|
+
children: [
|
|
76026
|
+
/* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
76027
|
+
dimColor: true,
|
|
76028
|
+
children: " · "
|
|
76029
|
+
}, undefined, false, undefined, this),
|
|
76030
|
+
/* @__PURE__ */ jsx_dev_runtime35.jsxDEV(dist_default4, {
|
|
76031
|
+
url: adeUrl,
|
|
76032
|
+
children: /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
76033
|
+
children: "Open in ADE ↗"
|
|
76034
|
+
}, undefined, false, undefined, this)
|
|
76035
|
+
}, undefined, false, undefined, this)
|
|
76036
|
+
]
|
|
76037
|
+
}, undefined, true, undefined, this),
|
|
76038
|
+
isCloudUser && adeUrl && isTmux && /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
75375
76039
|
dimColor: true,
|
|
75376
76040
|
children: [
|
|
75377
|
-
" · ",
|
|
75378
|
-
|
|
76041
|
+
" · Open in ADE: ",
|
|
76042
|
+
adeUrl
|
|
75379
76043
|
]
|
|
75380
76044
|
}, undefined, true, undefined, this),
|
|
75381
|
-
|
|
76045
|
+
isCloudUser && /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(jsx_dev_runtime35.Fragment, {
|
|
76046
|
+
children: [
|
|
76047
|
+
/* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
76048
|
+
dimColor: true,
|
|
76049
|
+
children: " · "
|
|
76050
|
+
}, undefined, false, undefined, this),
|
|
76051
|
+
/* @__PURE__ */ jsx_dev_runtime35.jsxDEV(dist_default4, {
|
|
76052
|
+
url: "https://app.letta.com/settings/organization/usage",
|
|
76053
|
+
children: /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
76054
|
+
children: "View usage ↗"
|
|
76055
|
+
}, undefined, false, undefined, this)
|
|
76056
|
+
}, undefined, false, undefined, this)
|
|
76057
|
+
]
|
|
76058
|
+
}, undefined, true, undefined, this),
|
|
76059
|
+
!isCloudUser && /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
75382
76060
|
dimColor: true,
|
|
75383
76061
|
children: [
|
|
75384
76062
|
" · ",
|
|
75385
|
-
|
|
76063
|
+
serverUrl
|
|
75386
76064
|
]
|
|
75387
76065
|
}, undefined, true, undefined, this)
|
|
75388
76066
|
]
|
|
@@ -75391,34 +76069,18 @@ var init_AgentInfoBar = __esm(async () => {
|
|
|
75391
76069
|
children: [
|
|
75392
76070
|
/* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
75393
76071
|
dimColor: true,
|
|
75394
|
-
children: " "
|
|
75395
|
-
}, undefined, false, undefined, this),
|
|
75396
|
-
isCloudUser && adeUrl && !isTmux && /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(dist_default4, {
|
|
75397
|
-
url: adeUrl,
|
|
75398
|
-
children: /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
75399
|
-
children: "Open in ADE ↗"
|
|
75400
|
-
}, undefined, false, undefined, this)
|
|
75401
|
-
}, undefined, false, undefined, this),
|
|
75402
|
-
isCloudUser && adeUrl && isTmux && /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
75403
76072
|
children: [
|
|
75404
|
-
"
|
|
75405
|
-
|
|
76073
|
+
" ",
|
|
76074
|
+
agentId
|
|
75406
76075
|
]
|
|
75407
76076
|
}, undefined, true, undefined, this),
|
|
75408
|
-
|
|
75409
|
-
dimColor: true,
|
|
75410
|
-
children: " · "
|
|
75411
|
-
}, undefined, false, undefined, this),
|
|
75412
|
-
isCloudUser && /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(dist_default4, {
|
|
75413
|
-
url: "https://app.letta.com/settings/organization/usage",
|
|
75414
|
-
children: /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
75415
|
-
children: "View usage ↗"
|
|
75416
|
-
}, undefined, false, undefined, this)
|
|
75417
|
-
}, undefined, false, undefined, this),
|
|
75418
|
-
!isCloudUser && /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
76077
|
+
conversationId && conversationId !== "default" && /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(Text, {
|
|
75419
76078
|
dimColor: true,
|
|
75420
|
-
children:
|
|
75421
|
-
|
|
76079
|
+
children: [
|
|
76080
|
+
" · ",
|
|
76081
|
+
conversationId
|
|
76082
|
+
]
|
|
76083
|
+
}, undefined, true, undefined, this)
|
|
75422
76084
|
]
|
|
75423
76085
|
}, undefined, true, undefined, this)
|
|
75424
76086
|
]
|
|
@@ -78516,26 +79178,6 @@ var init_MemoryTabViewer = __esm(async () => {
|
|
|
78516
79178
|
});
|
|
78517
79179
|
|
|
78518
79180
|
// src/cli/components/MessageSearch.tsx
|
|
78519
|
-
function formatRelativeTime5(dateStr) {
|
|
78520
|
-
if (!dateStr)
|
|
78521
|
-
return "";
|
|
78522
|
-
const date = new Date(dateStr);
|
|
78523
|
-
const now = new Date;
|
|
78524
|
-
const diffMs = now.getTime() - date.getTime();
|
|
78525
|
-
const diffMins = Math.floor(diffMs / 60000);
|
|
78526
|
-
const diffHours = Math.floor(diffMs / 3600000);
|
|
78527
|
-
const diffDays = Math.floor(diffMs / 86400000);
|
|
78528
|
-
const diffWeeks = Math.floor(diffDays / 7);
|
|
78529
|
-
if (diffMins < 1)
|
|
78530
|
-
return "just now";
|
|
78531
|
-
if (diffMins < 60)
|
|
78532
|
-
return `${diffMins}m ago`;
|
|
78533
|
-
if (diffHours < 24)
|
|
78534
|
-
return `${diffHours}h ago`;
|
|
78535
|
-
if (diffDays < 7)
|
|
78536
|
-
return `${diffDays}d ago`;
|
|
78537
|
-
return `${diffWeeks}w ago`;
|
|
78538
|
-
}
|
|
78539
79181
|
function formatLocalTime(dateStr) {
|
|
78540
79182
|
if (!dateStr)
|
|
78541
79183
|
return "";
|
|
@@ -78586,34 +79228,102 @@ function getMessageText(msg) {
|
|
|
78586
79228
|
}
|
|
78587
79229
|
return `[${msg.message_type || "unknown"}]`;
|
|
78588
79230
|
}
|
|
78589
|
-
function MessageSearch({
|
|
79231
|
+
function MessageSearch({
|
|
79232
|
+
onClose,
|
|
79233
|
+
initialQuery,
|
|
79234
|
+
agentId,
|
|
79235
|
+
conversationId,
|
|
79236
|
+
onOpenConversation
|
|
79237
|
+
}) {
|
|
78590
79238
|
const terminalWidth = useTerminalWidth();
|
|
78591
79239
|
const [searchInput, setSearchInput] = import_react70.useState(initialQuery ?? "");
|
|
78592
79240
|
const [activeQuery, setActiveQuery] = import_react70.useState(initialQuery ?? "");
|
|
78593
79241
|
const [searchMode, setSearchMode] = import_react70.useState("hybrid");
|
|
79242
|
+
const [searchRange, setSearchRange] = import_react70.useState("all");
|
|
78594
79243
|
const [results, setResults] = import_react70.useState([]);
|
|
78595
79244
|
const [loading, setLoading] = import_react70.useState(false);
|
|
78596
79245
|
const [error, setError] = import_react70.useState(null);
|
|
78597
|
-
const [currentPage, setCurrentPage] = import_react70.useState(0);
|
|
78598
79246
|
const [selectedIndex, setSelectedIndex] = import_react70.useState(0);
|
|
79247
|
+
const [expandedMessage, setExpandedMessage] = import_react70.useState(null);
|
|
78599
79248
|
const clientRef = import_react70.useRef(null);
|
|
78600
|
-
const
|
|
79249
|
+
const resultsCache = import_react70.useRef(new Map);
|
|
79250
|
+
const getCacheKey = import_react70.useCallback((query, mode, range2) => {
|
|
79251
|
+
const rangeKey = range2 === "agent" ? agentId || "no-agent" : range2 === "conv" ? conversationId || "no-conv" : "all";
|
|
79252
|
+
return `${query.trim()}-${mode}-${rangeKey}`;
|
|
79253
|
+
}, [agentId, conversationId]);
|
|
79254
|
+
const fetchSearchResults = import_react70.useCallback(async (client, query, mode, range2) => {
|
|
79255
|
+
const body = {
|
|
79256
|
+
query: query.trim(),
|
|
79257
|
+
search_mode: mode,
|
|
79258
|
+
limit: SEARCH_LIMIT
|
|
79259
|
+
};
|
|
79260
|
+
if (range2 === "agent" && agentId) {
|
|
79261
|
+
body.agent_id = agentId;
|
|
79262
|
+
} else if (range2 === "conv" && conversationId) {
|
|
79263
|
+
body.conversation_id = conversationId;
|
|
79264
|
+
}
|
|
79265
|
+
const searchResults = await client.post("/v1/messages/search", { body });
|
|
79266
|
+
return searchResults;
|
|
79267
|
+
}, [agentId, conversationId]);
|
|
79268
|
+
const executeSearch = import_react70.useCallback(async (query, mode, range2) => {
|
|
78601
79269
|
if (!query.trim())
|
|
78602
79270
|
return;
|
|
79271
|
+
const cacheKey = getCacheKey(query, mode, range2);
|
|
79272
|
+
const cached = resultsCache.current.get(cacheKey);
|
|
79273
|
+
if (cached) {
|
|
79274
|
+
setResults(cached);
|
|
79275
|
+
setSelectedIndex(0);
|
|
79276
|
+
return;
|
|
79277
|
+
}
|
|
78603
79278
|
setLoading(true);
|
|
78604
79279
|
setError(null);
|
|
78605
79280
|
try {
|
|
78606
79281
|
const client = clientRef.current || await getClient2();
|
|
78607
79282
|
clientRef.current = client;
|
|
78608
|
-
const
|
|
78609
|
-
|
|
78610
|
-
|
|
78611
|
-
|
|
78612
|
-
|
|
78613
|
-
|
|
78614
|
-
|
|
78615
|
-
|
|
78616
|
-
|
|
79283
|
+
const getOrFetch = (m, r) => {
|
|
79284
|
+
const key = getCacheKey(query, m, r);
|
|
79285
|
+
return resultsCache.current.get(key) ?? fetchSearchResults(client, query, m, r);
|
|
79286
|
+
};
|
|
79287
|
+
const [
|
|
79288
|
+
hybridAll,
|
|
79289
|
+
vectorAll,
|
|
79290
|
+
ftsAll,
|
|
79291
|
+
hybridAgent,
|
|
79292
|
+
vectorAgent,
|
|
79293
|
+
ftsAgent,
|
|
79294
|
+
hybridConv,
|
|
79295
|
+
vectorConv,
|
|
79296
|
+
ftsConv
|
|
79297
|
+
] = await Promise.all([
|
|
79298
|
+
getOrFetch("hybrid", "all"),
|
|
79299
|
+
getOrFetch("vector", "all"),
|
|
79300
|
+
getOrFetch("fts", "all"),
|
|
79301
|
+
agentId ? getOrFetch("hybrid", "agent") : Promise.resolve([]),
|
|
79302
|
+
agentId ? getOrFetch("vector", "agent") : Promise.resolve([]),
|
|
79303
|
+
agentId ? getOrFetch("fts", "agent") : Promise.resolve([]),
|
|
79304
|
+
conversationId ? getOrFetch("hybrid", "conv") : Promise.resolve([]),
|
|
79305
|
+
conversationId ? getOrFetch("vector", "conv") : Promise.resolve([]),
|
|
79306
|
+
conversationId ? getOrFetch("fts", "conv") : Promise.resolve([])
|
|
79307
|
+
]);
|
|
79308
|
+
resultsCache.current.set(getCacheKey(query, "hybrid", "all"), hybridAll);
|
|
79309
|
+
resultsCache.current.set(getCacheKey(query, "vector", "all"), vectorAll);
|
|
79310
|
+
resultsCache.current.set(getCacheKey(query, "fts", "all"), ftsAll);
|
|
79311
|
+
if (agentId) {
|
|
79312
|
+
resultsCache.current.set(getCacheKey(query, "hybrid", "agent"), hybridAgent);
|
|
79313
|
+
resultsCache.current.set(getCacheKey(query, "vector", "agent"), vectorAgent);
|
|
79314
|
+
resultsCache.current.set(getCacheKey(query, "fts", "agent"), ftsAgent);
|
|
79315
|
+
}
|
|
79316
|
+
if (conversationId) {
|
|
79317
|
+
resultsCache.current.set(getCacheKey(query, "hybrid", "conv"), hybridConv);
|
|
79318
|
+
resultsCache.current.set(getCacheKey(query, "vector", "conv"), vectorConv);
|
|
79319
|
+
resultsCache.current.set(getCacheKey(query, "fts", "conv"), ftsConv);
|
|
79320
|
+
}
|
|
79321
|
+
const resultMap = {
|
|
79322
|
+
hybrid: { all: hybridAll, agent: hybridAgent, conv: hybridConv },
|
|
79323
|
+
vector: { all: vectorAll, agent: vectorAgent, conv: vectorConv },
|
|
79324
|
+
fts: { all: ftsAll, agent: ftsAgent, conv: ftsConv }
|
|
79325
|
+
};
|
|
79326
|
+
setResults(resultMap[mode][range2]);
|
|
78617
79327
|
setSelectedIndex(0);
|
|
78618
79328
|
} catch (err) {
|
|
78619
79329
|
setError(err instanceof Error ? err.message : String(err));
|
|
@@ -78621,40 +79331,56 @@ function MessageSearch({ onClose, initialQuery }) {
|
|
|
78621
79331
|
} finally {
|
|
78622
79332
|
setLoading(false);
|
|
78623
79333
|
}
|
|
78624
|
-
}, []);
|
|
79334
|
+
}, [fetchSearchResults, getCacheKey, agentId, conversationId]);
|
|
78625
79335
|
const submitSearch = import_react70.useCallback(() => {
|
|
78626
79336
|
if (searchInput.trim() && searchInput !== activeQuery) {
|
|
78627
79337
|
setActiveQuery(searchInput);
|
|
78628
|
-
executeSearch(searchInput, searchMode);
|
|
79338
|
+
executeSearch(searchInput, searchMode, searchRange);
|
|
78629
79339
|
}
|
|
78630
|
-
}, [searchInput, activeQuery, searchMode, executeSearch]);
|
|
79340
|
+
}, [searchInput, activeQuery, searchMode, searchRange, executeSearch]);
|
|
78631
79341
|
const clearSearch = import_react70.useCallback(() => {
|
|
78632
79342
|
setSearchInput("");
|
|
78633
79343
|
setActiveQuery("");
|
|
78634
79344
|
setResults([]);
|
|
78635
|
-
setCurrentPage(0);
|
|
78636
79345
|
setSelectedIndex(0);
|
|
78637
79346
|
}, []);
|
|
78638
|
-
const cycleSearchMode = import_react70.useCallback(() => {
|
|
79347
|
+
const cycleSearchMode = import_react70.useCallback((reverse = false) => {
|
|
78639
79348
|
setSearchMode((current) => {
|
|
78640
79349
|
const currentIndex = SEARCH_MODES.indexOf(current);
|
|
78641
|
-
const nextIndex = (currentIndex + 1) % SEARCH_MODES.length;
|
|
79350
|
+
const nextIndex = reverse ? (currentIndex - 1 + SEARCH_MODES.length) % SEARCH_MODES.length : (currentIndex + 1) % SEARCH_MODES.length;
|
|
78642
79351
|
return SEARCH_MODES[nextIndex];
|
|
78643
79352
|
});
|
|
78644
79353
|
}, []);
|
|
79354
|
+
const cycleSearchRange = import_react70.useCallback(() => {
|
|
79355
|
+
setSearchRange((current) => {
|
|
79356
|
+
const currentIndex = SEARCH_RANGES.indexOf(current);
|
|
79357
|
+
const nextIndex = (currentIndex + 1) % SEARCH_RANGES.length;
|
|
79358
|
+
return SEARCH_RANGES[nextIndex];
|
|
79359
|
+
});
|
|
79360
|
+
}, []);
|
|
78645
79361
|
import_react70.useEffect(() => {
|
|
78646
79362
|
if (activeQuery) {
|
|
78647
|
-
executeSearch(activeQuery, searchMode);
|
|
79363
|
+
executeSearch(activeQuery, searchMode, searchRange);
|
|
78648
79364
|
}
|
|
78649
|
-
}, [searchMode, activeQuery, executeSearch]);
|
|
78650
|
-
const
|
|
78651
|
-
const
|
|
78652
|
-
const pageResults = results.slice(startIndex, startIndex + DISPLAY_PAGE_SIZE5);
|
|
79365
|
+
}, [searchMode, searchRange, activeQuery, executeSearch]);
|
|
79366
|
+
const startIndex = Math.max(0, Math.min(selectedIndex - 2, results.length - VISIBLE_ITEMS));
|
|
79367
|
+
const visibleResults = results.slice(startIndex, startIndex + VISIBLE_ITEMS);
|
|
78653
79368
|
use_input_default((input, key) => {
|
|
78654
79369
|
if (key.ctrl && input === "c") {
|
|
78655
79370
|
onClose();
|
|
78656
79371
|
return;
|
|
78657
79372
|
}
|
|
79373
|
+
if (expandedMessage) {
|
|
79374
|
+
if (key.escape) {
|
|
79375
|
+
setExpandedMessage(null);
|
|
79376
|
+
} else if (key.return && onOpenConversation) {
|
|
79377
|
+
const msgData = expandedMessage;
|
|
79378
|
+
if (msgData.agent_id) {
|
|
79379
|
+
onOpenConversation(msgData.agent_id, msgData.conversation_id);
|
|
79380
|
+
}
|
|
79381
|
+
}
|
|
79382
|
+
return;
|
|
79383
|
+
}
|
|
78658
79384
|
if (key.escape) {
|
|
78659
79385
|
if (searchInput || activeQuery) {
|
|
78660
79386
|
clearSearch();
|
|
@@ -78662,94 +79388,209 @@ function MessageSearch({ onClose, initialQuery }) {
|
|
|
78662
79388
|
onClose();
|
|
78663
79389
|
}
|
|
78664
79390
|
} else if (key.return) {
|
|
78665
|
-
|
|
79391
|
+
if (searchInput.trim() && searchInput !== activeQuery) {
|
|
79392
|
+
submitSearch();
|
|
79393
|
+
} else if (results.length > 0 && results[selectedIndex]) {
|
|
79394
|
+
setExpandedMessage(results[selectedIndex]);
|
|
79395
|
+
}
|
|
78666
79396
|
} else if (key.backspace || key.delete) {
|
|
78667
79397
|
setSearchInput((prev) => prev.slice(0, -1));
|
|
78668
|
-
} else if (key.tab) {
|
|
79398
|
+
} else if (key.tab && key.shift) {
|
|
78669
79399
|
cycleSearchMode();
|
|
79400
|
+
} else if (key.tab) {
|
|
79401
|
+
cycleSearchRange();
|
|
78670
79402
|
} else if (key.upArrow) {
|
|
78671
79403
|
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
78672
79404
|
} else if (key.downArrow) {
|
|
78673
|
-
setSelectedIndex((prev) => Math.min(
|
|
78674
|
-
} else if (input === "j" || input === "J") {
|
|
78675
|
-
if (currentPage > 0) {
|
|
78676
|
-
setCurrentPage((prev) => prev - 1);
|
|
78677
|
-
setSelectedIndex(0);
|
|
78678
|
-
}
|
|
78679
|
-
} else if (input === "k" || input === "K") {
|
|
78680
|
-
if (currentPage < totalPages - 1) {
|
|
78681
|
-
setCurrentPage((prev) => prev + 1);
|
|
78682
|
-
setSelectedIndex(0);
|
|
78683
|
-
}
|
|
79405
|
+
setSelectedIndex((prev) => Math.min(results.length - 1, prev + 1));
|
|
78684
79406
|
} else if (input && !key.ctrl && !key.meta) {
|
|
78685
79407
|
setSearchInput((prev) => prev + input);
|
|
78686
79408
|
}
|
|
78687
79409
|
});
|
|
79410
|
+
const solidLine = SOLID_LINE16.repeat(Math.max(terminalWidth, 10));
|
|
79411
|
+
const getRangeLabel = (range2) => {
|
|
79412
|
+
switch (range2) {
|
|
79413
|
+
case "all":
|
|
79414
|
+
return "all agents";
|
|
79415
|
+
case "agent":
|
|
79416
|
+
return "this agent";
|
|
79417
|
+
case "conv":
|
|
79418
|
+
return "this conversation";
|
|
79419
|
+
}
|
|
79420
|
+
};
|
|
78688
79421
|
return /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
78689
79422
|
flexDirection: "column",
|
|
78690
|
-
gap: 1,
|
|
78691
79423
|
children: [
|
|
78692
|
-
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(
|
|
78693
|
-
|
|
78694
|
-
|
|
78695
|
-
|
|
78696
|
-
|
|
78697
|
-
|
|
79424
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79425
|
+
dimColor: true,
|
|
79426
|
+
children: "> /search"
|
|
79427
|
+
}, undefined, false, undefined, this),
|
|
79428
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79429
|
+
dimColor: true,
|
|
79430
|
+
children: solidLine
|
|
78698
79431
|
}, undefined, false, undefined, this),
|
|
78699
79432
|
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79433
|
+
height: 1
|
|
79434
|
+
}, undefined, false, undefined, this),
|
|
79435
|
+
expandedMessage && (() => {
|
|
79436
|
+
const msgData = expandedMessage;
|
|
79437
|
+
const fullText = getMessageText(expandedMessage);
|
|
79438
|
+
const msgType = expandedMessage.message_type || "unknown";
|
|
79439
|
+
const isAssistant = msgType === "assistant_message" || msgType === "reasoning_message";
|
|
79440
|
+
const typeLabel = isAssistant ? "Agent message" : "User message";
|
|
79441
|
+
const timestamp = formatLocalTime(msgData.created_at || msgData.date);
|
|
79442
|
+
return /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(jsx_dev_runtime46.Fragment, {
|
|
79443
|
+
children: [
|
|
79444
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79445
|
+
paddingLeft: 2,
|
|
79446
|
+
children: /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79447
|
+
children: [
|
|
79448
|
+
'"',
|
|
79449
|
+
fullText,
|
|
79450
|
+
'"'
|
|
79451
|
+
]
|
|
79452
|
+
}, undefined, true, undefined, this)
|
|
79453
|
+
}, undefined, false, undefined, this),
|
|
79454
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79455
|
+
height: 1
|
|
79456
|
+
}, undefined, false, undefined, this),
|
|
79457
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79458
|
+
flexDirection: "column",
|
|
79459
|
+
paddingLeft: 2,
|
|
79460
|
+
children: [
|
|
79461
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79462
|
+
dimColor: true,
|
|
79463
|
+
children: [
|
|
79464
|
+
typeLabel,
|
|
79465
|
+
", sent ",
|
|
79466
|
+
timestamp
|
|
79467
|
+
]
|
|
79468
|
+
}, undefined, true, undefined, this),
|
|
79469
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79470
|
+
dimColor: true,
|
|
79471
|
+
children: [
|
|
79472
|
+
"Agent ID: ",
|
|
79473
|
+
msgData.agent_id || "unknown"
|
|
79474
|
+
]
|
|
79475
|
+
}, undefined, true, undefined, this),
|
|
79476
|
+
msgData.conversation_id && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79477
|
+
dimColor: true,
|
|
79478
|
+
children: [
|
|
79479
|
+
"Conv ID: ",
|
|
79480
|
+
msgData.conversation_id
|
|
79481
|
+
]
|
|
79482
|
+
}, undefined, true, undefined, this)
|
|
79483
|
+
]
|
|
79484
|
+
}, undefined, true, undefined, this),
|
|
79485
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79486
|
+
height: 1
|
|
79487
|
+
}, undefined, false, undefined, this),
|
|
79488
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79489
|
+
paddingLeft: 2,
|
|
79490
|
+
children: /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79491
|
+
dimColor: true,
|
|
79492
|
+
children: onOpenConversation ? "Enter to open conversation · Esc cancel" : "Esc cancel"
|
|
79493
|
+
}, undefined, false, undefined, this)
|
|
79494
|
+
}, undefined, false, undefined, this)
|
|
79495
|
+
]
|
|
79496
|
+
}, undefined, true, undefined, this);
|
|
79497
|
+
})(),
|
|
79498
|
+
!expandedMessage && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
78700
79499
|
flexDirection: "column",
|
|
79500
|
+
gap: 1,
|
|
79501
|
+
marginBottom: 1,
|
|
78701
79502
|
children: [
|
|
79503
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79504
|
+
bold: true,
|
|
79505
|
+
color: colors.selector.title,
|
|
79506
|
+
children: "Search messages across all agents"
|
|
79507
|
+
}, undefined, false, undefined, this),
|
|
78702
79508
|
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79509
|
+
flexDirection: "column",
|
|
79510
|
+
paddingLeft: 1,
|
|
78703
79511
|
children: [
|
|
78704
|
-
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(
|
|
78705
|
-
|
|
78706
|
-
children: "Search: "
|
|
78707
|
-
}, undefined, false, undefined, this),
|
|
78708
|
-
searchInput ? /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(jsx_dev_runtime46.Fragment, {
|
|
79512
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79513
|
+
flexDirection: "row",
|
|
78709
79514
|
children: [
|
|
78710
79515
|
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78711
|
-
|
|
79516
|
+
dimColor: true,
|
|
79517
|
+
children: " Search: "
|
|
78712
79518
|
}, undefined, false, undefined, this),
|
|
78713
|
-
searchInput
|
|
79519
|
+
searchInput ? /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(jsx_dev_runtime46.Fragment, {
|
|
79520
|
+
children: [
|
|
79521
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79522
|
+
children: searchInput
|
|
79523
|
+
}, undefined, false, undefined, this),
|
|
79524
|
+
searchInput !== activeQuery && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79525
|
+
dimColor: true,
|
|
79526
|
+
children: " (press Enter to search)"
|
|
79527
|
+
}, undefined, false, undefined, this)
|
|
79528
|
+
]
|
|
79529
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78714
79530
|
dimColor: true,
|
|
78715
|
-
children: "
|
|
79531
|
+
children: "(type to search)"
|
|
78716
79532
|
}, undefined, false, undefined, this)
|
|
78717
79533
|
]
|
|
78718
|
-
}, undefined, true, undefined, this)
|
|
78719
|
-
|
|
78720
|
-
|
|
78721
|
-
children: "(type your query)"
|
|
78722
|
-
}, undefined, false, undefined, this)
|
|
78723
|
-
]
|
|
78724
|
-
}, undefined, true, undefined, this),
|
|
78725
|
-
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
78726
|
-
children: [
|
|
78727
|
-
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78728
|
-
dimColor: true,
|
|
78729
|
-
children: "Mode: "
|
|
79534
|
+
}, undefined, true, undefined, this),
|
|
79535
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79536
|
+
height: 1
|
|
78730
79537
|
}, undefined, false, undefined, this),
|
|
78731
|
-
|
|
79538
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79539
|
+
flexDirection: "row",
|
|
78732
79540
|
children: [
|
|
78733
|
-
|
|
79541
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78734
79542
|
dimColor: true,
|
|
78735
|
-
children: "
|
|
79543
|
+
children: " Range (tab): "
|
|
78736
79544
|
}, undefined, false, undefined, this),
|
|
79545
|
+
SEARCH_RANGES.map((range2, i) => {
|
|
79546
|
+
const isActive = range2 === searchRange;
|
|
79547
|
+
return /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79548
|
+
children: [
|
|
79549
|
+
i > 0 && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79550
|
+
children: " "
|
|
79551
|
+
}, undefined, false, undefined, this),
|
|
79552
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79553
|
+
backgroundColor: isActive ? colors.selector.itemHighlighted : undefined,
|
|
79554
|
+
color: isActive ? "black" : undefined,
|
|
79555
|
+
bold: isActive,
|
|
79556
|
+
children: ` ${getRangeLabel(range2)} `
|
|
79557
|
+
}, undefined, false, undefined, this)
|
|
79558
|
+
]
|
|
79559
|
+
}, range2, true, undefined, this);
|
|
79560
|
+
})
|
|
79561
|
+
]
|
|
79562
|
+
}, undefined, true, undefined, this),
|
|
79563
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79564
|
+
flexDirection: "row",
|
|
79565
|
+
children: [
|
|
78737
79566
|
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78738
|
-
|
|
78739
|
-
|
|
78740
|
-
|
|
78741
|
-
|
|
79567
|
+
dimColor: true,
|
|
79568
|
+
children: " Mode (shift-tab): "
|
|
79569
|
+
}, undefined, false, undefined, this),
|
|
79570
|
+
SEARCH_MODES.map((mode, i) => {
|
|
79571
|
+
const isActive = mode === searchMode;
|
|
79572
|
+
return /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79573
|
+
children: [
|
|
79574
|
+
i > 0 && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79575
|
+
children: " "
|
|
79576
|
+
}, undefined, false, undefined, this),
|
|
79577
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79578
|
+
backgroundColor: isActive ? colors.selector.itemHighlighted : undefined,
|
|
79579
|
+
color: isActive ? "black" : undefined,
|
|
79580
|
+
bold: isActive,
|
|
79581
|
+
children: ` ${mode} `
|
|
79582
|
+
}, undefined, false, undefined, this)
|
|
79583
|
+
]
|
|
79584
|
+
}, mode, true, undefined, this);
|
|
79585
|
+
})
|
|
78742
79586
|
]
|
|
78743
|
-
},
|
|
78744
|
-
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78745
|
-
dimColor: true,
|
|
78746
|
-
children: " (Tab to change)"
|
|
78747
|
-
}, undefined, false, undefined, this)
|
|
79587
|
+
}, undefined, true, undefined, this)
|
|
78748
79588
|
]
|
|
78749
79589
|
}, undefined, true, undefined, this)
|
|
78750
79590
|
]
|
|
78751
79591
|
}, undefined, true, undefined, this),
|
|
78752
|
-
error && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79592
|
+
!expandedMessage && error && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79593
|
+
paddingLeft: 2,
|
|
78753
79594
|
children: /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78754
79595
|
color: "red",
|
|
78755
79596
|
children: [
|
|
@@ -78758,13 +79599,15 @@ function MessageSearch({ onClose, initialQuery }) {
|
|
|
78758
79599
|
]
|
|
78759
79600
|
}, undefined, true, undefined, this)
|
|
78760
79601
|
}, undefined, false, undefined, this),
|
|
78761
|
-
loading && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79602
|
+
!expandedMessage && loading && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79603
|
+
paddingLeft: 2,
|
|
78762
79604
|
children: /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78763
79605
|
dimColor: true,
|
|
78764
79606
|
children: "Searching..."
|
|
78765
79607
|
}, undefined, false, undefined, this)
|
|
78766
79608
|
}, undefined, false, undefined, this),
|
|
78767
|
-
!loading && activeQuery && results.length === 0 && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79609
|
+
!expandedMessage && !loading && activeQuery && results.length === 0 && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79610
|
+
paddingLeft: 2,
|
|
78768
79611
|
children: /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78769
79612
|
dimColor: true,
|
|
78770
79613
|
children: [
|
|
@@ -78774,22 +79617,24 @@ function MessageSearch({ onClose, initialQuery }) {
|
|
|
78774
79617
|
]
|
|
78775
79618
|
}, undefined, true, undefined, this)
|
|
78776
79619
|
}, undefined, false, undefined, this),
|
|
78777
|
-
!loading && results.length > 0 && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79620
|
+
!expandedMessage && !loading && results.length > 0 && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
78778
79621
|
flexDirection: "column",
|
|
78779
|
-
children:
|
|
78780
|
-
const
|
|
79622
|
+
children: visibleResults.map((msg, visibleIndex) => {
|
|
79623
|
+
const actualIndex = startIndex + visibleIndex;
|
|
79624
|
+
const isSelected = actualIndex === selectedIndex;
|
|
78781
79625
|
const messageText = getMessageText(msg);
|
|
78782
79626
|
const msgWithDate = msg;
|
|
78783
|
-
const
|
|
78784
|
-
const
|
|
78785
|
-
const
|
|
78786
|
-
const
|
|
78787
|
-
const
|
|
78788
|
-
const
|
|
78789
|
-
const availableWidth = Math.max(20, terminalWidth -
|
|
79627
|
+
const msgType = msg.message_type || "unknown";
|
|
79628
|
+
const agentIdFromMsg = msgWithDate.agent_id || "unknown";
|
|
79629
|
+
const conversationIdFromMsg = msgWithDate.conversation_id;
|
|
79630
|
+
const createdAt = formatLocalTime(msgWithDate.created_at || msgWithDate.date);
|
|
79631
|
+
const isAssistant = msgType === "assistant_message" || msgType === "reasoning_message";
|
|
79632
|
+
const emoji = isAssistant ? "\uD83D\uDC7E" : "\uD83D\uDC64";
|
|
79633
|
+
const availableWidth = Math.max(20, terminalWidth - 8);
|
|
78790
79634
|
const displayText = truncateText2(messageText.replace(/\n/g, " "), availableWidth);
|
|
79635
|
+
const idToShow = conversationIdFromMsg || agentIdFromMsg;
|
|
78791
79636
|
const msgId = "message_id" in msg ? String(msg.message_id) : "result";
|
|
78792
|
-
const uniqueKey = `${msgId}-${
|
|
79637
|
+
const uniqueKey = `${msgId}-${actualIndex}`;
|
|
78793
79638
|
return /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
78794
79639
|
flexDirection: "column",
|
|
78795
79640
|
marginBottom: 1,
|
|
@@ -78802,10 +79647,15 @@ function MessageSearch({ onClose, initialQuery }) {
|
|
|
78802
79647
|
children: isSelected ? ">" : " "
|
|
78803
79648
|
}, undefined, false, undefined, this),
|
|
78804
79649
|
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78805
|
-
children:
|
|
78806
|
-
|
|
79650
|
+
children: [
|
|
79651
|
+
" ",
|
|
79652
|
+
emoji,
|
|
79653
|
+
" "
|
|
79654
|
+
]
|
|
79655
|
+
}, undefined, true, undefined, this),
|
|
78807
79656
|
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78808
79657
|
bold: isSelected,
|
|
79658
|
+
italic: true,
|
|
78809
79659
|
color: isSelected ? colors.selector.itemHighlighted : undefined,
|
|
78810
79660
|
children: displayText
|
|
78811
79661
|
}, undefined, false, undefined, this)
|
|
@@ -78814,95 +79664,53 @@ function MessageSearch({ onClose, initialQuery }) {
|
|
|
78814
79664
|
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
78815
79665
|
flexDirection: "row",
|
|
78816
79666
|
marginLeft: 2,
|
|
78817
|
-
children:
|
|
78818
|
-
|
|
78819
|
-
|
|
78820
|
-
|
|
78821
|
-
|
|
78822
|
-
|
|
78823
|
-
|
|
78824
|
-
|
|
78825
|
-
agentId && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(jsx_dev_runtime46.Fragment, {
|
|
78826
|
-
children: [
|
|
78827
|
-
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78828
|
-
dimColor: true,
|
|
78829
|
-
children: " · "
|
|
78830
|
-
}, undefined, false, undefined, this),
|
|
78831
|
-
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(dist_default4, {
|
|
78832
|
-
url: `https://app.letta.com/projects/default-project/agents/${agentId}?searchTerm=${encodeURIComponent(activeQuery)}&messageId=${msgId}${conversationId ? `&conversation=${encodeURIComponent(conversationId)}` : ""}`,
|
|
78833
|
-
children: /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78834
|
-
color: colors.link.text,
|
|
78835
|
-
children: "view message"
|
|
78836
|
-
}, undefined, false, undefined, this)
|
|
78837
|
-
}, undefined, false, undefined, this),
|
|
78838
|
-
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78839
|
-
dimColor: true,
|
|
78840
|
-
children: " · agent: "
|
|
78841
|
-
}, undefined, false, undefined, this),
|
|
78842
|
-
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(dist_default4, {
|
|
78843
|
-
url: `https://app.letta.com/projects/default-project/agents/${agentId}${conversationId ? `?conversation=${encodeURIComponent(conversationId)}` : ""}`,
|
|
78844
|
-
children: /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78845
|
-
color: colors.link.text,
|
|
78846
|
-
children: agentId
|
|
78847
|
-
}, undefined, false, undefined, this)
|
|
78848
|
-
}, undefined, false, undefined, this)
|
|
78849
|
-
]
|
|
78850
|
-
}, undefined, true, undefined, this),
|
|
78851
|
-
createdAt && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78852
|
-
dimColor: true,
|
|
78853
|
-
children: [
|
|
78854
|
-
" · ",
|
|
78855
|
-
createdAt
|
|
78856
|
-
]
|
|
78857
|
-
}, undefined, true, undefined, this)
|
|
78858
|
-
]
|
|
78859
|
-
}, undefined, true, undefined, this)
|
|
79667
|
+
children: /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79668
|
+
dimColor: true,
|
|
79669
|
+
children: [
|
|
79670
|
+
createdAt,
|
|
79671
|
+
idToShow && ` · ${idToShow}`
|
|
79672
|
+
]
|
|
79673
|
+
}, undefined, true, undefined, this)
|
|
79674
|
+
}, undefined, false, undefined, this)
|
|
78860
79675
|
]
|
|
78861
79676
|
}, uniqueKey, true, undefined, this);
|
|
78862
79677
|
})
|
|
78863
79678
|
}, undefined, false, undefined, this),
|
|
78864
|
-
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
79679
|
+
!expandedMessage && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
78865
79680
|
flexDirection: "column",
|
|
78866
79681
|
marginTop: 1,
|
|
79682
|
+
paddingLeft: 2,
|
|
78867
79683
|
children: [
|
|
78868
|
-
results.length > 0 && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(
|
|
78869
|
-
|
|
78870
|
-
|
|
78871
|
-
|
|
78872
|
-
|
|
78873
|
-
|
|
78874
|
-
|
|
78875
|
-
|
|
78876
|
-
|
|
78877
|
-
|
|
78878
|
-
|
|
78879
|
-
|
|
78880
|
-
]
|
|
78881
|
-
}, undefined, true, undefined, this)
|
|
78882
|
-
}, undefined, false, undefined, this),
|
|
78883
|
-
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Box_default, {
|
|
78884
|
-
children: /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
78885
|
-
dimColor: true,
|
|
78886
|
-
children: "Type + Enter to search · Tab mode · J/K page · Esc close"
|
|
78887
|
-
}, undefined, false, undefined, this)
|
|
79684
|
+
results.length > 0 && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79685
|
+
dimColor: true,
|
|
79686
|
+
children: [
|
|
79687
|
+
selectedIndex + 1,
|
|
79688
|
+
"/",
|
|
79689
|
+
results.length,
|
|
79690
|
+
" results"
|
|
79691
|
+
]
|
|
79692
|
+
}, undefined, true, undefined, this),
|
|
79693
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(Text, {
|
|
79694
|
+
dimColor: true,
|
|
79695
|
+
children: "Enter expand · ↑↓ navigate · Esc close"
|
|
78888
79696
|
}, undefined, false, undefined, this)
|
|
78889
79697
|
]
|
|
78890
79698
|
}, undefined, true, undefined, this)
|
|
78891
79699
|
]
|
|
78892
79700
|
}, undefined, true, undefined, this);
|
|
78893
79701
|
}
|
|
78894
|
-
var import_react70, jsx_dev_runtime46,
|
|
79702
|
+
var import_react70, jsx_dev_runtime46, SOLID_LINE16 = "─", VISIBLE_ITEMS = 5, SEARCH_LIMIT = 100, SEARCH_MODES, SEARCH_RANGES;
|
|
78895
79703
|
var init_MessageSearch = __esm(async () => {
|
|
78896
79704
|
init_useTerminalWidth();
|
|
78897
79705
|
init_colors();
|
|
78898
79706
|
await __promiseAll([
|
|
78899
79707
|
init_build2(),
|
|
78900
|
-
init_dist4(),
|
|
78901
79708
|
init_client2()
|
|
78902
79709
|
]);
|
|
78903
79710
|
import_react70 = __toESM(require_react(), 1);
|
|
78904
79711
|
jsx_dev_runtime46 = __toESM(require_jsx_dev_runtime(), 1);
|
|
78905
|
-
SEARCH_MODES = ["
|
|
79712
|
+
SEARCH_MODES = ["fts", "vector", "hybrid"];
|
|
79713
|
+
SEARCH_RANGES = ["all", "agent", "conv"];
|
|
78906
79714
|
});
|
|
78907
79715
|
|
|
78908
79716
|
// src/cli/components/ModelSelector.tsx
|
|
@@ -78914,7 +79722,7 @@ function ModelSelector({
|
|
|
78914
79722
|
forceRefresh: forceRefreshOnMount
|
|
78915
79723
|
}) {
|
|
78916
79724
|
const terminalWidth = useTerminalWidth();
|
|
78917
|
-
const solidLine =
|
|
79725
|
+
const solidLine = SOLID_LINE17.repeat(Math.max(terminalWidth, 10));
|
|
78918
79726
|
const typedModels = models;
|
|
78919
79727
|
const [category, setCategory] = import_react71.useState("supported");
|
|
78920
79728
|
const [selectedIndex, setSelectedIndex] = import_react71.useState(0);
|
|
@@ -78997,7 +79805,7 @@ function ModelSelector({
|
|
|
78997
79805
|
description: ""
|
|
78998
79806
|
}));
|
|
78999
79807
|
}, [category, supportedModels, otherModelHandles]);
|
|
79000
|
-
const visibleCount =
|
|
79808
|
+
const visibleCount = VISIBLE_ITEMS2 - 1;
|
|
79001
79809
|
const startIndex = import_react71.useMemo(() => {
|
|
79002
79810
|
if (selectedIndex < visibleCount)
|
|
79003
79811
|
return 0;
|
|
@@ -79245,7 +80053,7 @@ function ModelSelector({
|
|
|
79245
80053
|
]
|
|
79246
80054
|
}, undefined, true, undefined, this);
|
|
79247
80055
|
}
|
|
79248
|
-
var import_react71, jsx_dev_runtime47,
|
|
80056
|
+
var import_react71, jsx_dev_runtime47, SOLID_LINE17 = "─", VISIBLE_ITEMS2 = 8, MODEL_CATEGORIES;
|
|
79249
80057
|
var init_ModelSelector = __esm(async () => {
|
|
79250
80058
|
init_model();
|
|
79251
80059
|
init_useTerminalWidth();
|
|
@@ -79476,7 +80284,7 @@ var init_PinDialog = __esm(async () => {
|
|
|
79476
80284
|
// src/cli/components/NewAgentDialog.tsx
|
|
79477
80285
|
function NewAgentDialog({ onSubmit, onCancel }) {
|
|
79478
80286
|
const terminalWidth = useTerminalWidth();
|
|
79479
|
-
const solidLine =
|
|
80287
|
+
const solidLine = SOLID_LINE18.repeat(Math.max(terminalWidth, 10));
|
|
79480
80288
|
const [nameInput, setNameInput] = import_react73.useState("");
|
|
79481
80289
|
const [error, setError] = import_react73.useState("");
|
|
79482
80290
|
use_input_default((input, key) => {
|
|
@@ -79584,7 +80392,7 @@ function NewAgentDialog({ onSubmit, onCancel }) {
|
|
|
79584
80392
|
]
|
|
79585
80393
|
}, undefined, true, undefined, this);
|
|
79586
80394
|
}
|
|
79587
|
-
var import_react73, jsx_dev_runtime49,
|
|
80395
|
+
var import_react73, jsx_dev_runtime49, SOLID_LINE18 = "─";
|
|
79588
80396
|
var init_NewAgentDialog = __esm(async () => {
|
|
79589
80397
|
init_constants();
|
|
79590
80398
|
init_useTerminalWidth();
|
|
@@ -80508,7 +81316,7 @@ function SystemPromptSelector({
|
|
|
80508
81316
|
onCancel
|
|
80509
81317
|
}) {
|
|
80510
81318
|
const terminalWidth = useTerminalWidth();
|
|
80511
|
-
const solidLine =
|
|
81319
|
+
const solidLine = SOLID_LINE19.repeat(Math.max(terminalWidth, 10));
|
|
80512
81320
|
const [showAll, setShowAll] = import_react80.useState(false);
|
|
80513
81321
|
const [selectedIndex, setSelectedIndex] = import_react80.useState(0);
|
|
80514
81322
|
const featuredPrompts = import_react80.useMemo(() => SYSTEM_PROMPTS.filter((prompt) => prompt.isFeatured), []);
|
|
@@ -80629,7 +81437,7 @@ function SystemPromptSelector({
|
|
|
80629
81437
|
]
|
|
80630
81438
|
}, undefined, true, undefined, this);
|
|
80631
81439
|
}
|
|
80632
|
-
var import_react80, jsx_dev_runtime56,
|
|
81440
|
+
var import_react80, jsx_dev_runtime56, SOLID_LINE19 = "─";
|
|
80633
81441
|
var init_SystemPromptSelector = __esm(async () => {
|
|
80634
81442
|
init_promptAssets();
|
|
80635
81443
|
init_useTerminalWidth();
|
|
@@ -82302,7 +83110,7 @@ function ToolsetSelector({
|
|
|
82302
83110
|
onCancel
|
|
82303
83111
|
}) {
|
|
82304
83112
|
const terminalWidth = useTerminalWidth();
|
|
82305
|
-
const solidLine =
|
|
83113
|
+
const solidLine = SOLID_LINE20.repeat(Math.max(terminalWidth, 10));
|
|
82306
83114
|
const [showAll, setShowAll] = import_react82.useState(false);
|
|
82307
83115
|
const [selectedIndex, setSelectedIndex] = import_react82.useState(0);
|
|
82308
83116
|
const featuredToolsets = import_react82.useMemo(() => toolsets.filter((toolset) => toolset.isFeatured), []);
|
|
@@ -82429,7 +83237,7 @@ function ToolsetSelector({
|
|
|
82429
83237
|
]
|
|
82430
83238
|
}, undefined, true, undefined, this);
|
|
82431
83239
|
}
|
|
82432
|
-
var import_react82, jsx_dev_runtime61,
|
|
83240
|
+
var import_react82, jsx_dev_runtime61, SOLID_LINE20 = "─", toolsets;
|
|
82433
83241
|
var init_ToolsetSelector = __esm(async () => {
|
|
82434
83242
|
init_useTerminalWidth();
|
|
82435
83243
|
init_colors();
|
|
@@ -84349,6 +85157,13 @@ function App2({
|
|
|
84349
85157
|
runSessionEndHooks(durationMs, undefined, undefined, agentIdRef.current ?? undefined, conversationIdRef.current ?? undefined).catch(() => {});
|
|
84350
85158
|
};
|
|
84351
85159
|
}, []);
|
|
85160
|
+
import_react86.useEffect(() => {
|
|
85161
|
+
return () => {
|
|
85162
|
+
if (queueAppendTimeoutRef.current) {
|
|
85163
|
+
clearTimeout(queueAppendTimeoutRef.current);
|
|
85164
|
+
}
|
|
85165
|
+
};
|
|
85166
|
+
}, []);
|
|
84352
85167
|
const [showExitStats, setShowExitStats] = import_react86.useState(false);
|
|
84353
85168
|
const hasSentSessionContextRef = import_react86.useRef(false);
|
|
84354
85169
|
const turnCountRef = import_react86.useRef(0);
|
|
@@ -84361,6 +85176,10 @@ function App2({
|
|
|
84361
85176
|
const llmApiErrorRetriesRef = import_react86.useRef(0);
|
|
84362
85177
|
const conversationBusyRetriesRef = import_react86.useRef(0);
|
|
84363
85178
|
const [messageQueue, setMessageQueue] = import_react86.useState([]);
|
|
85179
|
+
const messageQueueRef = import_react86.useRef([]);
|
|
85180
|
+
import_react86.useEffect(() => {
|
|
85181
|
+
messageQueueRef.current = messageQueue;
|
|
85182
|
+
}, [messageQueue]);
|
|
84364
85183
|
const waitingForQueueCancelRef = import_react86.useRef(false);
|
|
84365
85184
|
const queueSnapshotRef = import_react86.useRef([]);
|
|
84366
85185
|
const [restoreQueueOnCancel, setRestoreQueueOnCancel] = import_react86.useState(false);
|
|
@@ -84368,12 +85187,24 @@ function App2({
|
|
|
84368
85187
|
import_react86.useEffect(() => {
|
|
84369
85188
|
restoreQueueOnCancelRef.current = restoreQueueOnCancel;
|
|
84370
85189
|
}, [restoreQueueOnCancel]);
|
|
85190
|
+
const queueAppendTimeoutRef = import_react86.useRef(null);
|
|
84371
85191
|
const [dequeueEpoch, setDequeueEpoch] = import_react86.useState(0);
|
|
84372
85192
|
const lastDequeuedMessageRef = import_react86.useRef(null);
|
|
84373
85193
|
const [restoredInput, setRestoredInput] = import_react86.useState(null);
|
|
84374
85194
|
const isAgentBusy = import_react86.useCallback(() => {
|
|
84375
85195
|
return streamingRef.current || isExecutingTool || commandRunningRef.current || abortControllerRef.current !== null;
|
|
84376
85196
|
}, [isExecutingTool]);
|
|
85197
|
+
const consumeQueuedMessages = import_react86.useCallback(() => {
|
|
85198
|
+
if (messageQueueRef.current.length === 0)
|
|
85199
|
+
return null;
|
|
85200
|
+
if (queueAppendTimeoutRef.current) {
|
|
85201
|
+
clearTimeout(queueAppendTimeoutRef.current);
|
|
85202
|
+
queueAppendTimeoutRef.current = null;
|
|
85203
|
+
}
|
|
85204
|
+
const messages = [...messageQueueRef.current];
|
|
85205
|
+
setMessageQueue([]);
|
|
85206
|
+
return messages;
|
|
85207
|
+
}, []);
|
|
84377
85208
|
const withCommandLock = import_react86.useCallback(async (asyncFn) => {
|
|
84378
85209
|
setActiveOverlay(null);
|
|
84379
85210
|
setCommandRunning(true);
|
|
@@ -85032,7 +85863,35 @@ ${newState.originalPrompt}`
|
|
|
85032
85863
|
llmApiErrorRetriesRef.current = 0;
|
|
85033
85864
|
conversationBusyRetriesRef.current = 0;
|
|
85034
85865
|
lastDequeuedMessageRef.current = null;
|
|
85035
|
-
runStopHooks(stopReasonToHandle, buffersRef.current.order.length, Array.from(buffersRef.current.byId.values()).filter((item) => item.kind === "tool_call").length)
|
|
85866
|
+
const stopHookResult = await runStopHooks(stopReasonToHandle, buffersRef.current.order.length, Array.from(buffersRef.current.byId.values()).filter((item) => item.kind === "tool_call").length);
|
|
85867
|
+
if (stopHookResult.blocked) {
|
|
85868
|
+
const stderrOutput = stopHookResult.results.map((r) => r.stderr).filter(Boolean).join(`
|
|
85869
|
+
`);
|
|
85870
|
+
const feedback = stderrOutput || "Stop hook blocked";
|
|
85871
|
+
const hookMessage = `<stop-hook>
|
|
85872
|
+
${feedback}
|
|
85873
|
+
</stop-hook>`;
|
|
85874
|
+
const statusId = uid4("status");
|
|
85875
|
+
buffersRef.current.byId.set(statusId, {
|
|
85876
|
+
kind: "status",
|
|
85877
|
+
id: statusId,
|
|
85878
|
+
lines: [
|
|
85879
|
+
"Stop hook encountered blocking error, continuing loop with stderr feedback."
|
|
85880
|
+
]
|
|
85881
|
+
});
|
|
85882
|
+
buffersRef.current.order.push(statusId);
|
|
85883
|
+
refreshDerived();
|
|
85884
|
+
setTimeout(() => {
|
|
85885
|
+
processConversation([
|
|
85886
|
+
{
|
|
85887
|
+
type: "message",
|
|
85888
|
+
role: "user",
|
|
85889
|
+
content: hookMessage
|
|
85890
|
+
}
|
|
85891
|
+
], { allowReentry: true });
|
|
85892
|
+
}, 0);
|
|
85893
|
+
return;
|
|
85894
|
+
}
|
|
85036
85895
|
if (needsEagerApprovalCheck) {
|
|
85037
85896
|
setNeedsEagerApprovalCheck(false);
|
|
85038
85897
|
}
|
|
@@ -85288,6 +86147,31 @@ ${newState.originalPrompt}`
|
|
|
85288
86147
|
refreshDerived();
|
|
85289
86148
|
return;
|
|
85290
86149
|
}
|
|
86150
|
+
const queuedMessagesToAppend = consumeQueuedMessages();
|
|
86151
|
+
if (queuedMessagesToAppend?.length) {
|
|
86152
|
+
for (const msg of queuedMessagesToAppend) {
|
|
86153
|
+
const userId = uid4("user");
|
|
86154
|
+
buffersRef.current.byId.set(userId, {
|
|
86155
|
+
kind: "user",
|
|
86156
|
+
id: userId,
|
|
86157
|
+
text: msg
|
|
86158
|
+
});
|
|
86159
|
+
buffersRef.current.order.push(userId);
|
|
86160
|
+
}
|
|
86161
|
+
setThinkingMessage(getRandomThinkingVerb());
|
|
86162
|
+
refreshDerived();
|
|
86163
|
+
toolResultsInFlightRef.current = true;
|
|
86164
|
+
await processConversation([
|
|
86165
|
+
{ type: "approval", approvals: allResults },
|
|
86166
|
+
...queuedMessagesToAppend.map((msg) => ({
|
|
86167
|
+
type: "message",
|
|
86168
|
+
role: "user",
|
|
86169
|
+
content: msg
|
|
86170
|
+
}))
|
|
86171
|
+
], { allowReentry: true });
|
|
86172
|
+
toolResultsInFlightRef.current = false;
|
|
86173
|
+
return;
|
|
86174
|
+
}
|
|
85291
86175
|
if (waitingForQueueCancelRef.current) {
|
|
85292
86176
|
if (allResults.length > 0) {
|
|
85293
86177
|
queueApprovalResults(allResults, autoAllowedMetadata);
|
|
@@ -85636,7 +86520,8 @@ ${newState.originalPrompt}`
|
|
|
85636
86520
|
currentModelId,
|
|
85637
86521
|
updateStreamingOutput,
|
|
85638
86522
|
needsEagerApprovalCheck,
|
|
85639
|
-
queueApprovalResults
|
|
86523
|
+
queueApprovalResults,
|
|
86524
|
+
consumeQueuedMessages
|
|
85640
86525
|
]);
|
|
85641
86526
|
const handleExit = import_react86.useCallback(async () => {
|
|
85642
86527
|
saveLastAgentBeforeExit();
|
|
@@ -85810,7 +86695,7 @@ ${newState.originalPrompt}`
|
|
|
85810
86695
|
import_react86.useEffect(() => {
|
|
85811
86696
|
processConversationRef.current = processConversation;
|
|
85812
86697
|
}, [processConversation]);
|
|
85813
|
-
const handleAgentSelect = import_react86.useCallback(async (targetAgentId,
|
|
86698
|
+
const handleAgentSelect = import_react86.useCallback(async (targetAgentId, opts) => {
|
|
85814
86699
|
setActiveOverlay(null);
|
|
85815
86700
|
if (targetAgentId === agentId) {
|
|
85816
86701
|
const label = agentName || targetAgentId.slice(0, 12);
|
|
@@ -85860,7 +86745,7 @@ ${newState.originalPrompt}`
|
|
|
85860
86745
|
try {
|
|
85861
86746
|
const client = await getClient2();
|
|
85862
86747
|
const agent = await client.agents.retrieve(targetAgentId);
|
|
85863
|
-
const targetConversationId = "default";
|
|
86748
|
+
const targetConversationId = opts?.conversationId ?? "default";
|
|
85864
86749
|
await updateProjectSettings({ lastAgent: targetAgentId });
|
|
85865
86750
|
settingsManager.setLocalLastSession({ agentId: targetAgentId, conversationId: targetConversationId }, process.cwd());
|
|
85866
86751
|
settingsManager.setGlobalLastSession({
|
|
@@ -85880,7 +86765,12 @@ ${newState.originalPrompt}`
|
|
|
85880
86765
|
setLlmConfig(agent.llm_config);
|
|
85881
86766
|
setConversationId3(targetConversationId);
|
|
85882
86767
|
const agentLabel = agent.name || targetAgentId;
|
|
85883
|
-
const
|
|
86768
|
+
const isSpecificConv = opts?.conversationId && opts.conversationId !== "default";
|
|
86769
|
+
const successOutput = isSpecificConv ? [
|
|
86770
|
+
`Switched to **${agentLabel}**`,
|
|
86771
|
+
`⎿ Conversation: ${opts.conversationId}`
|
|
86772
|
+
].join(`
|
|
86773
|
+
`) : [
|
|
85884
86774
|
`Resumed the default conversation with **${agentLabel}**.`,
|
|
85885
86775
|
`⎿ Type /resume to browse all conversations`,
|
|
85886
86776
|
`⎿ Type /new to start a new conversation`
|
|
@@ -86277,29 +87167,34 @@ ${expanded.command}` : expanded.command;
|
|
|
86277
87167
|
setMessageQueue((prev) => {
|
|
86278
87168
|
const newQueue = [...prev, msg];
|
|
86279
87169
|
const isSlashCommand = msg.startsWith("/");
|
|
86280
|
-
if (!isSlashCommand && streamingRef.current && !waitingForQueueCancelRef.current) {
|
|
86281
|
-
|
|
86282
|
-
|
|
86283
|
-
|
|
86284
|
-
|
|
86285
|
-
|
|
86286
|
-
|
|
86287
|
-
|
|
86288
|
-
|
|
86289
|
-
|
|
86290
|
-
|
|
86291
|
-
return client.conversations.cancel(conversationIdRef.current);
|
|
86292
|
-
}).then(() => {}).catch(() => {
|
|
86293
|
-
waitingForQueueCancelRef.current = false;
|
|
86294
|
-
});
|
|
86295
|
-
setTimeout(() => {
|
|
86296
|
-
if (waitingForQueueCancelRef.current && abortControllerRef.current) {
|
|
86297
|
-
debugLog("queue", "Timeout fallback: aborting stream after 3s (server cancel was slow/failed)");
|
|
86298
|
-
abortControllerRef.current.abort();
|
|
86299
|
-
waitingForQueueCancelRef.current = false;
|
|
86300
|
-
queueSnapshotRef.current = [];
|
|
87170
|
+
if (!isSlashCommand && streamingRef.current && !waitingForQueueCancelRef.current && !queueAppendTimeoutRef.current) {
|
|
87171
|
+
queueAppendTimeoutRef.current = setTimeout(() => {
|
|
87172
|
+
if (messageQueueRef.current.length === 0) {
|
|
87173
|
+
queueAppendTimeoutRef.current = null;
|
|
87174
|
+
return;
|
|
87175
|
+
}
|
|
87176
|
+
queueAppendTimeoutRef.current = null;
|
|
87177
|
+
waitingForQueueCancelRef.current = true;
|
|
87178
|
+
queueSnapshotRef.current = [...messageQueueRef.current];
|
|
87179
|
+
if (toolAbortControllerRef.current) {
|
|
87180
|
+
toolAbortControllerRef.current.abort();
|
|
86301
87181
|
}
|
|
86302
|
-
|
|
87182
|
+
getClient2().then((client) => {
|
|
87183
|
+
if (conversationIdRef.current === "default") {
|
|
87184
|
+
return client.agents.messages.cancel(agentIdRef.current);
|
|
87185
|
+
}
|
|
87186
|
+
return client.conversations.cancel(conversationIdRef.current);
|
|
87187
|
+
}).catch(() => {
|
|
87188
|
+
waitingForQueueCancelRef.current = false;
|
|
87189
|
+
});
|
|
87190
|
+
setTimeout(() => {
|
|
87191
|
+
if (waitingForQueueCancelRef.current && abortControllerRef.current) {
|
|
87192
|
+
abortControllerRef.current.abort();
|
|
87193
|
+
waitingForQueueCancelRef.current = false;
|
|
87194
|
+
queueSnapshotRef.current = [];
|
|
87195
|
+
}
|
|
87196
|
+
}, 3000);
|
|
87197
|
+
}, 15000);
|
|
86303
87198
|
}
|
|
86304
87199
|
return newQueue;
|
|
86305
87200
|
});
|
|
@@ -86788,7 +87683,7 @@ Type your task to begin the loop.`,
|
|
|
86788
87683
|
return { submitted: true };
|
|
86789
87684
|
}
|
|
86790
87685
|
const client = await getClient2();
|
|
86791
|
-
const result2 = await client.
|
|
87686
|
+
const result2 = await client.conversations.messages.compact(conversationIdRef.current);
|
|
86792
87687
|
const outputLines = [
|
|
86793
87688
|
`Compaction completed. Message buffer length reduced from ${result2.num_messages_before} to ${result2.num_messages_after}.`,
|
|
86794
87689
|
"",
|
|
@@ -88218,13 +89113,29 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
88218
89113
|
waitingForQueueCancelRef.current = false;
|
|
88219
89114
|
queueSnapshotRef.current = [];
|
|
88220
89115
|
} else {
|
|
88221
|
-
|
|
88222
|
-
|
|
88223
|
-
{
|
|
88224
|
-
|
|
88225
|
-
|
|
89116
|
+
const queuedMessagesToAppend = consumeQueuedMessages();
|
|
89117
|
+
const input = [
|
|
89118
|
+
{ type: "approval", approvals: allResults }
|
|
89119
|
+
];
|
|
89120
|
+
if (queuedMessagesToAppend?.length) {
|
|
89121
|
+
for (const msg of queuedMessagesToAppend) {
|
|
89122
|
+
const userId = uid4("user");
|
|
89123
|
+
buffersRef.current.byId.set(userId, {
|
|
89124
|
+
kind: "user",
|
|
89125
|
+
id: userId,
|
|
89126
|
+
text: msg
|
|
89127
|
+
});
|
|
89128
|
+
buffersRef.current.order.push(userId);
|
|
89129
|
+
input.push({
|
|
89130
|
+
type: "message",
|
|
89131
|
+
role: "user",
|
|
89132
|
+
content: msg
|
|
89133
|
+
});
|
|
88226
89134
|
}
|
|
88227
|
-
|
|
89135
|
+
refreshDerived();
|
|
89136
|
+
}
|
|
89137
|
+
toolResultsInFlightRef.current = true;
|
|
89138
|
+
await processConversation(input);
|
|
88228
89139
|
toolResultsInFlightRef.current = false;
|
|
88229
89140
|
queueApprovalResults(null);
|
|
88230
89141
|
}
|
|
@@ -88245,7 +89156,8 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
88245
89156
|
appendError,
|
|
88246
89157
|
setStreaming,
|
|
88247
89158
|
updateStreamingOutput,
|
|
88248
|
-
queueApprovalResults
|
|
89159
|
+
queueApprovalResults,
|
|
89160
|
+
consumeQueuedMessages
|
|
88249
89161
|
]);
|
|
88250
89162
|
const handleApproveCurrent = import_react86.useCallback(async (diffs) => {
|
|
88251
89163
|
if (isExecutingTool)
|
|
@@ -89329,9 +90241,12 @@ Plan file path: ${planFilePath}`;
|
|
|
89329
90241
|
line: item
|
|
89330
90242
|
}, undefined, false, undefined, this) : item.kind === "status" ? /* @__PURE__ */ jsx_dev_runtime63.jsxDEV(StatusMessage, {
|
|
89331
90243
|
line: item
|
|
89332
|
-
}, undefined, false, undefined, this) : item.kind === "separator" ? /* @__PURE__ */ jsx_dev_runtime63.jsxDEV(
|
|
89333
|
-
|
|
89334
|
-
children:
|
|
90244
|
+
}, undefined, false, undefined, this) : item.kind === "separator" ? /* @__PURE__ */ jsx_dev_runtime63.jsxDEV(Box_default, {
|
|
90245
|
+
marginTop: 1,
|
|
90246
|
+
children: /* @__PURE__ */ jsx_dev_runtime63.jsxDEV(Text, {
|
|
90247
|
+
dimColor: true,
|
|
90248
|
+
children: "─".repeat(columns)
|
|
90249
|
+
}, undefined, false, undefined, this)
|
|
89335
90250
|
}, undefined, false, undefined, this) : item.kind === "command" ? /* @__PURE__ */ jsx_dev_runtime63.jsxDEV(CommandMessage, {
|
|
89336
90251
|
line: item
|
|
89337
90252
|
}, undefined, false, undefined, this) : item.kind === "bash_command" ? /* @__PURE__ */ jsx_dev_runtime63.jsxDEV(BashCommandMessage, {
|
|
@@ -89766,7 +90681,147 @@ Plan file path: ${planFilePath}`;
|
|
|
89766
90681
|
}, undefined, false, undefined, this),
|
|
89767
90682
|
activeOverlay === "search" && /* @__PURE__ */ jsx_dev_runtime63.jsxDEV(MessageSearch, {
|
|
89768
90683
|
onClose: closeOverlay,
|
|
89769
|
-
initialQuery: searchQuery || undefined
|
|
90684
|
+
initialQuery: searchQuery || undefined,
|
|
90685
|
+
agentId,
|
|
90686
|
+
conversationId,
|
|
90687
|
+
onOpenConversation: async (targetAgentId, targetConvId) => {
|
|
90688
|
+
closeOverlay();
|
|
90689
|
+
if (targetAgentId !== agentId) {
|
|
90690
|
+
await handleAgentSelect(targetAgentId, {
|
|
90691
|
+
conversationId: targetConvId
|
|
90692
|
+
});
|
|
90693
|
+
return;
|
|
90694
|
+
}
|
|
90695
|
+
const actualTargetConv = targetConvId || "default";
|
|
90696
|
+
if (actualTargetConv === conversationId) {
|
|
90697
|
+
return;
|
|
90698
|
+
}
|
|
90699
|
+
if (isAgentBusy()) {
|
|
90700
|
+
setQueuedOverlayAction({
|
|
90701
|
+
type: "switch_conversation",
|
|
90702
|
+
conversationId: actualTargetConv
|
|
90703
|
+
});
|
|
90704
|
+
const cmdId2 = uid4("cmd");
|
|
90705
|
+
buffersRef.current.byId.set(cmdId2, {
|
|
90706
|
+
kind: "command",
|
|
90707
|
+
id: cmdId2,
|
|
90708
|
+
input: "/search",
|
|
90709
|
+
output: `Conversation switch queued – will switch after current task completes`,
|
|
90710
|
+
phase: "finished",
|
|
90711
|
+
success: true
|
|
90712
|
+
});
|
|
90713
|
+
buffersRef.current.order.push(cmdId2);
|
|
90714
|
+
refreshDerived();
|
|
90715
|
+
return;
|
|
90716
|
+
}
|
|
90717
|
+
setCommandRunning(true);
|
|
90718
|
+
const cmdId = uid4("cmd");
|
|
90719
|
+
buffersRef.current.byId.set(cmdId, {
|
|
90720
|
+
kind: "command",
|
|
90721
|
+
id: cmdId,
|
|
90722
|
+
input: "/search",
|
|
90723
|
+
output: "Switching conversation...",
|
|
90724
|
+
phase: "running"
|
|
90725
|
+
});
|
|
90726
|
+
buffersRef.current.order.push(cmdId);
|
|
90727
|
+
refreshDerived();
|
|
90728
|
+
try {
|
|
90729
|
+
if (agentState) {
|
|
90730
|
+
const client = await getClient2();
|
|
90731
|
+
const resumeData = await getResumeData2(client, agentState, actualTargetConv);
|
|
90732
|
+
setConversationId3(actualTargetConv);
|
|
90733
|
+
settingsManager.setLocalLastSession({ agentId, conversationId: actualTargetConv }, process.cwd());
|
|
90734
|
+
settingsManager.setGlobalLastSession({
|
|
90735
|
+
agentId,
|
|
90736
|
+
conversationId: actualTargetConv
|
|
90737
|
+
});
|
|
90738
|
+
buffersRef.current.byId.clear();
|
|
90739
|
+
buffersRef.current.order = [];
|
|
90740
|
+
buffersRef.current.tokenCount = 0;
|
|
90741
|
+
emittedIdsRef.current.clear();
|
|
90742
|
+
setStaticItems([]);
|
|
90743
|
+
setStaticRenderEpoch((e) => e + 1);
|
|
90744
|
+
const currentAgentName = agentState.name || "Unnamed Agent";
|
|
90745
|
+
const successOutput = [
|
|
90746
|
+
`Switched to conversation with "${currentAgentName}"`,
|
|
90747
|
+
`⎿ Conversation: ${actualTargetConv}`
|
|
90748
|
+
].join(`
|
|
90749
|
+
`);
|
|
90750
|
+
const successItem = {
|
|
90751
|
+
kind: "command",
|
|
90752
|
+
id: uid4("cmd"),
|
|
90753
|
+
input: "/search",
|
|
90754
|
+
output: successOutput,
|
|
90755
|
+
phase: "finished",
|
|
90756
|
+
success: true
|
|
90757
|
+
};
|
|
90758
|
+
if (resumeData.messageHistory.length > 0) {
|
|
90759
|
+
hasBackfilledRef.current = false;
|
|
90760
|
+
backfillBuffers(buffersRef.current, resumeData.messageHistory);
|
|
90761
|
+
const backfilledItems = [];
|
|
90762
|
+
for (const id of buffersRef.current.order) {
|
|
90763
|
+
const ln = buffersRef.current.byId.get(id);
|
|
90764
|
+
if (!ln)
|
|
90765
|
+
continue;
|
|
90766
|
+
emittedIdsRef.current.add(id);
|
|
90767
|
+
backfilledItems.push({ ...ln });
|
|
90768
|
+
}
|
|
90769
|
+
const separator = {
|
|
90770
|
+
kind: "separator",
|
|
90771
|
+
id: uid4("sep")
|
|
90772
|
+
};
|
|
90773
|
+
setStaticItems([
|
|
90774
|
+
separator,
|
|
90775
|
+
...backfilledItems,
|
|
90776
|
+
successItem
|
|
90777
|
+
]);
|
|
90778
|
+
setLines(toLines(buffersRef.current));
|
|
90779
|
+
hasBackfilledRef.current = true;
|
|
90780
|
+
} else {
|
|
90781
|
+
const separator = {
|
|
90782
|
+
kind: "separator",
|
|
90783
|
+
id: uid4("sep")
|
|
90784
|
+
};
|
|
90785
|
+
setStaticItems([separator, successItem]);
|
|
90786
|
+
setLines(toLines(buffersRef.current));
|
|
90787
|
+
}
|
|
90788
|
+
if (resumeData.pendingApprovals.length > 0) {
|
|
90789
|
+
setPendingApprovals(resumeData.pendingApprovals);
|
|
90790
|
+
try {
|
|
90791
|
+
const contexts = await Promise.all(resumeData.pendingApprovals.map(async (approval) => {
|
|
90792
|
+
const parsedArgs = safeJsonParseOr(approval.toolArgs, {});
|
|
90793
|
+
return await analyzeToolApproval(approval.toolName, parsedArgs);
|
|
90794
|
+
}));
|
|
90795
|
+
setApprovalContexts(contexts);
|
|
90796
|
+
} catch {}
|
|
90797
|
+
}
|
|
90798
|
+
}
|
|
90799
|
+
} catch (error) {
|
|
90800
|
+
let errorMsg = "Unknown error";
|
|
90801
|
+
if (error instanceof APIError2) {
|
|
90802
|
+
if (error.status === 404) {
|
|
90803
|
+
errorMsg = "Conversation not found";
|
|
90804
|
+
} else if (error.status === 422) {
|
|
90805
|
+
errorMsg = "Invalid conversation ID";
|
|
90806
|
+
} else {
|
|
90807
|
+
errorMsg = error.message;
|
|
90808
|
+
}
|
|
90809
|
+
} else if (error instanceof Error) {
|
|
90810
|
+
errorMsg = error.message;
|
|
90811
|
+
}
|
|
90812
|
+
buffersRef.current.byId.set(cmdId, {
|
|
90813
|
+
kind: "command",
|
|
90814
|
+
id: cmdId,
|
|
90815
|
+
input: "/search",
|
|
90816
|
+
output: `Failed: ${errorMsg}`,
|
|
90817
|
+
phase: "finished",
|
|
90818
|
+
success: false
|
|
90819
|
+
});
|
|
90820
|
+
refreshDerived();
|
|
90821
|
+
} finally {
|
|
90822
|
+
setCommandRunning(false);
|
|
90823
|
+
}
|
|
90824
|
+
}
|
|
89770
90825
|
}, undefined, false, undefined, this),
|
|
89771
90826
|
activeOverlay === "feedback" && /* @__PURE__ */ jsx_dev_runtime63.jsxDEV(FeedbackDialog, {
|
|
89772
90827
|
onSubmit: handleFeedbackSubmit,
|
|
@@ -91067,7 +92122,7 @@ function sortChronological(messages) {
|
|
|
91067
92122
|
async function getResumeData(client, agent, conversationId) {
|
|
91068
92123
|
try {
|
|
91069
92124
|
let inContextMessageIds;
|
|
91070
|
-
let messages;
|
|
92125
|
+
let messages = [];
|
|
91071
92126
|
const useConversationsApi = conversationId && conversationId !== "default";
|
|
91072
92127
|
if (process.env.DEBUG) {
|
|
91073
92128
|
console.log(`[DEBUG] getResumeData: conversationId=${conversationId}, useConversationsApi=${useConversationsApi}, agentId=${agent.id}`);
|
|
@@ -91078,12 +92133,16 @@ async function getResumeData(client, agent, conversationId) {
|
|
|
91078
92133
|
if (!inContextMessageIds || inContextMessageIds.length === 0) {
|
|
91079
92134
|
debugWarn("check-approval", "No in-context messages - no pending approvals");
|
|
91080
92135
|
if (isBackfillEnabled()) {
|
|
91081
|
-
|
|
91082
|
-
|
|
91083
|
-
|
|
91084
|
-
|
|
91085
|
-
|
|
91086
|
-
|
|
92136
|
+
try {
|
|
92137
|
+
const backfill = await client.conversations.messages.list(conversationId, { limit: MESSAGE_HISTORY_LIMIT, order: "desc" });
|
|
92138
|
+
return {
|
|
92139
|
+
pendingApproval: null,
|
|
92140
|
+
pendingApprovals: [],
|
|
92141
|
+
messageHistory: sortChronological(backfill.getPaginatedItems())
|
|
92142
|
+
};
|
|
92143
|
+
} catch (backfillError) {
|
|
92144
|
+
debugWarn("check-approval", `Failed to load message history: ${backfillError instanceof Error ? backfillError.message : String(backfillError)}`);
|
|
92145
|
+
}
|
|
91087
92146
|
}
|
|
91088
92147
|
return {
|
|
91089
92148
|
pendingApproval: null,
|
|
@@ -91096,11 +92155,17 @@ async function getResumeData(client, agent, conversationId) {
|
|
|
91096
92155
|
throw new Error("Expected at least one in-context message");
|
|
91097
92156
|
}
|
|
91098
92157
|
const retrievedMessages = await client.messages.retrieve(lastInContextId);
|
|
91099
|
-
|
|
91100
|
-
|
|
91101
|
-
|
|
91102
|
-
|
|
91103
|
-
|
|
92158
|
+
if (isBackfillEnabled()) {
|
|
92159
|
+
try {
|
|
92160
|
+
const backfillPage = await client.conversations.messages.list(conversationId, {
|
|
92161
|
+
limit: MESSAGE_HISTORY_LIMIT,
|
|
92162
|
+
order: "desc"
|
|
92163
|
+
});
|
|
92164
|
+
messages = sortChronological(backfillPage.getPaginatedItems());
|
|
92165
|
+
} catch (backfillError) {
|
|
92166
|
+
debugWarn("check-approval", `Failed to load message history: ${backfillError instanceof Error ? backfillError.message : String(backfillError)}`);
|
|
92167
|
+
}
|
|
92168
|
+
}
|
|
91104
92169
|
const messageToCheck = retrievedMessages.find((msg) => msg.message_type === "approval_request_message") ?? retrievedMessages[0];
|
|
91105
92170
|
if (messageToCheck) {
|
|
91106
92171
|
debugWarn("check-approval", `Found last in-context message: ${messageToCheck.id} (type: ${messageToCheck.message_type})` + (retrievedMessages.length > 1 ? ` - had ${retrievedMessages.length} variants` : ""));
|
|
@@ -91135,14 +92200,20 @@ async function getResumeData(client, agent, conversationId) {
|
|
|
91135
92200
|
throw new Error("Expected at least one in-context message");
|
|
91136
92201
|
}
|
|
91137
92202
|
const retrievedMessages = await client.messages.retrieve(lastInContextId);
|
|
91138
|
-
|
|
91139
|
-
|
|
91140
|
-
|
|
91141
|
-
|
|
91142
|
-
|
|
91143
|
-
|
|
91144
|
-
|
|
91145
|
-
|
|
92203
|
+
if (isBackfillEnabled()) {
|
|
92204
|
+
try {
|
|
92205
|
+
const messagesPage = await client.agents.messages.list(agent.id, {
|
|
92206
|
+
limit: MESSAGE_HISTORY_LIMIT,
|
|
92207
|
+
order: "desc",
|
|
92208
|
+
conversation_id: "default"
|
|
92209
|
+
});
|
|
92210
|
+
messages = sortChronological(messagesPage.items);
|
|
92211
|
+
if (process.env.DEBUG) {
|
|
92212
|
+
console.log(`[DEBUG] agents.messages.list(conversation_id=default) returned ${messagesPage.items.length} messages`);
|
|
92213
|
+
}
|
|
92214
|
+
} catch (backfillError) {
|
|
92215
|
+
debugWarn("check-approval", `Failed to load message history: ${backfillError instanceof Error ? backfillError.message : String(backfillError)}`);
|
|
92216
|
+
}
|
|
91146
92217
|
}
|
|
91147
92218
|
const messageToCheck = retrievedMessages.find((msg) => msg.message_type === "approval_request_message") ?? retrievedMessages[0];
|
|
91148
92219
|
if (messageToCheck) {
|
|
@@ -94648,4 +95719,4 @@ Error during initialization: ${message}`);
|
|
|
94648
95719
|
}
|
|
94649
95720
|
main();
|
|
94650
95721
|
|
|
94651
|
-
//# debugId=
|
|
95722
|
+
//# debugId=4B93041AB98FEDD564756E2164756E21
|