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 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
- Debug, iterate, and manage your prompts across OpenAI, Anthropic, and Google — all from your terminal. No cloud, no accounts, no lock-in.
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
- ### Local First
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
- `npx echospace@alpha` to launch. Core TypeScript modules (`parseEcho`, `serializeEcho`, `smartParse`, provider registry) can be imported as a library for building your own tools.
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 Gemini with SSE streaming
32
- - **Universal `.echo` format** — NDJSON-based, human-readable conversation protocol
33
- - **Smart Paste** — auto-detects and converts conversations from ChatGPT, Claude, Gemini, or raw text
34
- - **Timeline / history with branching** — revert to any point in a conversation
35
- - **Tool use support** — `tool_call` / `tool_result` parts
36
- - **Token counting** — tiktoken-based token estimation
37
- - **Image support** — inline images in messages (base64 or URL)
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
- ## Quick Start
39
+ ## Getting Started
43
40
 
44
- ### 1. Install skills
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 skills add stonexer/echospace
44
+ npx echospace@alpha init
50
45
  ```
51
46
 
52
- ### 2. Configure providers
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
- ### 3. Launch
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
- This will:
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
- EchoSpace v0.1.0
93
- ╠══════════════════════════════════════╣
94
- Workspace: /my-project/.echo
95
- URL: http://localhost:3240
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
- On first launch, EchoSpace creates `~/.echospace/config.yaml`. Fill in the `api_key` for the providers you want to use — unconfigured providers are automatically ignored.
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 also supported for API keys — they are resolved from your environment at runtime. `.env` files in your project directory are auto-loaded.
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.trim()) return "URL is required";
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.5";
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("--no-open", "Don't open browser automatically").action(async (workdir, options) => {
1033
- const baseDir = path5.resolve(process.cwd(), workdir);
1034
- const workspaceDir = path5.join(baseDir, ".echo");
1035
- loadEnvFile(baseDir);
1036
- loadEnvFile(process.cwd());
1037
- if (!fs3.existsSync(workspaceDir)) {
1038
- fs3.mkdirSync(workspaceDir, { recursive: true });
1039
- }
1040
- fs3.mkdirSync(CONFIG_DIR2, { recursive: true });
1041
- ensureConfig(CONFIG_DIR2);
1042
- const port = options.port ? parseInt(options.port, 10) : await getPort({ port: portNumbers(3240, 3249) });
1043
- const url = `http://localhost:${port}`;
1044
- console.log(`
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
- const isDev = process.env.NODE_ENV !== "production" && import.meta.url.includes("/src/");
1054
- startServer({ port, workspaceDir, configDir: CONFIG_DIR2, dev: isDev });
1055
- if (options.open) {
1056
- await open(`http://localhost:${port}`);
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
- const shutdown = () => {
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();