@link-assistant/agent 0.7.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -155
- package/package.json +8 -8
- package/src/cli/continuous-mode.js +188 -18
- package/src/cli/event-handler.js +99 -0
- package/src/config/config.ts +51 -0
- package/src/index.js +82 -157
- package/src/mcp/index.ts +125 -0
- package/src/session/message-v2.ts +30 -1
- package/src/session/processor.ts +21 -2
- package/src/session/prompt.ts +23 -1
- package/src/session/retry.ts +18 -0
- package/EXAMPLES.md +0 -462
- package/LICENSE +0 -24
- package/MODELS.md +0 -143
- package/TOOLS.md +0 -154
package/README.md
CHANGED
|
@@ -18,11 +18,13 @@
|
|
|
18
18
|
|
|
19
19
|
> ⚠️ **Bun-only runtime** - This package requires [Bun](https://bun.sh) and does NOT support Node.js or Deno.
|
|
20
20
|
|
|
21
|
+
> This is the JavaScript/Bun implementation. See also the [Rust implementation](../rust/README.md).
|
|
22
|
+
|
|
21
23
|
This is an MVP implementation of an OpenCode-compatible CLI agent, focused on maximum efficiency and unrestricted execution. We reproduce OpenCode's `run --format json --model opencode/grok-code` mode with:
|
|
22
24
|
|
|
23
25
|
- ✅ **JSON Input/Output**: Compatible with `opencode run --format json --model opencode/grok-code`
|
|
24
26
|
- ✅ **Plain Text Input**: Also accepts plain text messages (auto-converted to JSON format)
|
|
25
|
-
- ✅ **Flexible Model Selection**: Defaults to free OpenCode Zen Grok Code Fast 1, supports [OpenCode Zen](https://opencode.ai/docs/zen/), [Claude OAuth](docs/claude-oauth.md), and [Groq](docs/groq.md) providers
|
|
27
|
+
- ✅ **Flexible Model Selection**: Defaults to free OpenCode Zen Grok Code Fast 1, supports [OpenCode Zen](https://opencode.ai/docs/zen/), [Claude OAuth](../docs/claude-oauth.md), and [Groq](../docs/groq.md) providers
|
|
26
28
|
- ✅ **No Restrictions**: Fully unrestricted file system and command execution access (no sandbox)
|
|
27
29
|
- ✅ **Minimal Footprint**: Built with Bun.sh for maximum efficiency
|
|
28
30
|
- ✅ **Full Tool Support**: 13 tools including websearch, codesearch, batch - all enabled by default
|
|
@@ -38,55 +40,12 @@ This is an MVP implementation of an OpenCode-compatible CLI agent, focused on ma
|
|
|
38
40
|
- ❌ **No External API**: Server runs only internally, not exposed to network
|
|
39
41
|
- ❌ **No ACP**: No Agent Client Protocol support
|
|
40
42
|
|
|
41
|
-
##
|
|
42
|
-
|
|
43
|
-
We're creating a slimmed-down, public domain version of OpenCode CLI focused on the "agentic run mode" for use in virtual machines, Docker containers, and other environments where unrestricted AI agent access is acceptable. This is **not** for general desktop use - it's for isolated environments where you want maximum AI agent freedom.
|
|
44
|
-
|
|
45
|
-
**OpenCode Compatibility**: We maintain 100% compatibility with OpenCode's JSON event streaming format, so tools expecting `opencode run --format json --model opencode/grok-code` output will work with our agent-cli.
|
|
46
|
-
|
|
47
|
-
## Design Choices
|
|
48
|
-
|
|
49
|
-
### Why Bun-only? No Node.js or Deno support?
|
|
50
|
-
|
|
51
|
-
This agent is **exclusively built for Bun** for the following reasons:
|
|
52
|
-
|
|
53
|
-
1. **Faster Development**: No compilation step - direct execution with `bun run`
|
|
54
|
-
2. **Simpler Dependencies**: Fewer dev dependencies, no TypeScript compiler overhead
|
|
55
|
-
3. **Performance**: Bun's fast runtime and native ESM support
|
|
56
|
-
4. **Minimalism**: Single runtime target keeps the codebase simple
|
|
57
|
-
5. **Bun Ecosystem**: Leverages Bun-specific features and optimizations
|
|
58
|
-
|
|
59
|
-
**Not supporting Node.js or Deno is intentional** to keep the project focused and minimal. If you need Node.js/Deno compatibility, consider using [OpenCode](https://github.com/sst/opencode) instead.
|
|
60
|
-
|
|
61
|
-
### Architecture: Reproducing OpenCode's JSON Event Streaming
|
|
62
|
-
|
|
63
|
-
This agent-cli reproduces the core architecture of [OpenCode](https://github.com/sst/opencode)'s `run --format json` command:
|
|
64
|
-
|
|
65
|
-
- **Streaming JSON Events**: Instead of single responses, outputs real-time event stream
|
|
66
|
-
- **Event Types**: `tool_use`, `text`, `step_start`, `step_finish`, `error`
|
|
67
|
-
- **Session Management**: Each request gets a unique session ID
|
|
68
|
-
- **Tool Execution**: 13 tools with unrestricted access (bash, read, write, edit, list, glob, grep, websearch, codesearch, batch, task, todo, webfetch)
|
|
69
|
-
- **Compatible Format**: Events match OpenCode's JSON schema for interoperability
|
|
70
|
-
|
|
71
|
-
The agent streams events as they occur, providing the same real-time experience as OpenCode's JSON mode.
|
|
72
|
-
|
|
73
|
-
## Features
|
|
43
|
+
## Requirements
|
|
74
44
|
|
|
75
|
-
-
|
|
76
|
-
- **Plain Text Input**: Also accepts plain text messages (auto-converted to JSON format)
|
|
77
|
-
- **Unrestricted Access**: Full file system and command execution access (no sandbox, no restrictions)
|
|
78
|
-
- **Tool Support**: 13 tools including websearch, codesearch, batch - all enabled by default
|
|
79
|
-
- **Flexible Model Selection**: Defaults to free Grok Code Fast 1, supports [OpenCode Zen](https://opencode.ai/docs/zen/), [Claude OAuth](docs/claude-oauth.md), and [Groq](docs/groq.md) - see [MODELS.md](MODELS.md)
|
|
80
|
-
- **Bun.sh First**: Built with Bun for maximum efficiency and minimal resource usage
|
|
81
|
-
- **No TUI**: Pure JSON CLI interface for automation and integration
|
|
82
|
-
- **Public Domain**: Unlicense - use it however you want
|
|
45
|
+
- [Bun](https://bun.sh) >= 1.0.0 (Node.js and Deno are NOT supported)
|
|
83
46
|
|
|
84
47
|
## Installation
|
|
85
48
|
|
|
86
|
-
**Requirements:**
|
|
87
|
-
|
|
88
|
-
- [Bun](https://bun.sh) >= 1.0.0 (Node.js and Deno are NOT supported)
|
|
89
|
-
|
|
90
49
|
```bash
|
|
91
50
|
# Install Bun first if you haven't already
|
|
92
51
|
curl -fsSL https://bun.sh/install | bash
|
|
@@ -177,9 +136,9 @@ agent auth login # Select GitHub Copilot
|
|
|
177
136
|
echo "hi" | agent --model github-copilot/gpt-4o # Uses Copilot
|
|
178
137
|
```
|
|
179
138
|
|
|
180
|
-
See [MODELS.md](MODELS.md) for complete list of available models and pricing.
|
|
181
|
-
See [docs/groq.md](docs/groq.md) for Groq provider documentation.
|
|
182
|
-
See [docs/claude-oauth.md](docs/claude-oauth.md) for Claude OAuth provider documentation.
|
|
139
|
+
See [MODELS.md](../MODELS.md) for complete list of available models and pricing.
|
|
140
|
+
See [docs/groq.md](../docs/groq.md) for Groq provider documentation.
|
|
141
|
+
See [docs/claude-oauth.md](../docs/claude-oauth.md) for Claude OAuth provider documentation.
|
|
183
142
|
|
|
184
143
|
### Direct Prompt Mode
|
|
185
144
|
|
|
@@ -193,7 +152,30 @@ agent -p "What is 2+2?"
|
|
|
193
152
|
result=$(agent -p "Summarize: $(cat file.txt)")
|
|
194
153
|
```
|
|
195
154
|
|
|
196
|
-
###
|
|
155
|
+
### Session Resume
|
|
156
|
+
|
|
157
|
+
Resume or continue previous sessions:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Continue the most recent session (creates a fork with new UUID by default)
|
|
161
|
+
echo "Continue where we left off" | agent --continue
|
|
162
|
+
|
|
163
|
+
# Short form
|
|
164
|
+
echo "Continue where we left off" | agent -c
|
|
165
|
+
|
|
166
|
+
# Resume a specific session by ID (creates a fork with new UUID by default)
|
|
167
|
+
echo "Let's continue" | agent --resume ses_abc123xyz
|
|
168
|
+
|
|
169
|
+
# Continue in the same session without forking
|
|
170
|
+
echo "Keep going" | agent --continue --no-fork
|
|
171
|
+
|
|
172
|
+
# Resume specific session without forking
|
|
173
|
+
echo "Keep going" | agent --resume ses_abc123xyz --no-fork
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Note**: By default, `--resume` and `--continue` create a new session ID (fork) to preserve the original conversation history. Use `--no-fork` to continue in the same session.
|
|
177
|
+
|
|
178
|
+
## CLI Options
|
|
197
179
|
|
|
198
180
|
```bash
|
|
199
181
|
agent [options]
|
|
@@ -222,6 +204,14 @@ Stdin Mode Options:
|
|
|
222
204
|
--no-always-accept-stdin Single-message mode - exit after first response
|
|
223
205
|
--compact-json Output compact JSON for program-to-program use
|
|
224
206
|
|
|
207
|
+
Session Resume Options:
|
|
208
|
+
-r, --resume <sessionID> Resume a specific session by ID
|
|
209
|
+
By default, forks with a new UUID
|
|
210
|
+
-c, --continue Continue the most recent session
|
|
211
|
+
By default, forks with a new UUID
|
|
212
|
+
--no-fork When used with --resume or --continue,
|
|
213
|
+
continue in the same session without forking
|
|
214
|
+
|
|
225
215
|
--help Show help
|
|
226
216
|
--version Show version number
|
|
227
217
|
|
|
@@ -233,7 +223,7 @@ Commands:
|
|
|
233
223
|
mcp MCP server commands
|
|
234
224
|
```
|
|
235
225
|
|
|
236
|
-
See [docs/stdin-mode.md](docs/stdin-mode.md) for comprehensive stdin mode documentation.
|
|
226
|
+
See [docs/stdin-mode.md](../docs/stdin-mode.md) for comprehensive stdin mode documentation.
|
|
237
227
|
|
|
238
228
|
### JSON Output Standards
|
|
239
229
|
|
|
@@ -289,7 +279,7 @@ echo "your message here" | agent
|
|
|
289
279
|
|
|
290
280
|
## Supported Tools
|
|
291
281
|
|
|
292
|
-
All 13 tools are **enabled by default** with **no configuration required**. See [TOOLS.md](TOOLS.md) for complete documentation.
|
|
282
|
+
All 13 tools are **enabled by default** with **no configuration required**. See [TOOLS.md](../TOOLS.md) for complete documentation.
|
|
293
283
|
|
|
294
284
|
### File Operations
|
|
295
285
|
|
|
@@ -396,7 +386,7 @@ The agent will automatically use the Playwright MCP tools when browser automatio
|
|
|
396
386
|
|
|
397
387
|
- [Playwright MCP GitHub Repository](https://github.com/microsoft/playwright-mcp)
|
|
398
388
|
- [Using Playwright MCP with Claude Code](https://til.simonwillison.net/claude-code/playwright-mcp-claude-code)
|
|
399
|
-
- [Playwright MCP Case Study](docs/case-studies/playwright-mcp-support/case-study.md)
|
|
389
|
+
- [Playwright MCP Case Study](../docs/case-studies/playwright-mcp-support/case-study.md)
|
|
400
390
|
|
|
401
391
|
### Managing MCP Servers
|
|
402
392
|
|
|
@@ -422,84 +412,6 @@ agent mcp add
|
|
|
422
412
|
|
|
423
413
|
The interactive prompt will guide you through configuring local or remote MCP servers.
|
|
424
414
|
|
|
425
|
-
## Examples
|
|
426
|
-
|
|
427
|
-
See [EXAMPLES.md](EXAMPLES.md) for detailed usage examples of each tool with both agent-cli and opencode commands.
|
|
428
|
-
|
|
429
|
-
## Testing
|
|
430
|
-
|
|
431
|
-
```bash
|
|
432
|
-
# Run all tests
|
|
433
|
-
bun test
|
|
434
|
-
|
|
435
|
-
# Run specific test file
|
|
436
|
-
bun test tests/mcp.test.js
|
|
437
|
-
bun test tests/websearch.tools.test.js
|
|
438
|
-
bun test tests/batch.tools.test.js
|
|
439
|
-
bun test tests/plaintext.input.test.js
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
For detailed testing information including how to run tests manually and trigger CI tests, see [TESTING.md](TESTING.md).
|
|
443
|
-
|
|
444
|
-
## Maintenance
|
|
445
|
-
|
|
446
|
-
### Development
|
|
447
|
-
|
|
448
|
-
Run the agent in development mode:
|
|
449
|
-
|
|
450
|
-
```bash
|
|
451
|
-
bun run dev
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
Or run directly:
|
|
455
|
-
|
|
456
|
-
```bash
|
|
457
|
-
bun run src/index.js
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
### Testing
|
|
461
|
-
|
|
462
|
-
Simply run:
|
|
463
|
-
|
|
464
|
-
```bash
|
|
465
|
-
bun test
|
|
466
|
-
```
|
|
467
|
-
|
|
468
|
-
Bun automatically discovers and runs all `*.test.js` files in the project.
|
|
469
|
-
|
|
470
|
-
### Test Coverage
|
|
471
|
-
|
|
472
|
-
- ✅ 13 tool implementation tests
|
|
473
|
-
- ✅ Plain text input support test
|
|
474
|
-
- ✅ OpenCode compatibility tests for websearch/codesearch
|
|
475
|
-
- ✅ JSON standard unit tests (opencode and claude formats)
|
|
476
|
-
- ✅ All tests pass with 100% OpenCode JSON format compatibility
|
|
477
|
-
|
|
478
|
-
### Publishing
|
|
479
|
-
|
|
480
|
-
To publish a new version to npm:
|
|
481
|
-
|
|
482
|
-
1. **Update version** in `package.json`:
|
|
483
|
-
|
|
484
|
-
```bash
|
|
485
|
-
# Update version field manually (e.g., 0.0.3 -> 0.0.4)
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
2. **Commit changes**:
|
|
489
|
-
|
|
490
|
-
```bash
|
|
491
|
-
git add .
|
|
492
|
-
git commit -m "Release v0.0.4"
|
|
493
|
-
git push
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
3. **Publish to npm**:
|
|
497
|
-
```bash
|
|
498
|
-
npm publish
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
The package publishes source files directly (no build step required). Bun handles TypeScript execution natively.
|
|
502
|
-
|
|
503
415
|
## Key Features
|
|
504
416
|
|
|
505
417
|
### No Configuration Required
|
|
@@ -574,42 +486,132 @@ Output (pretty-printed JSON events):
|
|
|
574
486
|
}
|
|
575
487
|
```
|
|
576
488
|
|
|
577
|
-
##
|
|
489
|
+
## Development
|
|
578
490
|
|
|
579
|
-
|
|
491
|
+
### Running in Development Mode
|
|
580
492
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
493
|
+
```bash
|
|
494
|
+
bun run dev
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
Or run directly:
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
bun run src/index.js
|
|
501
|
+
```
|
|
586
502
|
|
|
587
|
-
|
|
503
|
+
### Testing
|
|
588
504
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
- `tests/` - Comprehensive test suite
|
|
593
|
-
- [MODELS.md](MODELS.md) - Available models and pricing
|
|
594
|
-
- [TOOLS.md](TOOLS.md) - Complete tool documentation
|
|
595
|
-
- [EXAMPLES.md](EXAMPLES.md) - Usage examples for each tool
|
|
505
|
+
```bash
|
|
506
|
+
# Run all tests
|
|
507
|
+
bun test
|
|
596
508
|
|
|
597
|
-
|
|
509
|
+
# Run specific test file
|
|
510
|
+
bun test tests/mcp.test.js
|
|
511
|
+
bun test tests/websearch.tools.test.js
|
|
512
|
+
bun test tests/batch.tools.test.js
|
|
513
|
+
bun test tests/plaintext.input.test.js
|
|
514
|
+
```
|
|
598
515
|
|
|
599
|
-
|
|
516
|
+
For detailed testing information including how to run tests manually and trigger CI tests, see [TESTING.md](../TESTING.md).
|
|
600
517
|
|
|
601
|
-
|
|
602
|
-
- **reference-gemini-cookbook** - [Google Gemini Cookbook](https://github.com/google-gemini/cookbook) - Official examples and guides for using the Gemini API
|
|
603
|
-
- **reference-gemini-cli** - [Google Gemini CLI](https://github.com/google-gemini/gemini-cli) - Official AI agent bringing Gemini directly to the terminal
|
|
604
|
-
- **reference-qwen3-coder** - [Qwen3-Coder](https://github.com/QwenLM/Qwen3-Coder) - Official Qwen3 code model from Alibaba Cloud
|
|
518
|
+
### Test Coverage
|
|
605
519
|
|
|
606
|
-
|
|
520
|
+
- ✅ 13 tool implementation tests
|
|
521
|
+
- ✅ Plain text input support test
|
|
522
|
+
- ✅ OpenCode compatibility tests for websearch/codesearch
|
|
523
|
+
- ✅ JSON standard unit tests (opencode and claude formats)
|
|
524
|
+
- ✅ All tests pass with 100% OpenCode JSON format compatibility
|
|
525
|
+
|
|
526
|
+
### Linting and Formatting
|
|
607
527
|
|
|
608
528
|
```bash
|
|
609
|
-
|
|
529
|
+
# Run linting
|
|
530
|
+
bun run lint
|
|
531
|
+
|
|
532
|
+
# Fix linting issues
|
|
533
|
+
bun run lint:fix
|
|
534
|
+
|
|
535
|
+
# Format code
|
|
536
|
+
bun run format
|
|
537
|
+
|
|
538
|
+
# Check formatting
|
|
539
|
+
bun run format:check
|
|
610
540
|
```
|
|
611
541
|
|
|
612
|
-
|
|
542
|
+
### Publishing
|
|
543
|
+
|
|
544
|
+
The package uses [Changesets](https://github.com/changesets/changesets) for version management:
|
|
545
|
+
|
|
546
|
+
1. Create a changeset:
|
|
547
|
+
|
|
548
|
+
```bash
|
|
549
|
+
bun run changeset
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
2. Version the package:
|
|
553
|
+
|
|
554
|
+
```bash
|
|
555
|
+
bun run changeset:version
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
3. Publish to npm:
|
|
559
|
+
```bash
|
|
560
|
+
bun run changeset:publish
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
The package publishes source files directly (no build step required). Bun handles TypeScript execution natively.
|
|
564
|
+
|
|
565
|
+
## Why Bun-only? No Node.js or Deno support?
|
|
566
|
+
|
|
567
|
+
This agent is **exclusively built for Bun** for the following reasons:
|
|
568
|
+
|
|
569
|
+
1. **Faster Development**: No compilation step - direct execution with `bun run`
|
|
570
|
+
2. **Simpler Dependencies**: Fewer dev dependencies, no TypeScript compiler overhead
|
|
571
|
+
3. **Performance**: Bun's fast runtime and native ESM support
|
|
572
|
+
4. **Minimalism**: Single runtime target keeps the codebase simple
|
|
573
|
+
5. **Bun Ecosystem**: Leverages Bun-specific features and optimizations
|
|
574
|
+
|
|
575
|
+
**Not supporting Node.js or Deno is intentional** to keep the project focused and minimal. If you need Node.js/Deno compatibility, consider using [OpenCode](https://github.com/sst/opencode) instead.
|
|
576
|
+
|
|
577
|
+
## Project Structure
|
|
578
|
+
|
|
579
|
+
```
|
|
580
|
+
js/
|
|
581
|
+
├── src/ # Source code
|
|
582
|
+
│ ├── index.js # Main entry point with JSON/plain text input support
|
|
583
|
+
│ ├── session/ # Session management and agent implementation
|
|
584
|
+
│ └── tool/ # Tool implementations
|
|
585
|
+
├── tests/ # Comprehensive test suite
|
|
586
|
+
├── experiments/ # Experimental code
|
|
587
|
+
├── package.json # npm package configuration
|
|
588
|
+
└── tsconfig.json # TypeScript configuration
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
## Architecture
|
|
592
|
+
|
|
593
|
+
This agent-cli reproduces the core architecture of [OpenCode](https://github.com/sst/opencode)'s `run --format json` command:
|
|
594
|
+
|
|
595
|
+
- **Streaming JSON Events**: Instead of single responses, outputs real-time event stream
|
|
596
|
+
- **Event Types**: `tool_use`, `text`, `step_start`, `step_finish`, `error`
|
|
597
|
+
- **Session Management**: Each request gets a unique session ID
|
|
598
|
+
- **Tool Execution**: 13 tools with unrestricted access (bash, read, write, edit, list, glob, grep, websearch, codesearch, batch, task, todo, webfetch)
|
|
599
|
+
- **Compatible Format**: Events match OpenCode's JSON schema for interoperability
|
|
600
|
+
|
|
601
|
+
The agent streams events as they occur, providing the same real-time experience as OpenCode's JSON mode.
|
|
602
|
+
|
|
603
|
+
## Examples
|
|
604
|
+
|
|
605
|
+
See [EXAMPLES.md](../EXAMPLES.md) for detailed usage examples of each tool with both agent-cli and opencode commands.
|
|
606
|
+
|
|
607
|
+
## Documentation
|
|
608
|
+
|
|
609
|
+
For full documentation, see the [main README](../README.md) in the repository root.
|
|
610
|
+
|
|
611
|
+
- [Models and Pricing](../MODELS.md)
|
|
612
|
+
- [Tools Reference](../TOOLS.md)
|
|
613
|
+
- [Usage Examples](../EXAMPLES.md)
|
|
614
|
+
- [Testing Guide](../TESTING.md)
|
|
613
615
|
|
|
614
616
|
## License
|
|
615
617
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@link-assistant/agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "A minimal, public domain AI CLI agent compatible with OpenCode's JSON interface. Bun-only runtime.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
"lint:fix": "eslint . --fix",
|
|
15
15
|
"format": "prettier --write .",
|
|
16
16
|
"format:check": "prettier --check .",
|
|
17
|
-
"check:file-size": "node scripts/check-file-size.mjs",
|
|
17
|
+
"check:file-size": "node ../scripts/check-file-size.mjs",
|
|
18
18
|
"check": "npm run lint && npm run format:check && npm run check:file-size",
|
|
19
|
-
"prepare": "husky || true",
|
|
19
|
+
"prepare": "cd .. && husky || true",
|
|
20
20
|
"changeset": "changeset",
|
|
21
|
-
"changeset:version": "node scripts/changeset-version.mjs",
|
|
21
|
+
"changeset:version": "node ../scripts/changeset-version.mjs",
|
|
22
22
|
"changeset:publish": "changeset publish",
|
|
23
23
|
"changeset:status": "changeset status --since=origin/main"
|
|
24
24
|
},
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"src/",
|
|
46
46
|
"package.json",
|
|
47
47
|
"README.md",
|
|
48
|
-
"MODELS.md",
|
|
49
|
-
"TOOLS.md",
|
|
50
|
-
"EXAMPLES.md",
|
|
51
|
-
"LICENSE"
|
|
48
|
+
"../MODELS.md",
|
|
49
|
+
"../TOOLS.md",
|
|
50
|
+
"../EXAMPLES.md",
|
|
51
|
+
"../LICENSE"
|
|
52
52
|
],
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@actions/core": "^1.11.1",
|
|
@@ -10,6 +10,7 @@ import { Session } from '../session/index.ts';
|
|
|
10
10
|
import { SessionPrompt } from '../session/prompt.ts';
|
|
11
11
|
import { createEventHandler } from '../json-standard/index.ts';
|
|
12
12
|
import { createContinuousStdinReader } from './input-queue.js';
|
|
13
|
+
import { Log } from '../util/log.ts';
|
|
13
14
|
|
|
14
15
|
// Shared error tracking
|
|
15
16
|
let hasError = false;
|
|
@@ -42,6 +43,155 @@ function outputStatus(status, compact = false) {
|
|
|
42
43
|
console.error(json);
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
// Logger for resume operations
|
|
47
|
+
const log = Log.create({ service: 'resume' });
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the session to use based on --resume, --continue, and --no-fork options.
|
|
51
|
+
* Returns the session ID to use, handling forking as needed.
|
|
52
|
+
* @param {object} argv - Command line arguments
|
|
53
|
+
* @param {boolean} compactJson - Whether to use compact JSON output
|
|
54
|
+
* @returns {Promise<{sessionID: string, wasResumed: boolean, wasForked: boolean} | null>} - Session info or null if new session should be created
|
|
55
|
+
* @export
|
|
56
|
+
*/
|
|
57
|
+
export async function resolveResumeSession(argv, compactJson) {
|
|
58
|
+
const resumeSessionID = argv.resume;
|
|
59
|
+
const shouldContinue = argv.continue === true;
|
|
60
|
+
const noFork = argv['no-fork'] === true;
|
|
61
|
+
|
|
62
|
+
// If neither --resume nor --continue is specified, return null to create new session
|
|
63
|
+
if (!resumeSessionID && !shouldContinue) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let targetSessionID = resumeSessionID;
|
|
68
|
+
|
|
69
|
+
// If --continue is specified, find the most recent session
|
|
70
|
+
if (shouldContinue && !targetSessionID) {
|
|
71
|
+
let mostRecentSession = null;
|
|
72
|
+
let mostRecentTime = 0;
|
|
73
|
+
|
|
74
|
+
for await (const session of Session.list()) {
|
|
75
|
+
// Skip child sessions (those with parentID) - find top-level sessions only
|
|
76
|
+
if (session.parentID) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (session.time.updated > mostRecentTime) {
|
|
81
|
+
mostRecentTime = session.time.updated;
|
|
82
|
+
mostRecentSession = session;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!mostRecentSession) {
|
|
87
|
+
outputStatus(
|
|
88
|
+
{
|
|
89
|
+
type: 'error',
|
|
90
|
+
errorType: 'SessionNotFound',
|
|
91
|
+
message:
|
|
92
|
+
'No existing sessions found to continue. Start a new session first.',
|
|
93
|
+
},
|
|
94
|
+
compactJson
|
|
95
|
+
);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
targetSessionID = mostRecentSession.id;
|
|
100
|
+
log.info(() => ({
|
|
101
|
+
message: 'Found most recent session to continue',
|
|
102
|
+
sessionID: targetSessionID,
|
|
103
|
+
title: mostRecentSession.title,
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Verify the session exists
|
|
108
|
+
let existingSession;
|
|
109
|
+
try {
|
|
110
|
+
existingSession = await Session.get(targetSessionID);
|
|
111
|
+
} catch (_error) {
|
|
112
|
+
// Session.get throws an error when the session doesn't exist
|
|
113
|
+
outputStatus(
|
|
114
|
+
{
|
|
115
|
+
type: 'error',
|
|
116
|
+
errorType: 'SessionNotFound',
|
|
117
|
+
message: `Session not found: ${targetSessionID}`,
|
|
118
|
+
},
|
|
119
|
+
compactJson
|
|
120
|
+
);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!existingSession) {
|
|
125
|
+
outputStatus(
|
|
126
|
+
{
|
|
127
|
+
type: 'error',
|
|
128
|
+
errorType: 'SessionNotFound',
|
|
129
|
+
message: `Session not found: ${targetSessionID}`,
|
|
130
|
+
},
|
|
131
|
+
compactJson
|
|
132
|
+
);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
log.info(() => ({
|
|
137
|
+
message: 'Resuming session',
|
|
138
|
+
sessionID: targetSessionID,
|
|
139
|
+
title: existingSession.title,
|
|
140
|
+
noFork,
|
|
141
|
+
}));
|
|
142
|
+
|
|
143
|
+
// If --no-fork is specified, continue in the same session
|
|
144
|
+
if (noFork) {
|
|
145
|
+
outputStatus(
|
|
146
|
+
{
|
|
147
|
+
type: 'status',
|
|
148
|
+
mode: 'resume',
|
|
149
|
+
message: `Continuing session without forking: ${targetSessionID}`,
|
|
150
|
+
sessionID: targetSessionID,
|
|
151
|
+
title: existingSession.title,
|
|
152
|
+
forked: false,
|
|
153
|
+
},
|
|
154
|
+
compactJson
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
sessionID: targetSessionID,
|
|
159
|
+
wasResumed: true,
|
|
160
|
+
wasForked: false,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Fork the session to a new UUID (default behavior)
|
|
165
|
+
const forkedSession = await Session.fork({
|
|
166
|
+
sessionID: targetSessionID,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
outputStatus(
|
|
170
|
+
{
|
|
171
|
+
type: 'status',
|
|
172
|
+
mode: 'resume',
|
|
173
|
+
message: `Forked session ${targetSessionID} to new session: ${forkedSession.id}`,
|
|
174
|
+
originalSessionID: targetSessionID,
|
|
175
|
+
sessionID: forkedSession.id,
|
|
176
|
+
title: forkedSession.title,
|
|
177
|
+
forked: true,
|
|
178
|
+
},
|
|
179
|
+
compactJson
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
log.info(() => ({
|
|
183
|
+
message: 'Forked session',
|
|
184
|
+
originalSessionID: targetSessionID,
|
|
185
|
+
newSessionID: forkedSession.id,
|
|
186
|
+
}));
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
sessionID: forkedSession.id,
|
|
190
|
+
wasResumed: true,
|
|
191
|
+
wasForked: true,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
45
195
|
/**
|
|
46
196
|
* Run server mode with continuous stdin input
|
|
47
197
|
* Keeps the session alive and processes messages as they arrive
|
|
@@ -64,20 +214,30 @@ export async function runContinuousServerMode(
|
|
|
64
214
|
let stdinReader = null;
|
|
65
215
|
|
|
66
216
|
try {
|
|
67
|
-
//
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
217
|
+
// Check if we should resume an existing session
|
|
218
|
+
const resumeInfo = await resolveResumeSession(argv, compactJson);
|
|
219
|
+
|
|
220
|
+
let sessionID;
|
|
221
|
+
|
|
222
|
+
if (resumeInfo) {
|
|
223
|
+
// Use the resumed/forked session
|
|
224
|
+
sessionID = resumeInfo.sessionID;
|
|
225
|
+
} else {
|
|
226
|
+
// Create a new session
|
|
227
|
+
const createRes = await fetch(
|
|
228
|
+
`http://${server.hostname}:${server.port}/session`,
|
|
229
|
+
{
|
|
230
|
+
method: 'POST',
|
|
231
|
+
headers: { 'Content-Type': 'application/json' },
|
|
232
|
+
body: JSON.stringify({}),
|
|
233
|
+
}
|
|
234
|
+
);
|
|
235
|
+
const session = await createRes.json();
|
|
236
|
+
sessionID = session.id;
|
|
78
237
|
|
|
79
|
-
|
|
80
|
-
|
|
238
|
+
if (!sessionID) {
|
|
239
|
+
throw new Error('Failed to create session');
|
|
240
|
+
}
|
|
81
241
|
}
|
|
82
242
|
|
|
83
243
|
// Create event handler for the selected JSON standard
|
|
@@ -275,11 +435,21 @@ export async function runContinuousDirectMode(
|
|
|
275
435
|
let stdinReader = null;
|
|
276
436
|
|
|
277
437
|
try {
|
|
278
|
-
//
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
438
|
+
// Check if we should resume an existing session
|
|
439
|
+
const resumeInfo = await resolveResumeSession(argv, compactJson);
|
|
440
|
+
|
|
441
|
+
let sessionID;
|
|
442
|
+
|
|
443
|
+
if (resumeInfo) {
|
|
444
|
+
// Use the resumed/forked session
|
|
445
|
+
sessionID = resumeInfo.sessionID;
|
|
446
|
+
} else {
|
|
447
|
+
// Create a new session directly
|
|
448
|
+
const session = await Session.createNext({
|
|
449
|
+
directory: process.cwd(),
|
|
450
|
+
});
|
|
451
|
+
sessionID = session.id;
|
|
452
|
+
}
|
|
283
453
|
|
|
284
454
|
// Create event handler for the selected JSON standard
|
|
285
455
|
const eventHandler = createEventHandler(jsonStandard, sessionID);
|