thebird 1.2.25 → 1.2.27

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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ### Added
6
+ - `docs/index.html`: GEMINI_API_KEY input + Run Agent button in Terminal tab toolbar for in-browser agent validation
7
+ - `docs/terminal.js`: `window.__debug.runAgent(key, task)` spawns `node agent.js` with env, pipes output to terminal, tracks `{ running, output, exitCode }` in `window.__debug.validation`
8
+
9
+ ### Fixed
10
+ - `docs/terminal.js`: build nested WebContainer mount tree from flat path keys (fixes `EIO: invalid file name` for files in subdirectories like `lib/providers/openai.js`); bump IDB_KEY to `thebird_fs_v2` to force re-fetch of defaults.json for users with stale cache
11
+
5
12
  ### Added
6
13
  - `docs/defaults.json`: JSON blob of all thebird lib files + `server.js` + `agent.js` fetched by terminal.js on first boot
7
14
  - `docs/terminal.js`: fetches `defaults.json` instead of hardcoded DEFAULT_FILES; jsh PTY shell with resize; `server-ready` wires iframe src + `window.__debug.previewUrl`; all debug keys registered
package/docs/index.html CHANGED
@@ -13,8 +13,7 @@
13
13
  <style>
14
14
  html, body { height: 100%; background: #0f1117; }
15
15
  .tab-active { border-bottom: 2px solid oklch(var(--p)); }
16
- #term-container { height: 100%; }
17
- bird-chat { display: flex; flex-direction: column; height: 100%; }
16
+ bird-chat { display: flex; flex-direction: column; height: 100%; }
18
17
  .msg-bubble { max-width: 680px; white-space: pre-wrap; word-break: break-word; }
19
18
  #msg-list { scroll-behavior: smooth; }
20
19
  </style>
@@ -29,8 +28,12 @@
29
28
  <div id="pane-chat" class="flex-1 overflow-hidden">
30
29
  <bird-chat></bird-chat>
31
30
  </div>
32
- <div id="pane-term" class="flex-1 overflow-hidden hidden p-2 bg-black">
33
- <div id="term-container" style="height:100%"></div>
31
+ <div id="pane-term" class="flex flex-col flex-1 overflow-hidden hidden bg-black">
32
+ <div class="flex gap-2 px-2 py-1 bg-base-200 shrink-0">
33
+ <input id="gemini-key" type="password" class="input input-xs input-bordered flex-1 min-w-0" placeholder="GEMINI_API_KEY" />
34
+ <button class="btn btn-xs btn-primary" onclick="window.__debug.runAgent(document.getElementById('gemini-key').value, 'write a file called validate.txt with content hello from agent, then read it back and print the contents')">Run Agent</button>
35
+ </div>
36
+ <div id="term-container" class="flex-1"></div>
34
37
  </div>
35
38
  <div id="pane-preview" class="flex-1 overflow-hidden hidden">
36
39
  <iframe id="preview-frame" class="w-full h-full border-0" src="about:blank"></iframe>
package/docs/terminal.js CHANGED
@@ -2,7 +2,7 @@ import { WebContainer } from 'https://esm.sh/@webcontainer/api';
2
2
  import { Terminal } from 'https://esm.sh/@xterm/xterm';
3
3
  import { FitAddon } from 'https://esm.sh/@xterm/addon-fit';
4
4
 
5
- const IDB_KEY = 'thebird_fs';
5
+ const IDB_KEY = 'thebird_fs_v2';
6
6
 
7
7
  async function idbLoad() {
8
8
  return new Promise((res, rej) => {
@@ -59,13 +59,17 @@ async function boot() {
59
59
  files = await r.json();
60
60
  }
61
61
 
62
- const mountTree = Object.fromEntries(
63
- Object.entries(files).map(([p, c]) => {
64
- const parts = p.split('/');
65
- if (parts.length === 1) return [p, { file: { contents: c } }];
66
- return [p, { file: { contents: c } }];
67
- })
68
- );
62
+ const mountTree = {};
63
+ for (const [path, contents] of Object.entries(files)) {
64
+ const parts = path.split('/');
65
+ const name = parts.pop();
66
+ let node = mountTree;
67
+ for (const dir of parts) {
68
+ if (!node[dir]) node[dir] = { directory: {} };
69
+ node = node[dir].directory;
70
+ }
71
+ node[name] = { file: { contents } };
72
+ }
69
73
 
70
74
  term.write('Booting WebContainer...\r\n');
71
75
  let container;
@@ -112,6 +116,19 @@ async function boot() {
112
116
  window.__debug.previewUrl = null;
113
117
  window.__debug.shell = shell;
114
118
  window.__debug.srv = srv;
119
+ window.__debug.validation = null;
120
+ window.__debug.runAgent = async (key, task) => {
121
+ if (!key) { window.__debug.validation = { error: 'GEMINI_API_KEY required' }; return; }
122
+ window.__debug.validation = { running: true, output: '', exitCode: null };
123
+ const proc = await container.spawn('node', ['agent.js', task], { env: { GEMINI_API_KEY: key } });
124
+ proc.output.pipeTo(new WritableStream({ write: d => {
125
+ window.__debug.validation.output += d;
126
+ term.write(d);
127
+ }}));
128
+ const code = await proc.exit;
129
+ window.__debug.validation.running = false;
130
+ window.__debug.validation.exitCode = code;
131
+ };
115
132
  }
116
133
 
117
134
  boot().catch(e => console.error('[terminal] boot error:', e));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thebird",
3
- "version": "1.2.25",
3
+ "version": "1.2.27",
4
4
  "description": "Anthropic SDK to Gemini streaming bridge — drop-in proxy that translates Anthropic message format and tool calls to Google Gemini",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",