@mndrk/agx 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +2 -1
- package/README.md +88 -189
- package/index.js +519 -55
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -1,242 +1,141 @@
|
|
|
1
1
|
# agx
|
|
2
2
|
|
|
3
|
-
Unified AI Agent
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
### Via npm (recommended)
|
|
3
|
+
Unified AI Agent CLI with persistent memory. Wraps Claude, Gemini, and Ollama with automatic state management via [mem](https://github.com/ramarlina/memx).
|
|
8
4
|
|
|
9
5
|
```bash
|
|
10
6
|
npm install -g @mndrk/agx
|
|
11
7
|
```
|
|
12
8
|
|
|
13
|
-
### From source
|
|
14
|
-
|
|
15
|
-
Clone the repository and link locally:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
git clone https://github.com/ramarlina/agx.git
|
|
19
|
-
cd agx
|
|
20
|
-
npm link
|
|
21
|
-
```
|
|
22
|
-
|
|
23
9
|
## Quick Start
|
|
24
10
|
|
|
25
|
-
When you run `agx` for the first time, it will automatically start the setup wizard:
|
|
26
|
-
|
|
27
11
|
```bash
|
|
28
|
-
|
|
29
|
-
|
|
12
|
+
# Simple prompt
|
|
13
|
+
agx claude -p "explain this code"
|
|
30
14
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
2. Guide you through installing any missing providers
|
|
34
|
-
3. Help you authenticate with your chosen providers
|
|
35
|
-
4. Set your default provider
|
|
15
|
+
# Use default provider
|
|
16
|
+
agx -p "what does this function do?"
|
|
36
17
|
|
|
37
|
-
|
|
18
|
+
# With persistent memory (auto-detected)
|
|
19
|
+
agx claude -p "continue working on the todo app"
|
|
38
20
|
|
|
39
|
-
|
|
40
|
-
agx --
|
|
21
|
+
# Auto-create task (for agents, non-interactive)
|
|
22
|
+
agx claude --auto-task -p "Build a todo app with React"
|
|
41
23
|
```
|
|
42
24
|
|
|
43
|
-
##
|
|
25
|
+
## Memory Integration
|
|
44
26
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
Once configured, you can run prompts without specifying a provider:
|
|
27
|
+
agx integrates with [mem](https://github.com/ramarlina/memx) for persistent state across sessions:
|
|
48
28
|
|
|
49
29
|
```bash
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
### With Specific Provider
|
|
30
|
+
# If ~/.mem has a task mapped to cwd, context is auto-loaded
|
|
31
|
+
cd ~/Projects/my-app
|
|
32
|
+
agx claude -p "continue" # Knows where it left off
|
|
55
33
|
|
|
56
|
-
|
|
57
|
-
agx
|
|
34
|
+
# Create task with explicit criteria
|
|
35
|
+
agx claude --task todo-app \
|
|
36
|
+
--criteria "CRUD working" \
|
|
37
|
+
--criteria "Tests passing" \
|
|
38
|
+
--criteria "Deployed to Vercel" \
|
|
39
|
+
-p "Build a todo app"
|
|
58
40
|
```
|
|
59
41
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
| Provider | Aliases | Backend |
|
|
63
|
-
|----------|---------|---------|
|
|
64
|
-
| `gemini` | `gem`, `g` | Google Gemini CLI |
|
|
65
|
-
| `claude` | `cl`, `c` | Anthropic Claude CLI |
|
|
66
|
-
| `ollama` | `ol`, `o` | Local Ollama via Claude interface |
|
|
67
|
-
|
|
68
|
-
### Options
|
|
69
|
-
|
|
70
|
-
| Option | Short | Description |
|
|
71
|
-
|--------|-------|-------------|
|
|
72
|
-
| `--prompt <text>` | `-p` | The prompt to send |
|
|
73
|
-
| `--model <name>` | `-m` | Model name to use |
|
|
74
|
-
| `--yolo` | `-y` | Skip permission prompts |
|
|
75
|
-
| `--print` | | Non-interactive mode (output and exit) |
|
|
76
|
-
| `--interactive` | `-i` | Force interactive mode |
|
|
77
|
-
| `--sandbox` | `-s` | Enable sandbox (gemini only) |
|
|
78
|
-
| `--debug` | `-d` | Enable debug output |
|
|
79
|
-
| `--mcp <config>` | | MCP config file (claude/ollama only) |
|
|
42
|
+
## Output Markers
|
|
80
43
|
|
|
81
|
-
|
|
44
|
+
Agents control state via markers in their output:
|
|
82
45
|
|
|
83
|
-
Use `--` to pass arguments directly to the underlying CLI:
|
|
84
|
-
```bash
|
|
85
|
-
agx claude -- --resume
|
|
86
46
|
```
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
47
|
+
[checkpoint: Hero section complete] # Save progress
|
|
48
|
+
[learn: Tailwind is fast] # Record learning
|
|
49
|
+
[next: Add auth system] # Set next step
|
|
50
|
+
[criteria: 2] # Mark criterion #2 done
|
|
51
|
+
[approve: Deploy to production?] # Halt for approval
|
|
52
|
+
[blocked: Need API key from client] # Mark stuck
|
|
53
|
+
[pause] # Stop, resume later
|
|
54
|
+
[continue] # Keep going (daemon)
|
|
55
|
+
[done] # Task complete
|
|
56
|
+
[split: auth "Handle authentication"] # Create subtask
|
|
96
57
|
```
|
|
97
58
|
|
|
98
|
-
|
|
99
|
-
- Detect installed providers (claude, gemini, ollama)
|
|
100
|
-
- Guide you through installation and authentication
|
|
101
|
-
- Let you set or change your default provider
|
|
102
|
-
|
|
103
|
-
### `agx config`
|
|
104
|
-
|
|
105
|
-
Open an interactive configuration menu to manage your agx settings:
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
agx config
|
|
109
|
-
```
|
|
59
|
+
## Providers
|
|
110
60
|
|
|
111
|
-
|
|
61
|
+
| Provider | Aliases | Description |
|
|
62
|
+
|----------|---------|-------------|
|
|
63
|
+
| claude | c, cl | Anthropic Claude Code |
|
|
64
|
+
| gemini | g, gem | Google Gemini CLI |
|
|
65
|
+
| ollama | o, ol | Local Ollama models |
|
|
112
66
|
|
|
113
|
-
|
|
67
|
+
## Options
|
|
114
68
|
|
|
115
|
-
```bash
|
|
116
|
-
agx add claude # Install Claude CLI
|
|
117
|
-
agx add gemini # Install Gemini CLI
|
|
118
|
-
agx add ollama # Install Ollama
|
|
119
69
|
```
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
70
|
+
--prompt, -p <text> Prompt to send
|
|
71
|
+
--model, -m <name> Model name
|
|
72
|
+
--yolo, -y Skip permission prompts
|
|
73
|
+
--print Non-interactive output
|
|
74
|
+
--interactive, -i Force interactive mode
|
|
75
|
+
--mem Enable mem integration (auto-detected)
|
|
76
|
+
--no-mem Disable mem integration
|
|
77
|
+
--auto-task Auto-create task from prompt
|
|
78
|
+
--task <name> Specific task name
|
|
79
|
+
--criteria <text> Success criterion (repeatable)
|
|
80
|
+
--daemon Loop on [continue] marker
|
|
128
81
|
```
|
|
129
82
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
View your current configuration, including installed providers and default settings:
|
|
83
|
+
## Commands
|
|
133
84
|
|
|
134
85
|
```bash
|
|
135
|
-
agx
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
86
|
+
agx init # Setup wizard
|
|
87
|
+
agx config # Configuration menu
|
|
88
|
+
agx status # Show current config
|
|
89
|
+
agx skill # View LLM skill
|
|
90
|
+
agx skill install # Install skill to Claude/Gemini
|
|
139
91
|
```
|
|
140
|
-
agx Configuration Status
|
|
141
|
-
------------------------
|
|
142
|
-
Default Provider: claude
|
|
143
92
|
|
|
144
|
-
|
|
145
|
-
✓ claude (authenticated)
|
|
146
|
-
✓ gemini (authenticated)
|
|
147
|
-
✓ ollama (running)
|
|
93
|
+
## Loop Control
|
|
148
94
|
|
|
149
|
-
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
## Skill System
|
|
95
|
+
The agent controls execution flow via markers:
|
|
153
96
|
|
|
154
|
-
|
|
97
|
+
- `[done]` → Task complete, exit
|
|
98
|
+
- `[pause]` → Save state, exit (resume later with same command)
|
|
99
|
+
- `[blocked: reason]` → Mark stuck, notify human, exit
|
|
100
|
+
- `[continue]` → Keep going (daemon mode loops)
|
|
101
|
+
- `[approve: question]` → Halt until human approves
|
|
155
102
|
|
|
156
|
-
|
|
103
|
+
## Task Splitting
|
|
157
104
|
|
|
158
|
-
|
|
105
|
+
Break large tasks into subtasks:
|
|
159
106
|
|
|
160
|
-
```bash
|
|
161
|
-
agx skill
|
|
162
107
|
```
|
|
108
|
+
Agent output:
|
|
109
|
+
This is too big. Breaking it down.
|
|
163
110
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
```bash
|
|
171
|
-
agx skill install
|
|
111
|
+
[split: setup "Project scaffolding"]
|
|
112
|
+
[split: auth "Authentication system"]
|
|
113
|
+
[split: crud "CRUD operations"]
|
|
114
|
+
[next: Start with setup subtask]
|
|
115
|
+
[pause]
|
|
172
116
|
```
|
|
173
117
|
|
|
174
|
-
|
|
175
|
-
- AI agents can call other AI providers through agx
|
|
176
|
-
- Cross-provider collaboration (e.g., Claude can ask Gemini for help)
|
|
177
|
-
- Consistent command patterns across all providers
|
|
118
|
+
agx creates subtask branches in ~/.mem linked to the parent.
|
|
178
119
|
|
|
179
|
-
##
|
|
180
|
-
|
|
181
|
-
For LLMs constructing commands, use these canonical patterns:
|
|
120
|
+
## Example: Full Workflow
|
|
182
121
|
|
|
183
122
|
```bash
|
|
184
|
-
#
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
# Pattern: agx <provider> --prompt "<prompt>"
|
|
188
|
-
agx claude --prompt "explain this code"
|
|
189
|
-
agx gemini --prompt "summarize the file"
|
|
190
|
-
agx ollama --prompt "write a function"
|
|
191
|
-
|
|
192
|
-
# Pattern: agx <provider> --model <model> --prompt "<prompt>"
|
|
193
|
-
agx claude --model claude-sonnet-4-20250514 --prompt "fix the bug"
|
|
194
|
-
agx gemini --model gemini-2.0-flash --prompt "optimize this"
|
|
195
|
-
agx ollama --model qwen3:8b --prompt "refactor"
|
|
123
|
+
# Day 1: Start project
|
|
124
|
+
mkdir ~/Projects/my-app && cd ~/Projects/my-app
|
|
125
|
+
agx claude --auto-task -p "Build a React todo app with auth"
|
|
196
126
|
|
|
197
|
-
#
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
#
|
|
201
|
-
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
### Command Structure
|
|
205
|
-
|
|
206
|
-
```
|
|
207
|
-
agx [provider] [--model <name>] [--yolo] [--print] --prompt "<prompt>"
|
|
208
|
-
```
|
|
127
|
+
# Agent works, outputs markers
|
|
128
|
+
# [checkpoint: Scaffolded with Vite]
|
|
129
|
+
# [learn: Vite is faster than CRA]
|
|
130
|
+
# [next: Add todo list component]
|
|
131
|
+
# [pause]
|
|
209
132
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
4. Use full provider names (`claude`, `gemini`, `ollama`) for clarity
|
|
215
|
-
5. Provider is optional if a default is configured
|
|
216
|
-
|
|
217
|
-
## Configuration File
|
|
218
|
-
|
|
219
|
-
agx stores its configuration in `~/.agx/config.json`:
|
|
220
|
-
|
|
221
|
-
```json
|
|
222
|
-
{
|
|
223
|
-
"defaultProvider": "claude",
|
|
224
|
-
"providers": {
|
|
225
|
-
"claude": {
|
|
226
|
-
"installed": true,
|
|
227
|
-
"authenticated": true
|
|
228
|
-
},
|
|
229
|
-
"gemini": {
|
|
230
|
-
"installed": true,
|
|
231
|
-
"authenticated": true
|
|
232
|
-
},
|
|
233
|
-
"ollama": {
|
|
234
|
-
"installed": true
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
133
|
+
# Day 2: Continue
|
|
134
|
+
cd ~/Projects/my-app
|
|
135
|
+
agx claude -p "continue"
|
|
136
|
+
# Context auto-loaded, agent picks up where it left off
|
|
238
137
|
```
|
|
239
138
|
|
|
240
|
-
##
|
|
139
|
+
## License
|
|
241
140
|
|
|
242
|
-
|
|
141
|
+
MIT
|
package/index.js
CHANGED
|
@@ -12,18 +12,54 @@ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
|
12
12
|
// agx skill - instructions for LLMs on how to use agx
|
|
13
13
|
const AGX_SKILL = `---
|
|
14
14
|
name: agx
|
|
15
|
-
description:
|
|
15
|
+
description: Run AI agents with persistent memory. Wraps Claude, Gemini, Ollama with automatic state management.
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
-
# agx -
|
|
18
|
+
# agx - AI Agent CLI with Persistent Memory
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Run AI agents with automatic state persistence via mem integration.
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Basic Usage
|
|
23
23
|
|
|
24
24
|
\`\`\`bash
|
|
25
|
-
agx
|
|
26
|
-
agx
|
|
25
|
+
agx claude -p "explain this code" # simple prompt
|
|
26
|
+
agx -p "what does this do?" # use default provider
|
|
27
|
+
agx c --yolo -p "fix the bug" # skip confirmations
|
|
28
|
+
\`\`\`
|
|
29
|
+
|
|
30
|
+
## Memory Integration
|
|
31
|
+
|
|
32
|
+
agx auto-detects \`~/.mem\` and loads context:
|
|
33
|
+
|
|
34
|
+
\`\`\`bash
|
|
35
|
+
# Auto-load context if task exists for cwd
|
|
36
|
+
agx claude -p "continue working"
|
|
37
|
+
|
|
38
|
+
# Auto-create task (non-interactive, for agents)
|
|
39
|
+
agx claude --auto-task -p "Build todo app"
|
|
40
|
+
|
|
41
|
+
# Explicit task with criteria
|
|
42
|
+
agx claude --task todo-app \\
|
|
43
|
+
--criteria "CRUD working" \\
|
|
44
|
+
--criteria "Deployed" \\
|
|
45
|
+
-p "Build a todo app"
|
|
46
|
+
\`\`\`
|
|
47
|
+
|
|
48
|
+
## Output Markers
|
|
49
|
+
|
|
50
|
+
Use these in agent output to save state:
|
|
51
|
+
|
|
52
|
+
\`\`\`
|
|
53
|
+
[checkpoint: message] Save progress point
|
|
54
|
+
[learn: insight] Record learning
|
|
55
|
+
[next: step] Set next step
|
|
56
|
+
[criteria: N] Mark criterion #N complete
|
|
57
|
+
[approve: question] Halt for human approval
|
|
58
|
+
[blocked: reason] Mark blocked, stop
|
|
59
|
+
[pause] Save and stop (resume later)
|
|
60
|
+
[continue] Keep going (daemon mode)
|
|
61
|
+
[done] Mark task complete
|
|
62
|
+
[split: name "goal"] Create subtask
|
|
27
63
|
\`\`\`
|
|
28
64
|
|
|
29
65
|
## Providers
|
|
@@ -34,41 +70,50 @@ agx [options] --prompt "<prompt>" # uses default provider
|
|
|
34
70
|
| gemini | g, gem | Google Gemini CLI |
|
|
35
71
|
| ollama | o, ol | Local Ollama models |
|
|
36
72
|
|
|
37
|
-
##
|
|
73
|
+
## Options
|
|
38
74
|
|
|
39
|
-
| Option |
|
|
40
|
-
|
|
41
|
-
| --prompt
|
|
42
|
-
| --model
|
|
43
|
-
| --yolo
|
|
44
|
-
| --
|
|
45
|
-
| --
|
|
75
|
+
| Option | Description |
|
|
76
|
+
|--------|-------------|
|
|
77
|
+
| --prompt, -p | The prompt to send |
|
|
78
|
+
| --model, -m | Model name |
|
|
79
|
+
| --yolo, -y | Skip permission prompts |
|
|
80
|
+
| --mem | Enable mem (auto-detected) |
|
|
81
|
+
| --no-mem | Disable mem |
|
|
82
|
+
| --auto-task | Auto-create task from prompt |
|
|
83
|
+
| --task NAME | Specific task name |
|
|
84
|
+
| --criteria "..." | Success criterion (repeatable) |
|
|
85
|
+
| --daemon | Loop on [continue] marker |
|
|
86
|
+
| --until-done | Keep running until [done] |
|
|
46
87
|
|
|
47
|
-
##
|
|
88
|
+
## Continuous Work Loop
|
|
48
89
|
|
|
49
|
-
|
|
50
|
-
# Simple prompt
|
|
51
|
-
agx claude --prompt "explain this code"
|
|
90
|
+
New tasks auto-set \`wake: every 15m\`. The loop:
|
|
52
91
|
|
|
53
|
-
|
|
54
|
-
|
|
92
|
+
\`\`\`
|
|
93
|
+
WAKE → load context → review → work → save → SLEEP
|
|
94
|
+
↓
|
|
95
|
+
repeat until [done]
|
|
96
|
+
\`\`\`
|
|
55
97
|
|
|
56
|
-
|
|
57
|
-
|
|
98
|
+
Agent keeps working by default. Only output stopping markers when needed:
|
|
99
|
+
- \`[done]\` → task complete, stop loop
|
|
100
|
+
- \`[blocked: reason]\` → need human help, pause loop
|
|
101
|
+
- \`[approve: question]\` → need approval, wait
|
|
58
102
|
|
|
59
|
-
|
|
60
|
-
agx ollama --model qwen3:8b --prompt "write a function"
|
|
103
|
+
Install wake: \`mem cron export >> crontab\`
|
|
61
104
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
105
|
+
## Task Splitting
|
|
106
|
+
|
|
107
|
+
Break large tasks into subtasks:
|
|
65
108
|
|
|
66
|
-
|
|
109
|
+
\`\`\`
|
|
110
|
+
[split: setup "Project scaffolding"]
|
|
111
|
+
[split: auth "Authentication system"]
|
|
112
|
+
[split: crud "CRUD operations"]
|
|
113
|
+
[next: Start with setup]
|
|
114
|
+
\`\`\`
|
|
67
115
|
|
|
68
|
-
|
|
69
|
-
- Running prompts across different AI providers
|
|
70
|
-
- Scripting AI interactions
|
|
71
|
-
- When you need --yolo mode to skip confirmations
|
|
116
|
+
Creates subtask branches in ~/.mem, linked to parent.
|
|
72
117
|
`;
|
|
73
118
|
|
|
74
119
|
// ANSI colors
|
|
@@ -94,6 +139,201 @@ function commandExists(cmd) {
|
|
|
94
139
|
}
|
|
95
140
|
}
|
|
96
141
|
|
|
142
|
+
// ==================== MEM INTEGRATION ====================
|
|
143
|
+
|
|
144
|
+
// Find .mem directory (walk up from cwd, or check ~/.mem)
|
|
145
|
+
function findMemDir(startDir = process.cwd()) {
|
|
146
|
+
// First check local .mem
|
|
147
|
+
let dir = startDir;
|
|
148
|
+
while (dir !== path.dirname(dir)) {
|
|
149
|
+
const memDir = path.join(dir, '.mem');
|
|
150
|
+
if (fs.existsSync(memDir) && fs.existsSync(path.join(memDir, '.git'))) {
|
|
151
|
+
return memDir;
|
|
152
|
+
}
|
|
153
|
+
dir = path.dirname(dir);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Then check ~/.mem with index
|
|
157
|
+
const globalMem = path.join(process.env.HOME || process.env.USERPROFILE, '.mem');
|
|
158
|
+
if (fs.existsSync(globalMem)) {
|
|
159
|
+
const indexFile = path.join(globalMem, 'index.json');
|
|
160
|
+
if (fs.existsSync(indexFile)) {
|
|
161
|
+
try {
|
|
162
|
+
const index = JSON.parse(fs.readFileSync(indexFile, 'utf8'));
|
|
163
|
+
if (index[startDir]) {
|
|
164
|
+
return globalMem;
|
|
165
|
+
}
|
|
166
|
+
} catch {}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Load mem context
|
|
174
|
+
function loadMemContext(memDir) {
|
|
175
|
+
try {
|
|
176
|
+
const result = execSync('mem context', {
|
|
177
|
+
cwd: path.dirname(memDir),
|
|
178
|
+
encoding: 'utf8',
|
|
179
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
180
|
+
});
|
|
181
|
+
return result.trim();
|
|
182
|
+
} catch {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Parse output markers
|
|
188
|
+
function parseMemMarkers(output) {
|
|
189
|
+
const markers = [];
|
|
190
|
+
const patterns = [
|
|
191
|
+
{ type: 'checkpoint', regex: /\[checkpoint:\s*([^\]]+)\]/gi },
|
|
192
|
+
{ type: 'learn', regex: /\[learn:\s*([^\]]+)\]/gi },
|
|
193
|
+
{ type: 'next', regex: /\[next:\s*([^\]]+)\]/gi },
|
|
194
|
+
{ type: 'stuck', regex: /\[stuck:\s*([^\]]+)\]/gi },
|
|
195
|
+
{ type: 'blocked', regex: /\[blocked:\s*([^\]]+)\]/gi },
|
|
196
|
+
{ type: 'done', regex: /\[done\]/gi },
|
|
197
|
+
{ type: 'pause', regex: /\[pause(?::\s*([^\]]*))?\]/gi },
|
|
198
|
+
{ type: 'continue', regex: /\[continue\]/gi },
|
|
199
|
+
{ type: 'approve', regex: /\[approve:\s*([^\]]+)\]/gi },
|
|
200
|
+
{ type: 'criteria', regex: /\[criteria:\s*(\d+)\]/gi },
|
|
201
|
+
{ type: 'split', regex: /\[split:\s*([^\s\]]+)(?:\s+"([^"]+)")?\]/gi },
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
for (const { type, regex } of patterns) {
|
|
205
|
+
let match;
|
|
206
|
+
while ((match = regex.exec(output)) !== null) {
|
|
207
|
+
if (type === 'split') {
|
|
208
|
+
markers.push({ type, name: match[1], goal: match[2] || match[1] });
|
|
209
|
+
} else {
|
|
210
|
+
markers.push({ type, value: match[1] || true });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return markers;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Apply mem markers - returns control signals
|
|
219
|
+
function applyMemMarkers(markers, memDir) {
|
|
220
|
+
const workDir = path.dirname(memDir);
|
|
221
|
+
const result = {
|
|
222
|
+
approvals: [],
|
|
223
|
+
shouldContinue: false,
|
|
224
|
+
shouldPause: false,
|
|
225
|
+
isDone: false,
|
|
226
|
+
isBlocked: false,
|
|
227
|
+
splits: []
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
for (const marker of markers) {
|
|
231
|
+
try {
|
|
232
|
+
switch (marker.type) {
|
|
233
|
+
case 'checkpoint':
|
|
234
|
+
execSync(`mem checkpoint "${marker.value.replace(/"/g, '\\"')}"`, {
|
|
235
|
+
cwd: workDir, stdio: 'ignore'
|
|
236
|
+
});
|
|
237
|
+
console.log(`${c.green}✓${c.reset} ${c.dim}Checkpoint:${c.reset} ${marker.value}`);
|
|
238
|
+
break;
|
|
239
|
+
case 'learn':
|
|
240
|
+
execSync(`mem learn "${marker.value.replace(/"/g, '\\"')}"`, {
|
|
241
|
+
cwd: workDir, stdio: 'ignore'
|
|
242
|
+
});
|
|
243
|
+
console.log(`${c.green}✓${c.reset} ${c.dim}Learned:${c.reset} ${marker.value}`);
|
|
244
|
+
break;
|
|
245
|
+
case 'next':
|
|
246
|
+
execSync(`mem next "${marker.value.replace(/"/g, '\\"')}"`, {
|
|
247
|
+
cwd: workDir, stdio: 'ignore'
|
|
248
|
+
});
|
|
249
|
+
console.log(`${c.green}✓${c.reset} ${c.dim}Next:${c.reset} ${marker.value}`);
|
|
250
|
+
break;
|
|
251
|
+
case 'stuck':
|
|
252
|
+
case 'blocked':
|
|
253
|
+
execSync(`mem stuck "${marker.value.replace(/"/g, '\\"')}"`, {
|
|
254
|
+
cwd: workDir, stdio: 'ignore'
|
|
255
|
+
});
|
|
256
|
+
console.log(`${c.yellow}⚠${c.reset} ${c.dim}Blocked:${c.reset} ${marker.value}`);
|
|
257
|
+
result.isBlocked = true;
|
|
258
|
+
break;
|
|
259
|
+
case 'done':
|
|
260
|
+
console.log(`${c.green}✓${c.reset} ${c.dim}Task marked done${c.reset}`);
|
|
261
|
+
result.isDone = true;
|
|
262
|
+
break;
|
|
263
|
+
case 'pause':
|
|
264
|
+
console.log(`${c.cyan}⏸${c.reset} ${c.dim}Pausing${marker.value ? ': ' + marker.value : ''}${c.reset}`);
|
|
265
|
+
result.shouldPause = true;
|
|
266
|
+
break;
|
|
267
|
+
case 'continue':
|
|
268
|
+
console.log(`${c.cyan}▶${c.reset} ${c.dim}Continuing...${c.reset}`);
|
|
269
|
+
result.shouldContinue = true;
|
|
270
|
+
break;
|
|
271
|
+
case 'approve':
|
|
272
|
+
result.approvals.push(marker.value);
|
|
273
|
+
break;
|
|
274
|
+
case 'criteria':
|
|
275
|
+
execSync(`mem criteria ${marker.value}`, {
|
|
276
|
+
cwd: workDir, stdio: 'ignore'
|
|
277
|
+
});
|
|
278
|
+
console.log(`${c.green}✓${c.reset} ${c.dim}Criteria #${marker.value} complete${c.reset}`);
|
|
279
|
+
break;
|
|
280
|
+
case 'split':
|
|
281
|
+
result.splits.push({ name: marker.name, goal: marker.goal });
|
|
282
|
+
console.log(`${c.cyan}⑂${c.reset} ${c.dim}Split:${c.reset} ${marker.name} - ${marker.goal}`);
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
} catch (err) {
|
|
286
|
+
console.error(`${c.red}mem error:${c.reset} ${err.message}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return result;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Create subtasks from split markers
|
|
294
|
+
function createSubtasks(splits, memDir) {
|
|
295
|
+
const workDir = path.dirname(memDir);
|
|
296
|
+
|
|
297
|
+
for (const split of splits) {
|
|
298
|
+
try {
|
|
299
|
+
// Create subtask as new branch
|
|
300
|
+
execSync(`mem init ${split.name} "${split.goal.replace(/"/g, '\\"')}"`, {
|
|
301
|
+
cwd: workDir,
|
|
302
|
+
stdio: 'ignore'
|
|
303
|
+
});
|
|
304
|
+
console.log(`${c.green}✓${c.reset} Created subtask: ${c.bold}${split.name}${c.reset}`);
|
|
305
|
+
} catch (err) {
|
|
306
|
+
console.error(`${c.red}Failed to create subtask ${split.name}:${c.reset} ${err.message}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Handle approval prompts
|
|
312
|
+
async function handleApprovals(approvals) {
|
|
313
|
+
if (approvals.length === 0) return true;
|
|
314
|
+
|
|
315
|
+
const rl = readline.createInterface({
|
|
316
|
+
input: process.stdin,
|
|
317
|
+
output: process.stdout
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
for (const approval of approvals) {
|
|
321
|
+
const answer = await new Promise(resolve => {
|
|
322
|
+
rl.question(`\n${c.yellow}⚠ APPROVAL REQUIRED:${c.reset} ${approval}\n${c.dim}Continue? [y/N]:${c.reset} `, resolve);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
326
|
+
console.log(`${c.red}✗${c.reset} Rejected. Workflow halted.`);
|
|
327
|
+
rl.close();
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
console.log(`${c.green}✓${c.reset} Approved.`);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
rl.close();
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
|
|
97
337
|
// Load config
|
|
98
338
|
function loadConfig() {
|
|
99
339
|
try {
|
|
@@ -862,7 +1102,15 @@ const options = {
|
|
|
862
1102
|
interactive: false,
|
|
863
1103
|
sandbox: false,
|
|
864
1104
|
debug: false,
|
|
865
|
-
mcp: null
|
|
1105
|
+
mcp: null,
|
|
1106
|
+
mem: false,
|
|
1107
|
+
memDir: null,
|
|
1108
|
+
autoTask: false,
|
|
1109
|
+
taskName: null,
|
|
1110
|
+
criteria: [],
|
|
1111
|
+
daemon: false,
|
|
1112
|
+
untilDone: false,
|
|
1113
|
+
wakeInterval: null
|
|
866
1114
|
};
|
|
867
1115
|
|
|
868
1116
|
// Collect positional args (legacy support, but --prompt is preferred)
|
|
@@ -912,6 +1160,42 @@ for (let i = 0; i < processedArgs.length; i++) {
|
|
|
912
1160
|
i++;
|
|
913
1161
|
}
|
|
914
1162
|
break;
|
|
1163
|
+
case '--mem':
|
|
1164
|
+
options.mem = true;
|
|
1165
|
+
break;
|
|
1166
|
+
case '--no-mem':
|
|
1167
|
+
options.mem = false;
|
|
1168
|
+
break;
|
|
1169
|
+
case '--auto-task':
|
|
1170
|
+
options.autoTask = true;
|
|
1171
|
+
options.mem = true;
|
|
1172
|
+
break;
|
|
1173
|
+
case '--task':
|
|
1174
|
+
if (nextArg && !nextArg.startsWith('-')) {
|
|
1175
|
+
options.taskName = nextArg;
|
|
1176
|
+
options.mem = true;
|
|
1177
|
+
i++;
|
|
1178
|
+
}
|
|
1179
|
+
break;
|
|
1180
|
+
case '--criteria':
|
|
1181
|
+
if (nextArg && !nextArg.startsWith('-')) {
|
|
1182
|
+
options.criteria.push(nextArg);
|
|
1183
|
+
i++;
|
|
1184
|
+
}
|
|
1185
|
+
break;
|
|
1186
|
+
case '--daemon':
|
|
1187
|
+
options.daemon = true;
|
|
1188
|
+
break;
|
|
1189
|
+
case '--until-done':
|
|
1190
|
+
options.untilDone = true;
|
|
1191
|
+
options.daemon = true;
|
|
1192
|
+
break;
|
|
1193
|
+
case '--wake':
|
|
1194
|
+
if (nextArg && !nextArg.startsWith('-')) {
|
|
1195
|
+
options.wakeInterval = nextArg;
|
|
1196
|
+
i++;
|
|
1197
|
+
}
|
|
1198
|
+
break;
|
|
915
1199
|
default:
|
|
916
1200
|
if (arg.startsWith('-')) {
|
|
917
1201
|
// Unknown flag - pass through
|
|
@@ -986,29 +1270,209 @@ if (provider === 'gemini') {
|
|
|
986
1270
|
// Append raw args at the end
|
|
987
1271
|
translatedArgs.push(...rawArgs);
|
|
988
1272
|
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1273
|
+
// ==================== MEM INTEGRATION ====================
|
|
1274
|
+
|
|
1275
|
+
// Auto-detect mem if .mem exists (unless --no-mem)
|
|
1276
|
+
let memDir = options.mem !== false ? findMemDir() : null;
|
|
1277
|
+
if (memDir && options.mem !== false) {
|
|
1278
|
+
options.mem = true;
|
|
1279
|
+
options.memDir = memDir;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
// Auto-create task if --auto-task or --task specified but no mem found
|
|
1283
|
+
if ((options.autoTask || options.taskName) && !options.memDir && finalPrompt) {
|
|
1284
|
+
const taskName = options.taskName || finalPrompt
|
|
1285
|
+
.toLowerCase()
|
|
1286
|
+
.replace(/[^a-z0-9\s]/g, '')
|
|
1287
|
+
.split(/\s+/)
|
|
1288
|
+
.slice(0, 3)
|
|
1289
|
+
.join('-');
|
|
1290
|
+
|
|
1291
|
+
console.log(`${c.dim}[mem] Creating task: ${taskName}${c.reset}`);
|
|
1292
|
+
|
|
1293
|
+
try {
|
|
1294
|
+
// Build criteria args
|
|
1295
|
+
const criteriaArgs = options.criteria.length
|
|
1296
|
+
? options.criteria.map(c => `--criteria "${c}"`).join(' ')
|
|
1297
|
+
: '';
|
|
1298
|
+
|
|
1299
|
+
// Create task non-interactively
|
|
1300
|
+
const centralMem = path.join(process.env.HOME || process.env.USERPROFILE, '.mem');
|
|
1301
|
+
|
|
1302
|
+
// Ensure central mem exists
|
|
1303
|
+
if (!fs.existsSync(centralMem)) {
|
|
1304
|
+
fs.mkdirSync(centralMem, { recursive: true });
|
|
1305
|
+
execSync('git init', { cwd: centralMem, stdio: 'ignore' });
|
|
1306
|
+
fs.writeFileSync(path.join(centralMem, 'playbook.md'), '# Playbook\n\nGlobal learnings that transfer across tasks.\n');
|
|
1307
|
+
execSync('git add -A && git commit -m "init: memory repo"', { cwd: centralMem, stdio: 'ignore', shell: true });
|
|
1007
1308
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1309
|
+
|
|
1310
|
+
// Create task branch
|
|
1311
|
+
const branch = `task/${taskName}`;
|
|
1312
|
+
try {
|
|
1313
|
+
execSync(`git checkout main`, { cwd: centralMem, stdio: 'ignore' });
|
|
1314
|
+
} catch {}
|
|
1315
|
+
execSync(`git checkout -b ${branch}`, { cwd: centralMem, stdio: 'ignore' });
|
|
1316
|
+
|
|
1317
|
+
// Create task files
|
|
1318
|
+
const today = new Date().toISOString().split('T')[0];
|
|
1319
|
+
const criteriaText = options.criteria.length
|
|
1320
|
+
? options.criteria.map(c => `- [ ] ${c}`).join('\n')
|
|
1321
|
+
: '- [ ] Define success criteria';
|
|
1322
|
+
|
|
1323
|
+
fs.writeFileSync(path.join(centralMem, 'goal.md'),
|
|
1324
|
+
`---\ntask: ${taskName}\ncreated: ${today}\n---\n\n# Goal\n\n${finalPrompt}\n\n## Definition of Done\n\n${criteriaText}\n\n## Progress: 0%`);
|
|
1325
|
+
fs.writeFileSync(path.join(centralMem, 'state.md'),
|
|
1326
|
+
`---\nstatus: active\n---\n\n# State\n\n## Next Step\n\nBegin work\n\n## Checkpoints\n\n- [ ] Started`);
|
|
1327
|
+
fs.writeFileSync(path.join(centralMem, 'memory.md'), '# Learnings\n\n');
|
|
1328
|
+
|
|
1329
|
+
execSync('git add -A && git commit -m "init: ' + taskName + '"', { cwd: centralMem, stdio: 'ignore', shell: true });
|
|
1330
|
+
|
|
1331
|
+
// Update index
|
|
1332
|
+
const indexFile = path.join(centralMem, 'index.json');
|
|
1333
|
+
let index = {};
|
|
1334
|
+
try { index = JSON.parse(fs.readFileSync(indexFile, 'utf8')); } catch {}
|
|
1335
|
+
index[process.cwd()] = branch;
|
|
1336
|
+
fs.writeFileSync(indexFile, JSON.stringify(index, null, 2));
|
|
1337
|
+
|
|
1338
|
+
options.memDir = centralMem;
|
|
1339
|
+
console.log(`${c.green}✓${c.reset} Created task: ${c.bold}${taskName}${c.reset}`);
|
|
1340
|
+
console.log(`${c.green}✓${c.reset} Mapped: ${c.dim}${process.cwd()} → ${branch}${c.reset}`);
|
|
1341
|
+
|
|
1342
|
+
// Auto-set wake schedule for new tasks with proper command
|
|
1343
|
+
try {
|
|
1344
|
+
const projectDir = process.cwd();
|
|
1345
|
+
const wakeCmd = `cd ${projectDir} && agx claude -p "continue"`;
|
|
1346
|
+
execSync(`mem wake "every 15m" --run "${wakeCmd}"`, { cwd: process.cwd(), stdio: 'ignore' });
|
|
1347
|
+
console.log(`${c.green}✓${c.reset} Wake: ${c.dim}every 15m (until done)${c.reset}`);
|
|
1348
|
+
console.log(`${c.dim} Run: agx claude -p "continue"${c.reset}\n`);
|
|
1349
|
+
} catch {}
|
|
1350
|
+
|
|
1351
|
+
} catch (err) {
|
|
1352
|
+
console.error(`${c.yellow}Warning: Could not create task:${c.reset} ${err.message}`);
|
|
1010
1353
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
// Prepend mem context to prompt if mem is enabled
|
|
1357
|
+
if (options.mem && options.memDir && finalPrompt) {
|
|
1358
|
+
const context = loadMemContext(options.memDir);
|
|
1359
|
+
if (context) {
|
|
1360
|
+
console.log(`${c.dim}[mem] Loaded context from ${options.memDir}${c.reset}\n`);
|
|
1361
|
+
|
|
1362
|
+
// Prepend context to prompt with full marker documentation
|
|
1363
|
+
const augmentedPrompt = `## Current Context (from mem)\n\n${context}\n\n## Task\n\n${finalPrompt}\n\n## Instructions\n\nYou are continuing work on this task. Review the context above, then continue where you left off.\n\n## Output Markers\n\nUse these markers to save state (will be parsed automatically):\n\n- [checkpoint: message] - save progress point\n- [learn: insight] - record a learning \n- [next: step] - set what to work on next\n- [criteria: N] - mark criterion #N complete\n- [split: name "goal"] - break into subtask\n\nStopping markers (only use when needed):\n- [done] - task complete (all criteria met)\n- [blocked: reason] - need human help, cannot proceed\n- [approve: question] - need human approval before continuing\n\nThe default is to keep working. You will wake again in 15 minutes to continue.`;
|
|
1364
|
+
|
|
1365
|
+
// Replace the prompt in translatedArgs
|
|
1366
|
+
const promptIndex = translatedArgs.indexOf(finalPrompt);
|
|
1367
|
+
if (promptIndex !== -1) {
|
|
1368
|
+
translatedArgs[promptIndex] = augmentedPrompt;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
// Run with mem output capture or normal mode
|
|
1374
|
+
if (options.mem && options.memDir) {
|
|
1375
|
+
// Capture output for marker parsing
|
|
1376
|
+
const child = spawn(command, translatedArgs, {
|
|
1377
|
+
env,
|
|
1378
|
+
stdio: ['inherit', 'pipe', 'inherit'],
|
|
1379
|
+
shell: false
|
|
1380
|
+
});
|
|
1381
|
+
|
|
1382
|
+
let output = '';
|
|
1383
|
+
|
|
1384
|
+
child.stdout.on('data', (data) => {
|
|
1385
|
+
const text = data.toString();
|
|
1386
|
+
output += text;
|
|
1387
|
+
process.stdout.write(text);
|
|
1388
|
+
});
|
|
1389
|
+
|
|
1390
|
+
child.on('exit', async (code) => {
|
|
1391
|
+
// Parse and apply mem markers
|
|
1392
|
+
const markers = parseMemMarkers(output);
|
|
1393
|
+
|
|
1394
|
+
if (markers.length > 0) {
|
|
1395
|
+
console.log(`\n${c.dim}[mem] Processing markers...${c.reset}`);
|
|
1396
|
+
const result = applyMemMarkers(markers, options.memDir);
|
|
1397
|
+
|
|
1398
|
+
// Create subtasks if any
|
|
1399
|
+
if (result.splits.length > 0) {
|
|
1400
|
+
createSubtasks(result.splits, options.memDir);
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
// Handle approvals
|
|
1404
|
+
if (result.approvals.length > 0) {
|
|
1405
|
+
const approved = await handleApprovals(result.approvals);
|
|
1406
|
+
if (!approved) {
|
|
1407
|
+
console.log(`${c.yellow}Workflow halted. Resume later.${c.reset}`);
|
|
1408
|
+
process.exit(1);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
// Handle loop control - default is CONTINUE (wake again in 15m)
|
|
1413
|
+
if (result.isDone) {
|
|
1414
|
+
console.log(`\n${c.green}✓ Task complete!${c.reset}`);
|
|
1415
|
+
// Clear wake schedule on done
|
|
1416
|
+
try {
|
|
1417
|
+
execSync('mem wake clear', { cwd: process.cwd(), stdio: 'ignore' });
|
|
1418
|
+
console.log(`${c.dim}Wake schedule cleared.${c.reset}`);
|
|
1419
|
+
} catch {}
|
|
1420
|
+
process.exit(0);
|
|
1421
|
+
} else if (result.isBlocked) {
|
|
1422
|
+
console.log(`\n${c.yellow}⚠ Task blocked. Human intervention needed.${c.reset}`);
|
|
1423
|
+
console.log(`${c.dim}Wake continues - run 'mem stuck clear' when unblocked.${c.reset}`);
|
|
1424
|
+
process.exit(1);
|
|
1425
|
+
} else if (options.untilDone) {
|
|
1426
|
+
// Local loop mode: wait and run again
|
|
1427
|
+
console.log(`\n${c.cyan}▶ Continuing in 10s...${c.reset}`);
|
|
1428
|
+
setTimeout(() => {
|
|
1429
|
+
const { spawnSync } = require('child_process');
|
|
1430
|
+
spawnSync(process.argv[0], process.argv.slice(1), { stdio: 'inherit' });
|
|
1431
|
+
}, 10000);
|
|
1432
|
+
return;
|
|
1433
|
+
} else {
|
|
1434
|
+
// Default: save and exit, wake will resume in 15m
|
|
1435
|
+
console.log(`\n${c.dim}Progress saved. Will continue on next wake (~15m).${c.reset}`);
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
process.exit(code || 0);
|
|
1440
|
+
});
|
|
1441
|
+
|
|
1442
|
+
child.on('error', (err) => {
|
|
1443
|
+
if (err.code === 'ENOENT') {
|
|
1444
|
+
console.error(`${c.red}Error:${c.reset} "${command}" command not found.`);
|
|
1445
|
+
} else {
|
|
1446
|
+
console.error(`${c.red}Failed to start ${command}:${c.reset}`, err.message);
|
|
1447
|
+
}
|
|
1448
|
+
process.exit(1);
|
|
1449
|
+
});
|
|
1450
|
+
} else {
|
|
1451
|
+
// Normal mode - stdio inherit
|
|
1452
|
+
const child = spawn(command, translatedArgs, {
|
|
1453
|
+
env,
|
|
1454
|
+
stdio: 'inherit',
|
|
1455
|
+
shell: false
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1458
|
+
child.on('exit', (code) => {
|
|
1459
|
+
process.exit(code || 0);
|
|
1460
|
+
});
|
|
1461
|
+
|
|
1462
|
+
child.on('error', (err) => {
|
|
1463
|
+
if (err.code === 'ENOENT') {
|
|
1464
|
+
console.error(`${c.red}Error:${c.reset} "${command}" command not found.`);
|
|
1465
|
+
console.error(`\n${c.dim}Install it first:${c.reset}`);
|
|
1466
|
+
if (command === 'claude') {
|
|
1467
|
+
console.error(` npm install -g @anthropic-ai/claude-code`);
|
|
1468
|
+
} else if (command === 'gemini') {
|
|
1469
|
+
console.error(` npm install -g @anthropic-ai/gemini-cli`);
|
|
1470
|
+
}
|
|
1471
|
+
} else {
|
|
1472
|
+
console.error(`${c.red}Failed to start ${command}:${c.reset}`, err.message);
|
|
1473
|
+
}
|
|
1474
|
+
process.exit(1);
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1013
1477
|
|
|
1014
1478
|
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mndrk/agx",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Unified AI Agent Wrapper for Gemini, Claude, and Ollama",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,12 +16,17 @@
|
|
|
16
16
|
"gemini",
|
|
17
17
|
"claude",
|
|
18
18
|
"ollama",
|
|
19
|
-
"llm"
|
|
19
|
+
"llm",
|
|
20
|
+
"memory",
|
|
21
|
+
"persistent"
|
|
20
22
|
],
|
|
21
|
-
"author": "
|
|
23
|
+
"author": "Mendrika Ramarlina",
|
|
22
24
|
"license": "MIT",
|
|
23
25
|
"repository": {
|
|
24
26
|
"type": "git",
|
|
25
27
|
"url": "https://github.com/ramarlina/agx"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@mndrk/memx": "^0.2.0"
|
|
26
31
|
}
|
|
27
32
|
}
|