@ai-ecoverse/slicc-spectrum 1.74.0 → 1.75.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.
@@ -361,6 +361,7 @@ var defaults = {
361
361
  model: "",
362
362
  thinking: "off",
363
363
  sendOnEnter: true,
364
+ pushToTalk: false,
364
365
  showThinking: false,
365
366
  diffStyle: "unified"
366
367
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/kernel/files.ts", "../src/kernel/idle.ts", "../src/kernel/terminals.ts", "../src/kernel/index.ts"],
4
- "sourcesContent": ["import { Emitter } from '../model/emitter.ts';\nimport type { Change, FileEntry, FileEvents, FilePort } from '../model/types.ts';\n\nexport interface KernelFilesOptions {\n skip?: readonly string[];\n hide?: readonly string[];\n interval?: number;\n}\n\ninterface Observer {\n observe(handle: FileSystemHandle, options: { recursive: boolean }): Promise<void>;\n disconnect(): void;\n}\n\ntype ObserverConstructor = new (callback: () => void) => Observer;\n\nfunction split(path: string): string[] {\n return path.split('/').filter(Boolean);\n}\n\nfunction same(a: FileEntry | undefined, b: FileEntry): boolean {\n return a?.kind === b.kind && a.size === b.size && a.modified === b.modified;\n}\n\nexport class KernelFiles extends Emitter<FileEvents> implements FilePort {\n #root: FileSystemDirectoryHandle;\n #skip: Set<string>;\n #hide: Set<string>;\n #interval: number;\n #entries = new Map<string, FileEntry>();\n #scanned = false;\n #running: Promise<void> | null = null;\n #again = false;\n #timer: ReturnType<typeof setInterval> | null = null;\n #observer: Observer | null = null;\n\n constructor(\n root: FileSystemDirectoryHandle,\n { skip = [], hide = [], interval = 2000 }: KernelFilesOptions = {}\n ) {\n super();\n this.#root = root;\n this.#skip = new Set(skip);\n this.#hide = new Set(hide);\n this.#interval = interval;\n }\n\n start(): void {\n if (this.#timer || this.#observer) return;\n const Observer = (globalThis as { FileSystemObserver?: ObserverConstructor })\n .FileSystemObserver;\n if (!Observer) {\n this.#poll();\n return;\n }\n const observer = new Observer(() => void this.refresh());\n this.#observer = observer;\n observer.observe(this.#root, { recursive: true }).catch(() => {\n if (this.#observer !== observer) return;\n this.#observer = null;\n this.#poll();\n });\n }\n\n #poll(): void {\n this.#timer = setInterval(() => void this.refresh(), this.#interval);\n }\n\n stop(): void {\n if (this.#timer) clearInterval(this.#timer);\n this.#timer = null;\n this.#observer?.disconnect();\n this.#observer = null;\n }\n\n async #walk(\n dir: FileSystemDirectoryHandle,\n prefix: string,\n out: Map<string, FileEntry>\n ): Promise<void> {\n const values = (\n dir as FileSystemDirectoryHandle & {\n values(): AsyncIterable<FileSystemDirectoryHandle | FileSystemFileHandle>;\n }\n ).values();\n for await (const handle of values) {\n const path = `${prefix}/${handle.name}`;\n if (this.#hide.has(path)) continue;\n if (handle.kind === 'directory') {\n out.set(path, { path, kind: 'directory', size: 0, modified: 0 });\n if (!this.#skip.has(path)) await this.#walk(handle, path, out).catch(() => {});\n } else {\n const file = await handle.getFile().catch(() => null);\n if (file)\n out.set(path, { path, kind: 'file', size: file.size, modified: file.lastModified });\n }\n }\n }\n\n #list(): FileEntry[] {\n return [...this.#entries.values()].sort((a, b) => a.path.localeCompare(b.path));\n }\n\n async #scan(): Promise<void> {\n const next = new Map<string, FileEntry>();\n await this.#walk(this.#root, '', next);\n const touched = [...next.values()].filter(\n (entry) => !same(this.#entries.get(entry.path), entry)\n );\n const gone = [...this.#entries.values()].filter((entry) => !next.has(entry.path));\n const first = !this.#scanned;\n const previous = this.#entries;\n this.#entries = next;\n this.#scanned = true;\n if (first || touched.length + gone.length === 0) return;\n this.emit('files', this.#list());\n for (const entry of [...touched, ...gone]) {\n if (entry.kind === 'file' || previous.get(entry.path)?.kind === 'file')\n this.emit('file', entry.path);\n }\n }\n\n refresh(): Promise<void> {\n if (this.#running !== null) {\n this.#again = true;\n return this.#running;\n }\n this.#running = (async () => {\n do {\n this.#again = false;\n await this.#scan();\n } while (this.#again);\n })().finally(() => {\n this.#running = null;\n });\n return this.#running;\n }\n\n async list(): Promise<readonly FileEntry[]> {\n if (!this.#scanned) await this.refresh();\n return this.#list();\n }\n\n async #parent(path: string, create: boolean): Promise<[FileSystemDirectoryHandle, string]> {\n const parts = split(path);\n const name = parts.pop();\n if (!name) throw new Error(`EISDIR: ${path}`);\n let dir = this.#root;\n for (const part of parts) dir = await dir.getDirectoryHandle(part, { create });\n return [dir, name];\n }\n\n async read(path: string): Promise<string> {\n try {\n const [dir, name] = await this.#parent(path, false);\n return await (await (await dir.getFileHandle(name)).getFile()).text();\n } catch {\n throw new Error(`ENOENT: ${path}`);\n }\n }\n\n async write(path: string, text: string): Promise<void> {\n const [dir, name] = await this.#parent(path, true);\n const writable = await (await dir.getFileHandle(name, { create: true })).createWritable();\n await writable.write(text);\n await writable.close();\n await this.refresh();\n }\n\n async remove(path: string): Promise<void> {\n try {\n const [dir, name] = await this.#parent(path, false);\n await dir.removeEntry(name, { recursive: true });\n } catch {\n throw new Error(`ENOENT: ${path}`);\n }\n await this.refresh();\n }\n\n changes(): readonly Change[] {\n return [];\n }\n\n accept(): void {}\n\n async revert(): Promise<void> {}\n}\n", "import { Emitter } from '../model/emitter.ts';\nimport type {\n Agent,\n AgentEvents,\n AgentPort,\n BrowserEvents,\n BrowserPort,\n BrowserTab,\n FrozenCone,\n Memory,\n MemoryEvents,\n MemoryPort,\n Message,\n MonitorEvents,\n MonitorPort,\n MonitorSnapshot,\n SlashCommand,\n SprinkleEvents,\n SprinklePort,\n TrayEvents,\n TrayPort,\n TrayStatus,\n UserMessage,\n} from '../model/types.ts';\n\nfunction missing(what: string): Error {\n return new Error(`No ${what} in this SLICC yet`);\n}\n\nexport class IdleAgent extends Emitter<AgentEvents> implements AgentPort {\n list(): readonly Agent[] {\n return [];\n }\n active(): string {\n return '';\n }\n select(): void {}\n messages(): readonly Message[] {\n return [];\n }\n async send(): Promise<void> {\n throw missing('agent');\n }\n stop(): void {}\n busy(): boolean {\n return false;\n }\n queue(): readonly UserMessage[] {\n return [];\n }\n unqueue(): void {}\n suggestion(): string | null {\n return null;\n }\n answer(): void {}\n resolveLick(): void {}\n compact(): void {}\n clear(): void {}\n setModel(): void {}\n setThinking(): void {}\n async older(): Promise<readonly Message[]> {\n return [];\n }\n commands(): readonly SlashCommand[] {\n return [];\n }\n async ready(): Promise<void> {}\n createScoop(): Agent {\n throw missing('agent');\n }\n frozen(): readonly FrozenCone[] {\n return [];\n }\n freeze(): void {}\n thaw(): Agent | null {\n return null;\n }\n discard(): void {}\n}\n\nexport class IdleBrowser extends Emitter<BrowserEvents> implements BrowserPort {\n list(): readonly BrowserTab[] {\n return [];\n }\n active(): string | null {\n return null;\n }\n activate(): void {}\n open(): BrowserTab {\n throw missing('browser');\n }\n navigate(): void {}\n close(): void {}\n async screenshot(): Promise<string> {\n throw missing('browser');\n }\n}\n\nexport class IdleMemory extends Emitter<MemoryEvents> implements MemoryPort {\n list(): readonly Memory[] {\n return [];\n }\n save(): Memory {\n throw missing('memory');\n }\n remove(): void {}\n}\n\nexport class IdleMonitor extends Emitter<MonitorEvents> implements MonitorPort {\n snapshot(): MonitorSnapshot {\n return { vitals: [], alerts: [], sections: [], updatedAt: 0 };\n }\n resync(): void {}\n}\n\nexport class IdleSprinkles extends Emitter<SprinkleEvents> implements SprinklePort {\n list(): readonly [] {\n return [];\n }\n send(): void {}\n}\n\nexport class IdleTray extends Emitter<TrayEvents> implements TrayPort {\n status(): TrayStatus {\n return {\n name: 'slicc',\n kind: 'hosted',\n connection: 'offline',\n role: 'none',\n followers: [],\n spent: 0,\n rate: 0,\n budget: { percent: 0, window: 'daily', resets: '' },\n joinUrl: '',\n };\n }\n reconnect(): void {}\n disconnect(): void {}\n}\n", "import type { TerminalBackend } from '../backend.ts';\nimport { cwdPromptCommand, kernelBackend, type TerminalKernel } from '../kernel-backend.ts';\nimport { Emitter } from '../model/emitter.ts';\nimport type { TerminalEvents, TerminalInfo, TerminalPort } from '../model/types.ts';\n\nexport interface KernelTerminalsOptions {\n argv?: string[];\n cwd?: string;\n user?: string | number;\n env?: Record<string, string>;\n open?: number;\n}\n\nexport class KernelTerminals extends Emitter<TerminalEvents> implements TerminalPort {\n #kernel: TerminalKernel;\n #argv: string[];\n #cwd: string;\n #user: string | number | undefined;\n #env: Record<string, string> | undefined;\n #terminals: TerminalInfo[] = [];\n #backends = new Map<string, TerminalBackend>();\n #next = 1;\n\n constructor(\n kernel: TerminalKernel,\n { argv = ['bash', '-i'], cwd = '/home', user, env, open = 1 }: KernelTerminalsOptions = {}\n ) {\n super();\n this.#kernel = kernel;\n this.#argv = argv;\n this.#cwd = cwd;\n this.#user = user;\n this.#env = env;\n for (let i = 0; i < open; i++) this.open();\n }\n\n list(): readonly TerminalInfo[] {\n return this.#terminals.map((terminal) => ({ ...terminal }));\n }\n\n open({\n cwd = this.#cwd,\n agentId = null,\n }: {\n cwd?: string;\n agentId?: string | null;\n } = {}): TerminalInfo {\n const terminal: TerminalInfo = {\n id: `term-${this.#next}`,\n title: `${this.#argv[0]} ${this.#next}`,\n cwd,\n agentId,\n };\n this.#next += 1;\n this.#terminals.push(terminal);\n this.emit('terminals', this.list());\n return { ...terminal };\n }\n\n close(id: string): void {\n this.#terminals = this.#terminals.filter((terminal) => terminal.id !== id);\n this.#backends.delete(id);\n this.emit('terminals', this.list());\n }\n\n #move(id: string, cwd: string): void {\n const terminal = this.#terminals.find((candidate) => candidate.id === id);\n if (!terminal || terminal.cwd === cwd) return;\n terminal.cwd = cwd;\n this.emit('terminals', this.list());\n }\n\n backend(id: string): TerminalBackend {\n const terminal = this.#terminals.find((candidate) => candidate.id === id);\n if (!terminal) throw new Error(`No terminal ${id}`);\n let backend = this.#backends.get(id);\n if (!backend) {\n backend = kernelBackend(this.#kernel, {\n argv: this.#argv,\n cwd: terminal.cwd,\n user: this.#user,\n env: { PROMPT_COMMAND: cwdPromptCommand, ...this.#env },\n onCwd: (cwd) => this.#move(id, cwd),\n });\n this.#backends.set(id, backend);\n }\n return backend;\n }\n}\n", "import { clock } from '../dummy/clock.ts';\nimport { DummySettings, dummySettingsKey } from '../dummy/settings.ts';\nimport type { TerminalKernel } from '../kernel-backend.ts';\nimport type { Settings, SliccModel } from '../model/types.ts';\nimport { KernelFiles, type KernelFilesOptions } from './files.ts';\nimport {\n IdleAgent,\n IdleBrowser,\n IdleMemory,\n IdleMonitor,\n IdleSprinkles,\n IdleTray,\n} from './idle.ts';\nimport { KernelTerminals, type KernelTerminalsOptions } from './terminals.ts';\n\nexport interface KernelModelOptions {\n kernel: TerminalKernel;\n root: FileSystemDirectoryHandle;\n files?: KernelFilesOptions;\n terminals?: KernelTerminalsOptions;\n storage?: Storage | null;\n}\n\nexport interface KernelModel extends SliccModel {\n files: KernelFiles;\n terminals: KernelTerminals;\n}\n\nexport const settingsKey = 'slicc-agent.settings';\n\nconst defaults: Settings = {\n color: 'system',\n model: '',\n thinking: 'off',\n sendOnEnter: true,\n showThinking: false,\n diffStyle: 'unified',\n};\n\nexport function idleModel(storage: Storage | null = null): Omit<SliccModel, 'files' | 'terminals'> {\n return {\n agent: new IdleAgent(),\n browser: new IdleBrowser(),\n settings: new DummySettings(defaults, [], [], storage, clock(0), [\n settingsKey,\n dummySettingsKey,\n ]),\n memory: new IdleMemory(),\n monitor: new IdleMonitor(),\n sprinkles: new IdleSprinkles(),\n tray: new IdleTray(),\n };\n}\n\nexport function createKernelModel({\n kernel,\n root,\n files,\n terminals,\n storage = null,\n}: KernelModelOptions): KernelModel {\n const model: KernelModel = {\n ...idleModel(storage),\n files: new KernelFiles(root, files),\n terminals: new KernelTerminals(kernel, terminals),\n };\n model.files.start();\n return model;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Emitter } from '../model/emitter.ts';\nimport type { Change, FileEntry, FileEvents, FilePort } from '../model/types.ts';\n\nexport interface KernelFilesOptions {\n skip?: readonly string[];\n hide?: readonly string[];\n interval?: number;\n}\n\ninterface Observer {\n observe(handle: FileSystemHandle, options: { recursive: boolean }): Promise<void>;\n disconnect(): void;\n}\n\ntype ObserverConstructor = new (callback: () => void) => Observer;\n\nfunction split(path: string): string[] {\n return path.split('/').filter(Boolean);\n}\n\nfunction same(a: FileEntry | undefined, b: FileEntry): boolean {\n return a?.kind === b.kind && a.size === b.size && a.modified === b.modified;\n}\n\nexport class KernelFiles extends Emitter<FileEvents> implements FilePort {\n #root: FileSystemDirectoryHandle;\n #skip: Set<string>;\n #hide: Set<string>;\n #interval: number;\n #entries = new Map<string, FileEntry>();\n #scanned = false;\n #running: Promise<void> | null = null;\n #again = false;\n #timer: ReturnType<typeof setInterval> | null = null;\n #observer: Observer | null = null;\n\n constructor(\n root: FileSystemDirectoryHandle,\n { skip = [], hide = [], interval = 2000 }: KernelFilesOptions = {}\n ) {\n super();\n this.#root = root;\n this.#skip = new Set(skip);\n this.#hide = new Set(hide);\n this.#interval = interval;\n }\n\n start(): void {\n if (this.#timer || this.#observer) return;\n const Observer = (globalThis as { FileSystemObserver?: ObserverConstructor })\n .FileSystemObserver;\n if (!Observer) {\n this.#poll();\n return;\n }\n const observer = new Observer(() => void this.refresh());\n this.#observer = observer;\n observer.observe(this.#root, { recursive: true }).catch(() => {\n if (this.#observer !== observer) return;\n this.#observer = null;\n this.#poll();\n });\n }\n\n #poll(): void {\n this.#timer = setInterval(() => void this.refresh(), this.#interval);\n }\n\n stop(): void {\n if (this.#timer) clearInterval(this.#timer);\n this.#timer = null;\n this.#observer?.disconnect();\n this.#observer = null;\n }\n\n async #walk(\n dir: FileSystemDirectoryHandle,\n prefix: string,\n out: Map<string, FileEntry>\n ): Promise<void> {\n const values = (\n dir as FileSystemDirectoryHandle & {\n values(): AsyncIterable<FileSystemDirectoryHandle | FileSystemFileHandle>;\n }\n ).values();\n for await (const handle of values) {\n const path = `${prefix}/${handle.name}`;\n if (this.#hide.has(path)) continue;\n if (handle.kind === 'directory') {\n out.set(path, { path, kind: 'directory', size: 0, modified: 0 });\n if (!this.#skip.has(path)) await this.#walk(handle, path, out).catch(() => {});\n } else {\n const file = await handle.getFile().catch(() => null);\n if (file)\n out.set(path, { path, kind: 'file', size: file.size, modified: file.lastModified });\n }\n }\n }\n\n #list(): FileEntry[] {\n return [...this.#entries.values()].sort((a, b) => a.path.localeCompare(b.path));\n }\n\n async #scan(): Promise<void> {\n const next = new Map<string, FileEntry>();\n await this.#walk(this.#root, '', next);\n const touched = [...next.values()].filter(\n (entry) => !same(this.#entries.get(entry.path), entry)\n );\n const gone = [...this.#entries.values()].filter((entry) => !next.has(entry.path));\n const first = !this.#scanned;\n const previous = this.#entries;\n this.#entries = next;\n this.#scanned = true;\n if (first || touched.length + gone.length === 0) return;\n this.emit('files', this.#list());\n for (const entry of [...touched, ...gone]) {\n if (entry.kind === 'file' || previous.get(entry.path)?.kind === 'file')\n this.emit('file', entry.path);\n }\n }\n\n refresh(): Promise<void> {\n if (this.#running !== null) {\n this.#again = true;\n return this.#running;\n }\n this.#running = (async () => {\n do {\n this.#again = false;\n await this.#scan();\n } while (this.#again);\n })().finally(() => {\n this.#running = null;\n });\n return this.#running;\n }\n\n async list(): Promise<readonly FileEntry[]> {\n if (!this.#scanned) await this.refresh();\n return this.#list();\n }\n\n async #parent(path: string, create: boolean): Promise<[FileSystemDirectoryHandle, string]> {\n const parts = split(path);\n const name = parts.pop();\n if (!name) throw new Error(`EISDIR: ${path}`);\n let dir = this.#root;\n for (const part of parts) dir = await dir.getDirectoryHandle(part, { create });\n return [dir, name];\n }\n\n async read(path: string): Promise<string> {\n try {\n const [dir, name] = await this.#parent(path, false);\n return await (await (await dir.getFileHandle(name)).getFile()).text();\n } catch {\n throw new Error(`ENOENT: ${path}`);\n }\n }\n\n async write(path: string, text: string): Promise<void> {\n const [dir, name] = await this.#parent(path, true);\n const writable = await (await dir.getFileHandle(name, { create: true })).createWritable();\n await writable.write(text);\n await writable.close();\n await this.refresh();\n }\n\n async remove(path: string): Promise<void> {\n try {\n const [dir, name] = await this.#parent(path, false);\n await dir.removeEntry(name, { recursive: true });\n } catch {\n throw new Error(`ENOENT: ${path}`);\n }\n await this.refresh();\n }\n\n changes(): readonly Change[] {\n return [];\n }\n\n accept(): void {}\n\n async revert(): Promise<void> {}\n}\n", "import { Emitter } from '../model/emitter.ts';\nimport type {\n Agent,\n AgentEvents,\n AgentPort,\n BrowserEvents,\n BrowserPort,\n BrowserTab,\n FrozenCone,\n Memory,\n MemoryEvents,\n MemoryPort,\n Message,\n MonitorEvents,\n MonitorPort,\n MonitorSnapshot,\n SlashCommand,\n SprinkleEvents,\n SprinklePort,\n TrayEvents,\n TrayPort,\n TrayStatus,\n UserMessage,\n} from '../model/types.ts';\n\nfunction missing(what: string): Error {\n return new Error(`No ${what} in this SLICC yet`);\n}\n\nexport class IdleAgent extends Emitter<AgentEvents> implements AgentPort {\n list(): readonly Agent[] {\n return [];\n }\n active(): string {\n return '';\n }\n select(): void {}\n messages(): readonly Message[] {\n return [];\n }\n async send(): Promise<void> {\n throw missing('agent');\n }\n stop(): void {}\n busy(): boolean {\n return false;\n }\n queue(): readonly UserMessage[] {\n return [];\n }\n unqueue(): void {}\n suggestion(): string | null {\n return null;\n }\n answer(): void {}\n resolveLick(): void {}\n compact(): void {}\n clear(): void {}\n setModel(): void {}\n setThinking(): void {}\n async older(): Promise<readonly Message[]> {\n return [];\n }\n commands(): readonly SlashCommand[] {\n return [];\n }\n async ready(): Promise<void> {}\n createScoop(): Agent {\n throw missing('agent');\n }\n frozen(): readonly FrozenCone[] {\n return [];\n }\n freeze(): void {}\n thaw(): Agent | null {\n return null;\n }\n discard(): void {}\n}\n\nexport class IdleBrowser extends Emitter<BrowserEvents> implements BrowserPort {\n list(): readonly BrowserTab[] {\n return [];\n }\n active(): string | null {\n return null;\n }\n activate(): void {}\n open(): BrowserTab {\n throw missing('browser');\n }\n navigate(): void {}\n close(): void {}\n async screenshot(): Promise<string> {\n throw missing('browser');\n }\n}\n\nexport class IdleMemory extends Emitter<MemoryEvents> implements MemoryPort {\n list(): readonly Memory[] {\n return [];\n }\n save(): Memory {\n throw missing('memory');\n }\n remove(): void {}\n}\n\nexport class IdleMonitor extends Emitter<MonitorEvents> implements MonitorPort {\n snapshot(): MonitorSnapshot {\n return { vitals: [], alerts: [], sections: [], updatedAt: 0 };\n }\n resync(): void {}\n}\n\nexport class IdleSprinkles extends Emitter<SprinkleEvents> implements SprinklePort {\n list(): readonly [] {\n return [];\n }\n send(): void {}\n}\n\nexport class IdleTray extends Emitter<TrayEvents> implements TrayPort {\n status(): TrayStatus {\n return {\n name: 'slicc',\n kind: 'hosted',\n connection: 'offline',\n role: 'none',\n followers: [],\n spent: 0,\n rate: 0,\n budget: { percent: 0, window: 'daily', resets: '' },\n joinUrl: '',\n };\n }\n reconnect(): void {}\n disconnect(): void {}\n}\n", "import type { TerminalBackend } from '../backend.ts';\nimport { cwdPromptCommand, kernelBackend, type TerminalKernel } from '../kernel-backend.ts';\nimport { Emitter } from '../model/emitter.ts';\nimport type { TerminalEvents, TerminalInfo, TerminalPort } from '../model/types.ts';\n\nexport interface KernelTerminalsOptions {\n argv?: string[];\n cwd?: string;\n user?: string | number;\n env?: Record<string, string>;\n open?: number;\n}\n\nexport class KernelTerminals extends Emitter<TerminalEvents> implements TerminalPort {\n #kernel: TerminalKernel;\n #argv: string[];\n #cwd: string;\n #user: string | number | undefined;\n #env: Record<string, string> | undefined;\n #terminals: TerminalInfo[] = [];\n #backends = new Map<string, TerminalBackend>();\n #next = 1;\n\n constructor(\n kernel: TerminalKernel,\n { argv = ['bash', '-i'], cwd = '/home', user, env, open = 1 }: KernelTerminalsOptions = {}\n ) {\n super();\n this.#kernel = kernel;\n this.#argv = argv;\n this.#cwd = cwd;\n this.#user = user;\n this.#env = env;\n for (let i = 0; i < open; i++) this.open();\n }\n\n list(): readonly TerminalInfo[] {\n return this.#terminals.map((terminal) => ({ ...terminal }));\n }\n\n open({\n cwd = this.#cwd,\n agentId = null,\n }: {\n cwd?: string;\n agentId?: string | null;\n } = {}): TerminalInfo {\n const terminal: TerminalInfo = {\n id: `term-${this.#next}`,\n title: `${this.#argv[0]} ${this.#next}`,\n cwd,\n agentId,\n };\n this.#next += 1;\n this.#terminals.push(terminal);\n this.emit('terminals', this.list());\n return { ...terminal };\n }\n\n close(id: string): void {\n this.#terminals = this.#terminals.filter((terminal) => terminal.id !== id);\n this.#backends.delete(id);\n this.emit('terminals', this.list());\n }\n\n #move(id: string, cwd: string): void {\n const terminal = this.#terminals.find((candidate) => candidate.id === id);\n if (!terminal || terminal.cwd === cwd) return;\n terminal.cwd = cwd;\n this.emit('terminals', this.list());\n }\n\n backend(id: string): TerminalBackend {\n const terminal = this.#terminals.find((candidate) => candidate.id === id);\n if (!terminal) throw new Error(`No terminal ${id}`);\n let backend = this.#backends.get(id);\n if (!backend) {\n backend = kernelBackend(this.#kernel, {\n argv: this.#argv,\n cwd: terminal.cwd,\n user: this.#user,\n env: { PROMPT_COMMAND: cwdPromptCommand, ...this.#env },\n onCwd: (cwd) => this.#move(id, cwd),\n });\n this.#backends.set(id, backend);\n }\n return backend;\n }\n}\n", "import { clock } from '../dummy/clock.ts';\nimport { DummySettings, dummySettingsKey } from '../dummy/settings.ts';\nimport type { TerminalKernel } from '../kernel-backend.ts';\nimport type { Settings, SliccModel } from '../model/types.ts';\nimport { KernelFiles, type KernelFilesOptions } from './files.ts';\nimport {\n IdleAgent,\n IdleBrowser,\n IdleMemory,\n IdleMonitor,\n IdleSprinkles,\n IdleTray,\n} from './idle.ts';\nimport { KernelTerminals, type KernelTerminalsOptions } from './terminals.ts';\n\nexport interface KernelModelOptions {\n kernel: TerminalKernel;\n root: FileSystemDirectoryHandle;\n files?: KernelFilesOptions;\n terminals?: KernelTerminalsOptions;\n storage?: Storage | null;\n}\n\nexport interface KernelModel extends SliccModel {\n files: KernelFiles;\n terminals: KernelTerminals;\n}\n\nexport const settingsKey = 'slicc-agent.settings';\n\nconst defaults: Settings = {\n color: 'system',\n model: '',\n thinking: 'off',\n sendOnEnter: true,\n pushToTalk: false,\n showThinking: false,\n diffStyle: 'unified',\n};\n\nexport function idleModel(storage: Storage | null = null): Omit<SliccModel, 'files' | 'terminals'> {\n return {\n agent: new IdleAgent(),\n browser: new IdleBrowser(),\n settings: new DummySettings(defaults, [], [], storage, clock(0), [\n settingsKey,\n dummySettingsKey,\n ]),\n memory: new IdleMemory(),\n monitor: new IdleMonitor(),\n sprinkles: new IdleSprinkles(),\n tray: new IdleTray(),\n };\n}\n\nexport function createKernelModel({\n kernel,\n root,\n files,\n terminals,\n storage = null,\n}: KernelModelOptions): KernelModel {\n const model: KernelModel = {\n ...idleModel(storage),\n files: new KernelFiles(root, files),\n terminals: new KernelTerminals(kernel, terminals),\n };\n model.files.start();\n return model;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/slicc-ui.js CHANGED
@@ -8837,6 +8837,10 @@ var shared = i`
8837
8837
  padding: 0 var(--swc-spacing-75);
8838
8838
  }
8839
8839
  `;
8840
+ function speech() {
8841
+ const scope = globalThis;
8842
+ return scope.SpeechRecognition ?? scope.webkitSpeechRecognition;
8843
+ }
8840
8844
 
8841
8845
  // node_modules/@adobe/spectrum-wc/dist/components/button/button.js
8842
8846
  var t42 = i`.swc-Button{--_swc-button-border-width: 2px;--_swc-button-min-block-size: var(--swc-button-min-block-size, var(--swc-component-height-100));gap:var(--swc-button-gap, 6px);max-inline-size:var(--swc-button-max-inline-size, inherit);min-block-size:var(--_swc-button-min-block-size);padding-block:calc(var(--swc-button-padding-vertical, 7px) - var(--_swc-button-border-width));padding-inline:calc(var(--swc-button-edge-to-text, var(--swc-base-padding-horizontal-medium)) - var(--_swc-button-border-width));font-family:var(--swc-sans-font-family-stack);font-size:var(--swc-button-font-size, var(--swc-font-size-100));font-weight:700;line-height:round(down,1.3em,1px);color:var(--swc-button-content-color-default, var(--swc-gray-25));background-color:var(--swc-button-background-color-default, var(--swc-gray-800));border-color:var(--swc-button-border-color-default, transparent);border-width:var(--_swc-button-border-width);border-radius:var(--swc-button-border-radius, calc(var(--_swc-button-min-block-size) / 2));transition-timing-function:cubic-bezier(.45,0,.4,1);transition-duration:.13s;transition-property:outline,border-color,color,background-color,transform}.swc-Button:hover{color:var(--swc-button-content-color-hover, var(--swc-gray-25));background-color:var(--swc-button-background-color-hover, var(--swc-gray-900));border-color:var(--swc-button-border-color-hover, transparent)}.swc-Button:focus-visible{color:var(--swc-button-content-color-focus, var(--swc-gray-25));background-color:var(--swc-button-background-color-focus, var(--swc-gray-900));border-color:var(--swc-button-border-color-focus, transparent)}.swc-Button:active{color:var(--swc-button-content-color-down, var(--swc-gray-25));background-color:var(--swc-button-background-color-down, var(--swc-gray-900));border-color:var(--swc-button-border-color-down, transparent);transform:var(--swc-button-down-state-transform, perspective(var(--_swc-button-min-block-size)) translate3d(0, 0, -2px));will-change:transform}.swc-Button-label{text-align:center}.swc-Button--hasIcon .swc-Button-label{text-align:start}slot[name=icon]::slotted(*),.swc-PendingSpinner{--_swc-button-icon-size: var(--swc-button-icon-size, var(--swc-workflow-icon-medium));--_swc-button-icon-block-size: var(--swc-button-icon-block-size, var(--_swc-button-icon-size));--_swc-pending-spinner-size: var(--_swc-button-icon-size);box-sizing:border-box;flex-shrink:0;align-self:flex-start;inline-size:var(--swc-button-icon-inline-size, var(--_swc-button-icon-size));block-size:var(--_swc-button-icon-block-size);margin-block:calc((var(--_swc-button-icon-block-size) - 1lh) / 2 * -1);margin-inline-start:calc(var(--swc-button-edge-to-visual, var(--swc-base-padding-horizontal-medium)) - var(--swc-button-edge-to-text, var(--swc-base-padding-horizontal-medium)))}slot[name=icon]::slotted(*){color:inherit;fill:currentcolor}:host([size=\"s\"]){--swc-button-min-block-size: var(--swc-component-height-75);--swc-button-font-size: var(--swc-font-size-75);--swc-button-gap: 4px;--swc-button-edge-to-text: var(--swc-base-padding-horizontal-small);--swc-button-edge-to-visual: var(--swc-base-padding-horizontal-small);--swc-button-edge-to-visual-only: 4px;--swc-button-padding-vertical: 4px;--swc-button-icon-size: var(--swc-workflow-icon-small)}:host([size=\"l\"]){--swc-button-min-block-size: var(--swc-component-height-200);--swc-button-font-size: var(--swc-font-size-200);--swc-button-gap: 6px;--swc-button-edge-to-text: var(--swc-base-padding-horizontal-large);--swc-button-edge-to-visual: var(--swc-base-padding-horizontal-large);--swc-button-edge-to-visual-only: 7px;--swc-button-padding-vertical: 10px;--swc-button-icon-size: var(--swc-workflow-icon-large)}:host([size=\"xl\"]){--swc-button-min-block-size: var(--swc-component-height-300);--swc-button-font-size: var(--swc-font-size-300);--swc-button-gap: 6px;--swc-button-edge-to-text: var(--swc-base-padding-horizontal-extra-large);--swc-button-edge-to-visual: var(--swc-base-padding-horizontal-extra-large);--swc-button-edge-to-visual-only: 9px;--swc-button-padding-vertical: 13px;--swc-button-icon-size: var(--swc-workflow-icon-extra-large)}:host([variant=\"accent\"]){--swc-button-content-color-default: rgb(255, 255, 255);--swc-button-content-color-hover: rgb(255, 255, 255);--swc-button-content-color-down: rgb(255, 255, 255);--swc-button-content-color-focus: rgb(255, 255, 255);--swc-button-background-color-default: var(--swc-accent-background-color-default);--swc-button-background-color-hover: var(--swc-accent-background-color-hover);--swc-button-background-color-down: var(--swc-accent-background-color-down);--swc-button-background-color-focus: var(--swc-accent-background-color-key-focus)}:host([variant=\"negative\"]){--swc-button-content-color-default: rgb(255, 255, 255);--swc-button-content-color-hover: rgb(255, 255, 255);--swc-button-content-color-down: rgb(255, 255, 255);--swc-button-content-color-focus: rgb(255, 255, 255);--swc-button-background-color-default: var(--swc-negative-background-color-default);--swc-button-background-color-hover: var(--swc-negative-background-color-hover);--swc-button-background-color-down: var(--swc-negative-background-color-down);--swc-button-background-color-focus: var(--swc-negative-background-color-key-focus)}:host([variant=\"secondary\"]){--swc-button-content-color-default: var(--swc-gray-800);--swc-button-content-color-hover: var(--swc-gray-900);--swc-button-content-color-down: var(--swc-gray-900);--swc-button-content-color-focus: var(--swc-gray-900);--swc-button-background-color-default: var(--swc-gray-100);--swc-button-background-color-hover: var(--swc-gray-200);--swc-button-background-color-down: var(--swc-gray-200);--swc-button-background-color-focus: var(--swc-gray-200)}:host([variant=\"primary\"][fill-style=\"outline\"]){--swc-button-background-color-default: transparent;--swc-button-background-color-hover: var(--swc-gray-100);--swc-button-background-color-down: var(--swc-gray-100);--swc-button-background-color-focus: var(--swc-gray-100);--swc-button-border-color-default: var(--swc-gray-800);--swc-button-border-color-hover: var(--swc-gray-900);--swc-button-border-color-down: var(--swc-gray-900);--swc-button-border-color-focus: var(--swc-gray-900);--swc-button-content-color-default: var(--swc-gray-800);--swc-button-content-color-hover: var(--swc-gray-900);--swc-button-content-color-down: var(--swc-gray-900);--swc-button-content-color-focus: var(--swc-gray-900);--swc-button-background-color-disabled: transparent;--swc-button-border-color-disabled: var(--swc-gray-300)}:host([variant=\"secondary\"][fill-style=\"outline\"]){--swc-button-background-color-default: transparent;--swc-button-background-color-hover: var(--swc-gray-100);--swc-button-background-color-down: var(--swc-gray-100);--swc-button-background-color-focus: var(--swc-gray-100);--swc-button-border-color-default: var(--swc-gray-300);--swc-button-border-color-hover: var(--swc-gray-400);--swc-button-border-color-down: var(--swc-gray-400);--swc-button-border-color-focus: var(--swc-gray-400);--swc-button-background-color-disabled: transparent;--swc-button-border-color-disabled: var(--swc-gray-300)}:host([static-color=\"white\"]){--swc-button-focus-indicator-color: var(--swc-white);--swc-button-background-color-default: rgba(255, 255, 255, .85);--swc-button-background-color-hover: rgba(255, 255, 255, .94);--swc-button-background-color-down: rgba(255, 255, 255, .94);--swc-button-background-color-focus: rgba(255, 255, 255, .94);--swc-button-content-color-default: rgb(0, 0, 0);--swc-button-content-color-hover: rgb(0, 0, 0);--swc-button-content-color-down: rgb(0, 0, 0);--swc-button-content-color-focus: rgb(0, 0, 0);--swc-button-background-color-disabled: var(--swc-transparent-white-100);--swc-button-border-color-disabled: transparent;--swc-button-content-color-disabled: var(--swc-transparent-white-400)}:host([static-color=\"white\"][variant=\"secondary\"]){--swc-button-background-color-default: rgba(255, 255, 255, .11);--swc-button-background-color-hover: rgba(255, 255, 255, .14);--swc-button-background-color-down: rgba(255, 255, 255, .14);--swc-button-background-color-focus: rgba(255, 255, 255, .14);--swc-button-content-color-default: rgba(255, 255, 255, .85);--swc-button-content-color-hover: rgba(255, 255, 255, .94);--swc-button-content-color-down: rgba(255, 255, 255, .94);--swc-button-content-color-focus: rgba(255, 255, 255, .94)}:host([static-color=\"white\"][fill-style=\"outline\"]){--swc-button-background-color-default: rgba(255, 255, 255, 0);--swc-button-background-color-hover: rgba(255, 255, 255, .11);--swc-button-background-color-down: rgba(255, 255, 255, .11);--swc-button-background-color-focus: rgba(255, 255, 255, .11);--swc-button-border-color-default: rgba(255, 255, 255, .85);--swc-button-border-color-hover: rgba(255, 255, 255, .94);--swc-button-border-color-down: rgba(255, 255, 255, .94);--swc-button-border-color-focus: rgba(255, 255, 255, .94);--swc-button-content-color-default: rgba(255, 255, 255, .85);--swc-button-content-color-hover: rgba(255, 255, 255, .94);--swc-button-content-color-down: rgba(255, 255, 255, .94);--swc-button-content-color-focus: rgba(255, 255, 255, .94);--swc-button-background-color-disabled: rgba(255, 255, 255, 0);--swc-button-border-color-disabled: var(--swc-transparent-white-300);--swc-button-content-color-disabled: var(--swc-transparent-white-400)}:host([static-color=\"white\"][variant=\"secondary\"][fill-style=\"outline\"]){--swc-button-background-color-default: rgba(255, 255, 255, 0);--swc-button-background-color-hover: rgba(255, 255, 255, .11);--swc-button-background-color-down: rgba(255, 255, 255, .11);--swc-button-background-color-focus: rgba(255, 255, 255, .11);--swc-button-border-color-default: rgba(255, 255, 255, .17);--swc-button-border-color-hover: rgba(255, 255, 255, .21);--swc-button-border-color-down: rgba(255, 255, 255, .21);--swc-button-border-color-focus: rgba(255, 255, 255, .21)}:host([static-color=\"black\"]){--swc-button-focus-indicator-color: var(--swc-black);--swc-button-background-color-default: rgba(0, 0, 0, .84);--swc-button-background-color-hover: rgba(0, 0, 0, .93);--swc-button-background-color-down: rgba(0, 0, 0, .93);--swc-button-background-color-focus: rgba(0, 0, 0, .93);--swc-button-content-color-default: rgb(255, 255, 255);--swc-button-content-color-hover: rgb(255, 255, 255);--swc-button-content-color-down: rgb(255, 255, 255);--swc-button-content-color-focus: rgb(255, 255, 255);--swc-button-background-color-disabled: var(--swc-transparent-black-100);--swc-button-border-color-disabled: transparent;--swc-button-content-color-disabled: var(--swc-transparent-black-400)}:host([static-color=\"black\"][variant=\"secondary\"]){--swc-button-background-color-default: rgba(0, 0, 0, .09);--swc-button-background-color-hover: rgba(0, 0, 0, .12);--swc-button-background-color-down: rgba(0, 0, 0, .12);--swc-button-background-color-focus: rgba(0, 0, 0, .12);--swc-button-content-color-default: rgba(0, 0, 0, .84);--swc-button-content-color-hover: rgba(0, 0, 0, .93);--swc-button-content-color-down: rgba(0, 0, 0, .93);--swc-button-content-color-focus: rgba(0, 0, 0, .93)}:host([static-color=\"black\"][fill-style=\"outline\"]){--swc-button-background-color-default: rgba(0, 0, 0, 0);--swc-button-background-color-hover: rgba(0, 0, 0, .09);--swc-button-background-color-down: rgba(0, 0, 0, .09);--swc-button-background-color-focus: rgba(0, 0, 0, .09);--swc-button-border-color-default: rgba(0, 0, 0, .84);--swc-button-border-color-hover: rgba(0, 0, 0, .93);--swc-button-border-color-down: rgba(0, 0, 0, .93);--swc-button-border-color-focus: rgba(0, 0, 0, .93);--swc-button-content-color-default: rgba(0, 0, 0, .84);--swc-button-content-color-hover: rgba(0, 0, 0, .93);--swc-button-content-color-down: rgba(0, 0, 0, .93);--swc-button-content-color-focus: rgba(0, 0, 0, .93);--swc-button-background-color-disabled: rgba(0, 0, 0, 0);--swc-button-border-color-disabled: var(--swc-transparent-black-300);--swc-button-content-color-disabled: var(--swc-transparent-black-400)}:host([static-color=\"black\"][variant=\"secondary\"][fill-style=\"outline\"]){--swc-button-background-color-default: rgba(0, 0, 0, 0);--swc-button-background-color-hover: rgba(0, 0, 0, .09);--swc-button-background-color-down: rgba(0, 0, 0, .09);--swc-button-background-color-focus: rgba(0, 0, 0, .09);--swc-button-border-color-default: rgba(0, 0, 0, .15);--swc-button-border-color-hover: rgba(0, 0, 0, .22);--swc-button-border-color-down: rgba(0, 0, 0, .22);--swc-button-border-color-focus: rgba(0, 0, 0, .22)}.swc-Button--iconOnly{--swc-button-border-radius: 50%;--swc-button-gap: 0;inline-size:var(--_swc-button-min-block-size);padding-inline:calc(var(--swc-button-edge-to-visual-only, 5px) - var(--_swc-button-border-width))}.swc-Button--iconOnly slot[name=icon]::slotted(*){--swc-button-edge-to-visual: 0;align-self:center}:host([pending]) .swc-Button{cursor:default}.swc-Button--pendingActive{--swc-button-down-state-transform: none;justify-content:center;inline-size:var(--swc-pending-inline-size);transition:none;--swc-button-background-color-default: var(--swc-button-background-color-disabled, var(--swc-gray-100));--swc-button-background-color-hover: var(--swc-button-background-color-disabled, var(--swc-gray-100));--swc-button-background-color-down: var(--swc-button-background-color-disabled, var(--swc-gray-100));--swc-button-background-color-focus: var(--swc-button-background-color-disabled, var(--swc-gray-100));--swc-button-border-color-default: var(--swc-button-border-color-disabled, transparent);--swc-button-border-color-hover: var(--swc-button-border-color-disabled, transparent);--swc-button-border-color-down: var(--swc-button-border-color-disabled, transparent);--swc-button-border-color-focus: var(--swc-button-border-color-disabled, transparent);--swc-button-content-color-default: var(--swc-button-content-color-disabled, var(--swc-gray-400));--swc-button-content-color-hover: var(--swc-button-content-color-disabled, var(--swc-gray-400));--swc-button-content-color-down: var(--swc-button-content-color-disabled, var(--swc-gray-400));--swc-button-content-color-focus: var(--swc-button-content-color-disabled, var(--swc-gray-400))}.swc-Button--pendingActive .swc-Button-label,.swc-Button--pendingActive slot[name=icon]::slotted(*){display:none}:host([truncate]) .swc-Button-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host([justified]){flex-grow:1;justify-self:stretch;inline-size:100%}:host([justified]) .swc-Button{inline-size:100%}@media(prefers-reduced-motion:reduce){.swc-Button{transition-duration:0ms}}@media(forced-colors:active){.swc-Button--pendingActive{--swc-button-background-color-default: ButtonFace;--swc-button-background-color-hover: ButtonFace;--swc-button-background-color-down: ButtonFace;--swc-button-background-color-focus: ButtonFace;--swc-button-border-color-default: GrayText;--swc-button-border-color-hover: GrayText;--swc-button-border-color-down: GrayText;--swc-button-border-color-focus: GrayText;--swc-button-content-color-default: GrayText;--swc-button-content-color-hover: GrayText;--swc-button-content-color-down: GrayText;--swc-button-content-color-focus: GrayText}}`;
@@ -9777,10 +9781,18 @@ function following(model) {
9777
9781
  return state2 && !followPage(state2) ? state2 : null;
9778
9782
  }
9779
9783
  function watchOnly(model) {
9784
+ const text2 = model?.agent?.readOnly?.();
9785
+ if (text2) return text2;
9780
9786
  const state2 = following(model);
9781
9787
  if (!state2 || state2.access.control) return "";
9782
9788
  return `Watch only. To send prompts from this device, allow Control for it on ${state2.owner}.`;
9783
9789
  }
9790
+ function onWatch(model, listener) {
9791
+ return [
9792
+ ...model.agent.readOnly ? [model.agent.on("readOnly", listener)] : [],
9793
+ ...model.follow ? [model.follow.on("follow", listener)] : []
9794
+ ];
9795
+ }
9784
9796
  function terminalsAllowed(model) {
9785
9797
  const state2 = model?.follow?.state();
9786
9798
  return !state2 || !!state2.access.terminal;
@@ -10745,7 +10757,7 @@ var SliccFreezer = class extends ModelElement {
10745
10757
  model.agent.on("frozen", update),
10746
10758
  model.agent.on("active", update),
10747
10759
  model.agent.on("agents", update),
10748
- ...model.follow ? [model.follow.on("follow", update)] : []
10760
+ ...onWatch(model, update)
10749
10761
  ];
10750
10762
  }
10751
10763
  focus() {
@@ -11633,7 +11645,7 @@ var SliccAgents = class extends ModelElement {
11633
11645
  this.requestUpdate();
11634
11646
  }),
11635
11647
  watchTitles(model, () => this.requestUpdate()),
11636
- ...model.follow ? [model.follow.on("follow", () => this.requestUpdate())] : [],
11648
+ ...onWatch(model, () => this.requestUpdate()),
11637
11649
  this.#watchPointer()
11638
11650
  ];
11639
11651
  }
