teapot-coding-agent 0.12.1 → 0.13.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
@@ -6,7 +6,9 @@ tab, and any number of long-running agents.
6
6
 
7
7
  ## Design principles
8
8
 
9
- - **TypeScript + Node.js**, minimal dependencies (`hono`, `openai`, `@hono/node-server`)
9
+ - **TypeScript + Node.js**, small dependency set (`hono`, `openai`,
10
+ `@hono/node-server`, `ws`, `zod`, `@mozilla/readability` + `happy-dom` for
11
+ `read_url`)
10
12
  - **Idle cost ≈ 0**: no polling loops; everything is event-driven or driven by
11
13
  one 15-second scheduler tick. Verified: master sits at ~0% CPU when idle.
12
14
  - **No TUI** — Discord-style chat UI built with **SolidJS + Vite**
@@ -29,21 +31,22 @@ Requires Node.js **>= 24** (TypeScript is executed natively in dev mode).
29
31
 
30
32
  ```sh
31
33
  npm install -g teapot-coding-agent
32
- mkdir -p ~/.config/teapot-coding-agent
33
- curl -o ~/.config/teapot-coding-agent/config.json \
34
- https://raw.githubusercontent.com/akku1139/teapot/main/teapot.config.example.json # then edit it
35
34
  teapot
36
- # open http://localhost:7788
35
+ # open http://localhost:7788 — the first-run wizard walks you through
36
+ # provider → API key → model → first agent (writes config.json for you)
37
37
  ```
38
38
 
39
39
  The global install puts a `teapot` binary on your PATH (it serves the compiled
40
40
  server plus the pre-built web UI — no build step, no repo checkout needed).
41
+ Prefer hand-writing the config? Skip the wizard and drop an edited copy of
42
+ [`teapot.config.example.json`](teapot.config.example.json) at the path below.
41
43
  Alternatives:
42
44
 
43
45
  ```sh
44
- npx teapot-coding-agent # run without installing
45
- teapot ~/my-config.json # explicit config path
46
- TEAPOT_PORT=8080 teapot # env overrides work as usual
46
+ npx teapot-coding-agent # run without installing
47
+ teapot --port 8080 # CLI flags: --port/-p, --config/-c
48
+ teapot ~/my-config.json # explicit config path
49
+ TEAPOT_PORT=8080 teapot # env overrides work as usual
47
50
  ```
48
51
 
49
52
  ### Run from a checkout (development)
@@ -95,16 +98,21 @@ master (Hono server, src/master.ts + src/server/api.ts)
95
98
 
96
99
  - **Agent** (`src/agent/agent.ts`): an async loop that alternates LLM turns and
97
100
  tool executions until the model stops calling tools, then auto-continues
98
- toward its goal. Stop/resume at any time via API/UI — stop aborts an
101
+ toward its goal. `ask_user` parks the loop in a `waiting` status until the
102
+ operator replies. Stop/resume at any time via API/UI — stop aborts an
99
103
  in-flight LLM call immediately (AbortController). Runaway guards: turn cap
100
104
  per round, consecutive-tool-error cap, per-command timeouts.
