echospace 0.1.0-alpha.2 → 0.1.0-alpha.5

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
@@ -46,7 +46,7 @@ MIT-licensed. Pluggable provider adapters (OpenAI, Anthropic, Google). YAML-base
46
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.
47
47
 
48
48
  ```bash
49
- npx skills add https://github.com/stonexer/echospace/tree/master/skills/echospace
49
+ npx skills add stonexer/echospace
50
50
  ```
51
51
 
52
52
  ### 2. Configure providers
@@ -69,8 +69,6 @@ npx echospace init
69
69
  ✓ Config saved to ~/.echospace/config.yaml
70
70
  ```
71
71
 
72
- Or use the agent skill: `/echospace:init`
73
-
74
72
  ### 3. Launch
75
73
 
76
74
  ```bash
@@ -100,11 +98,10 @@ This will:
100
98
 
101
99
  ### Available Skills
102
100
 
103
- | Skill | Description |
104
- |-------|-------------|
105
- | `/echospace:init` | Interactive setup wizard select providers, enter API keys, generate config |
106
- | `/echospace:export` | Convert conversation files (OpenAI, Anthropic, Google, Helicone, raw text) into `.echo` format |
107
- | `/echospace:integrate` | Integrate `.echo` export into your own app |
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 |
108
105
 
109
106
  ### CLI Options
110
107
 
package/dist/cli/index.js CHANGED
@@ -330,20 +330,23 @@ var googleAdapter = {
330
330
  };
331
331
 
332
332
  // src/core/providers/openai.ts
333
- function toOpenAIMessage(msg) {
334
- const result = { role: msg.role };
333
+ function toOpenAIMessages(msg) {
335
334
  const textParts = msg.parts.filter((p2) => p2.type === "text");
336
335
  const toolCalls = msg.parts.filter((p2) => p2.type === "tool_call");
337
336
  const toolResults = msg.parts.filter((p2) => p2.type === "tool_result");
338
337
  const thinkingParts = msg.parts.filter((p2) => p2.type === "thinking");
339
338
  if (msg.role === "tool" && toolResults.length > 0) {
340
- const tr = toolResults[0];
341
- result.content = typeof tr.output === "string" ? tr.output : JSON.stringify(tr.output);
342
- result.tool_call_id = tr.tool_call_id;
343
- return result;
339
+ return toolResults.map((tr) => ({
340
+ role: "tool",
341
+ tool_call_id: tr.tool_call_id,
342
+ content: typeof tr.output === "string" ? tr.output : JSON.stringify(tr.output)
343
+ }));
344
344
  }
345
345
  if (msg.role === "assistant") {
346
- result.content = textParts.map((p2) => p2.text).join("") || null;
346
+ const result = {
347
+ role: "assistant",
348
+ content: textParts.map((p2) => p2.text).join("") || null
349
+ };
347
350
  if (thinkingParts.length > 0) {
348
351
  result.reasoning_content = thinkingParts.map((p2) => p2.text).join("");
349
352
  }
@@ -357,10 +360,9 @@ function toOpenAIMessage(msg) {
357
360
  }
358
361
  }));
359
362
  }
360
- return result;
363
+ return [result];
361
364
  }
362
- result.content = textParts.map((p2) => p2.text).join("");
363
- return result;
365
+ return [{ role: msg.role, content: textParts.map((p2) => p2.text).join("") }];
364
366
  }
365
367
  var openaiAdapter = {
366
368
  type: "openai",
@@ -369,7 +371,7 @@ var openaiAdapter = {
369
371
  const url = `${baseUrl.replace(/\/$/, "")}/chat/completions`;
370
372
  const body = {
371
373
  model: settings.model ?? config.models[0],
372
- messages: messages.map(toOpenAIMessage),
374
+ messages: messages.flatMap(toOpenAIMessages),
373
375
  stream: true
374
376
  };
375
377
  if (settings.temperature != null) body.temperature = settings.temperature;
@@ -592,7 +594,7 @@ function normalizeMessage(message) {
592
594
  const needsPartNormalization = msg.parts.some((p2) => {
593
595
  if (p2.type !== "tool_result") return false;
594
596
  const r = p2;
595
- return !r.tool_call_id && (r.id || r.tool_use_id);
597
+ return !r.tool_call_id && (r.id || r.tool_use_id || r.call_id);
596
598
  });
597
599
  if (needsPartNormalization) {
598
600
  msg = {
@@ -600,9 +602,9 @@ function normalizeMessage(message) {
600
602
  parts: msg.parts.map((p2) => {
601
603
  if (p2.type !== "tool_result") return p2;
602
604
  const r = p2;
603
- if (!r.tool_call_id && (r.id || r.tool_use_id)) {
604
- const { id, tool_use_id, ...rest } = r;
605
- return { ...rest, tool_call_id: id ?? tool_use_id };
605
+ if (!r.tool_call_id && (r.id || r.tool_use_id || r.call_id)) {
606
+ const { id, tool_use_id, call_id, ...rest } = r;
607
+ return { ...rest, tool_call_id: id ?? tool_use_id ?? call_id };
606
608
  }
607
609
  return p2;
608
610
  })
@@ -1004,11 +1006,11 @@ async function runInit() {
1004
1006
  saveConfig(CONFIG_DIR, config);
1005
1007
  const configPath = path4.join(CONFIG_DIR, "config.yaml");
1006
1008
  p.log.success(`Config saved to ${configPath}`);
1007
- p.outro("You're all set! Run `npx echospace` to start.");
1009
+ p.outro("You're all set! Run `npx echospace@alpha` to start.");
1008
1010
  }
1009
1011
 
1010
1012
  // src/cli/index.ts
1011
- var VERSION = "0.1.0-alpha.2";
1013
+ var VERSION = "0.1.0-alpha.5";
1012
1014
  var CONFIG_DIR2 = path5.join(homedir2(), ".echospace");
1013
1015
  function loadEnvFile(dir) {
1014
1016
  const envPath = path5.join(dir, ".env");
@@ -1038,13 +1040,15 @@ program.name("echospace").description("The best open-source local prompt debuggi
1038
1040
  fs3.mkdirSync(CONFIG_DIR2, { recursive: true });
1039
1041
  ensureConfig(CONFIG_DIR2);
1040
1042
  const port = options.port ? parseInt(options.port, 10) : await getPort({ port: portNumbers(3240, 3249) });
1043
+ const url = `http://localhost:${port}`;
1041
1044
  console.log(`
1042
- \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
1043
- \u2551 EchoSpace v${VERSION.padEnd(12)}\u2551
1044
- \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563
1045
- \u2551 Workspace: ${workspaceDir.padEnd(24)}\u2551
1046
- \u2551 URL: http://localhost:${String(port).padEnd(8)}\u2551
1047
- \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
1045
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
1046
+ \u2588\u2588 \u2588\u2588 EchoSpace v${VERSION}
1047
+ \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588
1048
+ \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 Workspace ${workspaceDir}
1049
+ \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 URL ${url}
1050
+ \u2588\u2588 \u2588\u2588
1051
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
1048
1052
  `);
1049
1053
  const isDev = process.env.NODE_ENV !== "production" && import.meta.url.includes("/src/");
1050
1054
  startServer({ port, workspaceDir, configDir: CONFIG_DIR2, dev: isDev });