sliccy 1.8.0 → 1.10.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/README.md CHANGED
@@ -31,7 +31,7 @@ SLICC runs in a browser and controls the browser it runs in. It combines a shell
31
31
  - **Browser-native, not browser-adjacent.** The agent runtime lives in the browser, and the agent can act on the same browser it lives in. A great mix of power and containment. If you don't like what the AI does, close the browser tab and it's over.
32
32
  - **A real shell environment.** Many browser agents are constrained by the tools provided to them. SLICC has an almost-too-real shell with commands like `git`, "`node`", `python`, `playwright`, built-in.
33
33
  - **UI on the fly.** SLICC can generate rich user interfaces on the fly. These can be small visualizations in a chat response, or full-blown web applications that run in a sidebar, or even a separate tab.
34
- - **Built around Skills.** Agents don't suffer from missing capabilities, they suffer from skill issues. SLICC has a powerful skills system and a skills marketplace to find and install new skills to support your work.
34
+ - **Built around Skills.** Agents don't suffer from missing capabilities, they suffer from skill issues. SLICC can install native skills into `/workspace/skills`, and it also discovers compatible `.agents` / `.claude` skills read-only across the reachable VFS.
35
35
  - **More than a coding panel.** Coding is one strong use case, but SLICC is built for practical browser work too: authenticated web apps, repetitive tab work, content operations, debugging, research, and automation.
36
36
  - **Works across runtimes.** Start in the CLI, run as a Chrome extension, connect multiple tray sessions, or attach to Electron apps with the same core model.
37
37
  - **Delegates in parallel.** The main agent can spin up isolated sub-agents for task-specific work instead of stuffing everything into one conversation.
@@ -18,11 +18,12 @@ interface FindChromeExecutableOptions {
18
18
  }
19
19
  export declare function isCliProfileName(value: string | null | undefined): value is CliProfileName;
20
20
  export declare function resolveQaProfilesRoot(projectRoot: string): string;
21
- export declare function resolveDefaultChromeUserDataDir(tmpDir?: string): string;
21
+ export declare function resolveDefaultChromeUserDataDir(tmpDir?: string, servePort?: number): string;
22
22
  export declare function resolveChromeLaunchProfile(options: {
23
23
  projectRoot: string;
24
24
  tmpDir?: string | null;
25
25
  profile?: string | null;
26
+ servePort?: number;
26
27
  }): ChromeLaunchProfile;
