clawcontainer 1.0.0
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/CONTRIBUTING.md +76 -0
- package/DOCS.md +370 -0
- package/LICENSE +21 -0
- package/README.md +147 -0
- package/black_logo.png +0 -0
- package/dist/assets/abap-DLDM7-KI.js +1 -0
- package/dist/assets/apex-DNDY2TF8.js +1 -0
- package/dist/assets/azcli-Y6nb8tq_.js +1 -0
- package/dist/assets/bat-BwHxbl9M.js +1 -0
- package/dist/assets/bicep-CFznDFnq.js +2 -0
- package/dist/assets/cameligo-Bf6VGUru.js +1 -0
- package/dist/assets/clojure-Dnu-v4kV.js +1 -0
- package/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
- package/dist/assets/coffee-Bd8akH9Z.js +1 -0
- package/dist/assets/cpp-BbWJElDN.js +1 -0
- package/dist/assets/csharp-Co3qMtFm.js +1 -0
- package/dist/assets/csp-D-4FJmMZ.js +1 -0
- package/dist/assets/css-DdJfP1eB.js +3 -0
- package/dist/assets/css.worker-GxEd3MMM.js +93 -0
- package/dist/assets/cssMode-DM_ONlf-.js +1 -0
- package/dist/assets/cypher-cTPe9QuQ.js +1 -0
- package/dist/assets/dart-BOtBlQCF.js +1 -0
- package/dist/assets/dockerfile-BG73LgW2.js +1 -0
- package/dist/assets/ecl-BEgZUVRK.js +1 -0
- package/dist/assets/elixir-BkW5O-1t.js +1 -0
- package/dist/assets/flow9-BeJ5waoc.js +1 -0
- package/dist/assets/freemarker2-VbwzOQPq.js +3 -0
- package/dist/assets/fsharp-PahG7c26.js +1 -0
- package/dist/assets/go-acbASCJo.js +1 -0
- package/dist/assets/graphql-BxJiqAUM.js +1 -0
- package/dist/assets/handlebars-DLvQ802u.js +1 -0
- package/dist/assets/hcl-DtV1sZF8.js +1 -0
- package/dist/assets/html-DuEPBzmS.js +1 -0
- package/dist/assets/html.worker-lU17Tx2m.js +470 -0
- package/dist/assets/htmlMode-BfeYTJaB.js +1 -0
- package/dist/assets/index-BnBKg8GZ.js +1291 -0
- package/dist/assets/index-Dq3FlPWe.css +32 -0
- package/dist/assets/ini-Kd9XrMLS.js +1 -0
- package/dist/assets/java-CXBNlu9o.js +1 -0
- package/dist/assets/javascript-DQO1Leza.js +1 -0
- package/dist/assets/json.worker-CUJs-dtA.js +58 -0
- package/dist/assets/jsonMode--qsURhHr.js +7 -0
- package/dist/assets/julia-cl7-CwDS.js +1 -0
- package/dist/assets/kotlin-s7OhZKlX.js +1 -0
- package/dist/assets/less-9HpZscsL.js +2 -0
- package/dist/assets/lexon-OrD6JF1K.js +1 -0
- package/dist/assets/liquid-PL6MZtM8.js +1 -0
- package/dist/assets/lspLanguageFeatures-Cy5rDFeq.js +4 -0
- package/dist/assets/lua-Cyyb5UIc.js +1 -0
- package/dist/assets/m3-B8OfTtLu.js +1 -0
- package/dist/assets/markdown-BFxVWTOG.js +1 -0
- package/dist/assets/mdx-Cb3Jy14X.js +1 -0
- package/dist/assets/mips-CiqrrVzr.js +1 -0
- package/dist/assets/msdax-DmeGPVcC.js +1 -0
- package/dist/assets/mysql-C_tMU-Nz.js +1 -0
- package/dist/assets/objective-c-BDtDVThU.js +1 -0
- package/dist/assets/pascal-vHIfCaH5.js +1 -0
- package/dist/assets/pascaligo-DtZ0uQbO.js +1 -0
- package/dist/assets/perl-Ub6l9XKa.js +1 -0
- package/dist/assets/pgsql-BlNEE0v7.js +1 -0
- package/dist/assets/php-BBUBE1dy.js +1 -0
- package/dist/assets/pla-DSh2-awV.js +1 -0
- package/dist/assets/postiats-CocnycG-.js +1 -0
- package/dist/assets/powerquery-tScXyioY.js +1 -0
- package/dist/assets/powershell-COWaemsV.js +1 -0
- package/dist/assets/protobuf-Brw8urJB.js +2 -0
- package/dist/assets/pug-8SOpv6rk.js +1 -0
- package/dist/assets/python-Usm4OUwq.js +1 -0
- package/dist/assets/qsharp-Bw9ernYp.js +1 -0
- package/dist/assets/r-j7ic8hl3.js +1 -0
- package/dist/assets/razor-BIOole7a.js +1 -0
- package/dist/assets/redis-Bu5POkcn.js +1 -0
- package/dist/assets/redshift-Bs9aos_-.js +1 -0
- package/dist/assets/restructuredtext-CqXO7rUv.js +1 -0
- package/dist/assets/ruby-zBfavPgS.js +1 -0
- package/dist/assets/rust-BzKRNQWT.js +1 -0
- package/dist/assets/sb-BBc9UKZt.js +1 -0
- package/dist/assets/scala-D9hQfWCl.js +1 -0
- package/dist/assets/scheme-BPhDTwHR.js +1 -0
- package/dist/assets/scss-CBJaRo0y.js +3 -0
- package/dist/assets/shell-DiJ1NA_G.js +1 -0
- package/dist/assets/solidity-Db0IVjzk.js +1 -0
- package/dist/assets/sophia-CnS9iZB_.js +1 -0
- package/dist/assets/sparql-CJmd_6j2.js +1 -0
- package/dist/assets/sql-ClhHkBeG.js +1 -0
- package/dist/assets/st-CHwy0fLd.js +1 -0
- package/dist/assets/swift-Bqt4WxQ4.js +3 -0
- package/dist/assets/systemverilog-Bs9z6M-B.js +1 -0
- package/dist/assets/tcl-Dm6ycUr_.js +1 -0
- package/dist/assets/ts.worker-Dy9lDQQT.js +67731 -0
- package/dist/assets/tsMode-CDjF3DWK.js +11 -0
- package/dist/assets/twig-Csy3S7wG.js +1 -0
- package/dist/assets/typescript-CJR4sLnG.js +1 -0
- package/dist/assets/typespec-Btyra-wh.js +1 -0
- package/dist/assets/vb-Db0cS2oM.js +1 -0
- package/dist/assets/wgsl-DumH7NcR.js +298 -0
- package/dist/assets/xml-CJZS3uh7.js +1 -0
- package/dist/assets/yaml-DB88cW5z.js +1 -0
- package/dist/audit.d.ts +48 -0
- package/dist/container.d.ts +100 -0
- package/dist/event-emitter.d.ts +7 -0
- package/dist/favicon.png +0 -0
- package/dist/git-service.d.ts +31 -0
- package/dist/index.html +188 -0
- package/dist/logo-sm.png +0 -0
- package/dist/logo.png +0 -0
- package/dist/main.d.ts +1 -0
- package/dist/monaco-editor.d.ts +11 -0
- package/dist/monacoeditorwork/css.worker.bundle.js +54264 -0
- package/dist/monacoeditorwork/editor.worker.bundle.js +14317 -0
- package/dist/monacoeditorwork/html.worker.bundle.js +30449 -0
- package/dist/monacoeditorwork/json.worker.bundle.js +22085 -0
- package/dist/monacoeditorwork/ts.worker.bundle.js +225552 -0
- package/dist/net-intercept.d.ts +2 -0
- package/dist/network-hook.d.ts +1 -0
- package/dist/plugin.d.ts +20 -0
- package/dist/policy.d.ts +58 -0
- package/dist/sdk.d.ts +61 -0
- package/dist/tab-manager.d.ts +11 -0
- package/dist/templates.d.ts +46 -0
- package/dist/terminal.d.ts +19 -0
- package/dist/types.d.ts +109 -0
- package/dist/ui.d.ts +81 -0
- package/dist/workspace.d.ts +16 -0
- package/index.html +159 -0
- package/logo.png +0 -0
- package/package.json +31 -0
- package/public/favicon.png +0 -0
- package/public/logo-sm.png +0 -0
- package/public/logo.png +0 -0
- package/src/audit.ts +196 -0
- package/src/container.ts +723 -0
- package/src/event-emitter.ts +28 -0
- package/src/git-service.ts +202 -0
- package/src/main.ts +9 -0
- package/src/monaco-editor.ts +111 -0
- package/src/net-intercept.ts +74 -0
- package/src/network-hook.ts +248 -0
- package/src/plugin.ts +63 -0
- package/src/policy.ts +403 -0
- package/src/sdk.ts +355 -0
- package/src/style.css +432 -0
- package/src/tab-manager.ts +30 -0
- package/src/templates.ts +271 -0
- package/src/terminal.ts +78 -0
- package/src/types.ts +113 -0
- package/src/ui.ts +1266 -0
- package/src/workspace.ts +107 -0
- package/tsconfig.json +20 -0
- package/vite.config.ts +52 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const NETWORK_HOOK_CJS = "'use strict';\n// \u2500\u2500 network-hook.cjs \u2500\u2500 injected via NODE_OPTIONS=--require \u2500\u2500\n\n// Skip logging when running inside npm to avoid flooding with registry requests\nif (process.env.npm_execpath || process.env.npm_lifecycle_event) {\n return;\n}\n\n(function () {\n var MARKER = '__NET_AUDIT__:';\n\n function maskVal(v) {\n if (!v || typeof v !== 'string') return '****';\n if (v.length <= 12) return '****';\n return v.slice(0, 7) + '...' + v.slice(-4);\n }\n\n var SENSITIVE = /^(authorization|x-api-key|api-key|x-goog-api-key)$/i;\n var SENSITIVE_PARTIAL = /secret|token/i;\n\n function maskHeaders(h) {\n if (!h || typeof h !== 'object') return {};\n var out = {};\n var keys = Object.keys(h);\n for (var i = 0; i < keys.length; i++) {\n var k = keys[i];\n var v = typeof h[k] === 'string' ? h[k] : String(h[k]);\n if (SENSITIVE.test(k) || SENSITIVE_PARTIAL.test(k)) {\n out[k] = maskVal(v);\n } else {\n out[k] = v;\n }\n }\n return out;\n }\n\n function emit(obj) {\n try {\n process.stderr.write(MARKER + JSON.stringify(obj) + '\\n');\n } catch (_) {\n // never crash the host process\n }\n }\n\n function buildUrl(opts) {\n if (typeof opts === 'string') return opts;\n if (opts && opts.href) return opts.href;\n if (!opts) return '<unknown>';\n var proto = opts.protocol || 'https:';\n var host = opts.hostname || opts.host || 'localhost';\n var port = opts.port ? ':' + opts.port : '';\n var path = opts.path || '/';\n return proto + '//' + host + port + path;\n }\n\n var BODY_MAX = 2000;\n\n // \u2500\u2500 Patch http/https \u2500\u2500\n\n function patchModule(modName) {\n try {\n var mod = require(modName);\n } catch (_) {\n return;\n }\n\n var origRequest = mod.request;\n var origGet = mod.get;\n\n function wrapRequest(orig) {\n return function patchedRequest(urlOrOpts, optsOrCb, maybeCb) {\n var opts, cb;\n if (typeof urlOrOpts === 'string' || (urlOrOpts && typeof urlOrOpts.href === 'string')) {\n opts = typeof optsOrCb === 'object' ? optsOrCb : {};\n cb = typeof optsOrCb === 'function' ? optsOrCb : maybeCb;\n } else {\n opts = urlOrOpts || {};\n cb = typeof optsOrCb === 'function' ? optsOrCb : maybeCb;\n }\n\n var url = buildUrl(urlOrOpts) !== '<unknown>' ? buildUrl(urlOrOpts) : buildUrl(opts);\n var method = (opts.method || 'GET').toUpperCase();\n var hdrs = opts.headers ? maskHeaders(opts.headers) : {};\n var startTime = Date.now();\n\n emit({\n type: 'request',\n url: url,\n method: method,\n headers: hdrs,\n ts: new Date().toISOString(),\n });\n\n var req = orig.apply(this, arguments);\n\n // Capture request body\n var bodyChunks = [];\n var bodyLen = 0;\n var origWrite = req.write;\n var origEnd = req.end;\n\n req.write = function (chunk) {\n if (bodyLen < BODY_MAX && chunk) {\n var s = typeof chunk === 'string' ? chunk : chunk.toString('utf-8');\n bodyChunks.push(s.slice(0, BODY_MAX - bodyLen));\n bodyLen += s.length;\n }\n return origWrite.apply(req, arguments);\n };\n\n req.end = function (chunk) {\n if (bodyLen < BODY_MAX && chunk && typeof chunk !== 'function') {\n var s = typeof chunk === 'string' ? chunk : (Buffer.isBuffer(chunk) ? chunk.toString('utf-8') : '');\n if (s) {\n bodyChunks.push(s.slice(0, BODY_MAX - bodyLen));\n bodyLen += s.length;\n }\n }\n\n if (bodyChunks.length > 0) {\n var body = bodyChunks.join('');\n emit({\n type: 'request.body',\n url: url,\n method: method,\n bodyPreview: body.length > BODY_MAX ? body.slice(0, BODY_MAX) + '...[truncated]' : body,\n ts: new Date().toISOString(),\n });\n }\n\n return origEnd.apply(req, arguments);\n };\n\n // Capture response\n req.on('response', function (res) {\n var durationMs = Date.now() - startTime;\n emit({\n type: 'response',\n url: url,\n method: method,\n status: res.statusCode,\n headers: maskHeaders(res.headers),\n durationMs: durationMs,\n ts: new Date().toISOString(),\n });\n });\n\n req.on('error', function (err) {\n var durationMs = Date.now() - startTime;\n emit({\n type: 'response',\n url: url,\n method: method,\n error: err.message,\n durationMs: durationMs,\n ts: new Date().toISOString(),\n });\n });\n\n return req;\n };\n }\n\n mod.request = wrapRequest(origRequest);\n mod.get = wrapRequest(origGet);\n }\n\n patchModule('http');\n patchModule('https');\n\n // \u2500\u2500 Patch globalThis.fetch (Node 18+) \u2500\u2500\n\n if (typeof globalThis.fetch === 'function') {\n var origFetch = globalThis.fetch;\n\n globalThis.fetch = function patchedFetch(input, init) {\n var url = typeof input === 'string' ? input\n : (input && input.url) ? input.url\n : String(input);\n var method = ((init && init.method) || (input && input.method) || 'GET').toUpperCase();\n\n var rawHeaders = {};\n var hdrSrc = (init && init.headers) || (input && input.headers);\n if (hdrSrc && typeof hdrSrc === 'object') {\n if (typeof hdrSrc.forEach === 'function') {\n hdrSrc.forEach(function (v, k) { rawHeaders[k] = v; });\n } else {\n var keys = Object.keys(hdrSrc);\n for (var i = 0; i < keys.length; i++) rawHeaders[keys[i]] = String(hdrSrc[keys[i]]);\n }\n }\n\n var bodyPreview;\n var bodySrc = (init && init.body) || (input && input.body);\n if (typeof bodySrc === 'string') {\n bodyPreview = bodySrc.length > BODY_MAX ? bodySrc.slice(0, BODY_MAX) + '...[truncated]' : bodySrc;\n }\n\n var startTime = Date.now();\n\n emit({\n type: 'request',\n url: url,\n method: method,\n headers: maskHeaders(rawHeaders),\n bodyPreview: bodyPreview,\n ts: new Date().toISOString(),\n });\n\n return origFetch.apply(globalThis, arguments).then(function (resp) {\n var durationMs = Date.now() - startTime;\n var respHeaders = {};\n if (resp.headers && typeof resp.headers.forEach === 'function') {\n resp.headers.forEach(function (v, k) { respHeaders[k] = v; });\n }\n\n emit({\n type: 'response',\n url: url,\n method: method,\n status: resp.status,\n headers: respHeaders,\n durationMs: durationMs,\n ts: new Date().toISOString(),\n });\n\n return resp;\n }, function (err) {\n var durationMs = Date.now() - startTime;\n emit({\n type: 'response',\n url: url,\n method: method,\n error: err.message,\n durationMs: durationMs,\n ts: new Date().toISOString(),\n });\n throw err;\n });\n };\n }\n})();\n";
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ClawContainerPlugin, ClawContainerSDK, TabDefinition } from './types.js';
|
|
2
|
+
export declare class PluginManager {
|
|
3
|
+
private plugins;
|
|
4
|
+
/** Register a plugin, storing it for lifecycle dispatch. */
|
|
5
|
+
register(plugin: ClawContainerPlugin): void;
|
|
6
|
+
/** Dispatch onInit to all registered plugins in order. */
|
|
7
|
+
dispatchInit(cc: ClawContainerSDK): void;
|
|
8
|
+
/** Dispatch onReady to all registered plugins in order. */
|
|
9
|
+
dispatchReady(cc: ClawContainerSDK): void;
|
|
10
|
+
/** Dispatch onDestroy to all registered plugins in order. */
|
|
11
|
+
dispatchDestroy(cc: ClawContainerSDK): void;
|
|
12
|
+
/** Collect merged extra npm dependencies from all plugins. */
|
|
13
|
+
get mergedServices(): Record<string, string>;
|
|
14
|
+
/** Collect merged extra workspace files from all plugins. */
|
|
15
|
+
get mergedWorkspace(): Record<string, string>;
|
|
16
|
+
/** Collect merged extra env vars from all plugins. */
|
|
17
|
+
get mergedEnv(): Record<string, string>;
|
|
18
|
+
/** Collect all tab definitions from plugins. */
|
|
19
|
+
get mergedTabs(): TabDefinition[];
|
|
20
|
+
}
|
package/dist/policy.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export type PolicyAction = 'file.read' | 'file.write' | 'process.spawn' | 'server.bind' | 'env.configure' | 'tool.use' | 'git.clone' | 'git.push';
|
|
2
|
+
export interface FileRule {
|
|
3
|
+
pattern: string;
|
|
4
|
+
allow: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface ProcessRule {
|
|
7
|
+
pattern: string;
|
|
8
|
+
allow: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface PortRule {
|
|
11
|
+
port: number | '*';
|
|
12
|
+
allow: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface ToolRule {
|
|
15
|
+
name: string;
|
|
16
|
+
allow: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface RuntimeLimits {
|
|
19
|
+
maxFileSize: number;
|
|
20
|
+
maxProcesses: number;
|
|
21
|
+
maxTurns: number;
|
|
22
|
+
timeoutSec: number;
|
|
23
|
+
}
|
|
24
|
+
export interface Policy {
|
|
25
|
+
version: '1';
|
|
26
|
+
mode: 'allow-all' | 'deny-all';
|
|
27
|
+
files: {
|
|
28
|
+
read: FileRule[];
|
|
29
|
+
write: FileRule[];
|
|
30
|
+
};
|
|
31
|
+
processes: ProcessRule[];
|
|
32
|
+
ports: PortRule[];
|
|
33
|
+
tools: ToolRule[];
|
|
34
|
+
limits: RuntimeLimits;
|
|
35
|
+
}
|
|
36
|
+
export interface CheckResult {
|
|
37
|
+
allowed: boolean;
|
|
38
|
+
rule?: string;
|
|
39
|
+
action: PolicyAction;
|
|
40
|
+
subject: string;
|
|
41
|
+
}
|
|
42
|
+
export declare class PolicyDeniedError extends Error {
|
|
43
|
+
action: PolicyAction;
|
|
44
|
+
subject: string;
|
|
45
|
+
rule: string;
|
|
46
|
+
constructor(action: PolicyAction, subject: string, rule: string);
|
|
47
|
+
}
|
|
48
|
+
export declare class PolicyEngine {
|
|
49
|
+
private policy;
|
|
50
|
+
constructor(policy?: Policy);
|
|
51
|
+
loadPolicy(policy: Policy): void;
|
|
52
|
+
getPolicy(): Policy;
|
|
53
|
+
check(action: PolicyAction, subject: string, meta?: Record<string, unknown>): CheckResult;
|
|
54
|
+
enforce(action: PolicyAction, subject: string, meta?: Record<string, unknown>): CheckResult;
|
|
55
|
+
toYaml(): string;
|
|
56
|
+
static fromYaml(yaml: string): Policy;
|
|
57
|
+
static defaultPolicy(): Policy;
|
|
58
|
+
}
|
package/dist/sdk.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { WebContainer } from '@webcontainer/api';
|
|
2
|
+
import { TerminalManager } from './terminal.js';
|
|
3
|
+
import { type AuditEntry, type AuditSource, type AuditLevel, type AuditEvent } from './audit.js';
|
|
4
|
+
import { TypedEventEmitter } from './event-emitter.js';
|
|
5
|
+
import type { ClawContainerOptions, ClawContainerPlugin, ClawContainerEvents, ClawContainerSDK, TabDefinition } from './types.js';
|
|
6
|
+
import { type ContainerTemplate } from './templates.js';
|
|
7
|
+
export declare class ClawContainer extends TypedEventEmitter<ClawContainerEvents> implements ClawContainerSDK {
|
|
8
|
+
private static _templateRegistry;
|
|
9
|
+
/** Registered templates (read-only). */
|
|
10
|
+
static get templates(): Map<string, ContainerTemplate>;
|
|
11
|
+
/** Register a named template for reuse. */
|
|
12
|
+
static registerTemplate(template: ContainerTemplate): void;
|
|
13
|
+
/** Parse a YAML string into a ContainerTemplate. */
|
|
14
|
+
static parseTemplate(yaml: string): ContainerTemplate;
|
|
15
|
+
private _container;
|
|
16
|
+
private _terminal;
|
|
17
|
+
private _ui;
|
|
18
|
+
private _audit;
|
|
19
|
+
private _policy;
|
|
20
|
+
private _plugins;
|
|
21
|
+
private _tabs;
|
|
22
|
+
private _options;
|
|
23
|
+
private _selector;
|
|
24
|
+
private _started;
|
|
25
|
+
constructor(selector: string, options?: ClawContainerOptions);
|
|
26
|
+
/** Raw WebContainer instance for direct access. */
|
|
27
|
+
get container(): WebContainer | null;
|
|
28
|
+
/** Terminal manager instance. */
|
|
29
|
+
get terminal(): TerminalManager;
|
|
30
|
+
start(): Promise<void>;
|
|
31
|
+
stop(): Promise<void>;
|
|
32
|
+
restart(): Promise<void>;
|
|
33
|
+
/** Run any shell command and return stdout. */
|
|
34
|
+
exec(cmd: string): Promise<string>;
|
|
35
|
+
/** Open a raw interactive shell. */
|
|
36
|
+
shell(): Promise<void>;
|
|
37
|
+
/** Write data to the active process stdin. */
|
|
38
|
+
sendInput(data: string): Promise<void>;
|
|
39
|
+
fs: {
|
|
40
|
+
read: (path: string) => Promise<string>;
|
|
41
|
+
write: (path: string, content: string) => Promise<void>;
|
|
42
|
+
list: (dir?: string) => Promise<string[]>;
|
|
43
|
+
mkdir: (path: string) => Promise<void>;
|
|
44
|
+
remove: (path: string) => Promise<void>;
|
|
45
|
+
};
|
|
46
|
+
git: {
|
|
47
|
+
clone: (url: string, token: string) => Promise<void>;
|
|
48
|
+
push: (message?: string) => Promise<string>;
|
|
49
|
+
};
|
|
50
|
+
/** Get audit log entries, optionally filtered. */
|
|
51
|
+
logs(filter?: {
|
|
52
|
+
source?: AuditSource;
|
|
53
|
+
level?: AuditLevel;
|
|
54
|
+
event?: AuditEvent;
|
|
55
|
+
}): AuditEntry[];
|
|
56
|
+
/** Register a plugin. Must be called before start(). */
|
|
57
|
+
use(plugin: ClawContainerPlugin): void;
|
|
58
|
+
addTab(def: TabDefinition): void;
|
|
59
|
+
removeTab(id: string): void;
|
|
60
|
+
private waitForConfig;
|
|
61
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TabDefinition } from './types.js';
|
|
2
|
+
import type { UIManager } from './ui.js';
|
|
3
|
+
export declare class TabManager {
|
|
4
|
+
private ui;
|
|
5
|
+
private customTabs;
|
|
6
|
+
constructor(ui: UIManager);
|
|
7
|
+
/** Add a custom tab to the UI. Delegates to UIManager's addCustomTab. */
|
|
8
|
+
addTab(def: TabDefinition): void;
|
|
9
|
+
/** Remove a custom tab from the UI. */
|
|
10
|
+
removeTab(id: string): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { AgentConfig, ClawContainerOptions, TabDefinition } from './types.js';
|
|
2
|
+
/** A named, reusable container configuration preset. */
|
|
3
|
+
export interface ContainerTemplate {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
agent?: AgentConfig | false;
|
|
7
|
+
workspace?: Record<string, string>;
|
|
8
|
+
services?: Record<string, string>;
|
|
9
|
+
env?: Record<string, string>;
|
|
10
|
+
startupScript?: string;
|
|
11
|
+
tabs?: TabDefinition[];
|
|
12
|
+
}
|
|
13
|
+
/** Built-in gitclaw template — mirrors the previous hardcoded defaults. */
|
|
14
|
+
export declare const GITCLAW_TEMPLATE: ContainerTemplate;
|
|
15
|
+
export declare class TemplateRegistry {
|
|
16
|
+
private templates;
|
|
17
|
+
constructor();
|
|
18
|
+
register(template: ContainerTemplate): void;
|
|
19
|
+
get(name: string): ContainerTemplate | undefined;
|
|
20
|
+
has(name: string): boolean;
|
|
21
|
+
list(): string[];
|
|
22
|
+
/** Expose the internal map (read-only use). */
|
|
23
|
+
get all(): Map<string, ContainerTemplate>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolve a template input to a concrete ContainerTemplate.
|
|
27
|
+
* - string → lookup by name in registry
|
|
28
|
+
* - object → use directly
|
|
29
|
+
* - undefined → default to 'gitclaw'
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveTemplate(input: string | ContainerTemplate | undefined, registry: TemplateRegistry): ContainerTemplate;
|
|
32
|
+
/**
|
|
33
|
+
* Merge a resolved template with user-supplied ClawContainerOptions.
|
|
34
|
+
* Options win for conflicts. Record fields (workspace, services, env) are merged per-key.
|
|
35
|
+
* Scalar fields (agent, startupScript) are replaced when present in options.
|
|
36
|
+
*/
|
|
37
|
+
export declare function mergeTemplateWithOptions(template: ContainerTemplate, options: ClawContainerOptions): ClawContainerOptions;
|
|
38
|
+
/**
|
|
39
|
+
* Parse a YAML string into a ContainerTemplate.
|
|
40
|
+
* Supports the simple subset needed for template definitions:
|
|
41
|
+
* - Top-level scalar keys (name, description, startupScript)
|
|
42
|
+
* - Top-level `agent:` with nested scalar keys + args/env
|
|
43
|
+
* - Top-level Record sections (workspace, services, env)
|
|
44
|
+
* - `agent: false` to skip agent launch
|
|
45
|
+
*/
|
|
46
|
+
export declare function parseTemplateYaml(yaml: string): ContainerTemplate;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Terminal } from '@xterm/xterm';
|
|
2
|
+
export declare class TerminalManager {
|
|
3
|
+
readonly xterm: Terminal;
|
|
4
|
+
private readonly fitAddon;
|
|
5
|
+
private resizeObserver;
|
|
6
|
+
constructor();
|
|
7
|
+
/** Mount the terminal into a DOM element and start auto-resize. */
|
|
8
|
+
mount(container: HTMLElement): void;
|
|
9
|
+
/** Write text/bytes to the terminal display (not to stdin). */
|
|
10
|
+
write(data: string | Uint8Array): void;
|
|
11
|
+
/** Register a handler for user keystrokes (sent to shell stdin). */
|
|
12
|
+
onData(handler: (data: string) => void): void;
|
|
13
|
+
/** Current terminal dimensions for pty resize. */
|
|
14
|
+
get dimensions(): {
|
|
15
|
+
cols: number;
|
|
16
|
+
rows: number;
|
|
17
|
+
};
|
|
18
|
+
dispose(): void;
|
|
19
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { WebContainer } from '@webcontainer/api';
|
|
2
|
+
import type { AuditEntry, AuditSource, AuditLevel, AuditEvent } from './audit.js';
|
|
3
|
+
import type { ContainerTemplate } from './templates.js';
|
|
4
|
+
/** Configuration for launching an agent inside the container. */
|
|
5
|
+
export interface AgentConfig {
|
|
6
|
+
/** npm package name (e.g. 'gitclaw') */
|
|
7
|
+
package: string;
|
|
8
|
+
/** Package version (e.g. '1.1.4'). Defaults to 'latest'. */
|
|
9
|
+
version?: string;
|
|
10
|
+
/** Entry file relative to the package directory (e.g. 'dist/index.js') */
|
|
11
|
+
entry: string;
|
|
12
|
+
/** Extra CLI args passed to node */
|
|
13
|
+
args?: string[];
|
|
14
|
+
/** Extra environment variables for the agent process */
|
|
15
|
+
env?: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
/** Options for creating a ClawContainer instance. */
|
|
18
|
+
export interface ClawContainerOptions {
|
|
19
|
+
/** Agent to launch. Pass `false` to skip agent launch entirely. Default: gitclaw. */
|
|
20
|
+
agent?: AgentConfig | false;
|
|
21
|
+
/** Extra workspace files to mount: flat map of relative path → content */
|
|
22
|
+
workspace?: Record<string, string>;
|
|
23
|
+
/** Extra npm dependencies to install: package → version */
|
|
24
|
+
services?: Record<string, string>;
|
|
25
|
+
/** Environment variables injected into the container */
|
|
26
|
+
env?: Record<string, string>;
|
|
27
|
+
/** Shell script to run after install, before agent launch */
|
|
28
|
+
startupScript?: string;
|
|
29
|
+
/** Template to use: name of a registered template, or a ContainerTemplate object. Default: 'gitclaw'. */
|
|
30
|
+
template?: string | ContainerTemplate;
|
|
31
|
+
/** Plugins to register before start */
|
|
32
|
+
plugins?: ClawContainerPlugin[];
|
|
33
|
+
/** Custom tabs to add on start */
|
|
34
|
+
tabs?: TabDefinition[];
|
|
35
|
+
}
|
|
36
|
+
/** Definition for a custom UI tab. */
|
|
37
|
+
export interface TabDefinition {
|
|
38
|
+
/** Unique identifier for the tab */
|
|
39
|
+
id: string;
|
|
40
|
+
/** Display label in the tab bar */
|
|
41
|
+
label: string;
|
|
42
|
+
/** HTML content or a callback that receives the content container */
|
|
43
|
+
render: string | ((container: HTMLDivElement) => void);
|
|
44
|
+
}
|
|
45
|
+
/** Plugin lifecycle hooks. All are optional. */
|
|
46
|
+
export interface ClawContainerPlugin {
|
|
47
|
+
/** Plugin name (for debugging) */
|
|
48
|
+
name: string;
|
|
49
|
+
/** Extra npm deps this plugin needs */
|
|
50
|
+
services?: Record<string, string>;
|
|
51
|
+
/** Extra workspace files to merge */
|
|
52
|
+
workspace?: Record<string, string>;
|
|
53
|
+
/** Extra env vars to inject */
|
|
54
|
+
env?: Record<string, string>;
|
|
55
|
+
/** Custom tabs to register */
|
|
56
|
+
tabs?: TabDefinition[];
|
|
57
|
+
/** Called after plugin is registered, before container boot */
|
|
58
|
+
onInit?(cc: ClawContainerSDK): void;
|
|
59
|
+
/** Called after container is ready */
|
|
60
|
+
onReady?(cc: ClawContainerSDK): void;
|
|
61
|
+
/** Called when container is stopped */
|
|
62
|
+
onDestroy?(cc: ClawContainerSDK): void;
|
|
63
|
+
}
|
|
64
|
+
/** Event map for ClawContainer typed events. */
|
|
65
|
+
export type ClawContainerEvents = {
|
|
66
|
+
ready: [];
|
|
67
|
+
error: [error: Error];
|
|
68
|
+
status: [status: string];
|
|
69
|
+
'file.change': [path: string];
|
|
70
|
+
'process.exit': [code: number];
|
|
71
|
+
'server.ready': [port: number, url: string];
|
|
72
|
+
log: [entry: AuditEntry];
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Public surface of the SDK passed to plugins.
|
|
76
|
+
* This is the same as ClawContainer but expressed as an interface
|
|
77
|
+
* so plugins don't depend on the concrete class.
|
|
78
|
+
*/
|
|
79
|
+
export interface ClawContainerSDK {
|
|
80
|
+
readonly container: WebContainer | null;
|
|
81
|
+
start(): Promise<void>;
|
|
82
|
+
stop(): Promise<void>;
|
|
83
|
+
restart(): Promise<void>;
|
|
84
|
+
exec(cmd: string): Promise<string>;
|
|
85
|
+
shell(): Promise<void>;
|
|
86
|
+
sendInput(data: string): Promise<void>;
|
|
87
|
+
fs: {
|
|
88
|
+
read(path: string): Promise<string>;
|
|
89
|
+
write(path: string, content: string): Promise<void>;
|
|
90
|
+
list(dir?: string): Promise<string[]>;
|
|
91
|
+
mkdir(path: string): Promise<void>;
|
|
92
|
+
remove(path: string): Promise<void>;
|
|
93
|
+
};
|
|
94
|
+
git: {
|
|
95
|
+
clone(url: string, token: string): Promise<void>;
|
|
96
|
+
push(message?: string): Promise<string>;
|
|
97
|
+
};
|
|
98
|
+
logs(filter?: {
|
|
99
|
+
source?: AuditSource;
|
|
100
|
+
level?: AuditLevel;
|
|
101
|
+
event?: AuditEvent;
|
|
102
|
+
}): AuditEntry[];
|
|
103
|
+
use(plugin: ClawContainerPlugin): void;
|
|
104
|
+
addTab(def: TabDefinition): void;
|
|
105
|
+
removeTab(id: string): void;
|
|
106
|
+
on<K extends keyof ClawContainerEvents>(event: K, fn: (...args: ClawContainerEvents[K]) => void): void;
|
|
107
|
+
off<K extends keyof ClawContainerEvents>(event: K, fn: (...args: ClawContainerEvents[K]) => void): void;
|
|
108
|
+
once<K extends keyof ClawContainerEvents>(event: K, fn: (...args: ClawContainerEvents[K]) => void): void;
|
|
109
|
+
}
|
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { ContainerManager, ContainerStatus } from './container.js';
|
|
2
|
+
import type { AuditLog } from './audit.js';
|
|
3
|
+
import { PolicyEngine } from './policy.js';
|
|
4
|
+
import type { TabDefinition } from './types.js';
|
|
5
|
+
export declare class UIManager {
|
|
6
|
+
private container;
|
|
7
|
+
private audit;
|
|
8
|
+
private policy;
|
|
9
|
+
private activePanelId;
|
|
10
|
+
private refreshTimer;
|
|
11
|
+
private tabs;
|
|
12
|
+
private activeTabPath;
|
|
13
|
+
private auditUnsubscribe;
|
|
14
|
+
private syncInProgress;
|
|
15
|
+
private autoSyncTimer;
|
|
16
|
+
private cloneInProgress;
|
|
17
|
+
private customTabPaths;
|
|
18
|
+
constructor(container: ContainerManager, audit: AuditLog, policy: PolicyEngine);
|
|
19
|
+
init(): void;
|
|
20
|
+
/** Auto-open the browser preview tab on initial load. */
|
|
21
|
+
openPreviewOnLoad(): void;
|
|
22
|
+
setStatus(status: ContainerStatus): void;
|
|
23
|
+
getSavedConfig(): {
|
|
24
|
+
provider: string;
|
|
25
|
+
model: string;
|
|
26
|
+
envVars: Record<string, string>;
|
|
27
|
+
} | null;
|
|
28
|
+
showConfigPanel(): void;
|
|
29
|
+
private bindKeyboard;
|
|
30
|
+
private bindResizeHandles;
|
|
31
|
+
private initHResize;
|
|
32
|
+
private initVResize;
|
|
33
|
+
private bindFileTree;
|
|
34
|
+
private htmlWatcherStarted;
|
|
35
|
+
private startHtmlFileWatcher;
|
|
36
|
+
private openHtmlInPreview;
|
|
37
|
+
private startFileTreeRefresh;
|
|
38
|
+
private refreshFileTree;
|
|
39
|
+
private openFile;
|
|
40
|
+
private closeTab;
|
|
41
|
+
private switchTab;
|
|
42
|
+
private renderTabBar;
|
|
43
|
+
private saveActiveFile;
|
|
44
|
+
private previewBound;
|
|
45
|
+
private openPreviewTab;
|
|
46
|
+
private cloudBrowserBound;
|
|
47
|
+
private openCloudBrowserTab;
|
|
48
|
+
/** Show editor-container, preview-container, audit-container, policy-container, cloud-browser-container, or custom tab based on active tab type. */
|
|
49
|
+
private updateContentVisibility;
|
|
50
|
+
private openAuditTab;
|
|
51
|
+
private bindAuditFilters;
|
|
52
|
+
private matchesAuditFilters;
|
|
53
|
+
private renderAuditLog;
|
|
54
|
+
private createAuditRow;
|
|
55
|
+
private escHtml;
|
|
56
|
+
private bindTopbarButtons;
|
|
57
|
+
private bindRepoControls;
|
|
58
|
+
private handleClone;
|
|
59
|
+
private handleSync;
|
|
60
|
+
private startAutoSync;
|
|
61
|
+
private stopAutoSync;
|
|
62
|
+
private bindConfigPanel;
|
|
63
|
+
private populateModelOptions;
|
|
64
|
+
/** Ensure the first env row key matches the selected provider. */
|
|
65
|
+
private syncDefaultEnvKey;
|
|
66
|
+
private addEnvRow;
|
|
67
|
+
private getEnvRows;
|
|
68
|
+
private restoreConfig;
|
|
69
|
+
private saveConfig;
|
|
70
|
+
private openPolicyTab;
|
|
71
|
+
private bindPolicyPanel;
|
|
72
|
+
private loadPolicyYaml;
|
|
73
|
+
private applyPolicyYaml;
|
|
74
|
+
private resetPolicy;
|
|
75
|
+
private togglePanel;
|
|
76
|
+
private openPanel;
|
|
77
|
+
/** Add a custom tab with user-defined content. */
|
|
78
|
+
addCustomTab(def: TabDefinition): void;
|
|
79
|
+
/** Remove a custom tab by its definition id. */
|
|
80
|
+
removeCustomTab(id: string): void;
|
|
81
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default workspace files mounted into the WebContainer /workspace directory.
|
|
3
|
+
*/
|
|
4
|
+
export declare const DEFAULT_AGENT_YAML = "spec_version: \"0.1.0\"\nname: my-agent\nversion: 1.0.0\nmodel:\n preferred: \"\" # set via API config panel\n fallback: []\ntools: [cli, read, write, memory]\nruntime:\n max_turns: 50\n timeout: 120\n";
|
|
5
|
+
export declare const DEFAULT_SOUL_MD = "# Agent Soul\n\nYou are a helpful, thoughtful AI assistant running inside ClawContainer.\nYou can read and write files, run commands, and remember things.\n";
|
|
6
|
+
export declare const DEFAULT_RULES_MD = "# Agent Rules\n\n1. Be concise and accurate.\n2. Ask for clarification before taking irreversible actions.\n3. Prefer small, focused changes over large rewrites.\n4. Always explain what you are doing and why.\n";
|
|
7
|
+
export declare const DEFAULT_MEMORY_MD = "# Memory Index\n\nNo memories saved yet.\n";
|
|
8
|
+
/**
|
|
9
|
+
* Node.js script that acts as a git stub.
|
|
10
|
+
* npm will create node_modules/.bin/git → ../../git-stub.js with execute bit set.
|
|
11
|
+
*/
|
|
12
|
+
export declare const GIT_STUB_JS = "#!/usr/bin/env node\nconst [,, cmd, ...args] = process.argv;\nif (cmd === 'init') {\n const fs = require('fs');\n if (!fs.existsSync('.git')) {\n fs.mkdirSync('.git/objects', { recursive: true });\n fs.mkdirSync('.git/refs/heads', { recursive: true });\n fs.writeFileSync('.git/HEAD', 'ref: refs/heads/main\\n');\n fs.writeFileSync('.git/config', '[core]\\n\\trepositoryformatversion = 0\\n\\tbare = false\\n');\n }\n console.log('Initialized empty Git repository in ' + process.cwd() + '/.git/');\n} else if (cmd === '--version' || cmd === 'version') {\n console.log('git version 2.39.0');\n} else if (cmd === 'rev-parse') {\n if (args.includes('--show-toplevel')) process.stdout.write(process.cwd() + '\\n');\n else process.stdout.write('\\n');\n}\n// add, commit, status, log, etc. silently succeed (exit 0)\nprocess.exit(0);\n";
|
|
13
|
+
/** Returns the FileSystem tree to mount under /workspace inside WebContainer. */
|
|
14
|
+
export declare function buildWorkspaceFiles(extra?: Record<string, string>): Record<string, any>;
|
|
15
|
+
/** Returns the inner-container package.json that requests gitclaw. */
|
|
16
|
+
export declare function buildContainerPackageJson(extraDeps?: Record<string, string>): string;
|
package/index.html
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>ClawLess — A ClawContainer for AI Agents</title>
|
|
7
|
+
<link rel="icon" type="image/png" href="/logo.png" />
|
|
8
|
+
<link rel="stylesheet" href="/node_modules/@xterm/xterm/css/xterm.css" />
|
|
9
|
+
<link rel="stylesheet" href="/src/style.css" />
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<!-- Loading overlay -->
|
|
13
|
+
<div id="loading-overlay">
|
|
14
|
+
<div class="loading-inner">
|
|
15
|
+
<div class="claw-logo"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAgKADAAQAAAABAAAAgAAAAABIjgR3AAAXMElEQVR4Ae1dCXwURbqfyTEh90ESghAuiQmBFTECAhFRjtWwIK7KW1S8Hoe6iux7iuCxL+891EUQd3mu/AA1iCvsqhAhIAmQEELINQRCbnIfkzuZJDOTO5O8f/VMd3qGHDOTSeew+pdMV3dXfVX1/6q/+uqrqq9FInpQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIjCaEBCPpsKas6ynTp3ynDBhgp/IyspKXl2dt2bNmhJz0h8ttH5NDcDy6tWrd3tMmPCom4tLkIODw3yJROJlYWEhamlpaWhtbU1UqFS/lBYXRy9dujQTDOwcLUwcTDnHdAM4dOiQ88KFC+93dXNbaWdnt9LB3t5/3LhxdnzAutRqkYWlJXerra2tvaW1NUOpUETW19eHX7lyRbpt2zYFF2GMBcZcAwgLuzjF13dqIN7w1fhfAsZPteQxuLWtTd3a0pqhUDRerqtrjOjq6mp1drZf5erqusLe3v5eNBAJy2N1V5cIcQtVKtW16ura8IKC3Jh169aVss/peQQg8Mwzz0iuXk0IyM/Pf7e2tjaqqampvlvvUDU1NVRXV0chzs7o6Oj5ItFsjsm8Kliev3Tp3szM7O3llZURCoXyDjpNzc11crk8HHT+IyEh4V6ktealH5XBUSkBINrdFyxatMDd1fUxZxeXh9GX+9tIJFYsB8B/UVNTcwne8oSamrrwnJzs6PXr1xeyzw05Hzt2DJLEP9Ddwy3IzdV1ib2DwzRrKy4LUTsO5JGlUikvqVStEXFxMcmbNm2SG0J7JMUZLQ1AHH45/O4Z3jMDHe3tVzs4Oiy2t3e4i1949N2dePuz6hsaohobGsITcbz++uv15gA7ODjYadmKFQETPTxWEX0CusRvbG1tOSmiaXBNMuR/ra6uIaK4uCAmKCgo3xx5/2pp7N271z4pKWlxaVnZfzU0NMRBU1fqSfZulQqivaY6Kicvb8fly7EP9CHazY2hVVhY2Nz09PTtpaWl4Qqlsla/XM3NzYpauTw6Ly/v/fjr1xdu2bJFR/E0d4EGQ4//Eg2GjlnSngwPn+jn7R3o7OzyuJOT00M242zullhbc2VUQ2PHW1YE0GPldXUXMzMLYjZseLLILJmbSOTbb7+d5Ovv/6CHm9vjbm7jH7K1HXePjY0NR629vaOrrb0tV6VUXoWOciE3Nzf2qaeequAiDHOAA3eYymEJZcrXy8vrEWjra6C13w/R6sEvC4ZkrWB6uqKxMbJaLr90JTJSunPnzkZ+nJES3rhxoz30gLnunp4r3FzcVmJUMc8RfRa/fJAONajPdUi081BML8+fPz8bz38VNgcOh5DQUJfi4uKd6K+lAKJFX4RCA6/EEXr79u3Xw8PDZyNhz0CdozLyA99//71PSkrKK8XFJf+CTaGks7NTp6oYkrY2NDTeLCgo+DAkJMRl5NfIDCVE/zkJYCTykYCY7Kytq0vF8OozqVQadPDgQU8zZDWiSGwPDnaBXvpQZnb2B1VVVVcgCVr5GNTVyRPOnTvnNaIKPQSFEVdUVPzArzgJY0TVWV5REZOXV/BGVGysL/Id7q5pCKouEp05c2Z6VlbOS+XlFWfRAO6QfOXllcfHat0ZQK9du3Y3uvRmwnQ0hEj8H4UILOaLRgznOurrG5KhYf8Fb8yjO3bscBwSbghAdNGiRbZxcXELcvNz/wwFMA76DMd0Umd0gQXFxaWHCBYEE+gGqpPnzk0VoGjDk0XG7dsPwbxK6tqdnJLye1IKjLFdkpOTH80rKPgUIBGdQEc0NjYq8tGHfpuamvrMQWjcw1Nyw3P95MsvXROTk38Lxv4NVsMsdG9MfckPGkAbujop+vxP0dUte/PNN50IZQwp/0Cek0Zx82b6EsNzG2UxodRxDSAjO/uJXopvefHixVkZGRlbSmWynyAJZAQY9lCqVHVQDk9nZ+e8GhER4Yf0I6GrEJ/4+WdvNOjnIcK/UyqVpWx5yRnXVWVlZWGpqRlvxMTE+KPMdyi02dnZT5O4HR0d3URP6AWXIbvVY9scsix4hK2sukUi/IFv4q6u3pinXrlyZRYikP/DkA5ujz22OsDFxXnVeHe3pbDAzcUc/lryP23alPaqquobGDGEy+W1F6A43jx69GgrLzeTggFr1thtXLvWcaq7uwN4Ygv9RI0JIhW0eSXKowRRNZ/wtfjEd2b53rPL1dWF0eI7OjtFePNvw3gVjWHehcTE9Gvbt2+u4qfRD2NKmoAiQn4iNAL9x2PnGlp+IIw5pLF3p6WlPWlkzSwwgvC7efPm5tJS2U+NCkU5Q0j7A+NQJvSGv0mlN4NgnBlvKG0M1abGJyWtz8nJ+RyKaDQseHmgVYOJnybMArZjIqm1CesFFAqFrLqm5kZZWflxiOw/xcYSy6PIetmyZVapqZlBZRUV32Tn5Lx/+fLlB0nfb2j+JF5WTs5TpBrtkACxAksAY8o56LjoAngNINPYBqCT/8cffzw+LilpORi3B7pDUnNLSzvbIMA8jLSqfszJydty8NixO4aUmEyamJqRsVVWVhYJEd3ApjPmDMnQDQU2KyMjaxfmHBx0CmfkBUYGw9YABE0CoORwYh+SgAsbiRcT/b733qsTvfdeJC7Iv8Xp06d9Jk+evNjT03Olg6PjQ5i0eVrV3GIh6eg4y9I/cuTI9EeWL3/N0919o6Ojo/6YmxHDbNw+zlyZMVopb29vS+0SdTX5+fkR8a/qI82At7FegckbHaNIjGPABKM1Al8CpKSkMaOAoajLli3vOqNBkPl65ggIWGOXnpm5A29sNfuWa8Yi3eRkyD+TjIjo6uqamFu3br144MABHZM1m5cpZ3SNvycZdHR0dl+7lrTUFBqjIg2GgVwXkJI2dA2AD0ZERFQA+ud4hoOaHx2GdzH877cRMKmqqmoSY2Pj14K2BZ++OcI9DaCjGyOFh81B01AagnYBloCSLVgfowD2sVnON26kbPS5Z+YBjB5YOzuXP8kAxSESV+eeXsZi6AiqgqKC3a9tfe1AfHx8i95z/Usivvujpx+fucYkp+ZgpL+gLBEJmxuv+lyleffMGUzLyNjlM3PmR1gpxDEFzY/0sByDBmI+hpnpCQnXN61btzpxoLKdOxfxu/au9uon16xJGiiu/nO1SKsPoYCWlmSoLNxhdnHWX9G7YQcQonYYGXw4y8/vYz7zSbn4zO+rnCgfaTBiDAkjjh37aaUhzA8OPuD0wPx5+6d6e8/qi25/92EZ4mDBklVBlUBBG4DYjKOAvgBNSU19Y/r06f9jifX+ODhg+4rP3ifdAQmTn6KikjMf7d799I4df6xkn/d3fv751Z96enj4QJs32P7QFz2hRbLQ+XH15q3U5u4NNhATF7fc18dnHzb7EFI6zOf39xyz0f8z4Z53TgxjUswnn3z0wuHDhw0a1t26lfbWtGlTt5IMra1NWyRsYSHRlPXXpAOwY18CnDmOv/89xGvOrFmHYbYl67F0mE/o8/v7XsMYgtfUyYswx/AcmG/QiqOkpOSXfX199qIuTBVgjKpmAqb+oINUq9t6mqOpdIxIJ6gE0Kx70vBmsIYg/TquWBX4vzDHz8D9O5jPxuVLAfae9izGhiD19aTr2zZv3izTe9brJUzZb/n43LPXxkbCvPYwcomalcqiXiMPeFO7IgwSwNLSps/yD0jGhAiC6gCktRFrl7kPvLULp3h7vzAQXf6brx8XBp5jQUG/DdO/r3+9b98+99z8/K/9/f3/qmU+wzDM9DZg1i9XP75B11pLIMalY1sCoG/mjQLumBU1CKveIvnPnv32OHADz0x5e8RYiKFIuJn8cW+0+fcSpNKnZs6YsXu8mxuZmiYHl59Spby1YcMGg5RGTVLer9YsTogJvTpU0C5AM9GpwQwi0yzS5+jx47PBkNU8OI0Oyuvrf1z/xBN5fSSUXL9+feVkb+9t48e7rbKyZCDjGI8Ao7phz9hJpO/qg4ZBt4lsFJQhQueH97+bfWcsrDVz4AYh00+kgLlzN2ApOZl+5ZjST3T9R+KOzo6uMpksRO+B5Pz5835Tps0I8nR3W4+No/NYRY9UAV0JF52EYCxskCYm/szdNDGgoStsExA2Nx4w5ugAsOPG+i6vib/jkeWC/Sh8aCkwAYs0JmAsOcvF/L48MjLyUQ+M5R2cnB5wcnBYiH0Kvvrbv4gOwWc+mxkshideeeWVUvba2DM7ItK0YGE7AUEbQCdBT/vyYFt2z2tkLGLa+Nh/52dvbzeLXBKmEhlAmESu2TMJ6x8s83G/28nBccqGDc8l2thYO2rtB/zoGp7gjj7jmaxwH4tHGq9cidvPT2RsmBsR8TQkY2mYGl/QBsDvArhKm1pypJsyffo8bMPSbNLkMd8YkhIbia2EWA40B8dw9sZA5zJZ+d5Nmzb2pT8MlJx5zp8XEfb9F1jn4C8IwYDXaLD10XRxdiZ7CMjb3+8br59O79qkchDxVVFZmXjkyKFBvf2kLJYSHhYCtwCzaOJ6gBp0aQ4JME4iYRZlcP2KQTnrRiK6Au4dg67EWJNYl5SYuPnzzz8faIrYIIJcJEFl8hAsbuAq0kvAytaWvKrME/SppgCvQxXWO/5aPEKP+eczlYT51zoEyAWK0e/zOxKIYDVsa8cWL0wTr0u78/Hg7rAK4eCoGJ5a2PZGljxrFR2L7sEPAzMy0g+WlMh+srOzUUODn4ndxUHYkfsw5gO4QUZ/yiCBCS2Ga5QGwCbGhs7u9IzsbYsXLhz0sI/Lj7cgRFiGCCwBuAqbIYCVvVMmTZrk5THB3cfB2dkH6/DTP/jgLxsuXrwcWIMdRchi0BJGr5jiNuwRSMOS8PkB9x3Seza4S7a54uUQWAUYXLmNTZ2VlbUYiiAkbnd3QoL0D8amJ/GJt43MzMzdGL/XMIR4PxiSyTJv3/7js88+61pSUvqz9pHOGkDcM+W6G7uSFMnJKc+bUuaB0sCTyDpSVmwqEXxN4EBlM+vzwTaAHTv2OBbLZGFaxmqWc2oZSrjKHkXFxYeXLFnrWFNTe117r1+mwyZBovUWh0leWVWV/ssvvywxKxg8Ylgt/STJiGwNwwbasbsqGO5RFrESAJsjjZYAuXkF/8dwRPMDvvXKOOYp3L29FhoWtoAobNo0vTG4r3tMEmxUVefl5R8MDt7nzuOX2YOcBEADiBrLq4L5yLF6D/9ef+FTp87OmTRp4iZtHGbs3oeCR56JJ3tP+vM77/yn/8L5C6InTvBc2R9t3jNOb8Bbn5iRnh68YsWKcN7zIQqySoBIZGM5ziS7hKkFGzY7gLEFnjXbZ60t1HukMwggRwcHr127dj0IX4Fn+8sLxJihI+JgpXqXqAb7/7Bd/aVFDz4Iz3BCMF+/dJo5U/27Q3Ut9KjD5HoQl69GJCaNROzu6TWntroyHesEibWQTEQw9/l0CPexl7C2Xl4fXVha8v3SF148L8rLa+PHGfpwjzwUehQgfAPQ2n8s79wm3z/OXd3NfUVAh03sSoS5zIEAk4ta3dFiY2PPzBVorYWMiId7lmZ4pSnCPI60Du7moJsQT6JlbHqhz9xUMzK27BZ2X4CwDUBn1WxPqzcE8HqFMnmKXkTCeHKLz3zmGj8wNYsqyqpuSewkdkVFRf9s7+ysgIeOMlVjY255XV0mFoCUIFo7iT/cB7R/pitmKiNwYYRtACKeJVDrFMHQ+ibGxYZP9Z5Uigkgb6Rh3nZ9xvNpVdfUZp2Kjb75ZXAwWd4dwX9Gwnv27HFcvmrVC9j87/3VV4c/MYdzCf08DL1ml4VzIszQhGaIJ7AS2LNuHssBjGrwW7durS0qLNmp9aDRX1pirlXn5uTt1DK/V5jmz1/sH3DffUf8Zvm+ijWBAr8IukXqEqs5CQArtqDtQNAGwOwM0vIdblGMXj83b969x/MLC98Gg4muRBrBHf/wvtacn5f36sMPB57RhVn3ys7OGkoD9uJZWHXCpDysDUDc0bM4BvqA0bjo1sy4K0EbAOz1SrUaC+hx2NhY3WVcUTWxZ/n6fpaUmLy6oqIyAm9uA7GewVtHF9y51Mpk5afj4q4tnzNnzlcD0SZaI1EM8WOhFIsFxUG/bGpL0d3kHjyotcP4JNd/Pmau9+/fbwsHShnEzAaGVcJT2Mtvv/22ji9dYyp74sQJb6k0ZQG2bd9PdgYZkxYWtyWkHA2NjZV/gjMqY9KaKy6cTjlgXmMTGjLjuAIri9MIRuaiPyLpwDPIephnGRsuYQAmdTLhI/CDH344M13IAmMzyVJSCCzsqCabPYTMOzQ0dBqcQrwLiZhFMCAHMVnfysggDijG/gE/gC9DAlRoqq75xbW8rKwiBN7DA4FAf0qeWQAKDQ1bRuYS4AWs9vjx4xPMQnQAIvFS6RKZrCwEb3wdv+6NSmUJ3ND92wDJx9ZjuHybhC1WO+EMMhVjdg4PzLl31tbKozFz+GLw/v1DJprDzp9nGgCsgPLTpy+YpI8YwhEsGXOBmN+ImcnLpG5sRcnULyRAcmFh4XahGqAh5RU8zksvvTTuxo0ba7HA8gwUIMaPMAsS+ufCEpls9yWNh02zli780qVHiARQNjUpT5wInWZW4iB2Bm7uC4qKsG6hsYCtDzmjjqry8vJTScnJj82e3evHq8xdlNFDLyw8fC6sdvvA+BI90Jqw+eInOIlcbS7Qrl6NX0HywEKP5q+++26mOVCaOXOmDcoYVFVd/SNxNMmvA+qETySU7omKiiXfP6BHfwh88cUX44l2DGePcfAuzuFIugrs40uGb923vv7660GJbeghjxPC0AFa4C3Up7/yDPTsHydOTkaZtWIpWzO/OyMGKew6jsVW8n8XWtEcqMyj5bkVXLI+gjfnO2jrOh494bq1Et48vtC6bDW6PmDYE6QBQCFrxXeE7zGaABLgU7QLsSj1IPYGcv4HCU1IFTnuH9UqtMNqYzClXiMyDd7SGfg62PsYK2cTkNmDuIiFU+ZwMPQZY1y2QuteT2hAVLedPXuW2V5mSMWDodRlZ+c+D6UuEv05p9SRISW+hJIOS+W7pKyG0KJxTECAMJl8OwBMP6f/2RW5vCErOzvnw5Nnzw7IACiejI9+0oBgExjQuxecQPtBY/9vfOQhn2185IzPGzSjLGfQ968byZ+HMwHqkZ8ECzXnFRYW/xXdgY7ncHxPUI6vcHwLH3+PoBY96614VYJ/n+e0DFTjqx7zeI96ggEB1lLpjcdlMtmPeNuVfMbDgWQZ8U4eFRU1tycBDQ0LAiEhIV7wBfw6xLKUzA2wB6xr3VjwkQCF71X9D1FJb9zYSOJhbN4VJ5Uu4Bf8yJF/TEaabXX19dLOTp6NAvSqamoSyYJTOJ4WxHjELxcND4yAhHyuBZNCP8CyqGAbAjk3NChksCl8hi9yMG8sGgzTBRCDDJlLAGkxvj4aSJaU4yMUukodXMoXFhadgKRYjnjDOnM4MAQ0BoMAvIX7wmPobljbcvkNAcPKFrzFoSUlJd8QxQ3L1NWwSO7HxyCi8Yx73dXqrm5MXKXBZr8Ltntmto5COwoRwIybE/koE4wzF7BWoKd/0LQK2ALZ/SWaG+jrm+Bd/AxWBq/BMWK/+TsKWTH8RY6MjFlQAtsBxukyvlQgYSh1xUUlJXvx0arfDH9JhSvBkM+6CVcVw3P65ptvPAIDA5fCu8gcLL/Bnry2jAux8dFvvPhineFUaEyKAEWAIkARoAhQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIkARoAhQBCgCFAGKAEWAIiAkAv8Pp+AptFTXbHQAAAAASUVORK5CYII=" alt="ClawContainer" width="64" height="64" class="loading-logo" /></div>
|
|
16
|
+
<p style="margin:0 0 4px;font-size:11px;opacity:.6;letter-spacing:.5px">Built by Shreyas Kapale @ Lyzr</p>
|
|
17
|
+
<h2>ClawLess</h2>
|
|
18
|
+
<p id="loading-status">Booting WebContainer…</p>
|
|
19
|
+
<div class="progress-bar"><div id="progress-fill"></div></div>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<!-- Main layout -->
|
|
24
|
+
<div id="app">
|
|
25
|
+
<!-- Header bar -->
|
|
26
|
+
<header id="topbar">
|
|
27
|
+
<div class="topbar-left">
|
|
28
|
+
<span class="logo"><img src="/logo.png" alt="ClawLess" width="20" height="20" class="topbar-logo" /> ClawLess</span>
|
|
29
|
+
<span id="container-status" class="status-badge status-booting">booting</span>
|
|
30
|
+
<span class="topbar-sep">|</span>
|
|
31
|
+
<span class="topbar-gitagent">supports agents built on <a href="https://gitagent.sh" target="_blank" rel="noopener noreferrer">GitAgent</a> standard</span>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="topbar-center">
|
|
34
|
+
<input id="repo-url-input" type="text" placeholder="https://github.com/owner/repo" />
|
|
35
|
+
<button id="btn-clone" class="btn-icon" title="Clone Repository"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg></button>
|
|
36
|
+
<button id="btn-sync" class="btn-icon" title="Sync to Repository" disabled><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg></button>
|
|
37
|
+
<label class="auto-sync-toggle" title="Auto-sync on file changes">
|
|
38
|
+
<input id="auto-sync-checkbox" type="checkbox" />
|
|
39
|
+
<span>Auto</span>
|
|
40
|
+
</label>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="topbar-right">
|
|
43
|
+
<button id="btn-preview" class="btn-icon" title="Preview (localhost:3333)"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></button>
|
|
44
|
+
<button id="btn-audit" class="btn-icon" title="Audit Log Viewer"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></button>
|
|
45
|
+
<button id="btn-config" class="btn-icon" title="API Keys & Config"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></button>
|
|
46
|
+
<!-- Cloud Browser disabled for now -->
|
|
47
|
+
<button id="btn-cloud-browser" class="btn-icon" title="Cloud Browser (Browserbase)" style="display:none"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/></svg></button>
|
|
48
|
+
<button id="btn-policy" class="btn-icon" title="Policy / Guardrails"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg></button>
|
|
49
|
+
</div>
|
|
50
|
+
</header>
|
|
51
|
+
|
|
52
|
+
<!-- Body: filetree | main-content | sidebar -->
|
|
53
|
+
<div id="body">
|
|
54
|
+
<!-- Always-on file tree -->
|
|
55
|
+
<aside id="filetree">
|
|
56
|
+
<div class="filetree-header">
|
|
57
|
+
<span>WORKSPACE</span>
|
|
58
|
+
<button id="btn-refresh-tree" title="Refresh"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg></button>
|
|
59
|
+
</div>
|
|
60
|
+
<div id="filetree-list"></div>
|
|
61
|
+
</aside>
|
|
62
|
+
|
|
63
|
+
<div class="resize-handle resize-h" id="resize-filetree"></div>
|
|
64
|
+
|
|
65
|
+
<!-- Main content: editor panel + terminal -->
|
|
66
|
+
<div id="main-content">
|
|
67
|
+
<div id="editor-panel" class="hidden">
|
|
68
|
+
<div id="tab-bar"></div>
|
|
69
|
+
<div id="editor-container"></div>
|
|
70
|
+
<div id="preview-container" class="hidden">
|
|
71
|
+
<div id="preview-toolbar">
|
|
72
|
+
<button id="preview-back" class="preview-nav-btn" title="Back">←</button>
|
|
73
|
+
<button id="preview-forward" class="preview-nav-btn" title="Forward">→</button>
|
|
74
|
+
<button id="preview-reload" class="preview-nav-btn" title="Reload">↻</button>
|
|
75
|
+
<input id="preview-url" type="text" placeholder="Enter URL…" />
|
|
76
|
+
</div>
|
|
77
|
+
<div id="preview-viewport">
|
|
78
|
+
<div id="preview-loading">Loading…</div>
|
|
79
|
+
<iframe id="preview-iframe" allow="microphone; camera; autoplay"></iframe>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
<div id="audit-container" class="hidden">
|
|
83
|
+
<div id="audit-toolbar">
|
|
84
|
+
<input id="audit-search" type="text" placeholder="Search logs…" />
|
|
85
|
+
<select id="audit-filter-source"><option value="">All Sources</option><option value="boot">boot</option><option value="user">user</option><option value="agent">agent</option><option value="system">system</option><option value="policy">policy</option></select>
|
|
86
|
+
<select id="audit-filter-level"><option value="">All Levels</option><option value="info">info</option><option value="warn">warn</option><option value="error">error</option></select>
|
|
87
|
+
<select id="audit-filter-event"><option value="">All Events</option><option value="process.spawn">process.spawn</option><option value="process.exit">process.exit</option><option value="file.read">file.read</option><option value="file.write">file.write</option><option value="io.stdout">io.stdout</option><option value="io.stdin">io.stdin</option><option value="env.configure">env.configure</option><option value="server.ready">server.ready</option><option value="status.change">status.change</option><option value="policy.deny">policy.deny</option><option value="policy.load">policy.load</option><option value="boot.mount">boot.mount</option><option value="net.request">net.request</option><option value="net.response">net.response</option><option value="git.clone">git.clone</option><option value="git.push">git.push</option></select>
|
|
88
|
+
<input id="audit-date-from" type="datetime-local" title="From" />
|
|
89
|
+
<input id="audit-date-to" type="datetime-local" title="To" />
|
|
90
|
+
<button id="btn-audit-download" class="btn-icon" title="Download Logs"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg></button>
|
|
91
|
+
</div>
|
|
92
|
+
<div id="audit-log-list"></div>
|
|
93
|
+
</div>
|
|
94
|
+
<div id="policy-container" class="hidden">
|
|
95
|
+
<div class="policy-editor-wrap">
|
|
96
|
+
<p class="panel-hint">Define what agents can and cannot do. YAML format.</p>
|
|
97
|
+
<textarea id="policy-yaml-editor" spellcheck="false"></textarea>
|
|
98
|
+
<div class="policy-actions">
|
|
99
|
+
<button id="btn-apply-policy" class="btn-primary">Apply Policy</button>
|
|
100
|
+
<button id="btn-reset-policy" class="btn-secondary">Reset to Default</button>
|
|
101
|
+
</div>
|
|
102
|
+
<div id="policy-message" class="message"></div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
<div id="cloud-browser-container" class="hidden">
|
|
106
|
+
<div id="cloud-browser-toolbar">
|
|
107
|
+
<button id="cloud-browser-reload" class="preview-nav-btn" title="Reload">↻</button>
|
|
108
|
+
<input id="cloud-browser-url" type="text" placeholder="Enter URL to browse…" />
|
|
109
|
+
<button id="cloud-browser-go" class="btn-primary">Go</button>
|
|
110
|
+
<span id="cloud-browser-status"></span>
|
|
111
|
+
</div>
|
|
112
|
+
<div id="cloud-browser-viewport">
|
|
113
|
+
<div id="cloud-browser-loading">Starting cloud browser…</div>
|
|
114
|
+
<iframe id="cloud-browser-iframe" credentialless allow="clipboard-read; clipboard-write"></iframe>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
<div class="resize-handle resize-v" id="resize-editor-terminal"></div>
|
|
119
|
+
<div id="terminal-panel">
|
|
120
|
+
<div id="terminal-container"></div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div class="resize-handle resize-h" id="resize-sidebar"></div>
|
|
125
|
+
|
|
126
|
+
<!-- Toggleable config/agent sidebar -->
|
|
127
|
+
<aside id="sidebar" class="sidebar-hidden">
|
|
128
|
+
<!-- Config Panel -->
|
|
129
|
+
<section id="config-panel" class="panel">
|
|
130
|
+
<h3>Generic API Key</h3>
|
|
131
|
+
|
|
132
|
+
<label for="provider-select">Provider</label>
|
|
133
|
+
<select id="provider-select">
|
|
134
|
+
<option value="anthropic">Anthropic</option>
|
|
135
|
+
<option value="openai">OpenAI</option>
|
|
136
|
+
<option value="google">Google (Gemini)</option>
|
|
137
|
+
</select>
|
|
138
|
+
|
|
139
|
+
<label for="model-select">Model</label>
|
|
140
|
+
<select id="model-select"></select>
|
|
141
|
+
|
|
142
|
+
<div class="env-section">
|
|
143
|
+
<label>Environment Variables</label>
|
|
144
|
+
<div id="env-rows"></div>
|
|
145
|
+
<button id="btn-add-env" class="btn-secondary">+ Add Variable</button>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<button id="btn-save-config" class="btn-primary">Save & Connect</button>
|
|
149
|
+
<div id="config-message" class="message"></div>
|
|
150
|
+
</section>
|
|
151
|
+
|
|
152
|
+
</aside>
|
|
153
|
+
</div>
|
|
154
|
+
<div id="bottom-bar"><img src="/logo.png" alt="" width="14" height="14" style="vertical-align:middle" /> <span class="bottom-bar-text">ClawLess</span> <span class="bottom-bar-sep">|</span> <span class="bottom-bar-desc">A ClawContainer — serverless AI agent runtime in your browser</span></div>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<script type="module" src="/src/main.ts"></script>
|
|
158
|
+
</body>
|
|
159
|
+
</html>
|
package/logo.png
ADDED
|
Binary file
|