@@ -12035,6 +12047,7 @@ function fallbackModel(options) {
12035
12047
  return offered.find((option2) => option2.default) ?? offered[0];
12036
12048
  }
12037
12049
  function controls(model) {
12050
+ if (model.agent.readOnly?.()) return false;
12038
12051
  const state2 = model.follow?.state();
12039
12052
  return !state2 || !!state2.access.control && state2.link === "connected";
12040
12053
  }
@@ -32946,6 +32959,12 @@ var SliccApp = class extends ThemedElement {
32946
32959
  ...model.updates ? [model.updates.on("items", update)] : [],
32947
32960
  ...model.network ? [model.network.on("network", update)] : [],
32948
32961
  ...model.tabs ? [model.tabs.on("tabs", update)] : [],
32962
+ ...model.agent.readOnly ? [
32963
+ model.agent.on("readOnly", () => {
32964
+ settle2();
32965
+ update();
32966
+ })
32967
+ ] : [],
32949
32968
  ...model.follow ? [
32950
32969
  model.follow.on("follow", () => {
32951
32970
  settle2();
@@ -34916,7 +34935,7 @@ var SliccBrowser = class extends ModelElement {
34916
34935
  this.requestUpdate();
34917
34936
  }),
34918
34937
  ...model.network ? [model.network.on("network", () => this.requestUpdate())] : [],
34919
- ...model.follow ? [model.follow.on("follow", () => this.requestUpdate())] : [],
34938
+ ...onWatch(model, () => this.requestUpdate()),
34920
34939
  () => clearInterval(timer),
34921
34940
  () => resize.disconnect(),
34922
34941
  () => document.removeEventListener("visibilitychange", visibility),
@@ -35585,7 +35604,10 @@ var SliccChanges = class extends ModelElement {
35585
35604
  `
35586
35605
  ];
35587
35606
  subscribe(model) {
35588
- return [changesOf(model).on("changes", () => this.requestUpdate())];
35607
+ return [
35608
+ changesOf(model).on("changes", () => this.requestUpdate()),
35609
+ ...onWatch(model, () => this.requestUpdate())
35610
+ ];
35589
35611
  }
35590
35612
  focus() {
35591
35613
  this.focusOn("li[data-path]");
@@ -35600,7 +35622,8 @@ var SliccChanges = class extends ModelElement {
35600
35622
  async #revert(event2, change) {
35601
35623
  event2.stopPropagation();
35602
35624
  this.error = "";
35603
- if (await confirmRevert(change)) this.error = await revertPaths(this.#port(), [change.path]);
35625
+ if (await confirmRevert(change) && !watchOnly(this.model))
35626
+ this.error = await revertPaths(this.#port(), [change.path]);
35604
35627
  }
35605
35628
  async #all(action) {
35606
35629
  const port = this.#port();
@@ -35612,7 +35635,7 @@ var SliccChanges = class extends ModelElement {
35612
35635
  }
35613
35636
  const count = changes2.length;
35614
35637
  const title = `Revert ${count} ${count === 1 ? "change" : "changes"}?`;
35615
- if (await confirm({ title, body: lost(changes2), action: "Revert all" }))
35638
+ if (await confirm({ title, body: lost(changes2), action: "Revert all" }) && !watchOnly(this.model))
35616
35639
  this.error = await revertPaths(
35617
35640
  port,
35618
35641
  changes2.map((change) => change.path)
@@ -35648,7 +35671,7 @@ var SliccChanges = class extends ModelElement {
35648
35671
  ${statusMark(change.status)}
35649
35672
  <span class="name">${basename(change.path)}</span>
35650
35673
  <span class="where"><bdi>${[at, by].filter(Boolean).join(" \xB7 ")}</bdi></span>
35651
- <span class="actions">
35674
+ ${watchOnly(this.model) ? A : b`<span class="actions">
35652
35675
  <swc-action-button
35653
35676
  size="xs"
35654
35677
  quiet
@@ -35667,7 +35690,7 @@ var SliccChanges = class extends ModelElement {
35667
35690
  >
35668
35691
  <swc-icon-revert slot="icon"></swc-icon-revert>
35669
35692
  </swc-action-button>
35670
- </span>
35693
+ </span>`}
35671
35694
  </li>`;
35672
35695
  }
35673
35696
  #list(changes2) {
@@ -35719,8 +35742,8 @@ var SliccChanges = class extends ModelElement {
35719
35742
  return b`<div class="bar">
35720
35743
  <span class="summary">${changes2.length} pending ${changes2.length === 1 ? "change" : "changes"}</span>
35721
35744
  <span class="spacer"></span>
35722
- ${changes2.length ? b`<swc-action-button size="s" quiet @click=${() => this.#all("accept")}>Accept all</swc-action-button>
35723
- <swc-action-button size="s" quiet @click=${() => this.#all("revert")}>Revert all</swc-action-button>` : A}
35745
+ ${changes2.length && !watchOnly(this.model) ? b`<swc-action-button size="s" quiet data-action="accept-all" @click=${() => this.#all("accept")}>Accept all</swc-action-button>
35746
+ <swc-action-button size="s" quiet data-action="revert-all" @click=${() => this.#all("revert")}>Revert all</swc-action-button>` : A}
35724
35747
  </div>
35725
35748
  ${errorLine(this.error)}
35726
35749
  ${changes2.length ? this.#list(changes2) : b`<div class="note">No pending changes. Edits by agents show up here for review.</div>`}`;
@@ -35775,11 +35798,16 @@ var SliccDiffPanel = class extends ThemedElement {
35775
35798
  `
35776
35799
  ];
35777
35800
  subscribe(model) {
35778
- return [...super.subscribe(model), changesOf(model).on("changes", () => this.requestUpdate())];
35801
+ return [
35802
+ ...super.subscribe(model),
35803
+ changesOf(model).on("changes", () => this.requestUpdate()),
35804
+ ...onWatch(model, () => this.requestUpdate())
35805
+ ];
35779
35806
  }
35780
35807
  async #revert(port, change) {
35781
35808
  this.error = "";
35782
- if (await confirmRevert(change)) this.error = await revertPaths(port, [this.path]);
35809
+ if (await confirmRevert(change) && !watchOnly(this.model))
35810
+ this.error = await revertPaths(port, [this.path]);
35783
35811
  }
35784
35812
  #body(change, style) {
35785
35813
  if (change.before === null && change.after === null) {
@@ -35828,12 +35856,12 @@ var SliccDiffPanel = class extends ThemedElement {
35828
35856
  >`
35829
35857
  )}
35830
35858
  </swc-action-group>`}
35831
- <swc-action-button size="s" quiet data-action="accept" accessible-label="Accept" title="Accept" @click=${() => port?.accept(this.path)}>
35859
+ ${watchOnly(model) ? A : b`<swc-action-button size="s" quiet data-action="accept" accessible-label="Accept" title="Accept" @click=${() => port?.accept(this.path)}>
35832
35860
  <swc-icon-checkmark slot="icon"></swc-icon-checkmark><span class="label">Accept</span>
35833
35861
  </swc-action-button>
35834
35862
  <swc-action-button size="s" quiet data-action="revert" accessible-label="Revert" title="Revert" @click=${() => this.#revert(port, change)}>
35835
35863
  <swc-icon-revert slot="icon"></swc-icon-revert><span class="label">Revert</span>
35836
- </swc-action-button>
35864
+ </swc-action-button>`}
35837
35865
  </div>
35838
35866
  ${errorLine(this.error)}
35839
35867
  ${this.#body(change, style)}`;
@@ -36348,7 +36376,7 @@ var SliccChat = class extends ThemedElement {
36348
36376
  }),
36349
36377
  model.agent.on("agents", settle2),
36350
36378
  ...model.tabs ? [model.tabs.on("tabs", () => this.requestUpdate())] : [],
36351
- ...model.follow ? [model.follow.on("follow", settle2)] : [],
36379
+ ...onWatch(model, settle2),
36352
36380
  model.agent.on("messages", (agentId) => {
36353
36381
  if (agentId === this.#id()) this.#refresh(this.#sent(agentId));
36354
36382
  }),
@@ -37925,6 +37953,10 @@ var SliccComposer = class extends ThemedElement {
37925
37953
  #abandon;
37926
37954
  #recognition = null;
37927
37955
  #erase;
37956
+ #release = (event2) => {
37957
+ const released = event2 instanceof KeyboardEvent && (event2.code === "KeyM" || event2.key === "Alt");
37958
+ if (this.dictating && (released || event2.type === "blur")) this.dictate();
37959
+ };
37928
37960
  #keys = { capture: true, handleEvent: (event2) => this.#keydown(event2) };
37929
37961
  constructor() {
37930
37962
  super();
@@ -38086,27 +38118,6 @@ var SliccComposer = class extends ThemedElement {
38086
38118
  .failed {
38087
38119
  color: var(--swc-negative-content-color-default);
38088
38120
  }
38089
- .below {
38090
- display: flex;
38091
- align-items: center;
38092
- gap: var(--swc-spacing-100);
38093
- max-width: 860px;
38094
- margin: var(--swc-spacing-75) auto 0;
38095
- min-height: var(--swc-component-height-75);
38096
- }
38097
- .below swc-action-button {
38098
- margin-inline-start: auto;
38099
- }
38100
- swc-action-button.selected {
38101
- --swc-action-button-background-color-default: var(--swc-neutral-background-color-selected-default);
38102
- --swc-action-button-background-color-hover: var(--swc-neutral-background-color-selected-hover);
38103
- --swc-action-button-background-color-down: var(--swc-neutral-background-color-selected-down);
38104
- --swc-action-button-background-color-focus: var(--swc-neutral-background-color-selected-key-focus);
38105
- --swc-action-button-content-color-default: var(--swc-gray-25);
38106
- --swc-action-button-content-color-hover: var(--swc-gray-25);
38107
- --swc-action-button-content-color-down: var(--swc-gray-25);
38108
- --swc-action-button-content-color-focus: var(--swc-gray-25);
38109
- }
38110
38121
  .popup {
38111
38122
  position: absolute;
38112
38123
  left: 0;
@@ -38212,6 +38223,8 @@ var SliccComposer = class extends ThemedElement {
38212
38223
  connectedCallback() {
38213
38224
  super.connectedCallback();
38214
38225
  clearTimeout(this.#abandon);
38226
+ globalThis.addEventListener("keyup", this.#release);
38227
+ globalThis.addEventListener("blur", this.#release);
38215
38228
  if (this.hasUpdated) this.#wire();
38216
38229
  }
38217
38230
  firstUpdated() {
@@ -38219,6 +38232,8 @@ var SliccComposer = class extends ThemedElement {
38219
38232
  }
38220
38233
  disconnectedCallback() {
38221
38234
  super.disconnectedCallback();
38235
+ globalThis.removeEventListener("keyup", this.#release);
38236
+ globalThis.removeEventListener("blur", this.#release);
38222
38237
  clearValues(this.renderRoot);
38223
38238
  const held = [
38224
38239
  this.attachments,
@@ -38564,10 +38579,21 @@ var SliccComposer = class extends ThemedElement {
38564
38579
  return this.#recall(-1);
38565
38580
  return false;
38566
38581
  }
38582
+ #talking() {
38583
+ return !!this.model?.settings.get().pushToTalk && !!speech();
38584
+ }
38585
+ #shortcut(event2) {
38586
+ if (event2.key === "Backspace" || event2.key === "Delete") this.#flash();
38587
+ const chord = event2.altKey && !event2.ctrlKey && !event2.metaKey && !event2.shiftKey;
38588
+ if (!chord || event2.code !== "KeyM" || !this.#talking()) return false;
38589
+ event2.preventDefault();
38590
+ if (!event2.repeat) this.dictate();
38591
+ return true;
38592
+ }
38567
38593
  #keydown(event2) {
38568
38594
  const area = this.#textarea;
38569
38595
  if (event2.isComposing || !area || event2.composedPath()[0] !== area) return;
38570
- if (event2.key === "Backspace" || event2.key === "Delete") this.#flash();
38596
+ if (this.#shortcut(event2)) return;
38571
38597
  const sendOnEnter = this.model?.settings.get().sendOnEnter ?? true;
38572
38598
  let handled = this.#popupKey(event2) || this.#historyKey(event2, area);
38573
38599
  if (!handled && event2.key === "Tab" && !event2.shiftKey && !this.value) {
@@ -38607,7 +38633,8 @@ var SliccComposer = class extends ThemedElement {
38607
38633
  keys.push(
38608
38634
  `${enter ? "Shift+Enter" : "Enter"} adds a new line`,
38609
38635
  "/ lists commands",
38610
- "@ mentions"
38636
+ "@ mentions",
38637
+ ...this.#talking() ? ["hold Alt+M to dictate"] : []
38611
38638
  );
38612
38639
  return `${keys.join(", ")}.`;
38613
38640
  }
@@ -38641,17 +38668,23 @@ var SliccComposer = class extends ThemedElement {
38641
38668
  );
38642
38669
  }
38643
38670
  }
38671
+ #toggleTalk = (event2) => {
38672
+ event2.stopPropagation();
38673
+ const settings = this.model?.settings;
38674
+ settings?.update({ pushToTalk: !settings.get().pushToTalk });
38675
+ };
38644
38676
  dictate() {
38645
38677
  if (this.#recognition) {
38646
38678
  this.#recognition.stop();
38647
38679
  return;
38648
38680
  }
38649
- const Speech = globalThis.SpeechRecognition ?? globalThis.webkitSpeechRecognition;
38681
+ const Speech = speech();
38650
38682
  if (!Speech) return;
38651
38683
  const recognition = new Speech();
38652
38684
  recognition.interimResults = false;
38685
+ recognition.continuous = true;
38653
38686
  recognition.onresult = (event2) => {
38654
- const text2 = [...event2.results].map((result) => result[0].transcript).join(" ");
38687
+ const text2 = [...event2.results].slice(event2.resultIndex ?? 0).map((result) => result[0].transcript).join(" ");
38655
38688
  this.value = `${this.value}${this.value && !this.value.endsWith(" ") ? " " : ""}${text2}`;
38656
38689
  };
38657
38690
  recognition.onend = () => {
@@ -38797,7 +38830,8 @@ var SliccComposer = class extends ThemedElement {
38797
38830
  const agent = this.model?.agent.list().find((candidate) => candidate.id === this.#agent);
38798
38831
  const suggestion = this.model?.agent.suggestion(this.#agent);
38799
38832
  const canSend = !!this.value.trim() || this.attachments.some((attachment2) => !attachment2.error);
38800
- const speech = "SpeechRecognition" in globalThis || "webkitSpeechRecognition" in globalThis;
38833
+ const pushToTalk = this.model?.settings.get().pushToTalk ?? false;
38834
+ const talk = !!speech();
38801
38835
  const held = this.#held();
38802
38836
  return b`<div class="column">
38803
38837
  <span id="keys" class="sr" aria-hidden="true">${this.#instructions(busy)}</span>
@@ -38835,6 +38869,10 @@ var SliccComposer = class extends ThemedElement {
38835
38869
  <sp-menu-item value="screenshot">Take a screenshot of the browser tab</sp-menu-item>
38836
38870
  <sp-menu-item value="file">Attach a file from SLICC</sp-menu-item>
38837
38871
  <sp-menu-item value="secret">Share a secret</sp-menu-item>
38872
+ ${talk ? b`<sp-menu-divider></sp-menu-divider>
38873
+ <sp-menu-group selects="multiple" data-group="talk" @change=${this.#toggleTalk}>
38874
+ <sp-menu-item value="push-to-talk" data-action="push-to-talk" ?selected=${pushToTalk}>Enable push to talk<span slot="description">Hold Alt+M to dictate</span></sp-menu-item>
38875
+ </sp-menu-group>` : A}
38838
38876
  </sp-menu>
38839
38877
  </swc-popover>
38840
38878
  <input type="file" multiple @change=${(event2) => {
@@ -38842,17 +38880,7 @@ var SliccComposer = class extends ThemedElement {
38842
38880
  void this.addFiles([...input.files ?? []]);
38843
38881
  input.value = "";
38844
38882
  }} />
38845
- </div>
38846
- ${speech ? b`<div class="below">
38847
- <swc-action-button
38848
- size="s"
38849
- quiet
38850
- class=${this.dictating ? "selected" : ""}
38851
- accessible-label=${this.dictating ? "Stop dictation" : "Dictate"}
38852
- data-action="dictate"
38853
- @click=${() => this.dictate()}
38854
- ><swc-icon-microphone slot="icon"></swc-icon-microphone></swc-action-button>
38855
- </div>` : A}`;
38883
+ </div>`;
38856
38884
  }
38857
38885
  };
38858
38886
 
@@ -39407,7 +39435,7 @@ var SliccNotices = class extends ModelElement {
39407
39435
  (action) => b`<swc-button size="s" variant="secondary" fill-style="outline" data-action=${action.id} ?pending=${pending === action.id} ?disabled=${!!pending && pending !== action.id} @click=${() => void this.act(notice.id, action.id)}>${action.label}</swc-button>`
39408
39436
  )}</div>` : A}
39409
39437
  </div>
39410
- <swc-close-button size="m" data-dismiss accessible-label=${`Dismiss: ${notice.title}`} @click=${() => this.dismiss(notice.id)}></swc-close-button>
39438
+ ${notice.dismissible === false ? A : b`<swc-close-button size="m" data-dismiss accessible-label=${`Dismiss: ${notice.title}`} @click=${() => this.dismiss(notice.id)}></swc-close-button>`}
39411
39439
  </div>`;
39412
39440
  }
39413
39441
  #tabs() {
@@ -39434,7 +39462,9 @@ var SliccNotices = class extends ModelElement {
39434
39462
  }
39435
39463
  render() {
39436
39464
  const port = this.model?.notices;
39437
- const notices = (port?.list() ?? []).filter((notice) => !this.dismissed.has(notice.id));
39465
+ const notices = (port?.list() ?? []).filter(
39466
+ (notice) => notice.dismissible === false || !this.dismissed.has(notice.id)
39467
+ );
39438
39468
  const tabs = this.#tabs();
39439
39469
  const approvals = this.model?.approvals?.decide ? [] : waiting(this.model, Date.now());
39440
39470
  if (!notices.length && !approvals.length && tabs === A) return A;
@@ -41154,6 +41184,7 @@ var SliccSettings = class extends ThemedElement {
41154
41184
  <div class="switches">
41155
41185
  <sp-switch ?checked=${value.sendOnEnter} data-setting="sendOnEnter" @change=${(e122) => this.#update({ sendOnEnter: this.#checked(e122) })}>Enter sends, Shift+Enter adds a line</sp-switch>
41156
41186
  <sp-switch ?checked=${value.showThinking} data-setting="showThinking" @change=${(e122) => this.#update({ showThinking: this.#checked(e122) })}>Show thinking</sp-switch>
41187
+ ${speech() ? b`<sp-switch ?checked=${value.pushToTalk ?? false} data-setting="pushToTalk" @change=${(e122) => this.#update({ pushToTalk: this.#checked(e122) })}>Push to talk: hold Alt+M to dictate</sp-switch>` : A}
41157
41188
  </div>
41158
41189
  </div>
41159
41190
  <div class="row">
@@ -41590,7 +41621,7 @@ var SliccSprinkle = class extends ThemedElement {
41590
41621
  () => globalThis.removeEventListener("message", this.#message),
41591
41622
  model.sprinkles.on("sprinkles", () => this.requestUpdate()),
41592
41623
  this.#dips.on("change", () => this.requestUpdate()),
41593
- ...model.follow ? [model.follow.on("follow", () => this.requestUpdate())] : []
41624
+ ...onWatch(model, () => this.requestUpdate())
41594
41625
  ];
41595
41626
  }
41596
41627
  #drag = (event2) => {