27
28
  export declare function buildChromeLaunchArgs(options: {
28
29
  cdpPort: number;
@@ -55,8 +55,9 @@ export function isCliProfileName(value) {
55
55
  export function resolveQaProfilesRoot(projectRoot) {
56
56
  return join(projectRoot, ...QA_PROFILE_ROOT_SEGMENTS);
57
57
  }
58
- export function resolveDefaultChromeUserDataDir(tmpDir = process.env['TMPDIR'] ?? '/tmp') {
59
- return join(tmpDir, DEFAULT_USER_DATA_DIR_NAME);
58
+ export function resolveDefaultChromeUserDataDir(tmpDir = process.env['TMPDIR'] ?? '/tmp', servePort) {
59
+ const suffix = servePort && servePort !== 5710 ? `-${servePort}` : '';
60
+ return join(tmpDir, `${DEFAULT_USER_DATA_DIR_NAME}${suffix}`);
60
61
  }
61
62
  export function resolveChromeLaunchProfile(options) {
62
63
  const profile = normalizeProfileName(options.profile);
@@ -64,7 +65,7 @@ export function resolveChromeLaunchProfile(options) {
64
65
  return {
65
66
  id: null,
66
67
  displayName: 'Chrome',
67
- userDataDir: resolveDefaultChromeUserDataDir(options.tmpDir ?? undefined),
68
+ userDataDir: resolveDefaultChromeUserDataDir(options.tmpDir ?? undefined, options.servePort),
68
69
  extensionPath: null,
69
70
  };
70
71
  }
package/dist/cli/index.js CHANGED
@@ -426,6 +426,7 @@ async function main() {
426
426
  projectRoot: PROJECT_ROOT,
427
427
  tmpDir: process.env['TMPDIR'] ?? '/tmp',
428
428
  profile: RUNTIME_FLAGS.profile,
429
+ servePort: SERVE_PORT,
429
430
  });
430
431
  }
431
432
  catch (error) {
@@ -789,7 +790,8 @@ async function main() {
789
790
  if (Object.keys(headers).length > 0)
790
791
  fetchInit.headers = headers;
791
792
  if (rawBody.length > 0 && !['GET', 'HEAD'].includes(req.method)) {
792
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
793
+ // Buffer extends Uint8Array (valid BodyInit at runtime) but TS can't
794
+ // prove the backing ArrayBuffer is non-shared, so double-cast is needed.
793
795
  fetchInit.body = rawBody;
794
796
  }
795
797
  const upstream = await fetch(targetUrl, fetchInit);
@@ -1 +1 @@
1
- import{_ as e}from"./__vite-browser-external-D7Ct-6yo.js";import{g as r}from"./index-CSrgwBpI.js";const a=r(e);export{a as r};
1
+ import{_ as e}from"./__vite-browser-external-D7Ct-6yo.js";import{g as r}from"./index-CszlSH8q.js";const a=r(e);export{a as r};
@@ -1,2 +1,2 @@
1
- import{c as u}from"./index-CSrgwBpI.js";const l=["/workspace","/shared"];async function d(s){const t=[],e=new Set;for(const r of l)await s.exists(r)&&await p(s,r,t,e);return t}async function p(s,t,e,r){for await(const n of s.walk(t)){if(!n.endsWith(".bsh")||r.has(n))continue;r.add(n);const i=g(n);if(!i)continue;const a=await s.readFile(n,{encoding:"utf-8"}),c=typeof a=="string"?a:new TextDecoder().decode(a),f=m(c);e.push({path:n,hostnamePattern:i,matchPatterns:f})}}function g(s){const t=s.split("/").pop()??"";if(!t.endsWith(".bsh"))return null;const e=t.slice(0,-4);return e?e.startsWith("-.")?"*"+e.slice(1):e:null}function m(s){const t=s.split(`
1
+ import{c as u}from"./index-CszlSH8q.js";const l=["/workspace","/shared"];async function d(s){const t=[],e=new Set;for(const r of l)await s.exists(r)&&await p(s,r,t,e);return t}async function p(s,t,e,r){for await(const n of s.walk(t)){if(!n.endsWith(".bsh")||r.has(n))continue;r.add(n);const i=g(n);if(!i)continue;const a=await s.readFile(n,{encoding:"utf-8"}),c=typeof a=="string"?a:new TextDecoder().decode(a),f=m(c);e.push({path:n,hostnamePattern:i,matchPatterns:f})}}function g(s){const t=s.split("/").pop()??"";if(!t.endsWith(".bsh"))return null;const e=t.slice(0,-4);return e?e.startsWith("-.")?"*"+e.slice(1):e:null}function m(s){const t=s.split(`
2
2
  `).slice(0,10),e=[];for(const r of t){const n=r.match(/^\s*\/\/\s*@match\s+(.+)$/);n&&e.push(n[1].trim())}return e}function h(s,t){if(t.startsWith("*.")){const e=t.slice(1);return s.endsWith(e)&&s.length>e.length}return s===t}function v(s,t){try{const e=new URL(s),r=t.match(/^(\*|https?):\/\/([^/]+)(\/.*)?$/);if(!r)return!1;const[,n,i,a]=r;return n!=="*"&&e.protocol.slice(0,-1)!==n||!h(e.hostname,i)?!1:a?x(e.pathname+e.search,a):!0}catch{return!1}}function x(s,t){const e="^"+t.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$";return new RegExp(e).test(s)}function w(s,t){try{const e=new URL(t);return s.filter(r=>h(e.hostname,r.hostnamePattern)?r.matchPatterns.length>0?r.matchPatterns.some(n=>v(t,n)):!0:!1)}catch{return[]}}const o=u("bsh-watchdog");class S{transport;fs;execute;discoveryIntervalMs;entries=[];discoveryTimer=null;running=!1;executing=new Set;constructor(t){this.transport=t.transport,this.fs=t.fs,this.execute=t.execute,this.discoveryIntervalMs=t.discoveryIntervalMs??3e4}async start(){this.running||(this.running=!0,await this.discover(),this.discoveryTimer=setInterval(()=>{this.discover()},this.discoveryIntervalMs),this.transport.on("Page.frameNavigated",this.onFrameNavigated),o.info("BSH watchdog started",{scriptCount:this.entries.length}))}stop(){this.running&&(this.running=!1,this.transport.off("Page.frameNavigated",this.onFrameNavigated),this.discoveryTimer&&(clearInterval(this.discoveryTimer),this.discoveryTimer=null),this.entries=[],this.executing.clear(),o.info("BSH watchdog stopped"))}async discover(){try{this.entries=await d(this.fs),o.debug("BSH discovery complete",{count:this.entries.length})}catch(t){o.error("BSH discovery failed",{error:t instanceof Error?t.message:String(t)})}}getEntries(){return this.entries}onFrameNavigated=t=>{const e=t.frame;if(e?.parentId||!e?.url)return;const r=e.url;if(!r.startsWith("http://")&&!r.startsWith("https://")||this.entries.length===0)return;const n=w(this.entries,r);if(n.length!==0)for(const i of n){const a=`${i.path}::${r}`;this.executing.has(a)||(this.executing.add(a),o.info("BSH watchdog executing script",{script:i.path,url:r}),this.execute(i.path).then(c=>{c.exitCode!==0?o.warn("BSH script failed",{script:i.path,url:r,exitCode:c.exitCode,stderr:c.stderr.slice(0,200)}):o.info("BSH script completed",{script:i.path,url:r})}).catch(c=>{o.error("BSH script execution error",{script:i.path,url:r,error:c instanceof Error?c.message:String(c)})}).finally(()=>{this.executing.delete(a)}))}}}export{S as BshWatchdog};
@@ -0,0 +1,11 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-CszlSH8q.js","assets/index-D2mLc9tI.css"])))=>i.map(i=>d[i]);
2
+ import{_ as c}from"./index-CszlSH8q.js";const o={origins:["<all_urls>"]};async function d(){return chrome.permissions.contains(o)}async function l(){return chrome.permissions.request(o)}function f(s){chrome.permissions.onRemoved.addListener(n=>{n.origins?.includes("<all_urls>")&&s()})}const u=`
3
+ <div class="sprinkle-action-card">
4
+ <div class="sprinkle-action-card__header">Web access required <span class="sprinkle-badge sprinkle-badge--notice">approval</span></div>
5
+ <div class="sprinkle-action-card__body">The agent needs permission to access web pages for cross-origin requests. This enables fetching external resources and connecting to APIs.</div>
6
+ <div class="sprinkle-action-card__actions">
7
+ <button class="sprinkle-btn sprinkle-btn--secondary" data-action="deny">Deny</button>
8
+ <button class="sprinkle-btn sprinkle-btn--primary" data-action="grant">Grant access</button>
9
+ </div>
10
+ </div>
11
+ `;async function g(){if(!(typeof chrome<"u"&&!!chrome?.runtime?.id)||await d())return!0;const{getToolExecutionContext:n,showToolUIFromContext:i}=await c(async()=>{const{getToolExecutionContext:e,showToolUIFromContext:r}=await import("./index-CszlSH8q.js").then(a=>a.N);return{getToolExecutionContext:e,showToolUIFromContext:r}},__vite__mapDeps([0,1]));if(!n())return!1;const t=await i({html:u,onAction:async e=>e==="grant"?{granted:await l()}:{denied:!0}});return t?!!t.granted:!1}export{g as ensureHostPermission,d as hasHostPermission,f as onHostPermissionRevoked,l as requestHostPermission};
@@ -0,0 +1 @@
1
+ import{requestHostPermission as d}from"./host-permission-DHN0LidV.js";import"./index-CszlSH8q.js";function p(a,i){return new Promise(c=>{const e=document.createElement("div");e.className="dialog-overlay";const t=document.createElement("div");t.className="dialog",t.style.maxWidth="420px",t.innerHTML=['<div class="dialog__title">Web access required</div>','<div class="dialog__desc">',`slicc needs permission to access web pages to <strong>${r(i)}</strong>. `,"This lets the agent interact with websites on your behalf. ","No browsing data is collected — all processing stays local.","</div>",'<div class="dialog__desc" style="font-size: 11px; opacity: 0.7;">',"You can revoke this anytime in chrome://extensions.","</div>",'<div style="display:flex;gap:8px;margin-top:16px;">','<button class="dialog__btn--secondary" style="flex:1;" data-action="dismiss">Not now</button>','<button class="dialog__btn" style="flex:1;width:auto;" data-action="grant">Grant access</button>',"</div>"].join(""),e.appendChild(t);function n(s){e.remove(),c(s)}t.addEventListener("click",async s=>{const o=s.target.dataset?.action;if(o==="grant"){const l=await d();n(l)}else o==="dismiss"&&n(!1)}),e.addEventListener("click",s=>{s.target===e&&n(!1)}),a.appendChild(e)})}function r(a){const i=document.createElement("div");return i.textContent=a,i.innerHTML}export{p as showHostPermissionDialog};
@@ -1 +1 @@
1
- import{t as z,f as x}from"./index-CSrgwBpI.js";class T{marshaller;serializer;deserializer;serdeContext;defaultContentType;constructor({marshaller:i,serializer:n,deserializer:o,serdeContext:c,defaultContentType:y}){this.marshaller=i,this.serializer=n,this.deserializer=o,this.serdeContext=c,this.defaultContentType=y}async serializeEventStream({eventStream:i,requestSchema:n,initialRequest:o}){const c=this.marshaller,y=n.getEventStreamMember(),p=n.getMemberSchema(y),d=this.serializer,u=this.defaultContentType,h=Symbol("initialRequestMarker"),S={async*[Symbol.asyncIterator](){if(o){const r={":event-type":{type:"string",value:"initial-request"},":message-type":{type:"string",value:"event"},":content-type":{type:"string",value:u}};d.write(n,o);const t=d.flush();yield{[h]:!0,headers:r,body:t}}for await(const r of i)yield r}};return c.serialize(S,r=>{if(r[h])return{headers:r.headers,body:r.body};const t=Object.keys(r).find(s=>s!=="__type")??"",{additionalHeaders:e,body:a,eventType:l,explicitPayloadContentType:m}=this.writeEventBody(t,p,r);return{headers:{":event-type":{type:"string",value:l},":message-type":{type:"string",value:"event"},":content-type":{type:"string",value:m??u},...e},body:a}})}async deserializeEventStream({response:i,responseSchema:n,initialResponseContainer:o}){const c=this.marshaller,y=n.getEventStreamMember(),d=n.getMemberSchema(y).getMemberSchemas(),u=Symbol("initialResponseMarker"),h=c.deserialize(i.body,async t=>{const e=Object.keys(t).find(l=>l!=="__type")??"",a=t[e].body;if(e==="initial-response"){const l=await this.deserializer.read(n,a);return delete l[y],{[u]:!0,...l}}else if(e in d){const l=d[e];if(l.isStructSchema()){const m={};let f=!1;for(const[s,g]of l.structIterator()){const{eventHeader:v,eventPayload:w}=g.getMergedTraits();if(f=f||!!(v||w),w)g.isBlobSchema()?m[s]=a:g.isStringSchema()?m[s]=(this.serdeContext?.utf8Encoder??z)(a):g.isStructSchema()&&(m[s]=await this.deserializer.read(g,a));else if(v){const b=t[e].headers[s]?.value;b!=null&&(g.isNumericSchema()?b&&typeof b=="object"&&"bytes"in b?m[s]=BigInt(b.toString()):m[s]=Number(b):m[s]=b)}}if(f)return{[e]:m};if(a.byteLength===0)return{[e]:{}}}return{[e]:await this.deserializer.read(l,a)}}else return{$unknown:t}}),S=h[Symbol.asyncIterator](),r=await S.next();if(r.done)return h;if(r.value?.[u]){if(!n)throw new Error("@smithy::core/protocols - initial-response event encountered in event stream but no response schema given.");for(const[t,e]of Object.entries(r.value))o[t]=e}return{async*[Symbol.asyncIterator](){for(r?.value?.[u]||(yield r.value);;){const{done:t,value:e}=await S.next();if(t)break;yield e}}}}writeEventBody(i,n,o){const c=this.serializer;let y=i,p=null,d;const u=n.getSchema()[4].includes(i),h={};if(u){const t=n.getMemberSchema(i);if(t.isStructSchema()){for(const[e,a]of t.structIterator()){const{eventHeader:l,eventPayload:m}=a.getMergedTraits();if(m)p=e;else if(l){const f=o[i][e];let s="binary";a.isNumericSchema()?(-2)**31<=f&&f<=2**31-1?s="integer":s="long":a.isTimestampSchema()?s="timestamp":a.isStringSchema()?s="string":a.isBooleanSchema()&&(s="boolean"),f!=null&&(h[e]={type:s,value:f},delete o[i][e])}}if(p!==null){const e=t.getMemberSchema(p);e.isBlobSchema()?d="application/octet-stream":e.isStringSchema()&&(d="text/plain"),c.write(e,o[i][p])}else c.write(t,o[i])}else if(t.isUnitSchema())c.write(t,{});else throw new Error("@smithy/core/event-streams - non-struct member not supported in event stream union.")}else{const[t,e]=o[i];y=t,c.write(15,e)}const S=c.flush();return{body:typeof S=="string"?(this.serdeContext?.utf8Decoder??x)(S):S,eventType:y,explicitPayloadContentType:d,additionalHeaders:h}}}export{T as EventStreamSerde};
1
+ import{t as z,f as x}from"./index-CszlSH8q.js";class T{marshaller;serializer;deserializer;serdeContext;defaultContentType;constructor({marshaller:i,serializer:n,deserializer:o,serdeContext:c,defaultContentType:y}){this.marshaller=i,this.serializer=n,this.deserializer=o,this.serdeContext=c,this.defaultContentType=y}async serializeEventStream({eventStream:i,requestSchema:n,initialRequest:o}){const c=this.marshaller,y=n.getEventStreamMember(),p=n.getMemberSchema(y),d=this.serializer,u=this.defaultContentType,h=Symbol("initialRequestMarker"),S={async*[Symbol.asyncIterator](){if(o){const r={":event-type":{type:"string",value:"initial-request"},":message-type":{type:"string",value:"event"},":content-type":{type:"string",value:u}};d.write(n,o);const t=d.flush();yield{[h]:!0,headers:r,body:t}}for await(const r of i)yield r}};return c.serialize(S,r=>{if(r[h])return{headers:r.headers,body:r.body};const t=Object.keys(r).find(s=>s!=="__type")??"",{additionalHeaders:e,body:a,eventType:l,explicitPayloadContentType:m}=this.writeEventBody(t,p,r);return{headers:{":event-type":{type:"string",value:l},":message-type":{type:"string",value:"event"},":content-type":{type:"string",value:m??u},...e},body:a}})}async deserializeEventStream({response:i,responseSchema:n,initialResponseContainer:o}){const c=this.marshaller,y=n.getEventStreamMember(),d=n.getMemberSchema(y).getMemberSchemas(),u=Symbol("initialResponseMarker"),h=c.deserialize(i.body,async t=>{const e=Object.keys(t).find(l=>l!=="__type")??"",a=t[e].body;if(e==="initial-response"){const l=await this.deserializer.read(n,a);return delete l[y],{[u]:!0,...l}}else if(e in d){const l=d[e];if(l.isStructSchema()){const m={};let f=!1;for(const[s,g]of l.structIterator()){const{eventHeader:v,eventPayload:w}=g.getMergedTraits();if(f=f||!!(v||w),w)g.isBlobSchema()?m[s]=a:g.isStringSchema()?m[s]=(this.serdeContext?.utf8Encoder??z)(a):g.isStructSchema()&&(m[s]=await this.deserializer.read(g,a));else if(v){const b=t[e].headers[s]?.value;b!=null&&(g.isNumericSchema()?b&&typeof b=="object"&&"bytes"in b?m[s]=BigInt(b.toString()):m[s]=Number(b):m[s]=b)}}if(f)return{[e]:m};if(a.byteLength===0)return{[e]:{}}}return{[e]:await this.deserializer.read(l,a)}}else return{$unknown:t}}),S=h[Symbol.asyncIterator](),r=await S.next();if(r.done)return h;if(r.value?.[u]){if(!n)throw new Error("@smithy::core/protocols - initial-response event encountered in event stream but no response schema given.");for(const[t,e]of Object.entries(r.value))o[t]=e}return{async*[Symbol.asyncIterator](){for(r?.value?.[u]||(yield r.value);;){const{done:t,value:e}=await S.next();if(t)break;yield e}}}}writeEventBody(i,n,o){const c=this.serializer;let y=i,p=null,d;const u=n.getSchema()[4].includes(i),h={};if(u){const t=n.getMemberSchema(i);if(t.isStructSchema()){for(const[e,a]of t.structIterator()){const{eventHeader:l,eventPayload:m}=a.getMergedTraits();if(m)p=e;else if(l){const f=o[i][e];let s="binary";a.isNumericSchema()?(-2)**31<=f&&f<=2**31-1?s="integer":s="long":a.isTimestampSchema()?s="timestamp":a.isStringSchema()?s="string":a.isBooleanSchema()&&(s="boolean"),f!=null&&(h[e]={type:s,value:f},delete o[i][e])}}if(p!==null){const e=t.getMemberSchema(p);e.isBlobSchema()?d="application/octet-stream":e.isStringSchema()&&(d="text/plain"),c.write(e,o[i][p])}else c.write(t,o[i])}else if(t.isUnitSchema())c.write(t,{});else throw new Error("@smithy/core/event-streams - non-struct member not supported in event stream union.")}else{const[t,e]=o[i];y=t,c.write(15,e)}const S=c.flush();return{body:typeof S=="string"?(this.serdeContext?.utf8Decoder??x)(S):S,eventType:y,explicitPayloadContentType:d,additionalHeaders:h}}}export{T as EventStreamSerde};