101
- - **Context compaction**: message history is token-estimated each turn; past a
102
- budget (`contextTokenBudget`, default ~96k) older turns are summarized by
103
- the LLM into dense continuation notes (fallback: safe truncation). Cut
104
- points never split a tool_call/tool_result pair.
105
+ - **Context management (staged)**: each turn prefers the provider's real
106
+ `prompt_tokens`; past ~60% of budget, old oversized tool outputs are pruned
107
+ (recent window protected); past the budget (`contextTokenBudget`, default
108
+ ~96k — auto-derived at 75% when a model's `contextWindowTokens` is known)
109
+ older turns are summarized into dense continuation notes plus a
110
+ "## Durable lessons" section harvested into memory.md. Cut points never
111
+ split a tool_call/tool_result pair.
105
112
  - **Session persistence**: conversations are rebuilt from the JSONL log on
106
- restart (`restoreSession`), so agents resume mid-task across master
107
- restarts instead of starting blank.
113
+ first interaction (lazy — boot cost stays O(agents)), so agents resume
114
+ mid-task across master restarts instead of starting blank. Restores replay
115
+ byte-identical request payloads, keeping provider prefix caches warm.
108
116
  - **LLM** (`src/agent/llm.ts`): official `openai` npm client against any
109
117
  OpenAI-compatible endpoint (OpenRouter, vLLM, Ollama...). Model is config,
110
118
  never hard-coded.
@@ -115,24 +123,43 @@ master (Hono server, src/master.ts + src/server/api.ts)
115
123
  (Codex-style multi-file add/update/rename/delete patches, validated
116
124
  atomically before writing) and `list_dir`; `bash` for git/builds/tests and
117
125
  quick bulk transforms; `read_url` fetches a web page's readable content
118
- (Mozilla Readability + happy-dom); plus meta tools `finish` /
119
- `report_progress` / `get_goal` / `set_goal` / `read_memory` / `set_memory` /
120
- `list_skills`. Paths are confined to the workspace; bash runs detached in its
121
- own process group and the whole group is SIGKILLed on timeout or shutdown.
126
+ (Mozilla Readability + happy-dom); plus meta tools `finish` / `ask_user` /
127
+ `report_progress` / `get_goal` / `set_goal` / `get_todo` / `set_todo` /
128
+ `read_memory` / `set_memory` / `get_feedback` / `add_feedback` /
129
+ `record_decision` / `get_decisions` / `list_skills`. Paths are confined to
130
+ the workspace (symlink-aware); bash runs detached in its own process group
131
+ and the whole group is SIGKILLed on timeout or shutdown.
132
+ - **Sub-agents** — an agent can `spawn_agent({task, context, persona?})` to
133
+ delegate work: `context:"fork"` starts the child with a byte-exact copy of
134
+ the parent's conversation prefix (provider prefix caches stay warm; stored
135
+ as a reference header in the child's log — parent history is never copied),
136
+ `"none"` starts fresh. Parents steer children via `message_agent`, check on
137
+ them with `list_children`, and can bulk-stop them (`stop_children`,
138
+ descendants included). Children mirror their activity into the parent's
139
+ timeline tagged `@<id>`, and their finish/error reports are delivered back
140
+ automatically. Nesting depth is capped by `maxSpawnDepth` (default 3).
141
+ Default personas: reviewer/tester/researcher/implementer (+ read-only
142
+ enforcement for researcher/reviewer), plus `@mention` spawning from the
143
+ composer.
122
144
  - **Cache-friendly prompt design** — the system prompt is byte-identical on
123
145
  every turn; session state (goal, memory, skills) is fetched via tools, never
124
146
  injected. Combined with the append-only message history this keeps provider
125
147
  prefix caches hot, so long sessions pay incremental input prices instead of
126
148
  re-sending full context every turn.
127
149
  - **Session storage** — everything teapot manages lives under
128
- `<dataDir>/sessions/<sid>/` (`chat.jsonl`, `goal.md`, `memory.md`), so agent
129
- workspaces stay clean. Each incarnation gets a fresh `<agentId>-<uuid>`
130
- directory (no history leaks across projects); restarts reuse the latest one.
131
- Legacy layouts are migrated automatically.
150
+ `<dataDir>/sessions/<sid>/` (`chat.jsonl`, `goal.md`, `todo.md`,
151
+ `memory.md`, `feedback.md`, `decisions.md`), so agent workspaces stay
152
+ clean. Each incarnation gets a fresh `<agentId>-<uuid>` directory (no
153
+ history leaks across projects); restarts reuse the latest one. Legacy
154
+ layouts are migrated automatically.
132
155
  - **Goal / knowledge** — goal + memory are harness-managed and read/written
133
156
  through tools (`get_goal` / `set_goal` / `read_memory` / `set_memory`);
134
157
  `AGENTS.md` is optional project knowledge in the workspace root that agents
135
158
  are told to read at session start. Nothing is seeded into your project.
159
+ - **Decisions & feedback** — `record_decision(decision, rationale,
160
+ alternatives?)` keeps the *why* behind choices in `decisions.md`
161
+ (compaction forgets reasoning, this file doesn't); corrections become
162
+ durable rules via `add_feedback(rule)` with repetition counts.
136
163
  - **Task list** — `todo.md` in the session dir, editable by BOTH sides:
137
164
  humans write it from the web UI (✅ tasks panel) or
138
165
  `POST /api/agents/:id/todo {text, notify?}`, the agent reads and updates it
package/dist/master.js CHANGED
@@ -11,6 +11,7 @@ import { fileURLToPath } from "node:url";
11
11
  import { Agent } from "./agent/agent.js";
12
12
  import { parseSchedule, matches, nextFireAt } from "./scheduler/cron.js";
13
13
  import { bus } from "./bus.js";
14
+ import { fetchModelList, contextLengthFor } from "./model-meta.js";
14
15
  /** how deep sub-agent spawning may nest (parent=0, its subs=1, …) */
15
16
  const MAX_SPAWN_DEPTH = 3;
16
17
  /**
@@ -282,6 +283,20 @@ export class Master {
282
283
  this.raw.llm = llm;
283
284
  if (body.password)
284
285
  this.raw.password = body.password;
286
+ // learn the window size up front so compaction derives 75% of it
287
+ try {
288
+ const list = await fetchModelList(llm.baseUrl, body.apiKey);
289
+ const cl = contextLengthFor(list, llm.model);
290
+ if (cl) {
291
+ this.config.contextWindowTokens = cl;
292
+ this.raw.contextWindowTokens = cl;
293
+ raw.contextWindowTokens = cl; // also persist into the fresh config file
294
+ writeFileSync(this.configPath, JSON.stringify(raw, null, 2) + "\n");
295
+ }
296
+ }
297
+ catch {
298
+ /* metadata is best-effort */
299
+ }
285
300
  let agentId;
286
301
  if (body.workspace?.trim()) {
287
302
  const ws = path.resolve(body.workspace.replace(/^~/, process.env.HOME ?? "~"));
@@ -326,6 +341,13 @@ export class Master {
326
341
  // spawn-tree depth: computed from the config chain (ac may not be
327
342
  // registered yet when this runs — spawnChildFor persists AFTER creation)
328
343
  const myDepth = ac.parent ? this.depthOf(ac.parent) + 1 : 0;
344
+ // learn the model's real context window from provider metadata (once per
345
+ // endpoint, cached) unless the config already pins one explicitly
346
+ let inferredWindow;
347
+ if (!ac.contextWindowTokens && !this.config.contextWindowTokens) {
348
+ const list = await fetchModelList(llm.baseUrl, llm.apiKey).catch(() => []);
349
+ inferredWindow = contextLengthFor(list, llm.model);
350
+ }
329
351
  const sessionDir = this.resolveSessionDir(ac.id, opts.fresh === true);
330
352
  await mkdirSync(sessionDir, { recursive: true });
331
353
  const agent = new Agent({
@@ -337,8 +359,12 @@ export class Master {
337
359
  ...(this.config.progressMinChars ? { progressMinChars: this.config.progressMinChars } : {}),
338
360
  autoContinue: true,
339
361
  ...(this.config.contextTokenBudget ? { contextTokenBudget: this.config.contextTokenBudget } : {}),
340
- ...(ac.contextWindowTokens || this.config.contextWindowTokens
341
- ? { contextWindowTokens: (ac.contextWindowTokens ?? this.config.contextWindowTokens) }
362
+ ...(ac.contextWindowTokens || this.config.contextWindowTokens || inferredWindow
363
+ ? {
364
+ contextWindowTokens: (ac.contextWindowTokens ??
365
+ this.config.contextWindowTokens ??
366
+ inferredWindow),
367
+ }
342
368
  : {}),
343
369
  globalSkillsDir: path.join(CONFIG_DIR, "skills"),
344
370
  bundledSkillsDir: BUNDLED_SKILLS_DIR,
@@ -601,7 +627,7 @@ export class Master {
601
627
  * Without: keep the current endpoint, swap only the model name.
602
628
  * The choice is persisted on the agent config so it survives restarts.
603
629
  */
604
- setAgentModel(id, providerName, model) {
630
+ async setAgentModel(id, providerName, model, contextWindowTokens) {
605
631
  const agent = this.agents.get(id);
606
632
  if (!agent)
607
633
  throw new Error(`no such agent: ${id}`);
@@ -635,6 +661,22 @@ export class Master {
635
661
  ac.provider = providerName;
636
662
  if (ac)
637
663
  ac.model = llm.model;
664
+ // learn the new model's window (metadata lookup) unless explicitly given
665
+ let win = contextWindowTokens;
666
+ if (win === undefined && ac && !ac.contextWindowTokens && !this.config.contextWindowTokens) {
667
+ try {
668
+ const list = await fetchModelList(llm.baseUrl, llm.apiKey);
669
+ win = contextLengthFor(list, llm.model);
670
+ }
671
+ catch {
672
+ /* metadata is best-effort */
673
+ }
674
+ }
675
+ if (win !== undefined) {
676
+ if (ac)
677
+ ac.contextWindowTokens = win;
678
+ agent.opts.contextWindowTokens = win;
679
+ }
638
680
  this.saveConfig();
639
681
  void agent.log.append("system_note", agent.currentSession, agent.currentBranch, {
640
682
  event: "model-changed",
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Provider model metadata (context window sizes) with a small TTL cache.
3
+ * Used to auto-populate contextWindowTokens so compaction budgets derive
4
+ * from the real window instead of the safe default.
5
+ */
6
+ import fs from "node:fs";
7
+ const cache = new Map();
8
+ const TTL = 10 * 60_000;
9
+ /** Fetch GET /models from an OpenAI-compatible endpoint (cached ~10 min). */
10
+ export async function fetchModelList(baseUrl, apiKey) {
11
+ const root = baseUrl.replace(/\/+$/, "");
12
+ const hit = cache.get(root);
13
+ if (hit && Date.now() - hit.at < TTL)
14
+ return hit.list;
15
+ try {
16
+ const res = await fetch(`${root}/models`, {
17
+ headers: apiKey ? { authorization: `Bearer ${apiKey}` } : {},
18
+ signal: AbortSignal.timeout(15_000),
19
+ });
20
+ if (!res.ok)
21
+ throw new Error(`HTTP ${res.status}`);
22
+ const j = (await res.json());
23
+ const list = (j.data ?? [])
24
+ .map((m) => ({
25
+ id: typeof m.id === "string" ? m.id : "",
26
+ contextLength: typeof m.context_length === "number" ? m.context_length : undefined,
27
+ }))
28
+ .filter((m) => m.id);
29
+ cache.set(root, { at: Date.now(), list });
30
+ return list;
31
+ }
32
+ catch {
33
+ return []; // unreachable provider — caller treats as "unknown"
34
+ }
35
+ }
36
+ export function contextLengthFor(list, model) {
37
+ return list.find((m) => m.id === model)?.contextLength;
38
+ }
39
+ /** test hook */
40
+ export function clearModelListCache() {
41
+ cache.clear();
42
+ void fs;
43
+ }
@@ -5,6 +5,7 @@ import { Hono } from "hono";
5
5
  import { serve, upgradeWebSocket } from "@hono/node-server";
6
6
  import { WebSocketServer } from "ws";
7
7
  import { readFileSync, existsSync } from "node:fs";
8
+ import { currentSkills } from "../agent/tools.js";
8
9
  import { spawn } from "node:child_process";
9
10
  import { promises as fs } from "node:fs";
10
11
  import { fileURLToPath } from "node:url";
@@ -354,11 +355,13 @@ export function buildApp(master) {
354
355
  });
355
356
  // switch a running session's model/provider
356
357
  app.post("/api/agents/:id/model", async (c) => {
357
- const body = await c.req.json().catch(() => null);
358
+ const body = await c.req
359
+ .json()
360
+ .catch(() => null);
358
361
  if (!body)
359
362
  return c.json({ error: "invalid JSON" }, 400);
360
363
  try {
361
- const r = master.setAgentModel(c.req.param("id"), body.provider, body.model);
364
+ const r = await master.setAgentModel(c.req.param("id"), body.provider, body.model, body.contextWindowTokens);
362
365
  return c.json({ ok: true, ...r });
363
366
  }
364
367
  catch (err) {
@@ -390,6 +393,21 @@ export function buildApp(master) {
390
393
  return c.json({ error: "text or status required" }, 400);
391
394
  return c.json({ ok: true });
392
395
  });
396
+ // skills visible to an agent (workspace + global + bundled roots)
397
+ app.get("/api/agents/:id/skills", async (c) => {
398
+ const a = master.agents.get(c.req.param("id"));
399
+ if (!a)
400
+ return c.json({ error: "not found" }, 404);
401
+ try {
402
+ const list = await currentSkills(a.toolCtx);
403
+ return c.json({
404
+ skills: list.map((s) => ({ name: s.name, description: s.description, source: s.source })),
405
+ });
406
+ }
407
+ catch (err) {
408
+ return c.json({ error: err.message }, 400);
409
+ }
410
+ });
393
411
  // force a context compaction pass (slash command /compact)
394
412
  app.post("/api/agents/:id/compact", async (c) => {
395
413
  const a = master.agents.get(c.req.param("id"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teapot-coding-agent",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "A lightweight, always-on multi-agent harness for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-or-later",
@@ -0,0 +1,15 @@
1
+ (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e={context:void 0,registry:void 0,effects:void 0,done:!1,getContextId(){return t(this.context.count)},getNextContextId(){return t(this.context.count++)}};function t(t){let n=String(t),r=n.length-1;return e.context.id+(r?String.fromCharCode(96+r):``)+n}function n(t){e.context=t}var r=(e,t)=>e===t,i=Symbol(`solid-track`),a={equals:r},o=null,s=ie,c=1,l=2,u={owned:null,cleanups:null,context:null,owner:null},d=null,f=null,p=null,m=null,h=null,g=0;function _(e,t){let n=p,r=d,i=e.length===0,a=t===void 0?r:t,o=i?u:{owned:null,cleanups:null,context:a?a.context:null,owner:a},s=i?e:()=>e(()=>S(()=>N(o)));d=o,p=null;try{return M(s,!0)}finally{p=n,d=r}}function v(e,t){t=t?Object.assign({},a,t):a;let n={value:e,observers:null,observerSlots:null,comparator:t.equals||void 0};return[k.bind(n),e=>(typeof e==`function`&&(e=f&&f.running&&f.sources.has(n)?e(n.tValue):e(n.value)),ee(n,e))]}function y(e,t,n){A(ne(e,t,!1,c))}function b(e,t,n){s=ae;let r=ne(e,t,!1,c),i=O&&D(O);i&&(r.suspense=i),(!n||!n.render)&&(r.user=!0),h?h.push(r):A(r)}function x(e,t,n){n=n?Object.assign({},a,n):a;let r=ne(e,t,!0,0);return r.observers=null,r.observerSlots=null,r.comparator=n.equals||void 0,A(r),k.bind(r)}function S(e){if(p===null)return e();let t=p;p=null;try{return e()}finally{p=t}}function C(e){b(()=>S(e))}function w(e){return d===null||(d.cleanups===null?d.cleanups=[e]:d.cleanups.push(e)),e}var[T,E]=v(!1);function D(e){let t;return d&&d.context&&(t=d.context[e.id])!==void 0?t:e.defaultValue}var O;function k(){let e=f&&f.running;if(this.sources&&(e?this.tState:this.state)){if((e?this.tState:this.state)===c)A(this);else{let e=m;m=null,M(()=>oe(this),!1),m=e}}if(p){let e=this.observers;if(!e||e[e.length-1]!==p){let t=e?e.length:0;p.sources?(p.sources.push(this),p.sourceSlots.push(t)):(p.sources=[this],p.sourceSlots=[t]),e?(e.push(p),this.observerSlots.push(p.sources.length-1)):(this.observers=[p],this.observerSlots=[p.sources.length-1])}}return e&&f.sources.has(this)?this.tValue:this.value}function ee(e,t,n){let r=f&&f.running&&f.sources.has(e)?e.tValue:e.value;if(!e.comparator||!e.comparator(r,t)){if(f){let r=f.running;(r||!n&&f.sources.has(e))&&(f.sources.add(e),e.tValue=t),r||(e.value=t)}else e.value=t;e.observers&&e.observers.length&&M(()=>{for(let t=0;t<e.observers.length;t+=1){let n=e.observers[t],r=f&&f.running;r&&f.disposed.has(n)||((r?!n.tState:!n.state)&&(n.pure?m.push(n):h.push(n),n.observers&&se(n)),r?n.tState=c:n.state=c)}if(m.length>1e6)throw m=[],Error()},!1)}return t}function A(e){if(!e.fn)return;N(e);let t=g;te(e,f&&f.running&&f.sources.has(e)?e.tValue:e.value,t),f&&!f.running&&f.sources.has(e)&&queueMicrotask(()=>{M(()=>{f&&(f.running=!0),p=d=e,te(e,e.tValue,t),p=d=null},!1)})}function te(e,t,n){let r,i=d,a=p;p=d=e;try{r=e.fn(t)}catch(t){return e.pure&&(f&&f.running?(e.tState=c,e.tOwned&&e.tOwned.forEach(N),e.tOwned=void 0):(e.state=c,e.owned&&e.owned.forEach(N),e.owned=null)),e.updatedAt=n+1,P(t)}finally{p=a,d=i}(!e.updatedAt||e.updatedAt<=n)&&(e.updatedAt!=null&&`observers`in e?ee(e,r,!0):f&&f.running&&e.pure?(f.sources.has(e)||(e.value=r),f.sources.add(e),e.tValue=r):e.value=r,e.updatedAt=n)}function ne(e,t,n,r=c,i){let a={fn:e,state:r,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:t,owner:d,context:d?d.context:null,pure:n};return f&&f.running&&(a.state=0,a.tState=r),d===null||d!==u&&(f&&f.running&&d.pure?d.tOwned?d.tOwned.push(a):d.tOwned=[a]:d.owned?d.owned.push(a):d.owned=[a]),a}function j(e){let t=f&&f.running;if((t?e.tState:e.state)===0)return;if((t?e.tState:e.state)===l)return oe(e);if(e.suspense&&S(e.suspense.inFallback))return e.suspense.effects.push(e);let n=[e];for(;(e=e.owner)&&(!e.updatedAt||e.updatedAt<g);){if(t&&f.disposed.has(e))return;(t?e.tState:e.state)&&n.push(e)}for(let r=n.length-1;r>=0;r--){if(e=n[r],t){let t=e,i=n[r+1];for(;(t=t.owner)&&t!==i;)if(f.disposed.has(t))return}if((t?e.tState:e.state)===c)A(e);else if((t?e.tState:e.state)===l){let t=m;m=null,M(()=>oe(e,n[0]),!1),m=t}}}function M(e,t){if(m)return e();let n=!1;t||(m=[]),h?n=!0:h=[],g++;try{let t=e();return re(n),t}catch(e){n||(h=null),m=null,P(e)}}function re(e){if(m&&=(ie(m),null),e)return;let t;if(f){if(!f.promises.size&&!f.queue.size){let e=f.sources,n=f.disposed;h.push.apply(h,f.effects),t=f.resolve;for(let e of h)`tState`in e&&(e.state=e.tState),delete e.tState;f=null,M(()=>{for(let e of n)N(e);for(let t of e){if(t.value=t.tValue,t.owned)for(let e=0,n=t.owned.length;e<n;e++)N(t.owned[e]);t.tOwned&&(t.owned=t.tOwned),delete t.tValue,delete t.tOwned,t.tState=0}E(!1)},!1)}else if(f.running){f.running=!1,f.effects.push.apply(f.effects,h),h=null,E(!0);return}}let n=h;h=null,n.length&&M(()=>s(n),!1),t&&t()}function ie(e){for(let t=0;t<e.length;t++)j(e[t])}function ae(t){let r,i=0;for(r=0;r<t.length;r++){let e=t[r];e.user?t[i++]=e:j(e)}if(e.context){if(e.count){e.effects||=[],e.effects.push(...t.slice(0,i));return}n()}for(e.effects&&(e.done||!e.count)&&(t=[...e.effects,...t],i+=e.effects.length,delete e.effects),r=0;r<i;r++)j(t[r])}function oe(e,t){let n=f&&f.running;n?e.tState=0:e.state=0;for(let r=0;r<e.sources.length;r+=1){let i=e.sources[r];if(i.sources){let e=n?i.tState:i.state;e===c?i!==t&&(!i.updatedAt||i.updatedAt<g)&&j(i):e===l&&oe(i,t)}}}function se(e){let t=f&&f.running;for(let n=0;n<e.observers.length;n+=1){let r=e.observers[n];(t?!r.tState:!r.state)&&(t?r.tState=l:r.state=l,r.pure?m.push(r):h.push(r),r.observers&&se(r))}}function N(e){let t;if(e.sources)for(;e.sources.length;){let t=e.sources.pop(),n=e.sourceSlots.pop(),r=t.observers;if(r&&r.length){let e=r.pop(),i=t.observerSlots.pop();n<r.length&&(e.sourceSlots[i]=n,r[n]=e,t.observerSlots[n]=i)}}if(e.tOwned){for(t=e.tOwned.length-1;t>=0;t--)N(e.tOwned[t]);delete e.tOwned}if(f&&f.running&&e.pure)ce(e,!0);else if(e.owned){for(t=e.owned.length-1;t>=0;t--)N(e.owned[t]);e.owned=null}if(e.cleanups){for(t=e.cleanups.length-1;t>=0;t--)e.cleanups[t]();e.cleanups=null}f&&f.running?e.tState=0:e.state=0}function ce(e,t){if(t||(e.tState=0,f.disposed.add(e)),e.owned)for(let t=0;t<e.owned.length;t++)ce(e.owned[t])}function le(e){return e instanceof Error?e:Error(typeof e==`string`?e:`Unknown error`,{cause:e})}function ue(e,t,n){try{for(let n of t)n(e)}catch(e){P(e,n&&n.owner||null)}}function P(e,t=d){let n=o&&t&&t.context&&t.context[o],r=le(e);if(!n)throw r;h?h.push({fn(){ue(r,n,t)},state:c}):ue(r,n,t)}var de=Symbol(`fallback`);function fe(e){for(let t=0;t<e.length;t++)e[t]()}function pe(e,t,n={}){let r=[],a=[],o=[],s=0,c=t.length>1?[]:null;return w(()=>fe(o)),()=>{let l=e()||[],u=l.length,d,f;return l[i],S(()=>{let e,t,i,m,h,g,v,y,b;if(u===0)s!==0&&(fe(o),o=[],r=[],a=[],s=0,c&&=[]),n.fallback&&(r=[de],a[0]=_(e=>(o[0]=e,n.fallback())),s=1);else if(s===0){for(a=Array(u),f=0;f<u;f++)r[f]=l[f],a[f]=_(p);s=u}else{for(i=Array(u),m=Array(u),c&&(h=Array(u)),g=0,v=Math.min(s,u);g<v&&r[g]===l[g];g++);for(v=s-1,y=u-1;v>=g&&y>=g&&r[v]===l[y];v--,y--)i[y]=a[v],m[y]=o[v],c&&(h[y]=c[v]);for(e=new Map,t=Array(y+1),f=y;f>=g;f--)b=l[f],d=e.get(b),t[f]=d===void 0?-1:d,e.set(b,f);for(d=g;d<=v;d++)b=r[d],f=e.get(b),f!==void 0&&f!==-1?(i[f]=a[d],m[f]=o[d],c&&(h[f]=c[d]),f=t[f],e.set(b,f)):o[d]();for(f=g;f<u;f++)f in i?(a[f]=i[f],o[f]=m[f],c&&(c[f]=h[f],c[f](f))):a[f]=_(p);a=a.slice(0,s=u),r=l.slice(0)}return a});function p(e){if(o[f]=e,c){let[e,n]=v(f);return c[f]=n,t(l[f],e)}return t(l[f])}}}function F(e,t){return S(()=>e(t||{}))}var me=e=>`Stale read from <${e}>.`;function I(e){let t=`fallback`in e&&{fallback:()=>e.fallback};return x(pe(()=>e.each,e.children,t||void 0))}function L(e){let t=e.keyed,n=x(()=>e.when,void 0,void 0),r=t?n:x(n,void 0,{equals:(e,t)=>!e==!t});return x(()=>{let i=r();if(i){let a=e.children;return typeof a==`function`&&a.length>0?S(()=>a(t?i:()=>{if(!S(r))throw me(`Show`);return n()})):a}return e.fallback},void 0,void 0)}var R=e=>x(()=>e());function z(e,t,n){let r=n.length,i=t.length,a=r,o=0,s=0,c=t[i-1].nextSibling,l=null;for(;o<i||s<a;){if(t[o]===n[s]){o++,s++;continue}for(;t[i-1]===n[a-1];)i--,a--;if(i===o){let t=a<r?s?n[s-1].nextSibling:n[a-s]:c;for(;s<a;)e.insertBefore(n[s++],t)}else if(a===s)for(;o<i;)(!l||!l.has(t[o]))&&t[o].remove(),o++;else if(t[o]===n[a-1]&&n[s]===t[i-1]){let r=t[--i].nextSibling;e.insertBefore(n[s++],t[o++].nextSibling),e.insertBefore(n[--a],r),t[i]=n[a]}else{if(!l){l=new Map;let e=s;for(;e<a;)l.set(n[e],e++)}let r=l.get(t[o]);if(r!=null){if(s<r&&r<a){let c=o,u=1,d;for(;++c<i&&c<a&&(d=l.get(t[c]))!=null&&d===r+u;)u++;if(u>r-s){let i=t[o];for(;s<r;)e.insertBefore(n[s++],i)}else e.replaceChild(n[s++],t[o++])}else o++}else t[o++].remove()}}}var he=`_$DX_DELEGATE`;function ge(e,t,n,r={}){let i;return _(r=>{i=r,t===document?e():U(t,e(),t.firstChild?null:void 0,n)},r.owner),()=>{i(),t.textContent=``}}function B(e,t,n,r){let i,a=()=>{let t=r?document.createElementNS(`http://www.w3.org/1998/Math/MathML`,`template`):document.createElement(`template`);return t.innerHTML=e,n?t.content.firstChild.firstChild:r?t.firstChild:t.content.firstChild},o=t?()=>S(()=>document.importNode(i||=a(),!0)):()=>(i||=a()).cloneNode(!0);return o.cloneNode=o,o}function _e(e,t=window.document){let n=t[he]||(t[he]=new Set);for(let r=0,i=e.length;r<i;r++){let i=e[r];n.has(i)||(n.add(i),t.addEventListener(i,Ce))}}function V(e,t,n){Se(e)||(n==null?e.removeAttribute(t):e.setAttribute(t,n))}function H(e,t){Se(e)||(t==null?e.removeAttribute(`class`):e.className=t)}function ve(e,t,n,r){if(r)Array.isArray(n)?(e[`$$${t}`]=n[0],e[`$$${t}Data`]=n[1]):e[`$$${t}`]=n;else if(Array.isArray(n)){let r=n[0];e.addEventListener(t,n[0]=t=>r.call(e,n[1],t))}else e.addEventListener(t,n,typeof n!=`function`&&n)}function ye(e,t,n){if(!t)return n?V(e,`style`):t;let r=e.style;if(typeof t==`string`)return r.cssText=t;typeof n==`string`&&(r.cssText=n=void 0),n||={},t||={};let i,a;for(a in n)t[a]??r.removeProperty(a),delete n[a];for(a in t)i=t[a],i!==n[a]&&(r.setProperty(a,i),n[a]=i);return n}function be(e,t,n){n==null?e.style.removeProperty(t):e.style.setProperty(t,n)}function xe(e,t,n){return S(()=>e(t,n))}function U(e,t,n,r){if(n!==void 0&&!r&&(r=[]),typeof t!=`function`)return we(e,t,r,n);y(r=>we(e,t(),r,n),r)}function Se(t){return!!e.context&&!e.done&&(!t||t.isConnected)}function Ce(t){if(e.registry&&e.events&&e.events.find(([e,n])=>n===t))return;let n=t.target,r=`$$${t.type}`,i=t.target,a=t.currentTarget,o=e=>Object.defineProperty(t,"target",{configurable:!0,value:e}),s=()=>{let e=n[r];if(e&&!n.disabled){let i=n[`${r}Data`];if(i===void 0?e.call(n,t):e.call(n,i,t),t.cancelBubble)return}return n.host&&typeof n.host!=`string`&&!n.host._$host&&n.contains(t.target)&&o(n.host),!0},c=()=>{for(;s()&&(n=n._$host||n.parentNode||n.host););};if(Object.defineProperty(t,"currentTarget",{configurable:!0,get(){return n||document}}),e.registry&&!e.done&&(e.done=_$HY.done=!0),t.composedPath){let e=t.composedPath();o(e[0]);for(let t=0;t<e.length-2&&(n=e[t],s());t++){if(n._$host){n=n._$host,c();break}if(n.parentNode===a)break}}else c();o(i)}function we(e,t,n,r,i){let a=Se(e);if(a){!n&&(n=[...e.childNodes]);let t=[];for(let e=0;e<n.length;e++){let r=n[e];r.nodeType===8&&r.data.slice(0,2)===`!$`?r.remove():t.push(r)}n=t}for(;typeof n==`function`;)n=n();if(t===n)return n;let o=typeof t,s=r!==void 0;if(e=s&&n[0]&&n[0].parentNode||e,o===`string`||o===`number`){if(a||o===`number`&&(t=t.toString(),t===n))return n;if(s){let i=n[0];i&&i.nodeType===3?i.data!==t&&(i.data=t):i=document.createTextNode(t),n=W(e,n,r,i)}else n=n!==``&&typeof n==`string`?e.firstChild.data=t:e.textContent=t}else if(t==null||o===`boolean`){if(a)return n;n=W(e,n,r)}else if(o===`function`)return y(()=>{let i=t();for(;typeof i==`function`;)i=i();n=we(e,i,n,r)}),()=>n;else if(Array.isArray(t)){let o=[],c=n&&Array.isArray(n);if(Te(o,t,n,i))return y(()=>n=we(e,o,n,r,!0)),()=>n;if(a){if(!o.length)return n;if(r===void 0)return n=[...e.childNodes];let t=o[0];if(t.parentNode!==e)return n;let i=[t];for(;(t=t.nextSibling)!==r;)i.push(t);return n=i}if(o.length===0){if(n=W(e,n,r),s)return n}else c?n.length===0?Ee(e,o,r):z(e,n,o):(n&&W(e),Ee(e,o));n=o}else if(t.nodeType){if(a&&t.parentNode)return n=s?[t]:t;if(Array.isArray(n)){if(s)return n=W(e,n,r,t);W(e,n,null,t)}else n==null||n===``||!e.firstChild?e.appendChild(t):e.replaceChild(t,e.firstChild);n=t}return n}function Te(e,t,n,r){let i=!1;for(let a=0,o=t.length;a<o;a++){let o=t[a],s=n&&n[e.length],c;if(o!=null&&o!==!0&&o!==!1){if((c=typeof o)==`object`&&o.nodeType)e.push(o);else if(Array.isArray(o))i=Te(e,o,s)||i;else if(c===`function`){if(r){for(;typeof o==`function`;)o=o();i=Te(e,Array.isArray(o)?o:[o],Array.isArray(s)?s:[s])||i}else e.push(o),i=!0}else{let t=String(o);s&&s.nodeType===3&&s.data===t?e.push(s):e.push(document.createTextNode(t))}}}return i}function Ee(e,t,n=null){for(let r=0,i=t.length;r<i;r++)e.insertBefore(t[r],n)}function W(e,t,n,r){if(n===void 0)return e.textContent=``;let i=r||document.createTextNode(``);if(t.length){let r=!1;for(let a=t.length-1;a>=0;a--){let o=t[a];if(i!==o){let t=o.parentNode===e;!r&&!a?t?e.replaceChild(i,o):e.insertBefore(i,n):t&&o.remove()}else r=!0}}else e.insertBefore(i,n);return[i]}var G=/^(\s*)([-*+]|\d+[.)])\s+(.*)$/;function De(e){return Oe(K(e.replace(/\r\n/g,`
2
+ `)).split(`
3
+ `))}function Oe(e){let t=[],n=0;for(;n<e.length;){let o=e[n];if(/^```\w*\s*$/.test(o)){let r=[];for(n++;n<e.length&&!/^```\s*$/.test(e[n]);)r.push(e[n++]);n++,t.push(`<pre><code>${r.join(`
4
+ `)}</code></pre>`);continue}if(/^ {0,3}(?:-{3,}|\*{3,}|_{3,})\s*$/.test(o)){t.push(`<hr>`),n++;continue}let s=o.match(/^(#{1,6})\s+(.*)$/);if(s){t.push(`<h${s[1].length}>${a(s[2])}</h${s[1].length}>`),n++;continue}if(/^\s*&gt;/.test(o)){let r=[];for(;n<e.length&&/^\s*&gt;/.test(e[n]);)r.push(e[n++].replace(/^\s*&gt;\s?/,``));t.push(`<blockquote>${Oe(r)}</blockquote>`);continue}if(o.includes(`|`)&&n+1<e.length&&Ae(e[n+1])){let r=ke(e[n+1]).map(e=>e.startsWith(`:`)&&e.endsWith(`:`)?`center`:e.endsWith(`:`)?`right`:`left`),i=ke(o);n+=2;let s=[];for(;n<e.length&&/\S/.test(e[n])&&e[n].includes(`|`);)s.push(ke(e[n])),n++;let c=(e,t,n)=>{let i=r[t];return`<${n}${i&&i!==`left`?` style="text-align:${i}"`:``}>${a(e)}</${n}>`};t.push(`<div class="tbl"><table><thead><tr>${i.map((e,t)=>c(e,t,`th`)).join(``)}</tr></thead><tbody>${s.map(e=>`<tr>${e.map((e,t)=>c(e,t,`td`)).join(``)}</tr>`).join(``)}</tbody></table></div>`);continue}if(G.test(o)){t.push(i(r(o.match(G)[1])));continue}if(/^\s*$/.test(o)){n++;continue}let c=[];for(;n<e.length&&!/^\s*$/.test(e[n])&&!/^#{1,6}\s/.test(e[n])&&!/^```/.test(e[n])&&!/^ {0,3}(?:-{3,}|\*{3,}|_{3,})\s*$/.test(e[n])&&!/^\s*&gt;/.test(e[n])&&!G.test(e[n])&&!(e[n].includes(`|`)&&n+1<e.length&&Ae(e[n+1]));)c.push(e[n++]);t.push(`<p>${c.map(a).join(`<br>`)}</p>`)}return t.join(`
5
+ `);function r(e){return e.replace(/\t/g,` `).length}function i(t){let o=null,s=[];for(;n<e.length;){let c=e[n].match(G);if(!c)break;let l=r(c[1]);if(l<t)break;let u=/^\d/.test(c[2]);if(o===null)o=u;else if(u!==o)break;n++;let d=c[3];for(;n<e.length&&/\S/.test(e[n])&&!G.test(e[n])&&!/^#{1,6}\s/.test(e[n])&&!/^```/.test(e[n])&&!/^\s*&gt;/.test(e[n]);)d+=` `+e[n].trim(),n++;let f=``,p=e[n]?.match(G);p&&r(p[1])>l&&(f=i(r(p[1])));let m=d.match(/^\[( |x|X)\]\s+(.*)$/),h=m?`<input type="checkbox" disabled${m[1].toLowerCase()===`x`?` checked`:``}> `:``;s.push(`<li>${h}${a(m?m[2]:d)}${f}</li>`)}return o?`<ol>${s.join(``)}</ol>`:`<ul>${s.join(``)}</ul>`}function a(e){let t=[];return e=e.replace(/`([^`]+)`/g,(e,n)=>(t.push(`<code>${n}</code>`),`\u0000${t.length-1}\u0000`)),e=e.replace(/!\[([^\]]*)\]\((https?:\/\/[^)\s]+)(?:\s+&quot;[^)]*&quot;)?\)/g,`<img src="$2" alt="$1" loading="lazy">`),e=e.replace(/\[([^\]]+)\]\((https?:\/\/[^)\s]+)(?:\s+&quot;[^)]*&quot;)?\)/g,`<a href="$2" rel="noopener noreferrer" target="_blank">$1</a>`),e=e.replace(/(?<!["'=\w])(https?:\/\/[^\s<>"')\]]*[^\s<>"')\].,;:!?"')\]])/g,`<a href="$1">$1</a>`),e=e.replace(/\*\*\*([\s\S]+?)\*\*\*/g,`<strong><em>$1</em></strong>`),e=e.replace(/\*\*([\s\S]+?)\*\*/g,`<strong>$1</strong>`),e=e.replace(/(^|[^\w])__(?=\S)([\s\S]*?\S)__(?!\w)/g,`$1<strong>$2</strong>`),e=e.replace(/(^|[^\w*])\*(?!\s)([^*\n]+?)\*(?![\w*])/g,`$1<em>$2</em>`),e=e.replace(/(^|[^\w])_(?!\s)([^_\n]+?)_(?!\w)/g,`$1<em>$2</em>`),e=e.replace(/~~([\s\S]+?)~~/g,`<del>$1</del>`),e.replace(/\u0000(\d+)\u0000/g,(e,n)=>t[+n])}}function ke(e){let t=e.trim();t.startsWith(`|`)&&(t=t.slice(1));let n=[],r=``;for(let e=0;e<t.length;e++){if(t[e]===`\\`&&t[e+1]===`|`){r+=`|`,e++;continue}if(t[e]===`|`&&e===t.length-1)break;if(t[e]===`|`){n.push(r.trim()),r=``;continue}r+=t[e]}return n.push(r.trim()),n.filter((e,r)=>!(e===``&&r===n.length-1&&t.endsWith(`|`)))}function Ae(e){let t=e.trim();if(!t.includes(`|`)||!t.includes(`-`))return!1;let n=ke(t);return n.every(e=>/^:?-+:?$/.test(e))&&n.some(e=>e!==``)}function K(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`)}var je=`modulepreload`,Me=function(e){return`/`+e},Ne={},Pe=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=Me(t,n),t=s(t),t in Ne)return;Ne[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:je,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},Fe=B(`<div class=overlay><div class=modal style=max-width:360px><div class=modal-head><b>🔒 sign in</b><span></span></div><form style=display:flex;flex-direction:column;gap:10px><input id=pw-input type=password placeholder=password autofocus><button type=submit style="background:var(--acc);border:none;border-radius:6px;color:#fff;padding:7px 12px;cursor:pointer">unlock</button><span class=muted style=font-size:11px>the token is stored locally and sent as Bearer to this server only`),Ie=B(`<br>`),Le=B(`<span class="badge queued">⏳ <!> queued`),Re=B(`<span class="badge cron">⏰ `),ze=B(`<span class=sub>ℹ`),Be=B(`<header class=chan-head><span class=hash>#</span><span class=title></span><span></span><span class=sub> · <!>/<!> · turns <!> · tools </span><span style=margin-left:auto;display:flex;gap:4px><button class=iconbtn title="terminal (t)">⌨</button><button class=iconbtn title="toggle details panel (d)">▤`),Ve=B(`<details class=reasoning><summary>💭 reasoning</summary><div class=mono>`),He=B(`<div class=content>`),Ue=B(`<div class="msg live"><div class=avatar style="background:#5865f233;border:1px solid #5865f266">🫖</div><div class=msg-body><div class=msg-head><span class=author style=color:var(--acc)>agent</span><span class=ts>streaming…`),We=B(`<div class=feed>`),Ge=B(`<button class=jump>↓ `),Ke=B(`<div class=termdrawer><div class=termbar><span>⌨ terminal — <span class=mono></span></span><button class=iconbtn title="close terminal (t)">✕</button></div><div class=termhost>`),qe=B(`<div class=cmds>`),Je=B(`<label class=forkchip title="inherit the conversation prefix byte-exactly — the sub-agent's provider prefix cache starts warm"><input type=checkbox>fork ctx`),Ye=B(`<div class=composer><form><textarea rows=1></textarea><button type=submit>send</button></form><div class=hint>`),Xe=B(`<h3>🎛 session`),Ze=B(`<div class="card sesscard"><div class=sessrow><span class=k>agent</span><b></b><span></span></div><div class=sessrow><span class=k>workspace</span><span class="mono ellip"></span></div><div class=sessrow><span class=k>session</span><span class=mono>/`),Qe=B(`<h3>🧦 model`),$e=B(`<div class=meta style=color:var(--fg)>`),et=B(`<div class=modelbox><select title="provider (OpenAI-compatible endpoint)"></select><div style=display:flex;gap:4px><input type=text list=model-list style=flex:1;min-width:0><datalist id=model-list></datalist><button title="apply to this session — takes effect from the agent's next turn">apply</button></div><div class=meta>current: `),tt=B(`<h3>⏯ controls`),nt=B(`<button class=danger title="interrupt: aborts the current LLM call; the running tool finishes first">■ stop`),rt=B(`<button title="stop every sub-agent this agent spawned (descendants included)">⏹ subs`),it=B(`<div class=btnrow><button title="branch off the conversation here — try things without disturbing the main line">⑂ fork</button><button title="remove agent from teapot (session log stays on disk)">🗑 remove`),at=B(`<div class=ctrlrow><label title="after each round the agent keeps working toward its goal without waiting for input; sending a prompt also starts an idle agent"><input type=checkbox>auto-continue</label><span class=muted>loops while the goal is active`),ot=B(`<h3>🎯 goal <span>`),st=B(`<form style=display:flex;flex-direction:column;gap:6px;margin-bottom:6px><textarea id=goal-input rows=3 placeholder="set new goal…"style="background:var(--bg-darkest);border:none;border-radius:6px;padding:6px 8px;color:var(--fg);font:inherit;width:100%;resize:vertical"></textarea><div style=display:flex;justify-content:flex-end;align-items:center;gap:10px><label class=muted title="queue a harness prompt telling the agent about the new goal at its next turn boundary"style=display:flex;align-items:center;gap:4px;font-size:11.5px;white-space:nowrap;cursor:pointer><input id=goal-notify type=checkbox checked> notify agent</label><button type=submit style="background:var(--acc);border:none;border-radius:6px;color:#fff;padding:4px 12px;cursor:pointer">✓ save`),ct=B(`<div class=card>`),lt=B(`<div class=muted style=font-size:11px;margin-top:4px>stored with the session · the model reads it via get_goal() ·`),ut=B(`<h3>✅ tasks <span class=muted style=text-transform:none;letter-spacing:0>· todo.md, editable by you and the agent`),dt=B(`<textarea id=todo-input class=mono rows=5 placeholder="- task one
6
+ - task two"title="shared with the agent — it may check items off via set_todo; your unsaved edits win until you save"style="width:100%;background:var(--bg-darkest);border:none;border-radius:6px;padding:6px 8px;color:var(--fg);font-family:ui-monospace,Menlo,monospace;font-size:12.5px;resize:vertical">`),ft=B(`<div style=display:flex;justify-content:flex-end;align-items:center;gap:10px;margin-top:4px><label class=muted title="queue a harness prompt telling the agent the task list changed"style=display:flex;align-items:center;gap:4px;font-size:11.5px;white-space:nowrap;cursor:pointer><input id=todo-notify type=checkbox checked> notify agent</label><button style="background:var(--ok);border:none;border-radius:6px;color:#fff;padding:4px 12px;cursor:pointer">✓ save tasks`),pt=B(`<h3>📈 progress`),mt=B(`<h3>📊 runtime`),ht=B(`<div class="card muted">turns <!> · tools <!> · compacted <!>
7
+ tokens in/out <!>/`),gt=B(`<h3>🌿 branches <span class=muted style=text-transform:none;letter-spacing:0>· click to filter the feed`),_t=B(`<h3>⏰ schedule <span class=muted style=text-transform:none;letter-spacing:0>· cron tasks, all agents · edit in settings`),vt=B(`<div><nav class=sidebar><h1>🫖 teapot<span></span><span style=float:right;display:flex;gap:4px><button class=iconbtn title="new agent">+</button><button class=iconbtn title=settings>⚙</button></span></h1><div class=agent-list></div><div class=metrics></div></nav><section class=channel></section><aside>`),yt=B(`<span class=caret>`),bt=B(`<span class=subtag>🧩`),xt=B(`<span class=mini-cron>⏰`),St=B(`<span title="goal done">✓`),Ct=B(`<div><span></span><span>`),wt=B(`<span class=caret-spacer>`),Tt=B(`<div class=muted style=display:grid;place-items:center;height:100%>select an agent`),Et=B(`<div class=muted style=display:grid;place-items:center;height:100%>no events yet — say something or press ▶ start`),Dt=B(`<div class="content muted">thinking…`),Ot=B(`<div><b class=mono></b><span class=muted>`),kt=B(`<div class=cmdrow><b>@</b><span class=muted>`),At=B(`<option>`),jt=B(`<button class=runbtn title="run toward the goal (starts the loop)">▶ start`),Mt=B(`<div class=muted>none yet — the harness asks for a report after real activity, and the agent can report_progress anytime`),Nt=B(`<div class=progrow><b>recent</b><span>`),Pt=B(`<div class="progrow warn"><b>⚠ problems</b><span>`),Ft=B(`<div class=progrow><b>next</b><span>`),It=B(`<div class=progrow><b>goal</b><span>`),Lt=B(`<div class="card prog"><div class=progrow><b>doing</b><span></span></div><div class="meta muted">`),Rt=B(`<span>% of `),zt=B(`<div><span></span><span> events`),Bt=B(`<div class=muted>no scheduled tasks — add them in ⚙ settings ("scheduled tasks")`),Vt=B(`<span title="runs on a forked branch so chatter stays off the main line">⑂`),Ht=B(`<div><div class=sched-top><b></b><span class=muted>@</span></div><div class="sched-meta mono"> → next </div><div class="sched-prompt muted">`),Ut=B(`<div><div style=font-size:12.5px;margin-bottom:4px> event(s) came after this prompt — what should happen to them on the new branch?</div><label style=display:flex;gap:6px;align-items:center;font-size:13px;color:var(--fg)><input type=radio name=tail>summarize them into a note the agent can still read</label><label style=display:flex;gap:6px;align-items:center;font-size:13px;color:var(--fg)><input type=radio name=tail>discard them entirely (clean timeline)`),Wt=B(`<form style=display:flex;flex-direction:column;gap:10px><textarea id=edit-text class="mono w100"rows=6></textarea><div style=display:flex;justify-content:flex-end;gap:8px><button type=button>cancel</button><button type=submit style="background:var(--acc);border:none;border-radius:6px;color:#fff;padding:6px 12px;cursor:pointer">⑂ fork & resend`),Gt=B(`<div class=mono>`),Kt=B(`<pre class="mono toolbody">`),qt=B(`<div class=meta>ms`),Jt=B(`<div class=meta>waiting for output…`),Yt=B(`<div class=meta>`),Xt=B(`<div class=meta>writing…`),Zt=B(`<pre class="mono toolbody del">`),Qt=B(`<pre class="mono toolbody add">`),q=B(`<div class=meta> · <!>ms`),$t=B(`<div class=meta>applying…`),en=B(`<pre class="mono toolbody patch">`),tn=B(`<div>`),nn=B(`<div class=meta>validating…`),rn=B(`<a target=_blank rel="noopener noreferrer"referrerpolicy=no-referrer>open ↗`),J=B(`<span class=muted>`),an=B(`<div class=meta>loading…`),on=B(`<div class=meta>bundled: `),Y=B(`<div class=meta>saving…`),sn=B(`<span class=actor>@`),cn=B(`<details><summary><b>⚙ </b><span class=meta>`),ln=B(`<div class=divider-msg>⑂ forked from <!> → `),un=B(`<div class=divider-msg>🎯 goal <!>: `),dn=B(`<div class=divider-msg>✅ tasks updated (<!>)`),fn=B(`<div> → `),pn=B(`<div class=avatar>`),mn=B(`<button class=editbtn title="edit this prompt — forks the conversation here (later events are dropped or summarized)">✎ edit`),hn=B(`<div class=msg-head><span class=author></span><span class=ts></span><span class=ts>`),gn=B(`<div><div class=msg-body>`),_n=B(`<span style=width:38px>`),vn=B(`<div class=interrupted>⚠ interrupted — partial output kept`),yn=B(`<div class=msgfoot><span>copy summary`),bn=B(`<details><summary><span class=meta></span></summary><div class=mono></div><div class=meta>ms`),xn=B(`<div class="content muted">Rejected: `),Sn=B(`<details class="embed decision"><summary><b>📌 </b><span class=meta>decision logged</span></summary><div class=content><b>Why:`),Cn=B(`<div class=qopts>`),wn=B(`<div class="embed question"><div>❓ </div><div class=meta>the agent is waiting for your reply — answer below or tap an option`),X=B(`<button class=qopt>`),Tn=B(`<div class=meta>⚠ `),En=B(`<div class=meta>→ `),Dn=B(`<div class=embed style=border-color:var(--ok)><div>📈 `),On=B(`<div class="embed fail"><div class=mono>⚠ `),kn=B(`<div class="content muted">`),An=B(`<button class=copybtn title="copy to clipboard">`),jn=B(`<div class=overlay><div class=modal><div class=modal-head><b></b><button class=iconbtn>✕`),Mn=B(`<span style=color:var(--err);font-size:13px>`),Nn=B(`<form style=display:flex;flex-direction:column;gap:10px><label>workspace directory<div style=display:flex;gap:6px><input type=text class="w100 mono"><button type=button>go</button><button type=button>↑</button></div></label><div class=dirlist></div><div style=display:flex;gap:10px><label style=flex:1>agent name <input type=text placeholder="(directory name)"></label><label>provider<select></select></label><label style=flex:1>model <input type=text placeholder="(provider default)"></label></div><button type=submit style=align-self:flex-end>create & start`),Pn=B(`<div class=direntry>📁 `),Fn=B(`<div class=overlay style=background:var(--bg-darkest)><div class=modal style=max-width:560px><div class=modal-head><b>🫖 welcome to teapot</b></div><p class=muted style="margin:0 0 10px;font-size:13px">first run — pick an OpenAI-compatible provider and you're done. everything below can be changed later in ⚙ settings.</p><form style=display:flex;flex-direction:column;gap:12px><div style=display:flex;gap:6px></div><label>base url<input type=text class="w100 mono"></label><label>api key <input type=password class=w100 placeholder="(local providers may not need one)"></label><label>default model <input type=text class="w100 mono"></label><fieldset><legend>first agent</legend><label>workspace directory<input type=text class="w100 mono"></label><label style=margin-top:4px>protect the API with a password? <input type=password class=w100 placeholder="(optional — LAN traffic is still plain HTTP)"></label></fieldset><button type=submit style="background:var(--acc);border:none;border-radius:8px;color:#fff;padding:9px 14px;font-weight:600;cursor:pointer">`),In=B(`<button type=button>`),Z=B(`<label><input type=number min=0>`),Ln=B(`<form style=display:flex;flex-direction:column;gap:14px><fieldset><legend>providers</legend><button type=button>+ add provider</button><div><label style=display:flex;align-items:center;gap:6px;margin-top:6px>default provider<input type=text></label></div></fieldset><fieldset><legend>agent runtime</legend><div class=cfggrid></div></fieldset><fieldset><legend>scheduled tasks</legend><button type=button>+ add task</button></fieldset><fieldset><legend>agents (read-only — edit config file or use +)</legend></fieldset><button type=submit style="align-self:flex-end;background:var(--acc);border:none;border-radius:6px;color:#fff;padding:6px 14px;cursor:pointer">save settings`),Rn=B(`<div class=cfgrow><input class=cfgname placeholder=name><input placeholder=https://…/v1><input placeholder="api key"type=password><input placeholder="default model"><button type=button class=danger title="remove provider">✕`),zn=B(`<div class=cfgcol><div class=cfgrow><input placeholder=id><input placeholder="agent id"><input placeholder="every 30m / cron"><label style=display:flex;gap:3px;align-items:center;white-space:nowrap;color:var(--dim);font-size:11px><input type=checkbox>fork</label><button type=button class=danger>✕</button></div><textarea rows=2 placeholder="prompt to send">`),Bn=B(`<span class=muted>🧩 sub of @`),Vn=B(`<div class=cfgrow><b></b><span class=muted>`),Hn={prompt:{name:`you`,icon:`🟧`,color:`#faa81a`},user:{name:`you`,icon:`🟧`,color:`#faa81a`},message:{name:`agent`,icon:`🫖`,color:`#5865f2`},progress:{name:`progress`,icon:`📈`,color:`#3ba55d`},question:{name:`agent`,icon:`❓`,color:`#5865f2`}},Un={name:`harness`,icon:`📣`,color:`#3ba55d`},Wn=e=>{if(e.data?.actor)return{name:`@${String(e.data.actor)}`,icon:`🧩`,color:`#3ba0c9`};if(e.type===`tool_call`||e.type===`tool_result`)return{name:String(e.data?.name??`tool`),icon:`⚙`,color:`#3ba0c9`};if(e.type===`prompt`){let t=String(e.data?.source??`user`);return t===`user`?Hn.prompt:t.startsWith(`scheduler:`)?{name:t.slice(10),icon:`📣`,color:`#3ba55d`}:Un}return Hn[e.type]??{name:e.type,icon:`•`,color:`#9298a5`}},Gn=new Set([`user`,`message`,`prompt`,`tool_call`,`tool_result`,`progress`,`state`,`error`,`fork`,`goal`,`todo`,`question`,`decision`]),Kn=e=>{let t=new Date(e);return`${String(t.getHours()).padStart(2,`0`)}:${String(t.getMinutes()).padStart(2,`0`)}`};async function Q(e,t){let n=localStorage.getItem(`teapot.token`),r=new Headers(t?.headers);n&&!r.has(`authorization`)&&r.set(`authorization`,`Bearer ${n}`);let i=await fetch(e,{...t,headers:r});if(!i.ok){i.status===401&&window.dispatchEvent(new CustomEvent(`teapot:unauthorized`));let t=``;try{t=(await i.json())?.error??``}catch{}throw Error(t||`${e}: HTTP ${i.status}`)}return i.json()}var qn=location.hash.match(/[#&]token=([^&]+)/);qn&&(localStorage.setItem(`teapot.token`,decodeURIComponent(qn[1])),history.replaceState(null,``,location.pathname+location.search));var Jn=()=>{let e=localStorage.getItem(`teapot.token`);return e?`?token=${encodeURIComponent(e)}`:``};function Yn(){let[e,t]=v([]),[n,r]=v(null),[i,a]=v([]),[o,s]=v(0),[c,l]=v([]),[u,d]=v(null),[f,p]=v(``),[m,h]=v(localStorage.getItem(`teapot.autostart`)!==`0`),g=e=>{h(e),localStorage.setItem(`teapot.autostart`,e?`1`:`0`)},[_,S]=v({providers:{}}),[T,E]=v(!1),[D,O]=v(!1),[k,ee]=v(localStorage.getItem(`teapot.panel`)===null?window.innerWidth>1100:localStorage.getItem(`teapot.panel`)===`1`),A=()=>{let e=!k();ee(e),localStorage.setItem(`teapot.panel`,e?`1`:`0`)},[te,ne]=v(``),[j,M]=v(``),[re,ie]=v([]),ae=()=>Object.keys(_().providers??{});async function oe(e){if(e)try{let t=await Q(`/api/models?provider=${encodeURIComponent(e)}`);ie(t.models??[])}catch{ie([])}}let se=()=>{let e=j().trim()||z()?.model||``;if(!e)return``;let t=re().find(t=>t.id===e);if(!t)return``;let n=[];t.contextLength&&n.push(`ctx ${tr(t.contextLength)} tok`);let r=e=>e===void 0?``:`$${e*1e6>=10?Math.round(e*1e6):+(e*1e6).toFixed(1)}/M`;if(t.pricing){let e=r(t.pricing.prompt),i=r(t.pricing.completion);e&&i?n.push(`${e} in · ${i} out`):(e||i)&&n.push(r(t.pricing.prompt??t.pricing.completion))}return n.join(` · `)};b(()=>{let e=z();e&&(ne(e.provider||_().defaultProvider||ae()[0]||``),M(``),oe(te()))});let[N,ce]=v(!0),[le,ue]=v(0),[P,de]=v(null),[fe,pe]=v(``),me;b(()=>{if(!P()){clearTimeout(me),me=void 0,pe(``);return}me||=setTimeout(()=>{me=void 0,pe(P()?.text??``)},60)}),w(()=>clearTimeout(me));let z=x(()=>e().find(e=>e.id===n())),[he,ge]=v(null),[B,_e]=v([]),be=x(()=>{let e=new Map,t=new Set,n=new Map;for(let r of i())if(Gn.has(r.type)){if(r.type===`tool_call`){let e=n.get(r.data.callId)??[];e.push(r),n.set(r.data.callId,e)}else if(r.type===`tool_result`){let i=n.get(r.data.callId)?.shift();i&&(e.set(i.id,r),t.add(r.id))}}return{resFor:e,consumed:t}}),Se=x(()=>{let{consumed:e}=be(),t=i().filter(t=>Gn.has(t.type)?t.type===`tool_result`?!e.has(t.id):t.type!==`message`||String(t.data?.content??``).trim()!==``||String(t.data?.reasoning??``).trim()!==``||!!t.data?.final:!1),n=[];for(let e of t)if(e.type===`sub`){let t=e.data,r=String(t?.type??`message`);if(r===`state`)continue;n.push({...e,type:r,data:{...t?.data??{},actor:t?.sub}})}else n.push(e);let r=B().filter(e=>!n.some(t=>t.type===`prompt`&&t.data?.source===`user`&&t.data?.text===e.text&&new Date(t.ts).getTime()>=e.at-1e3)).map(e=>({id:e.id,seq:0,ts:new Date(e.at).toISOString(),session:z()?.session??``,branch:z()?.branch??`br0`,parent:null,type:`prompt`,data:{source:`user`,text:e.text,pending:!0}}));return[...n,...r]}),Ce=()=>Q(`/api/config`).then(S).catch(()=>{}),[we,Te]=v(!1);C(()=>{let e=()=>Te(!0);window.addEventListener(`teapot:unauthorized`,e),w(()=>window.removeEventListener(`teapot:unauthorized`,e))});let[Ee,W]=v(``),[G,Oe]=v(!1),ke=``;b(()=>{let t=n(),r=e().find(e=>e.id===t)?.todo??``;t&&t!==ke?(ke=t,Oe(!1),W(r)):t&&!G()&&W(r)});let Ae=async()=>{let e=document.getElementById(`todo-notify`)?.checked??!0;if(n())try{await Q(`/api/agents/${n()}/todo`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({text:Ee(),notify:e})}),Oe(!1),X(`tasks saved${e&&Ee().trim()?` & notification queued`:``}`),K()}catch(e){X(`save failed: ${e.message}`)}},K=()=>Q(`/api/agents`).then(e=>t(e.agents)).catch(()=>{}),je=()=>Q(`/api/metrics`).then(d).catch(()=>{}),[Me,Ne]=v([]),Gt=()=>Q(`/api/tasks`).then(e=>Ne(e.tasks)).catch(()=>{}),Kt=e=>Me().filter(t=>t.agent===e),[qt,Jt]=v((()=>{try{return new Set(JSON.parse(localStorage.getItem(`teapot.collapsed`)??`[]`))}catch{return new Set}})()),Yt=e=>{let t=new Set(qt());t.has(e)?t.delete(e):t.add(e),Jt(t),localStorage.setItem(`teapot.collapsed`,JSON.stringify([...t]))},Xt=x(()=>{let t=e(),n=new Map,r=[];for(let e of t)e.parent&&t.some(t=>t.id===e.parent)?(n.has(e.parent)||n.set(e.parent,[]),n.get(e.parent).push(e)):r.push(e);let i=[],a=(e,t)=>{for(let r of e){i.push({a:r,depth:t});let e=n.get(r.id);e?.length&&!qt().has(r.id)&&a(e,t+1)}};return a(r,0),i}),[Zt,Qt]=v(null),q=new Map;function $t(e){let t=Array(e.length);for(let n=0;n<e.length;n++){let r=e[n],i=q.get(r.id);if(t[n]=i??r,!i&&(q.set(r.id,r),q.size>3e3)){let e=q.keys().next().value;e!==void 0&&q.delete(e)}}return t}async function en(e){try{let t=Zt(),[n,r,i]=await Promise.all([Q(`/api/agents/${e}/events?limit=300${t?`&branch=${encodeURIComponent(t)}`:``}`),Q(`/api/agents/${e}/branches`),Q(`/api/agents/${e}/skills`).catch(()=>({skills:[]}))]);a($t(n.events)),s(n.total??n.events.length),l(r.branches),Fn(i.skills??[])}catch{}}function tn(){return document.querySelector(`.feed`)}function nn(){let e=tn();return!e||e.scrollHeight-e.scrollTop-e.clientHeight<80}function rn(e=!1){let t=tn();t&&(e||N())&&(t.scrollTop=t.scrollHeight,ue(0))}async function J(e,t=!0){r(e),de(null),Qt(null),_e([]),localStorage.setItem(`teapot.session`,e),un(e,t),Q(`/api/agents/${e}/load`,{method:`POST`}).then(K).catch(()=>{}),await en(e),requestAnimationFrame(()=>rn(!0))}let[an,on]=v(!1),Y=null,sn=null;w(()=>Y?.close());function cn(){let e=location.protocol===`https:`?`wss://`:`ws://`;Y=new WebSocket(`${e}${location.host}/api/ws${Jn()}`),Y.onopen=()=>on(!0),Y.onclose=()=>{on(!1),setTimeout(cn,1500)},Y.onerror=()=>Y?.close();let t=new Set([`state`,`usage`,`session_start`]),r=null;Y.onmessage=e=>{let a=JSON.parse(e.data);if(a.kind!==`ping`&&a.kind!==`pong`){if(a.kind===`llm-delta`){r={id:a.agentId,at:Date.now()},a.agentId===n()&&de({text:a.text??``,reasoning:a.reasoning??``});return}a.kind===`event`&&t.has(a.event?.type)||(sn||=setTimeout(async()=>{if(sn=null,await K(),await je(),n()){let e=i().at(-1)?.id,t=o(),a=Date.now();await en(n()),i().at(-1)?.id!==e&&(r?.id===n()&&r.at>=a||de(null),nn()?rn(!0):ue(le()+Math.max(0,o()-t))),_e(e=>e.filter(e=>!i().some(t=>t.type===`prompt`&&t.data?.text===e.text&&new Date(t.ts).getTime()>=e.at-1e3)))}},400))}}}let ln=()=>decodeURIComponent(location.pathname.split(`/`)[2]??``);function un(e,t=!0){let n=`/session/${encodeURIComponent(e)}`;t?history.pushState(null,``,n):history.replaceState(null,``,n)}window.addEventListener(`popstate`,()=>{let t=ln();t&&e().some(e=>e.id===t)&&t!==n()&&J(t,!1)}),b(()=>{let e=z();document.title=e?`${e.status===`running`?`▶ `:e.status===`error`?`⚠ `:``}${e.id} · teapot`:`teapot`}),window.addEventListener(`keydown`,e=>{let t=e.target;if(t&&(t.tagName===`INPUT`||t.tagName===`TEXTAREA`||t.isContentEditable)){e.key===`Escape`&&t.blur();return}if(e.key===`Escape`){if(T()){E(!1);return}if(D()){O(!1);return}let e=z();if(e?.status===`running`){Q(`/api/agents/${e.id}/stop`,{method:`POST`}).then(K);return}k()&&window.innerWidth<=1100&&ee(!1);return}if(!(T()||D())){if(e.key===`/`)e.preventDefault(),document.querySelector(`.composer textarea`)?.focus();else if(e.key===`d`)A();else if(e.key===`t`)pn();else if(e.key===`ArrowDown`||e.key===`ArrowUp`){let t=Xt().map(e=>e.a);if(t.length===0)return;e.preventDefault();let r=t.findIndex(e=>e.id===n()),i=e.key===`ArrowDown`?Math.min(r+1,t.length-1):Math.max(r-1,0);i!==r&&J(t[i].id)}}});let[dn,fn]=v(localStorage.getItem(`teapot.term`)===`1`),pn=()=>{let e=!dn();fn(e),localStorage.setItem(`teapot.term`,e?`1`:`0`)},mn=null,hn=null,gn=null,_n=null,vn={cols:0,rows:0},yn=null;function bn(){_n?.disconnect(),_n=null,gn?.close(),gn=null,hn?.dispose(),hn=null}function xn(e){bn(),mn&&Promise.all([Pe(()=>import(`./xterm-C3BHN0de.js`),[]),Pe(()=>import(`./addon-fit-DIOBYJe3.js`),[])]).then(([{Terminal:t},{FitAddon:n}])=>{let r=new t({cursorBlink:!0,fontSize:12.5,fontFamily:`ui-monospace, Menlo, Consolas, monospace`,theme:{background:`#0d0e12`,foreground:`#dcdee4`}}),i=new n;r.loadAddon(i),r.open(mn),i.fit(),hn=r;let a=location.protocol===`https:`?`wss://`:`ws://`,o=new WebSocket(`${a}${location.host}/api/agents/${e}/term${Jn()}`);gn=o,o.onmessage=e=>{let t=JSON.parse(e.data);t.kind===`data`?r.write(t.data):t.kind===`exit`&&r.write(`\r\n\x1b[2m[terminal exited ${t.code??``}]\x1b[0m\r\n`)},r.onData(e=>{o.readyState===WebSocket.OPEN&&o.send(JSON.stringify({kind:`input`,data:e}))});let s=()=>{try{i.fit()}catch{}let{cols:e,rows:t}=r;(e!==vn.cols||t!==vn.rows)&&o.readyState===WebSocket.OPEN&&(vn={cols:e,rows:t},o.send(JSON.stringify({kind:`resize`,cols:e,rows:t})))};_n=new ResizeObserver(()=>{yn&&clearTimeout(yn),yn=setTimeout(s,300)}),_n.observe(mn),setTimeout(s,50)})}b(()=>{let e=n();!dn()||!e?bn():requestAnimationFrame(()=>e&&xn(e))}),w(bn),C(()=>{Ce(),K().then(()=>{let t=ln()||localStorage.getItem(`teapot.session`)||``,n=e().find(e=>e.id===t)??e()[0];n&&J(n.id,!1)}),je(),Gt(),On(),cn();let t=setInterval(()=>{je(),Gt()},3e4);w(()=>clearInterval(t))});let[Sn,Cn]=v(``),wn,X=e=>{Cn(e),clearTimeout(wn),wn=setTimeout(()=>Cn(``),3200)},Tn=[{cmd:`/start`,desc:`start working toward the goal`},{cmd:`/stop`,desc:`interrupt the running agent`},{cmd:`/fork`,desc:`branch the conversation here`},{cmd:`/goal`,desc:`/goal <text> — set goal & notify the agent`},{cmd:`/compact`,desc:`force a context compaction now`},{cmd:`/skill`,desc:`/skill <name> — force-load a skill and follow it`}],[En,Dn]=v([]),On=()=>Q(`/api/personas`).then(e=>Dn(e.personas)).catch(()=>{}),[kn,An]=v(!1),jn=()=>{let e=f().match(/^@([A-Za-z0-9._-]*)$/);return e?e[1].toLowerCase():null},Mn=()=>{let t=jn();return t===null?[]:[...En().map(e=>({key:e.key,label:`${e.label} — spawns a sub-agent`,kind:`persona`})),...e().filter(e=>e.id!==n()).map(e=>({key:e.id,label:`${e.status} — send directly`,kind:`agent`}))].filter(e=>e.key.toLowerCase().startsWith(t))},Nn=new Set([`start`,`stop`,`fork`,`compact`]),[Pn,Fn]=v([]),[In,Z]=v(-1),Ln=()=>{let e=f();if(!e.startsWith(`/`)||e.includes(`
8
+ `))return[];let t=e.match(/^\/([a-z]*)(?:\s+(.*))?$/i);if(!t)return[];let n=t[1].toLowerCase(),r=(t[3]??``).trim();if(!r&&n!==`skill`){let e=Tn.filter(e=>e.cmd.slice(1).startsWith(n));return e.find(e=>e.cmd.slice(1)===n)&&Nn.has(n)?[]:e.map(e=>({insert:e.cmd+` `,title:e.desc}))}if(n===`skill`){let e=Pn().filter(e=>e.name.toLowerCase().startsWith(r.toLowerCase()));return e.length===1&&e[0].name.toLowerCase()===r.toLowerCase()?[]:e.map(e=>({insert:`/skill ${e.name} `,title:e.description||`(bundled skill)`}))}return[]},Rn,zn=()=>{Rn&&(Rn.style.height=`auto`,Rn.style.height=`${Math.min(Rn.scrollHeight,160)}px`)};b(()=>{f(),zn()});let Bn=async e=>{let t=n();if(t)try{await Q(`/api/agents/${t}/prompt`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({text:e,start:m()})}),_e(t=>[...t,{id:`@p${Date.now()}${Math.random().toString(36).slice(2,6)}`,text:e,at:Date.now()}])}catch(t){p(e),console.error(`send failed:`,t)}},Vn=async t=>{t.preventDefault();let r=n(),i=f().trim();if(!(!r||!i)){if(i.startsWith(`@`)){let t=i.indexOf(` `),r=(t===-1?i.slice(1):i.slice(1,t)).toLowerCase(),a=t===-1?``:i.slice(t+1).trim(),o=En().some(e=>e.key.toLowerCase()===r),s=e().some(e=>e.id.toLowerCase()===r);try{if(o){if(!a){X(`usage: @${r} <task>`);return}let e=await Q(`/api/agents/${n()}/spawn`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({persona:r,task:a,context:kn()?`fork`:`none`})});X(`🧩 spawned ${e.id}${kn()?` (forked context)`:``}`),K(),p(``)}else if(s){if(!a){X(`usage: @${r} <message>`);return}await Q(`/api/agents/${encodeURIComponent(r)}/prompt`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({text:a,start:m()})}),X(`→ delivered to @${r}`),p(``)}else{X(`unknown @${r} — personas: ${En().map(e=>e.key).join(`, `)||`(none)`}`);return}}catch(e){X(`@${r} failed: ${e.message}`)}return}if(i.startsWith(`/`)){let e=i.indexOf(` `),t=(e===-1?i.slice(1):i.slice(1,e)).toLowerCase(),n=e===-1?``:i.slice(e+1).trim();if(t===`goal`&&!n){p(`/goal `);return}if(t===`skill`&&!n){p(`/skill `);return}p(``),await Hn(t,n);return}p(``),await Bn(i)}},Hn=async(e,t)=>{let r=n();if(!r)return;let i=(e,t)=>Q(`/api/agents/${r}${e}`,{method:`POST`,headers:{"content-type":`application/json`},...t===void 0?{}:{body:JSON.stringify(t)}}).then(K);try{if(e===`start`)await i(`/start`);else if(e===`stop`)await i(`/stop`);else if(e===`fork`)await i(`/fork`,{}),await J(r);else if(e===`compact`){let e=await i(`/compact`);X(e?.ran?`context compacted`:`nothing to compact yet`)}else if(e===`goal`){if(!t){X(`usage: /goal <text>`);return}await i(`/goal`,{text:t,notify:!0}),X(`goal saved & notification queued`)}else if(e===`skill`){if(!t){X(`usage: /skill <name>`);return}await Bn(`[harness] Force-load and follow the skill "${t}" now: call load_skill("${t}") and execute its playbook for the current task.`),X(`skill "${t}" dispatched`)}else X(`unknown command "${e}" — /start /stop /fork /goal /skill /compact`)}catch(t){X(`/${e} failed: ${t.message}`)}},Un=e=>()=>n()&&Q(`/api/agents/${n()}${e}`,{method:`POST`}).then(K),Wn=async e=>{e.preventDefault();let t=document.getElementById(`goal-input`),r=document.getElementById(`goal-notify`)?.checked??!0;!n()||!t.value.trim()||(await Q(`/api/agents/${n()}/goal`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({text:t.value,notify:r})}),t.value=``,K())};return[F(L,{get when(){return _()?.needsSetup},fallback:null,get children(){return F(or,{onDone:()=>location.reload()})}}),F(L,{get when(){return we()},get children(){var e=Fe();return e.firstChild.firstChild.nextSibling.addEventListener(`submit`,e=>{e.preventDefault();let t=document.getElementById(`pw-input`);localStorage.setItem(`teapot.token`,t.value),location.reload()}),e}}),F(L,{get when(){return!_()?.needsSetup},get children(){var i=vt(),o=i.firstChild,s=o.firstChild,l=s.firstChild.nextSibling,d=l.nextSibling.firstChild,h=d.nextSibling,v=s.nextSibling,b=v.nextSibling,x=o.nextSibling,S=x.nextSibling;return d.$$click=()=>{Ce(),E(!0)},h.$$click=()=>{Ce(),O(!0)},U(v,F(I,{get each(){return Xt()},children:({a:t,depth:r})=>(()=>{var i=Ct(),a=i.firstChild,o=a.nextSibling;return i.$$click=()=>J(t.id),U(i,F(L,{get when(){return e().some(e=>e.parent===t.id)},get fallback(){return wt()},get children(){var e=yt();return e.$$click=e=>{e.stopPropagation(),Yt(t.id)},U(e,()=>qt().has(t.id)?`▸`:`▾`),y(()=>V(e,`title`,qt().has(t.id)?`expand sub-agents`:`collapse sub-agents`)),e}}),a),U(o,()=>t.id),U(i,F(L,{get when(){return t.parent},get children(){return bt()}}),null),U(i,F(L,{get when(){return Kt(t.id).length>0},get children(){var e=xt();return y(()=>V(e,`title`,Kt(t.id).map(e=>`${e.id}: ${e.schedule}`).join(`
9
+ `))),e}}),null),U(i,F(L,{get when(){return t.goal.status===`done`},get children(){return St()}}),null),y(e=>{var o=`agent-item`+(t.id===n()?` sel`:``)+(r>0?` sub-row`:``),s=r>0?`padding-left:${10+r*14}px`:``,c=t.parent?`sub-agent of @${t.parent}`:void 0,l=`dot ${t.status}`;return o!==e.e&&H(i,e.e=o),e.t=ye(i,s,e.t),c!==e.a&&V(i,`title`,e.a=c),l!==e.o&&H(a,e.o=l),e},{e:void 0,t:void 0,a:void 0,o:void 0}),i})()})),U(b,F(L,{get when(){return u()},get children(){return[`master rss `,R(()=>u().rssMb),`MB · heap `,R(()=>u().heapUsedMb),`MB`,Ie(),`load1 `,R(()=>u().loadavg1),` · up `,R(()=>Math.floor(u().uptimeSec/60)),`m`]}})),U(x,F(L,{get when(){return z()},get fallback(){return Tt()},get children(){return[(()=>{var e=Be(),t=e.firstChild.nextSibling,n=t.nextSibling,r=n.nextSibling,i=r.firstChild,a=i.nextSibling,o=a.nextSibling.nextSibling,s=o.nextSibling.nextSibling;s.nextSibling;var c=r.nextSibling,l=c.firstChild,u=l.nextSibling;return U(t,()=>z().id),U(n,()=>z().status),U(e,F(L,{get when(){return(z().pendingPrompts??0)>0},get children(){var e=Le(),t=e.firstChild.nextSibling;return t.nextSibling,U(e,()=>z().pendingPrompts,t),y(()=>V(e,`title`,`${z().pendingPrompts} prompt(s) waiting — the agent picks them up at the next turn boundary`)),e}}),r),U(e,F(L,{get when(){return Kt(z().id).length>0},get children(){var e=Re();return e.firstChild,U(e,()=>Kt(z().id).length,null),y(()=>V(e,`title`,`scheduled tasks:\n${Kt(z().id).map(e=>`${e.schedule} · ${e.id}${e.forked?` (forked)`:``}`).join(`
10
+ `)}`)),e}}),r),U(r,()=>z().model,i),U(r,()=>z().session,a),U(r,()=>z().branch,o),U(r,()=>z().stats.turns,s),U(r,()=>z().stats.toolCalls,null),U(c,F(L,{get when(){return z().statusReason},get children(){var e=ze();return y(()=>V(e,`title`,z().statusReason)),e}}),l),l.$$click=pn,u.$$click=A,y(()=>H(n,`badge ${z().status}`)),e})(),(()=>{var e=We();return e.addEventListener(`scroll`,()=>{let e=nn();e&&le()&&ue(0),ce(e)}),U(e,F(L,{get when(){return Se().length>0},get fallback(){return Et()},get children(){return[F(I,{get each(){return Se()},children:(e,t)=>F(Zn,{e,get prev(){return Se()[t()-1]},get res(){return be().resFor.get(e.id)},onOption:e=>void Bn(e),get onEdit(){return e.type===`prompt`&&e.data?.source===`user`?()=>ge({eventId:e.id,text:String(e.data?.text??``)}):void 0}})}),F(L,{get when(){return P()},get children(){var e=Ue(),t=e.firstChild.nextSibling;return t.firstChild,U(t,F(L,{get when(){return P().reasoning},get children(){var e=Ve(),t=e.firstChild.nextSibling;return U(t,()=>P().reasoning),e}}),null),U(t,F(L,{get when(){return fe()},get fallback(){return Dt()},get children(){var e=He();return y(()=>e.innerHTML=De(fe()+`▍`)),e}}),null),e}})]}})),e})(),F(L,{get when(){return!N()||le()>0},get children(){var e=Ge();return e.firstChild,e.$$click=()=>rn(!0),U(e,(()=>{var e=R(()=>le()>0);return()=>e()?`${le()} new message${le()>1?`s`:``}`:`jump to present`})(),null),e}}),F(L,{get when(){return R(()=>!!dn())()&&z()},get children(){var e=Ke(),t=e.firstChild,n=t.firstChild,r=n.firstChild.nextSibling,i=n.nextSibling,a=t.nextSibling;return U(r,()=>z().workspace),i.$$click=pn,xe(e=>mn=e,a),e}}),(()=>{var e=Ye(),t=e.firstChild,n=t.firstChild,r=n.nextSibling,i=t.nextSibling;U(e,F(L,{get when(){return Ln().length>0},get children(){var e=qe();return U(e,F(I,{get each(){return Ln()},children:(e,t)=>(()=>{var n=Ot(),r=n.firstChild,i=r.nextSibling;return n.$$click=()=>{p(e.insert),Z(-1)},U(r,()=>e.insert.trim()),U(i,()=>e.title),y(r=>{var i=`cmdrow`+(t()===In()?` active`:``),a=e.title;return i!==r.e&&H(n,r.e=i),a!==r.t&&V(n,`title`,r.t=a),r},{e:void 0,t:void 0}),n})()})),e}}),t),U(e,F(L,{get when(){return Mn().length>0},get children(){var e=qe();return U(e,F(I,{get each(){return Mn()},children:e=>(()=>{var t=kt(),n=t.firstChild;n.firstChild;var r=n.nextSibling;return t.$$click=()=>{p(`@${e.key} `),Z(-1)},U(n,()=>e.key,null),U(r,()=>e.label),y(()=>V(t,`title`,e.label)),t})()})),e}}),t),t.addEventListener(`submit`,Vn),n.$$keydown=e=>{let t=Ln();if(t.length>0&&e.key===`ArrowDown`){e.preventDefault(),Z(e=>Math.min(e()+1,t.length-1));return}if(t.length>0&&e.key===`ArrowUp`){e.preventDefault(),Z(e=>Math.max(e()-1,0));return}if(t.length>0&&(e.key===`Tab`||e.key===`Enter`)&&!e.shiftKey&&In()>=0){e.preventDefault(),p(t[In()].insert),Z(-1);return}if(e.key===`Escape`&&t.length>0){Z(-1);return}e.key===`Enter`&&!e.shiftKey&&!e.isComposing&&(e.preventDefault(),Vn(e))},n.$$input=e=>{p(e.currentTarget.value),Z(0),zn()};var a=Rn;return typeof a==`function`?xe(a,n):Rn=n,U(t,F(L,{get when(){return R(()=>!!f().startsWith(`@`))()&&f().includes(` `)},get children(){var e=Je(),t=e.firstChild;return t.addEventListener(`change`,e=>An(e.currentTarget.checked)),y(()=>t.checked=kn()),e}}),r),U(i,()=>Sn()||`enter send · shift+enter newline · ↑↓ sessions · / commands & focus · t terminal · d panel · esc interrupt · messages sent while the agent works queue up and land at the next turn boundary`),y(()=>V(n,`placeholder`,`message #${z().id} — / for commands`)),y(()=>n.value=f()),e})()]}})),U(S,F(L,{get when(){return z()},get children(){return[Xe(),(()=>{var e=Ze(),t=e.firstChild,n=t.firstChild.nextSibling,r=n.nextSibling,i=t.nextSibling,a=i.firstChild.nextSibling,o=i.nextSibling.firstChild.nextSibling,s=o.firstChild;return U(n,()=>z().id),U(r,()=>z().status),U(a,()=>z().workspace),U(o,()=>z().session,s),U(o,()=>z().branch,null),y(e=>{var t=`badge ${z().status}`,n=z().workspace;return t!==e.e&&H(r,e.e=t),n!==e.t&&V(a,`title`,e.t=n),e},{e:void 0,t:void 0}),e})(),Qe(),(()=>{var e=et(),t=e.firstChild,r=t.nextSibling,i=r.firstChild,a=i.nextSibling,o=a.nextSibling,s=r.nextSibling;return s.firstChild,t.addEventListener(`change`,e=>{ne(e.currentTarget.value),oe(e.currentTarget.value)}),U(t,F(I,{get each(){return ae()},children:e=>(()=>{var t=At();return t.value=e,U(t,e,null),U(t,()=>e===_().defaultProvider?` ★`:``,null),t})()})),i.$$input=e=>M(e.currentTarget.value),U(a,F(I,{get each(){return re()},children:e=>(()=>{var t=At();return y(()=>t.value=e.id),t})()})),o.$$click=async e=>{if(!n())return;let t=e.currentTarget;t.disabled=!0;try{await Q(`/api/agents/${n()}/model`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({provider:te(),model:j().trim()||void 0,contextWindowTokens:re().find(e=>e.id===(j().trim()||void 0))?.contextLength})}),t.textContent=`✓ applied`,K()}catch(e){alert(`model switch failed: ${e.message}`)}finally{setTimeout(()=>{t.textContent=`apply`,t.disabled=!1},1200)}},U(s,()=>z().model,null),U(s,F(L,{get when(){return re().length},get children(){return[` · `,R(()=>re().length),` models loaded`]}}),null),U(e,F(L,{get when(){return se()},get children(){var e=$e();return U(e,se),e}}),null),y(()=>V(i,`placeholder`,z().model)),y(()=>t.value=te()),y(()=>i.value=j()),e})(),tt(),(()=>{var i=it(),o=i.firstChild,s=o.nextSibling;return U(i,F(L,{get when(){return z().status===`running`},get fallback(){return(()=>{var e=jt();return ve(e,`click`,Un(`/start`),!0),e})()},get children(){var e=nt();return ve(e,`click`,Un(`/stop`),!0),e}}),o),o.$$click=()=>Q(`/api/agents/${z().id}/fork`,{method:`POST`,headers:{"content-type":`application/json`},body:`{}`}).then(()=>J(z().id)),s.$$click=async()=>{let i=n();if(!i||!confirm(`remove agent ${i}? (log is kept)`))return;await Q(`/api/agents/${i}`,{method:`DELETE`}).catch(()=>{});let o=e().filter(e=>e.id!==i);t(o),o[0]?J(o[0].id):(r(null),a([]))},U(i,F(L,{get when(){return e().some(e=>e.parent===n())},get children(){var e=rt();return e.$$click=async()=>{if(!n())return;let e=await Q(`/api/agents/${n()}/stop-children`,{method:`POST`});X(`stopped: ${(e.stopped??[]).join(`, `)||`(none)`}`),K()},e}}),null),i})(),(()=>{var e=at(),t=e.firstChild.firstChild;return t.addEventListener(`change`,e=>g(e.currentTarget.checked)),y(()=>t.checked=m()),e})(),(()=>{var e=ot(),t=e.firstChild.nextSibling;return U(t,()=>z().goal.status),y(()=>H(t,`badge ${z().goal.status===`done`?`done`:``}`)),e})(),(()=>{var e=st();return e.addEventListener(`submit`,Wn),e})(),(()=>{var e=ct();return U(e,()=>z().goal.text||`no goal set — the agent has nothing to auto-continue toward`),e})(),(()=>{var e=lt();return e.firstChild,U(e,F(L,{get when(){return R(()=>!!z().goal.text)()&&z().goal.status===`active`},children:` auto-continue keeps it working until this is done`}),null),U(e,F(L,{get when(){return!z().goal.text},children:` set one and tick ▶ start to begin`}),null),e})(),ut(),(()=>{var e=dt();return e.$$input=e=>{W(e.currentTarget.value),Oe(!0)},y(()=>e.value=Ee()),e})(),(()=>{var e=ft(),t=e.firstChild.nextSibling;return t.$$click=Ae,e})(),pt(),F(L,{get when(){return z().latestProgress},get fallback(){return Mt()},children:e=>(()=>{var t=Lt(),n=t.firstChild,r=n.firstChild.nextSibling,i=n.nextSibling;return U(r,()=>e().doing),U(t,F(L,{get when(){return e().recent},get children(){var t=Nt(),n=t.firstChild.nextSibling;return U(n,()=>e().recent),t}}),i),U(t,F(L,{get when(){return e().problems},get children(){var t=Pt(),n=t.firstChild.nextSibling;return U(n,()=>e().problems),t}}),i),U(t,F(L,{get when(){return e().next},get children(){var t=Ft(),n=t.firstChild.nextSibling;return U(n,()=>e().next),t}}),i),U(t,F(L,{get when(){return e().goalStatus},get children(){var t=It(),n=t.firstChild.nextSibling;return U(n,()=>e().goalStatus),t}}),i),U(i,()=>er(e().ts)),t})()}),mt(),(()=>{var e=ht(),t=e.firstChild.nextSibling,n=t.nextSibling.nextSibling,r=n.nextSibling.nextSibling,i=r.nextSibling.nextSibling;return i.nextSibling,U(e,()=>z().stats.turns,t),U(e,()=>z().stats.toolCalls,n),U(e,()=>z().stats.compactions??0,r),U(e,()=>tr(z().stats.inputTokens),i),U(e,()=>tr(z().stats.outputTokens),null),U(e,F(L,{get when(){return z().stats.cachedInputTokens>0},get children(){return[` · `,`cached `,R(()=>Math.round(z().stats.cachedInputTokens/Math.max(1,z().stats.inputTokens)*100)),`% (`,R(()=>tr(z().stats.cachedInputTokens)),`)`]}}),null),U(e,F(L,{get when(){return z().ctx},children:e=>{let t=Math.min(999,Math.round(e().usedTokens/e().window*100)),n=e().window?t>=85?` ctxcrit`:t>=70?` ctxwarn`:``:``;return[`
11
+ `,`context ~`,R(()=>tr(e().usedTokens)),` tok`,F(L,{get when(){return e().window},get children(){return[` · `,(()=>{var r=Rt(),i=r.firstChild;return U(r,t,i),U(r,()=>tr(e().window),null),y(()=>H(r,n.trim())),r})()]}}),`
12
+ `,`compaction at ~`,R(()=>tr(e().compactAt)),` tok (older turns summarized)`]}}),null),e})(),gt(),F(I,{get each(){return c()},children:e=>(()=>{var t=zt(),r=t.firstChild,i=r.nextSibling,a=i.firstChild;return t.$$click=()=>{let t=Zt()===e.branch?null:e.branch;Qt(t),n()&&en(n())},U(r,()=>e.branch,null),U(r,()=>e.branch===z().branch?` (current)`:``,null),U(i,()=>e.events,a),y(n=>{var r=`branch-row`+(e.branch===z().branch||e.branch===Zt()?` cur`:``),i=e.branch===Zt()?`click to show all branches again`:`show only ${e.branch}`;return r!==n.e&&H(t,n.e=r),i!==n.t&&V(t,`title`,n.t=i),n},{e:void 0,t:void 0}),t})()}),_t(),F(L,{get when(){return Me().length>0},get fallback(){return Bt()},get children(){return F(I,{get each(){return Me()},children:e=>(()=>{var t=Ht(),r=t.firstChild,i=r.firstChild,a=i.nextSibling;a.firstChild;var o=r.nextSibling,s=o.firstChild,c=o.nextSibling;return t.$$click=()=>J(e.agent),U(i,()=>e.id),U(a,()=>e.agent,null),U(r,F(L,{get when(){return e.forked},get children(){return Vt()}}),null),U(o,()=>e.schedule,s),U(o,(()=>{var t=R(()=>!!e.next);return()=>t()?er(e.next):`—`})(),null),U(o,(()=>{var t=R(()=>!!e.last);return()=>t()?` · last ${er(e.last)}`:` · never ran`})(),null),U(c,()=>$(e.prompt,90)),y(r=>{var i=`sched-row`+(e.agent===n()?` cur`:``),a=`${$(e.prompt,200)}\nclick to open #${e.agent}`;return i!==r.e&&H(t,r.e=i),a!==r.t&&V(t,`title`,r.t=a),r},{e:void 0,t:void 0}),t})()})}})]}})),y(e=>{var t=`layout`+(k()?``:` right-hidden`),n=`conn`+(an()?` ok`:``),r=an()?`live (websocket)`:`reconnecting…`,a=`rightbar`+(k()?` open`:``);return t!==e.e&&H(i,e.e=t),n!==e.t&&H(l,e.t=n),r!==e.a&&V(l,`title`,e.a=r),a!==e.o&&H(S,e.o=a),e},{e:void 0,t:void 0,a:void 0,o:void 0}),i}}),F(L,{get when(){return T()},get children(){return F(ir,{get providers(){return Object.keys(_().providers??{})},onClose:()=>E(!1),onCreated:e=>{E(!1),K(),J(e)}})}}),F(L,{get when(){return D()},get children(){return F(sr,{get cfg(){return _()},onClose:()=>O(!1),onSaved:()=>{Ce(),Gt()}})}}),F(L,{get when(){return he()},fallback:null,children:e=>{let t=()=>i().findIndex(t=>t.id===e().eventId),r=()=>Math.max(0,i().length-t()-1),[a,o]=v(r()>0?`summarize`:`discard`);return F(rr,{title:`edit prompt — forks the conversation`,onClose:()=>ge(null),get children(){var t=Wt(),i=t.firstChild,s=i.nextSibling,c=s.firstChild;return t.addEventListener(`submit`,async t=>{t.preventDefault();let r=document.getElementById(`edit-text`);try{await Q(`/api/agents/${n()}/edit-prompt`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({eventId:e().eventId,text:r.value,tail:a()})}),ge(null),K(),n()&&await J(n())}catch(e){alert(`edit failed: ${e.message}`)}}),U(t,F(L,{get when(){return r()>0},get children(){var e=Ut(),t=e.firstChild,n=t.firstChild,i=t.nextSibling,s=i.firstChild,c=i.nextSibling.firstChild;return U(t,r,n),s.addEventListener(`change`,()=>o(`summarize`)),c.addEventListener(`change`,()=>o(`discard`)),y(()=>s.checked=a()===`summarize`),y(()=>c.checked=a()===`discard`),e}}),s),c.$$click=()=>ge(null),y(()=>i.value=e().text),t}})}})]}function Xn(e){let t=e.e,n=e.res,r=t.data??{},i=String(r.name??`tool`),a=()=>n?String(n.data?.result??``):``,o=i,s=``,c=(()=>{var e=Gt();return U(e,()=>$n(JSON.stringify(r.args??{},null,1),2e3)),e})(),l=e=>String(r.args?.[e]??``),u=(e,t=1500)=>(()=>{var n=Kt();return U(n,()=>$n(e,t)),n})(),d=(e=4e3)=>n?[R(()=>u(a(),e)),(()=>{var e=qt(),t=e.firstChild;return U(e,()=>n.data?.durationMs,t),U(e,()=>n.data?.ok===!1?` · FAILED`:``,null),U(e,F(nr,{get text(){return a()}}),null),e})()]:Jt();try{switch(i){case`bash`:{let e=l(`command`);o=`$ `+$(e,96),s=l(`timeout_ms`)?`timeout ${Math.round(Number(l(`timeout_ms`))/1e3)}s`:``,c=[R(()=>R(()=>e!==o.slice(2))()?u(e,800):null),R(()=>d(6e3))];break}case`read_file`:{o=l(`path`)||`(no path)`;let e=[];l(`pattern`)&&e.push(`grep /${$(l(`pattern`),40)}/`),Number(r.args?.offset)<0?e.push(`last ${-Number(r.args.offset)} lines`):r.args?.offset&&e.push(`from L${r.args.offset}`),r.args?.limit&&e.push(`≤${r.args.limit} lines`),s=e.join(` · `),c=d(6e3);break}case`write_file`:{let e=String(r.args?.content??``);o=l(`path`)||`(no path)`,s=`${e.length} bytes`,c=[R(()=>u(e)),n?(()=>{var e=Yt();return U(e,()=>$(a(),160)),e})():Xt()];break}case`edit_file`:o=l(`path`)||`(no path)`,s=r.args?.replace_all===!0?`replace all`:`unique spot`,c=[(()=>{var e=Zt();return U(e,()=>$n(`- `+l(`old_text`),900)),e})(),(()=>{var e=Qt();return U(e,()=>`+ `+$n(l(`new_text`),900)),e})(),n?(()=>{var e=q(),t=e.firstChild,r=t.nextSibling;return r.nextSibling,U(e,()=>$(a(),120),t),U(e,()=>n.data?.durationMs,r),e})():$t()];break;case`apply_patch`:{let e=l(`patch`).split(`
13
+ `).filter(e=>e&&!/^---$/.test(e.trim())),t=e.map(e=>e.match(/^\*\*\* (?:Add|Update|Delete) File: (.+)$/)?.[1]).filter(Boolean);o=t.length?`${t.length} file${t.length>1?`s`:``}: ${$(t.join(`, `),80)}`:`patch`,c=[(()=>{var t=en();return U(t,()=>e.map(e=>{let t=e.startsWith(`+`)?` add`:e.startsWith(`-`)?` del`:/^\*\*\*|^@@/.test(e)?` meta`:``;return(()=>{var n=tn();return H(n,`pline`+t),U(n,(()=>{var t=R(()=>e.length>240);return()=>t()?e.slice(0,240)+`…`:e})()),n})()})),t})(),n?(()=>{var e=Yt();return U(e,()=>$(a().split(`
14
+ `)[0]??``,140),null),U(e,()=>n.data?.ok===!1?` · FAILED`:``,null),e})():nn()];break}case`list_dir`:o=l(`path`)||`.`,c=d(4e3);break;case`read_url`:{let e=l(`url`);try{let t=new URL(e);e=t.host+t.pathname}catch{}o=$(e,70),s=`web`,c=[(()=>{var e=Yt();return U(e,F(L,{get when(){return/^https?:/i.test(l(`url`))},get fallback(){return(()=>{var e=J();return U(e,()=>$(l(`url`),80)),e})()},get children(){var e=rn();return y(()=>V(e,`href`,l(`url`))),e}})),e})(),R(()=>d(3e3))];break}case`load_skill`:{o=`skill: ${l(`name`)}`;let e=a().replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/,``);c=n?[(()=>{var t=He();return y(()=>t.innerHTML=De(e)),t})(),(()=>{var e=qt(),t=e.firstChild;return U(e,()=>n.data?.durationMs,t),e})()]:an();break}case`save_skill`:{o=`skill: ${l(`name`)}`,s=$(l(`description`),60);let e=Array.isArray(r.args?.files)?r.args.files.map(e=>e?.name).filter(Boolean):[];c=[R(()=>R(()=>!!e.length)()?(()=>{var t=on();return t.firstChild,U(t,()=>e.join(`, `),null),t})():null),n?(()=>{var e=q(),t=e.firstChild,r=t.nextSibling;return r.nextSibling,U(e,()=>$(a(),160),t),U(e,()=>n.data?.durationMs,r),e})():Y()];break}}}catch{}return(()=>{var e=cn(),r=e.firstChild,a=r.firstChild;a.firstChild;var l=a.nextSibling;return V(e,`title`,`${i}${s?` — `+s:``}`),U(a,o,null),U(r,F(L,{get when(){return t.data?.actor},get children(){var e=sn();return e.firstChild,U(e,()=>String(t.data.actor),null),e}}),l),U(l,n?s||``:`running…`),U(e,c,null),y(()=>H(e,`embed`+(n?n.data?.ok===!1?` fail`:` done`:` running`))),e})()}function Zn(e){let t=e.e,n=Wn(t),r=e.prev&&e.prev.type===t.type&&Wn(e.prev).name===n.name&&t.session===e.prev.session&&t.branch===e.prev.branch;if(t.type===`fork`){let e=t.data??{};return(()=>{var n=ln(),r=n.firstChild.nextSibling;return r.nextSibling,U(n,()=>String(e.fromBranch??`?`),r),U(n,()=>String(e.newBranch??t.branch),null),n})()}if(t.type===`goal`){let e=t.data??{},n=e.event===`status`?`marked ${String(e.status??``)}`:$(String(e.text??``),80);return(()=>{var t=un(),r=t.firstChild.nextSibling;return r.nextSibling,U(t,()=>String(e.event??``),r),U(t,n,null),t})()}return t.type===`todo`?(()=>{var e=dn(),n=e.firstChild.nextSibling;return n.nextSibling,U(e,()=>String(t.data?.by??`human`),n),e})():t.type===`state`?t.data.from===t.data.to?null:(()=>{var e=fn(),n=e.firstChild;return U(e,()=>t.data.from,n),U(e,()=>t.data.to,null),U(e,(()=>{var e=R(()=>!!t.data.reason);return()=>e()?` — ${t.data.reason}`:``})(),null),y(()=>H(e,`divider-msg`+(t.data.to===`error`?` err`:``))),e})():(()=>{var i=gn(),a=i.firstChild;return U(i,F(L,{when:!r,get fallback(){return _n()},get children(){var e=pn();return U(e,()=>n.icon),y(t=>{var r=n.color+`33`,i=`1px solid ${n.color}66`;return r!==t.e&&be(e,`background`,t.e=r),i!==t.t&&be(e,`border`,t.t=i),t},{e:void 0,t:void 0}),e}}),a),U(a,F(L,{when:!r,get children(){var r=hn(),i=r.firstChild,a=i.nextSibling,o=a.nextSibling;return U(i,()=>n.name),U(r,F(L,{get when(){return t.data?.actor},get children(){var e=sn();return e.firstChild,U(e,()=>String(t.data.actor),null),e}}),a),U(a,(()=>{var e=R(()=>!!t.data?.pending);return()=>e()?`pending…`:Kn(t.ts)})()),U(o,()=>t.branch),U(r,F(L,{get when(){return e.onEdit},get children(){var t=mn();return t.$$click=t=>{t.stopPropagation(),e.onEdit()},t}}),null),y(e=>be(i,`color`,n.color)),r}}),null),U(a,F(Qn,{e:t,get res(){return e.res},get onOption(){return e.onOption}}),null),y(()=>H(i,`msg`+(r?` grouped`:``)+(t.data?.pending?` pending`:``))),i})()}function Qn(e){let t=e.e;switch(t.type){case`prompt`:return(()=>{var e=He();return y(()=>e.innerHTML=De(String(t.data.text??``))),e})();case`message`:return[F(L,{get when(){return R(()=>typeof t.data.reasoning==`string`)()&&t.data.reasoning.trim()},get children(){var e=Ve(),n=e.firstChild.nextSibling;return U(n,()=>String(t.data.reasoning)),e}}),(()=>{var e=He();return y(()=>e.innerHTML=De(String(t.data.content??``))),e})(),F(L,{get when(){return t.data.interrupted},get children(){return vn()}}),F(L,{get when(){return t.data.final},get children(){var e=yn(),n=e.firstChild;return U(e,F(nr,{get text(){return String(t.data.content??``)}}),n),e}})];case`tool_call`:return F(Xn,{e:t,get res(){return e.res}});case`tool_result`:{let e=String(t.data.result);return(()=>{var n=bn(),r=n.firstChild,i=r.firstChild,a=r.nextSibling,o=a.nextSibling,s=o.firstChild;return U(i,()=>$(e,120)),U(r,F(nr,{text:e}),null),U(a,()=>$n(e,4e3)),U(o,()=>t.data.durationMs,s),U(o,()=>t.data.ok?``:` · FAILED`,null),y(()=>H(n,`embed`+(t.data.ok?``:` fail`))),n})()}case`decision`:{let e=Array.isArray(t.data?.alternatives)?t.data.alternatives:[];return(()=>{var n=Sn(),r=n.firstChild,i=r.firstChild;i.firstChild;var a=r.nextSibling;return a.firstChild,U(i,()=>$(String(t.data?.decision??``),90),null),U(a,()=>String(t.data?.rationale??``),null),U(n,F(L,{get when(){return e.length},get children(){var t=xn();return t.firstChild,U(t,()=>e.join(` / `),null),t}}),null),n})()}case`question`:{let n=Array.isArray(t.data?.options)?t.data.options:[];return(()=>{var r=wn(),i=r.firstChild;i.firstChild;var a=i.nextSibling;return U(i,()=>String(t.data?.question??``),null),U(r,F(L,{get when(){return n.length>0},get children(){var t=Cn();return U(t,F(I,{each:n,children:t=>(()=>{var n=X();return n.$$click=()=>e.onOption?.(t),U(n,t),n})()})),t}}),a),r})()}case`progress`:return(()=>{var e=Dn(),n=e.firstChild;return n.firstChild,U(n,()=>String(t.data.doing??``),null),U(e,F(L,{get when(){return t.data.recent},get children(){var e=Yt();return U(e,()=>String(t.data.recent)),e}}),null),U(e,F(L,{get when(){return t.data.problems},get children(){var e=Tn();return e.firstChild,U(e,()=>String(t.data.problems),null),e}}),null),U(e,F(L,{get when(){return t.data.next},get children(){var e=En();return e.firstChild,U(e,()=>String(t.data.next),null),e}}),null),e})();case`error`:return(()=>{var e=On(),n=e.firstChild;return n.firstChild,U(n,()=>String(t.data.message??``),null),e})();default:return(()=>{var e=kn();return U(e,()=>$n(JSON.stringify(t.data),200)),e})()}}function $n(e,t){return e.length>t?e.slice(0,t)+` …`:e}function er(e){let t=new Date(e).getTime()-Date.now(),n=Math.abs(t),r=n<9e4?`${Math.round(n/1e3)}s`:n<54e5?`${Math.round(n/6e4)}m`:`${(n/36e5).toFixed(1)}h`;return t>=0?`in ${r}`:`${r} ago`}function tr(e){return e>=1e9?`${+(e/1e9).toFixed(1)}b`:e>=1e6?`${+(e/1e6).toFixed(1)}m`:e>=1e4?`${Math.round(e/1e3)}k`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function $(e,t){return $n(e.replace(/\s+/g,` `).trim(),t)}function nr(e){let[t,n]=v(!1);return(()=>{var r=An();return r.$$click=t=>{t.stopPropagation(),navigator.clipboard.writeText(e.text).then(()=>{n(!0),setTimeout(()=>n(!1),900)})},U(r,()=>t()?`✓`:`⧉`),r})()}function rr(e){return(()=>{var t=jn(),n=t.firstChild,r=n.firstChild.firstChild,i=r.nextSibling;return t.$$click=t=>t.target===t.currentTarget&&e.onClose(),U(r,()=>e.title),ve(i,`click`,e.onClose,!0),U(n,()=>e.children,null),t})()}function ir(e){let[t,n]=v(`~`),[r,i]=v([]),[a,o]=v(``),[s,c]=v(e.providers[0]??``),[l,u]=v(``),[d,f]=v(``);async function p(e){let t=await Q(`/api/fs${e?`?path=${encodeURIComponent(e)}`:``}`);n(t.path),i(t.entries)}C(()=>p(t()));let m=async n=>{n.preventDefault(),f(``);try{let n=await Q(`/api/agents`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({workspace:t(),id:a(),provider:s()||void 0,model:l()||void 0})});e.onCreated(n.agent.id)}catch(e){f(String(e.message))}};return F(rr,{title:`new agent`,get onClose(){return e.onClose},get children(){var i=Nn(),f=i.firstChild,h=f.firstChild.nextSibling.firstChild,g=h.nextSibling,_=g.nextSibling,v=f.nextSibling,b=v.nextSibling,x=b.firstChild,S=x.firstChild.nextSibling,C=x.nextSibling,w=C.firstChild.nextSibling,T=C.nextSibling.firstChild.nextSibling,E=b.nextSibling;return i.addEventListener(`submit`,m),h.$$input=e=>n(e.currentTarget.value),g.$$click=()=>p(t()),_.$$click=()=>p(`..`),U(v,F(I,{get each(){return r()},children:e=>(()=>{var n=Pn();return n.firstChild,n.$$click=()=>p(`${t()}/${e}`.replace(/\/+/g,`/`)),U(n,e,null),n})()})),S.$$input=e=>o(e.currentTarget.value),w.addEventListener(`change`,e=>c(e.currentTarget.value)),U(w,F(I,{get each(){return e.providers},children:e=>(()=>{var t=At();return U(t,e),t})()})),T.$$input=e=>u(e.currentTarget.value),U(i,F(L,{get when(){return d()},get children(){var e=Mn();return U(e,d),e}}),E),y(()=>h.value=t()),y(()=>S.value=a()),y(()=>w.value=s()),y(()=>T.value=l()),i}})}var ar=[{key:`openrouter`,label:`OpenRouter`,url:`https://openrouter.ai/api/v1`,model:`anthropic/claude-sonnet-4`},{key:`openai`,label:`OpenAI`,url:`https://api.openai.com/v1`,model:`gpt-4o-mini`},{key:`ollama`,label:`Ollama (local)`,url:`http://localhost:11434/v1`,model:`qwen3-coder`}];function or(e){let[t,n]=v(ar[0]),[r,i]=v(ar[0].url),[a,o]=v(``),[s,c]=v(ar[0].model),[l,u]=v(`~/teapot-workspace`),[d,f]=v(``),[p,m]=v(!1),[h,g]=v(``),_=e=>{n(e),e.url&&(i(e.url),c(e.model))},b=async t=>{t.preventDefault(),g(``),m(!0);try{await Q(`/api/setup`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({baseUrl:r(),apiKey:a()||void 0,model:s(),workspace:l(),...d()?{password:d()}:{}})}),e.onDone()}catch(e){g(e.message),m(!1)}};return(()=>{var e=Fn(),n=e.firstChild.firstChild.nextSibling.nextSibling,m=n.firstChild,g=m.nextSibling,v=g.firstChild.nextSibling,x=g.nextSibling,S=x.firstChild.nextSibling,C=x.nextSibling,w=C.firstChild.nextSibling,T=C.nextSibling,E=T.firstChild.nextSibling,D=E.firstChild.nextSibling,O=E.nextSibling.firstChild.nextSibling,k=T.nextSibling;return n.addEventListener(`submit`,b),U(m,F(I,{each:ar,children:e=>(()=>{var n=In();return n.$$click=()=>_(e),U(n,()=>e.label),y(()=>H(n,`presetbtn`+(t().key===e.key?` active`:``))),n})()})),v.$$input=e=>i(e.currentTarget.value),S.$$input=e=>o(e.currentTarget.value),w.$$input=e=>c(e.currentTarget.value),D.$$input=e=>u(e.currentTarget.value),O.$$input=e=>f(e.currentTarget.value),U(n,F(L,{get when(){return h()},get children(){var e=Mn();return U(e,h),e}}),k),U(k,()=>p()?`saving…`:`finish setup`),y(()=>k.disabled=p()),y(()=>v.value=r()),y(()=>S.value=a()),y(()=>w.value=s()),y(()=>D.value=l()),y(()=>O.value=d()),e})()}function sr(e){let[t,n]=v(Object.entries(e.cfg.providers??{}).map(([e,t])=>({name:e,baseUrl:t.baseUrl??``,apiKey:t.apiKey??``,model:t.model??``}))),[r,i]=v(e.cfg.defaultProvider??``),[a,o]=v(Math.round((e.cfg.progressIntervalMs??6e5)/6e4)),[s,c]=v(e.cfg.progressMinChars??4e3),[l,u]=v(Math.round((e.cfg.contextTokenBudget??96e3)/1e3)),[d,f]=v(e.cfg.contextWindowTokens?Math.round(e.cfg.contextWindowTokens/1e3):0),[p,m]=v(e.cfg.maxSpawnDepth??3),[h,g]=v((e.cfg.tasks??[]).map(e=>({...e}))),[_,b]=v(``),x=()=>(e.cfg.agents??[]).map(e=>e.id),S=()=>{let e={};for(let n of t()){if(!n.name.trim())return b(`provider name is required`),null;if(n.baseUrl&&!/^https?:\/\//.test(n.baseUrl))return b(`provider ${n.name}: baseUrl must start with http(s)://`),null;e[n.name.trim()]={baseUrl:n.baseUrl,...n.apiKey?{apiKey:n.apiKey}:{},...n.model?{model:n.model}:{}}}return e},C=async t=>{t.preventDefault(),b(``);let n=S();if(!n)return;let i=h().filter(e=>e.id?.trim()||e.prompt?.trim()).map((e,t)=>({id:e.id?.trim()||`task-${t+1}`,agent:e.agent,schedule:e.schedule,prompt:e.prompt,...e.forked?{forked:!0}:{}}));for(let e of i){if(!e.agent){b(`task "${e.id}": agent is required`);return}if(!e.schedule?.trim()){b(`task "${e.id}": schedule is required`);return}}try{await Q(`/api/config`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({providers:n,defaultProvider:r()||void 0,progressIntervalMs:Math.max(1,a())*6e4,progressMinChars:Math.max(100,s()),contextTokenBudget:Math.max(1e3,l())*1e3,...d()>0?{contextWindowTokens:d()*1e3}:{},maxSpawnDepth:Math.max(0,p()),tasks:i})}),e.onSaved(),e.onClose()}catch(e){b(e.message)}},w=(e,t,n,r)=>(()=>{var i=Z(),a=i.firstChild;return V(i,`title`,r),U(i,e,a),a.$$input=e=>n(Number(e.currentTarget.value)),a.value=t,i})();return F(rr,{title:`settings`,get onClose(){return e.onClose},get children(){var v=Ln(),b=v.firstChild,S=b.firstChild.nextSibling,T=S.nextSibling.firstChild.firstChild.nextSibling,E=b.nextSibling,D=E.firstChild.nextSibling,O=E.nextSibling,k=O.firstChild.nextSibling,ee=O.nextSibling;ee.firstChild;var A=ee.nextSibling;return v.addEventListener(`submit`,C),U(b,F(I,{get each(){return t()},children:(e,r)=>(()=>{var i=Rn(),a=i.firstChild,o=a.nextSibling,s=o.nextSibling,c=s.nextSibling,l=c.nextSibling;return a.$$input=e=>n(t().map((t,n)=>n===r()?{...t,name:e.currentTarget.value}:t)),o.$$input=e=>n(t().map((t,n)=>n===r()?{...t,baseUrl:e.currentTarget.value}:t)),s.$$input=e=>n(t().map((t,n)=>n===r()?{...t,apiKey:e.currentTarget.value}:t)),c.$$input=e=>n(t().map((t,n)=>n===r()?{...t,model:e.currentTarget.value}:t)),l.$$click=()=>n(t().filter((e,t)=>t!==r())),y(()=>a.value=e.name),y(()=>o.value=e.baseUrl),y(()=>s.value=e.apiKey),y(()=>c.value=e.model),i})()}),S),S.$$click=()=>n([...t(),{name:``,baseUrl:``,apiKey:``,model:``}]),T.$$input=e=>i(e.currentTarget.value),U(D,()=>w(`progress interval (min)`,a(),e=>o(e),`how often the harness asks for a progress report`),null),U(D,()=>w(`progress min chars`,s(),e=>c(e),`progress prompts wait for this much real output`),null),U(D,()=>w(`compact budget (k tok)`,l(),e=>u(e),`auto-compact when estimated context exceeds this`),null),U(D,()=>w(`context window (k tok)`,d(),e=>f(e),`model's real window — 0/blank hides the % gauge`),null),U(D,()=>w(`max spawn depth`,p(),e=>m(e),`sub-agent nesting limit (0 = no spawning)`),null),U(O,F(L,{get when(){return h().length>0},get children(){return F(I,{get each(){return h()},children:(e,t)=>(()=>{var n=zn(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=a.nextSibling,s=o.nextSibling,c=s.firstChild,l=s.nextSibling,u=r.nextSibling;return i.$$input=e=>g(h().map((n,r)=>r===t()?{...n,id:e.currentTarget.value}:n)),a.$$input=e=>g(h().map((n,r)=>r===t()?{...n,agent:e.currentTarget.value}:n)),o.$$input=e=>g(h().map((n,r)=>r===t()?{...n,schedule:e.currentTarget.value}:n)),c.addEventListener(`change`,e=>g(h().map((n,r)=>r===t()?{...n,forked:e.currentTarget.checked}:n))),l.$$click=()=>g(h().filter((e,n)=>n!==t())),u.$$input=e=>g(h().map((n,r)=>r===t()?{...n,prompt:e.currentTarget.value}:n)),y(()=>i.value=e.id),y(()=>a.value=e.agent),y(()=>o.value=e.schedule),y(()=>c.checked=!!e.forked),y(()=>u.value=e.prompt),n})()})}}),k),k.$$click=()=>g([...h(),{id:``,agent:x()[0]??``,schedule:`every 30m`,prompt:``}]),U(ee,F(I,{get each(){return e.cfg.agents??[]},children:e=>(()=>{var t=Vn(),n=t.firstChild,r=n.nextSibling;return U(n,()=>e.id),U(r,()=>e.workspace),U(t,F(L,{get when(){return e.parent},get children(){var t=Bn();return t.firstChild,U(t,()=>e.parent,null),t}}),null),t})()}),null),U(v,F(L,{get when(){return _()},get children(){var e=Mn();return U(e,_),e}}),A),y(()=>T.value=r()),v}})}_e([`click`,`input`,`keydown`]),ge(()=>F(Yn,{}),document.getElementById(`root`));
15
+ //# sourceMappingURL=index-DC44teo7.js.map