echospace 0.1.0-alpha.5 → 0.1.0-alpha.6
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 +74 -46
- package/dist/cli/index.js +46 -26
- package/dist/client/assets/index-BTjnLaRd.js +151 -0
- package/dist/client/assets/index-Dt4ZMQMX.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/core/chunk-LGVA3Y5G.js +110 -0
- package/dist/core/smart-paste/index.js +4 -4
- package/package.json +1 -1
- package/dist/client/assets/index-DFTLQ23A.js +0 -186
- package/dist/client/assets/index-gZkfzHQ0.css +0 -1
package/README.md
CHANGED
|
@@ -6,54 +6,45 @@
|
|
|
6
6
|
|
|
7
7
|
<p align="center"><strong>The open-source, local-first prompt debugging workspace for LLM developers.</strong></p>
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
<p align="center">
|
|
10
|
+
Debug, iterate, and manage your prompts across multiple LLM providers — all from your terminal.<br/>
|
|
11
|
+
No cloud. No accounts. No lock-in.
|
|
12
|
+
</p>
|
|
10
13
|
|
|
11
14
|
---
|
|
12
15
|
|
|
13
16
|
## Why EchoSpace?
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
All data stored as `.echo` files on disk. No cloud, no accounts. Your prompts stay on your machine, version-controlled alongside your code.
|
|
18
|
-
|
|
19
|
-
### Open Source & Customizable
|
|
20
|
-
|
|
21
|
-
MIT-licensed. Pluggable provider adapters (OpenAI, Anthropic, Google). YAML-based config with `${ENV_VAR}` substitution.
|
|
22
|
-
|
|
23
|
-
### CLI & SDK
|
|
18
|
+
Prompt engineering is iterative, but most tools make you choose between a polished UI and full control over your data. EchoSpace gives you both: a browser-based workspace that runs entirely on your machine, stores conversations as plain files you can version-control, and works with any OpenAI-compatible provider out of the box.
|
|
24
19
|
|
|
25
|
-
|
|
20
|
+
- **Local-first** — all data stored as `.echo` files on disk, version-controlled alongside your code
|
|
21
|
+
- **Open source** — MIT-licensed, pluggable provider adapters, `${ENV_VAR}` substitution in config
|
|
22
|
+
- **CLI & library** — `npx echospace@alpha` to launch; core modules (`parseEcho`, `serializeEcho`, `smartParse`, provider registry) are importable as a library
|
|
26
23
|
|
|
27
24
|
---
|
|
28
25
|
|
|
29
26
|
## Features
|
|
30
27
|
|
|
31
|
-
- **Multi-provider streaming** — OpenAI, Anthropic, Google
|
|
32
|
-
- **Universal `.echo` format** — NDJSON-based, human-readable conversation protocol
|
|
33
|
-
- **Smart Paste** — auto-detects and converts
|
|
34
|
-
- **Timeline
|
|
35
|
-
- **Tool use support** — `tool_call` / `tool_result` parts
|
|
36
|
-
- **Token counting** — tiktoken-based token estimation
|
|
37
|
-
- **Image support** — inline images in messages
|
|
28
|
+
- **Multi-provider streaming** — SSE streaming across all configured providers (OpenAI, Anthropic, Google, or any OpenAI-compatible gateway)
|
|
29
|
+
- **Universal `.echo` format** — NDJSON-based, human-readable conversation protocol designed for diffing and version control
|
|
30
|
+
- **Smart Paste** — auto-detects and converts conversation exports from major LLM platforms or raw text
|
|
31
|
+
- **Timeline & branching** — revert to any point in a conversation, fork branches, compare results
|
|
32
|
+
- **Tool use support** — first-class `tool_call` / `tool_result` message parts
|
|
33
|
+
- **Token counting** — tiktoken-based token estimation shown in real time
|
|
34
|
+
- **Image support** — inline images in messages via base64 or URL
|
|
38
35
|
- **Per-conversation model settings** — temperature, max_tokens, top_p, response_format, JSON schema, tools
|
|
39
36
|
|
|
40
37
|
---
|
|
41
38
|
|
|
42
|
-
##
|
|
39
|
+
## Getting Started
|
|
43
40
|
|
|
44
|
-
### 1.
|
|
45
|
-
|
|
46
|
-
EchoSpace ships with agent skills that work with any coding agent — [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [OpenAI Codex](https://openai.com/index/codex/), or any tool that supports the skills/SKILL.md convention.
|
|
41
|
+
### 1. Initialize
|
|
47
42
|
|
|
48
43
|
```bash
|
|
49
|
-
npx
|
|
44
|
+
npx echospace@alpha init
|
|
50
45
|
```
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
npx echospace init
|
|
56
|
-
```
|
|
47
|
+
The interactive setup wizard configures your provider and API key:
|
|
57
48
|
|
|
58
49
|
```
|
|
59
50
|
◆ Which LLM service do you use?
|
|
@@ -67,9 +58,14 @@ npx echospace init
|
|
|
67
58
|
│ sk-xxxxxxxx
|
|
68
59
|
|
|
69
60
|
✓ Config saved to ~/.echospace/config.yaml
|
|
61
|
+
|
|
62
|
+
◆ Install agent skills for your coding agent? (Claude Code, Codex, etc.)
|
|
63
|
+
│ ● Yes / ○ No
|
|
64
|
+
|
|
65
|
+
✓ Skills installed!
|
|
70
66
|
```
|
|
71
67
|
|
|
72
|
-
###
|
|
68
|
+
### 2. Launch
|
|
73
69
|
|
|
74
70
|
```bash
|
|
75
71
|
npx echospace@alpha
|
|
@@ -78,31 +74,25 @@ npx echospace@alpha
|
|
|
78
74
|
Or install globally:
|
|
79
75
|
|
|
80
76
|
```bash
|
|
81
|
-
pnpm add -g echospace
|
|
77
|
+
pnpm add -g echospace@alpha
|
|
82
78
|
echospace ./my-project
|
|
83
79
|
```
|
|
84
80
|
|
|
85
|
-
|
|
81
|
+
EchoSpace will:
|
|
86
82
|
|
|
87
83
|
1. Create a `.echo/` workspace in your project directory
|
|
88
84
|
2. Start a local server and open the UI in your browser
|
|
89
85
|
|
|
90
86
|
```
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
87
|
+
██████████████
|
|
88
|
+
██ ██ EchoSpace v0.1.0
|
|
89
|
+
██ ██████ ██
|
|
90
|
+
██ ██ ██ ██ Workspace /my-project/.echo
|
|
91
|
+
██ ██████ ██ URL http://localhost:3240
|
|
92
|
+
██ ██
|
|
93
|
+
██████████████
|
|
97
94
|
```
|
|
98
95
|
|
|
99
|
-
### Available Skills
|
|
100
|
-
|
|
101
|
-
| Skill | Description |
|
|
102
|
-
| ------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
103
|
-
| `/echospace-export` | Convert conversation files (OpenAI, Anthropic, Google, Helicone, raw text) into `.echo` format |
|
|
104
|
-
| `/echospace-integrate` | Integrate `.echo` export into your own app |
|
|
105
|
-
|
|
106
96
|
### CLI Options
|
|
107
97
|
|
|
108
98
|
```
|
|
@@ -113,6 +103,26 @@ echospace [workdir] [options]
|
|
|
113
103
|
--no-open Don't open browser automatically
|
|
114
104
|
```
|
|
115
105
|
|
|
106
|
+
### Agent Skills
|
|
107
|
+
|
|
108
|
+
| Skill | Description |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `/echospace-export` | Convert conversation exports from major LLM platforms into `.echo` format |
|
|
111
|
+
| `/echospace-integrate` | Integrate a `.echo` export into your own app |
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Tech Stack
|
|
116
|
+
|
|
117
|
+
| Layer | Technology |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| Frontend | React 19, Tailwind CSS v4, Zustand, CodeMirror |
|
|
120
|
+
| Backend | Hono, Node.js |
|
|
121
|
+
| Build | Vite, tsup, TypeScript 5 |
|
|
122
|
+
| Testing | Vitest |
|
|
123
|
+
| Tokenization | tiktoken |
|
|
124
|
+
| Package manager | pnpm |
|
|
125
|
+
|
|
116
126
|
---
|
|
117
127
|
|
|
118
128
|
## The `.echo` Format
|
|
@@ -131,7 +141,7 @@ Each message can contain multiple part types: `text`, `thinking`, `tool_call`, `
|
|
|
131
141
|
|
|
132
142
|
## Configuration
|
|
133
143
|
|
|
134
|
-
|
|
144
|
+
Run `npx echospace@alpha init` to create `~/.echospace/config.yaml`, or edit it manually:
|
|
135
145
|
|
|
136
146
|
```yaml
|
|
137
147
|
providers:
|
|
@@ -162,9 +172,26 @@ providers:
|
|
|
162
172
|
- gemini-2.5-pro
|
|
163
173
|
- gemini-2.5-flash
|
|
164
174
|
- gemini-2.0-flash
|
|
175
|
+
|
|
176
|
+
- name: vercel-ai-gateway
|
|
177
|
+
type: openai
|
|
178
|
+
api_key: xxxxxxxx
|
|
179
|
+
base_url: https://ai-gateway.vercel.sh/v1
|
|
180
|
+
models:
|
|
181
|
+
- anthropic/claude-sonnet-4-6
|
|
182
|
+
- openai/gpt-4.1
|
|
183
|
+
- google/gemini-2.5-pro
|
|
184
|
+
|
|
185
|
+
# Custom OpenAI-compatible gateway
|
|
186
|
+
- name: custom
|
|
187
|
+
type: openai # or: anthropic, google
|
|
188
|
+
api_key: xxxxxxxx
|
|
189
|
+
base_url: https://my-proxy.example.com/v1
|
|
190
|
+
models:
|
|
191
|
+
- my-model-name
|
|
165
192
|
```
|
|
166
193
|
|
|
167
|
-
> **Tip:** `${ENV_VAR}` syntax is
|
|
194
|
+
> **Tip:** `${ENV_VAR}` syntax is supported for API keys — values are resolved from your environment at runtime. `.env` files in your project directory are auto-loaded.
|
|
168
195
|
|
|
169
196
|
---
|
|
170
197
|
|
|
@@ -182,6 +209,7 @@ pnpm build # Build for production
|
|
|
182
209
|
pnpm typecheck # Type-check without emitting
|
|
183
210
|
pnpm lint # ESLint
|
|
184
211
|
pnpm format # Prettier
|
|
212
|
+
pnpm test # Run tests
|
|
185
213
|
```
|
|
186
214
|
|
|
187
215
|
---
|
package/dist/cli/index.js
CHANGED
|
@@ -866,6 +866,7 @@ function startServer(options) {
|
|
|
866
866
|
|
|
867
867
|
// src/cli/init.ts
|
|
868
868
|
import * as p from "@clack/prompts";
|
|
869
|
+
import { execSync } from "child_process";
|
|
869
870
|
import { homedir } from "os";
|
|
870
871
|
import path4 from "path";
|
|
871
872
|
var CONFIG_DIR = path4.join(homedir(), ".echospace");
|
|
@@ -942,7 +943,7 @@ async function runInit() {
|
|
|
942
943
|
const baseUrl = await p.text({
|
|
943
944
|
message: "Base URL (e.g. https://my-proxy.example.com/v1):",
|
|
944
945
|
validate: (v) => {
|
|
945
|
-
if (!v
|
|
946
|
+
if (!v?.trim()) return "URL is required";
|
|
946
947
|
try {
|
|
947
948
|
new URL(v.trim());
|
|
948
949
|
} catch {
|
|
@@ -1006,11 +1007,25 @@ async function runInit() {
|
|
|
1006
1007
|
saveConfig(CONFIG_DIR, config);
|
|
1007
1008
|
const configPath = path4.join(CONFIG_DIR, "config.yaml");
|
|
1008
1009
|
p.log.success(`Config saved to ${configPath}`);
|
|
1010
|
+
const installSkills = await p.confirm({
|
|
1011
|
+
message: "Install agent skills for Claude Code / Cursor? (npx skills add stonexer/echospace)"
|
|
1012
|
+
});
|
|
1013
|
+
if (installSkills && !isCancel2(installSkills)) {
|
|
1014
|
+
const s = p.spinner();
|
|
1015
|
+
s.start("Installing skills...");
|
|
1016
|
+
try {
|
|
1017
|
+
execSync("npx skills add stonexer/echospace", { stdio: "pipe" });
|
|
1018
|
+
s.stop("Skills installed!");
|
|
1019
|
+
} catch {
|
|
1020
|
+
s.stop("Failed to install skills");
|
|
1021
|
+
p.log.warn("Run manually: npx skills add stonexer/echospace");
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1009
1024
|
p.outro("You're all set! Run `npx echospace@alpha` to start.");
|
|
1010
1025
|
}
|
|
1011
1026
|
|
|
1012
1027
|
// src/cli/index.ts
|
|
1013
|
-
var VERSION = "0.1.0-alpha.
|
|
1028
|
+
var VERSION = "0.1.0-alpha.6";
|
|
1014
1029
|
var CONFIG_DIR2 = path5.join(homedir2(), ".echospace");
|
|
1015
1030
|
function loadEnvFile(dir) {
|
|
1016
1031
|
const envPath = path5.join(dir, ".env");
|
|
@@ -1029,19 +1044,23 @@ function loadEnvFile(dir) {
|
|
|
1029
1044
|
}
|
|
1030
1045
|
}
|
|
1031
1046
|
var program = new Command();
|
|
1032
|
-
program.name("echospace").description("The best open-source local prompt debugging tool").version(VERSION).argument("[workdir]", "Workspace directory", ".").option("-p, --port <port>", "Port to serve on").option(
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1047
|
+
program.name("echospace").description("The best open-source local prompt debugging tool").version(VERSION).argument("[workdir]", "Workspace directory", ".").option("-p, --port <port>", "Port to serve on").option(
|
|
1048
|
+
"-d, --dir <path>",
|
|
1049
|
+
"Open this directory directly as the workspace (skips the .echo subdir)"
|
|
1050
|
+
).option("--no-open", "Don't open browser automatically").action(
|
|
1051
|
+
async (workdir, options) => {
|
|
1052
|
+
const baseDir = path5.resolve(process.cwd(), workdir);
|
|
1053
|
+
const workspaceDir = options.dir ? path5.resolve(process.cwd(), options.dir) : path5.join(baseDir, ".echo");
|
|
1054
|
+
loadEnvFile(baseDir);
|
|
1055
|
+
loadEnvFile(process.cwd());
|
|
1056
|
+
if (!fs3.existsSync(workspaceDir)) {
|
|
1057
|
+
fs3.mkdirSync(workspaceDir, { recursive: true });
|
|
1058
|
+
}
|
|
1059
|
+
fs3.mkdirSync(CONFIG_DIR2, { recursive: true });
|
|
1060
|
+
ensureConfig(CONFIG_DIR2);
|
|
1061
|
+
const port = options.port ? parseInt(options.port, 10) : await getPort({ port: portNumbers(3240, 3249) });
|
|
1062
|
+
const url = `http://localhost:${port}`;
|
|
1063
|
+
console.log(`
|
|
1045
1064
|
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
|
|
1046
1065
|
\u2588\u2588 \u2588\u2588 EchoSpace v${VERSION}
|
|
1047
1066
|
\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588
|
|
@@ -1050,17 +1069,18 @@ program.name("echospace").description("The best open-source local prompt debuggi
|
|
|
1050
1069
|
\u2588\u2588 \u2588\u2588
|
|
1051
1070
|
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
|
|
1052
1071
|
`);
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1072
|
+
const isDev = process.env.NODE_ENV !== "production" && import.meta.url.includes("/src/");
|
|
1073
|
+
startServer({ port, workspaceDir, configDir: CONFIG_DIR2, dev: isDev });
|
|
1074
|
+
if (options.open) {
|
|
1075
|
+
await open(`http://localhost:${port}`);
|
|
1076
|
+
}
|
|
1077
|
+
const shutdown = () => {
|
|
1078
|
+
console.log("\nShutting down EchoSpace...");
|
|
1079
|
+
process.exit(0);
|
|
1080
|
+
};
|
|
1081
|
+
process.on("SIGINT", shutdown);
|
|
1082
|
+
process.on("SIGTERM", shutdown);
|
|
1057
1083
|
}
|
|
1058
|
-
|
|
1059
|
-
console.log("\nShutting down EchoSpace...");
|
|
1060
|
-
process.exit(0);
|
|
1061
|
-
};
|
|
1062
|
-
process.on("SIGINT", shutdown);
|
|
1063
|
-
process.on("SIGTERM", shutdown);
|
|
1064
|
-
});
|
|
1084
|
+
);
|
|
1065
1085
|
program.command("init").description("Interactive setup for LLM provider configuration").action(runInit);
|
|
1066
1086
|
program.parse();
|