Skip to content

Commit f4cb061

Browse files
authored
Merge branch 'open-gitagent:main' into feature/ui-improvements
2 parents 002d4bf + f5d6c95 commit f4cb061

9 files changed

Lines changed: 624 additions & 30 deletions

File tree

index.html

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,23 @@
1515
<div class="claw-logo"><img src="data:image/png;base64,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" alt="ClawContainer" width="64" height="64" class="loading-logo" /></div>
1616
<p style="margin:0 0 4px;font-size:11px;opacity:.6;letter-spacing:.5px">Built by Shreyas Kapale @ Lyzr</p>
1717
<h2>ClawLess</h2>
18-
<p id="loading-status">Booting WebContainer…</p>
19-
<div class="progress-bar"><div id="progress-fill"></div></div>
18+
<div id="template-picker" style="margin:16px 0">
19+
<p style="font-size:11px;color:#8b949e;margin-bottom:8px;letter-spacing:.3px">Choose your agent template</p>
20+
<div style="display:flex;gap:10px;justify-content:center">
21+
<button class="tpl-btn" data-template="gitclaw">
22+
<span style="font-size:18px">🐙</span>
23+
<strong>GitClaw</strong>
24+
<span style="font-size:10px;color:#8b949e">A better claw</span>
25+
</button>
26+
<button class="tpl-btn" data-template="openclaw">
27+
<span style="font-size:18px">🦞</span>
28+
<strong>OpenClaw</strong>
29+
<span style="font-size:10px;color:#8b949e">A famous claw</span>
30+
</button>
31+
</div>
32+
</div>
33+
<p id="loading-status" style="display:none">Booting WebContainer…</p>
34+
<div class="progress-bar" style="display:none"><div id="progress-fill"></div></div>
2035
</div>
2136
</div>
2237

src/container.ts

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { WebContainer, type WebContainerProcess } from '@webcontainer/api';
22
import type { TerminalManager } from './terminal.js';
3-
import { buildWorkspaceFiles, buildContainerPackageJson, GIT_STUB_JS } from './workspace.js';
3+
import { buildWorkspaceFiles, buildContainerPackageJson, buildStubLoaderRegister, buildStubLoaderHooks, GIT_STUB_JS, OPENCLAW_START_SCRIPT, OPENCLAW_SETUP_SCRIPT } from './workspace.js';
44
import { AuditLog, type AuditSource } from './audit.js';
55
import { NETWORK_HOOK_CJS } from './network-hook.js';
66
import { PolicyEngine, PolicyDeniedError, type PolicyAction } from './policy.js';
@@ -148,7 +148,13 @@ export class ContainerManager {
148148
}
149149

150150
/** Boot the WebContainer and mount all workspace files. */
151-
async boot(opts?: { workspace?: Record<string, string>; services?: Record<string, string> }): Promise<void> {
151+
async boot(opts?: {
152+
workspace?: Record<string, string>;
153+
services?: Record<string, string>;
154+
agentPackage?: string;
155+
agentVersion?: string;
156+
agentOverrides?: Record<string, string>;
157+
}): Promise<void> {
152158
this.setStatus('booting');
153159
this.wc = await WebContainer.boot();
154160

@@ -165,12 +171,28 @@ export class ContainerManager {
165171
for (const fn of this.serverListeners) fn(port, url);
166172
});
167173

168-
await this.wc.mount({
169-
'package.json': { file: { contents: buildContainerPackageJson(opts?.services) } },
174+
const mountTree: Record<string, any> = {
175+
'package.json': { file: { contents: buildContainerPackageJson({
176+
agentPackage: opts?.agentPackage,
177+
agentVersion: opts?.agentVersion,
178+
extraDeps: opts?.services,
179+
extraOverrides: opts?.agentOverrides,
180+
}) } },
170181
'git-stub.js': { file: { contents: GIT_STUB_JS } },
171182
'network-hook.cjs': { file: { contents: NETWORK_HOOK_CJS } },
172183
workspace: { directory: buildWorkspaceFiles(opts?.workspace) },
173-
});
184+
};
185+
186+
// Mount stub loader hooks when native deps are stubbed via overrides
187+
if (opts?.agentOverrides && Object.keys(opts.agentOverrides).length > 0) {
188+
const pkgs = Object.keys(opts.agentOverrides);
189+
mountTree['stub-loader.mjs'] = { file: { contents: buildStubLoaderRegister(pkgs) } };
190+
mountTree['stub-loader-hooks.mjs'] = { file: { contents: buildStubLoaderHooks(pkgs) } };
191+
mountTree['openclaw-start.mjs'] = { file: { contents: OPENCLAW_START_SCRIPT } };
192+
mountTree['openclaw-setup.cjs'] = { file: { contents: OPENCLAW_SETUP_SCRIPT } };
193+
}
194+
195+
await this.wc.mount(mountTree);
174196

175197
this.audit?.log('boot.mount', 'mounted workspace files', {
176198
files: ['package.json', 'git-stub.js', 'network-hook.cjs', 'workspace/'],
@@ -627,14 +649,19 @@ export class ContainerManager {
627649
this.audit?.log('process.spawn', spawnCmd, undefined, { source: 'agent' });
628650
this.activeProcessCount++;
629651

652+
const nodeOptions = [`--require ${homeDir}/network-hook.cjs`];
653+
if (config.overrides && Object.keys(config.overrides).length > 0) {
654+
nodeOptions.push(`--import ${homeDir}/stub-loader.mjs`);
655+
}
656+
630657
this.shellProcess = await this.wc.spawn('node', [entry, ...args], {
631658
terminal: { cols, rows },
632659
env: {
633660
...this.apiEnvVars,
634661
...config.env,
635662
PATH: `${homeDir}/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`,
636663
HOME: homeDir,
637-
NODE_OPTIONS: `--require ${homeDir}/network-hook.cjs`,
664+
NODE_OPTIONS: nodeOptions.join(' '),
638665
},
639666
});
640667

src/main.ts

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,44 @@
11
import { ClawContainer } from './sdk.js';
22

3-
// ─── Boot sequence ───────────────────────────────────────────────────────────
3+
// ─── Template Selection → Boot ──────────────────────────────────────────────
44

5-
const cc = new ClawContainer('#app');
6-
cc.start().catch(console.error);
5+
function waitForTemplateSelection(): Promise<string> {
6+
return new Promise((resolve) => {
7+
// Pre-select the last used template (but still require a click)
8+
const saved = localStorage.getItem('clawchef_template');
9+
const buttons = document.querySelectorAll<HTMLButtonElement>('.tpl-btn');
10+
if (saved) {
11+
buttons.forEach((btn) => {
12+
if (btn.dataset['template'] === saved) btn.classList.add('tpl-btn-last');
13+
});
14+
}
715

8-
// Expose SDK globally for console access and external scripts
9-
(window as any).clawcontainer = cc;
16+
buttons.forEach((btn) => {
17+
btn.addEventListener('click', () => {
18+
const template = btn.dataset['template'] ?? 'gitclaw';
19+
localStorage.setItem('clawchef_template', template);
20+
resolve(template);
21+
});
22+
});
23+
});
24+
}
25+
26+
async function boot() {
27+
const template = await waitForTemplateSelection();
28+
29+
// Hide picker, show loading status
30+
const picker = document.getElementById('template-picker');
31+
const status = document.getElementById('loading-status');
32+
const progressBar = status?.nextElementSibling as HTMLElement | null;
33+
if (picker) picker.style.display = 'none';
34+
if (status) status.style.display = '';
35+
if (progressBar) progressBar.style.display = '';
36+
37+
const cc = new ClawContainer('#app', { template });
38+
cc.start().catch(console.error);
39+
40+
// Expose SDK globally for console access and external scripts
41+
(window as any).clawcontainer = cc;
42+
}
43+
44+
boot();

src/sdk.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ export class ClawContainer extends TypedEventEmitter<ClawContainerEvents> implem
153153
const extraWorkspace = { ...this._plugins.mergedWorkspace, ...opts.workspace };
154154
const extraEnv = { ...this._plugins.mergedEnv, ...opts.env };
155155

156+
// Extract agent config for boot (package.json generation)
157+
const resolvedAgent = opts.agent !== false ? opts.agent as AgentConfig | undefined : undefined;
158+
156159
// Step 1: Boot
157160
this._terminal.write('\x1b[90m[ClawLess] Booting WebContainer…\x1b[0m\r\n');
158161
this._audit.log('status.change', 'boot sequence started', undefined, { source: 'boot' });
@@ -161,6 +164,9 @@ export class ClawContainer extends TypedEventEmitter<ClawContainerEvents> implem
161164
await this._container.boot({
162165
workspace: Object.keys(extraWorkspace).length > 0 ? extraWorkspace : undefined,
163166
services: Object.keys(extraServices).length > 0 ? extraServices : undefined,
167+
agentPackage: resolvedAgent?.package,
168+
agentVersion: resolvedAgent?.version,
169+
agentOverrides: resolvedAgent?.overrides,
164170
});
165171
this._audit.log('status.change', 'webcontainer booted', undefined, { source: 'boot' });
166172
} catch (e) {
@@ -214,29 +220,29 @@ export class ClawContainer extends TypedEventEmitter<ClawContainerEvents> implem
214220
const config = agentConfig as AgentConfig;
215221
const isGitclaw = config.package === 'gitclaw';
216222

217-
if (isGitclaw) {
218-
// Gitclaw flow — check API keys
219-
const savedConfig = this._ui.getSavedConfig();
220-
if (!savedConfig) {
221-
this._ui.showConfigPanel();
222-
this._terminal.write('\x1b[33m[ClawLess] Configure your API key in the sidebar to continue.\x1b[0m\r\n\r\n');
223-
await this.waitForConfig();
224-
}
223+
// Prompt for API key if not yet configured
224+
const savedConfig = this._ui.getSavedConfig();
225+
if (!savedConfig) {
226+
this._ui.showConfigPanel();
227+
this._terminal.write('\x1b[33m[ClawLess] Configure your API key in the sidebar to continue.\x1b[0m\r\n\r\n');
228+
await this.waitForConfig();
229+
}
230+
231+
const envConfig = this._ui.getSavedConfig()!;
232+
await this._container.configureEnv(envConfig);
225233

226-
const envConfig = this._ui.getSavedConfig()!;
234+
if (isGitclaw) {
227235
this._terminal.write('\x1b[90m[ClawLess] Launching gitclaw…\x1b[0m\r\n\r\n');
228236
this._audit.log('status.change', 'launching gitclaw', undefined, { source: 'boot' });
229237

230238
try {
231-
await this._container.configureEnv(envConfig);
232239
await this._container.startGitclaw(this._terminal);
233240
} catch (e) {
234241
this._terminal.write(`\r\n\x1b[31m[ClawLess] Launch failed: ${(e as Error).message}\x1b[0m\r\n`);
235242
this.emit('error', e as Error);
236243
return;
237244
}
238245
} else {
239-
// Custom agent config
240246
this._terminal.write(`\x1b[90m[ClawLess] Launching agent (${config.package})…\x1b[0m\r\n\r\n`);
241247
this._audit.log('status.change', `launching ${config.package}`, undefined, { source: 'boot' });
242248

src/style.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ html, body { height: 100%; background: var(--bg); color: var(--text);
4141
#progress-fill { height: 100%; width: 0%; background: var(--accent);
4242
transition: width 0.3s ease; }
4343

44+
/* Template picker buttons */
45+
.tpl-btn {
46+
display: flex; flex-direction: column; align-items: center; gap: 4px;
47+
padding: 14px 28px; border-radius: 10px; border: 1px solid var(--border);
48+
background: var(--bg2); color: var(--text); cursor: pointer;
49+
transition: all 0.15s ease; min-width: 120px;
50+
}
51+
.tpl-btn-last { border-color: var(--accent); opacity: 1; }
52+
.tpl-btn:hover { border-color: var(--accent); background: var(--bg3); transform: translateY(-2px); }
53+
.tpl-btn:active { transform: translateY(0); }
54+
.tpl-btn strong { font-size: 13px; }
55+
4456
/* ─── App shell ─────────────────────────────────────────────────── */
4557
#app { display: flex; flex-direction: column; height: 100vh; }
4658

0 commit comments

Comments
 (0)