ask-coding-harness 0.2.0 → 0.2.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3fef50d92fb06108330d8976a625372fb12ec8edca50ea5e777317da3e36e2b4
4
- data.tar.gz: e8da881f33b685ca384653d9d5fcdc825f2cf954aa117b14e544d3c39f247a54
3
+ metadata.gz: 69387c402be4baf7feac38128c4ba8c8e5ef9b45990fb1e2ac6c6c88ae2475a4
4
+ data.tar.gz: 195abd511e806b952d02a1b17da3c3373371d6e7c54b294a571390684e74e6e3
5
5
  SHA512:
6
- metadata.gz: cd3e2adfef79ac48479349187ea5f1f10ee3a6a2f041235a3466f021ce25c3d1f0ac7b23145d42895a09fb5a9c7694246fee98bb73474ad8c57c9b965269fae6
7
- data.tar.gz: a9ca377914655989f1524cc06a46380b046b6d0a9e22b53bb8a7575066f2fb3375a436574d30877e37b72e7b8f0c2df5256e905dbeeabf11f35141553a16ab4c
6
+ metadata.gz: 6631d79089e2d2c94d78431f6c2b831d63a76dd9e03e76ba1976ffe58153b48c09fb88c1976ee1699e47ae32a29952a3457a85ba986c1a05749828ef971e7030
7
+ data.tar.gz: 75c4e27cf9e1ed89cfae4f0db8973aeb5ce18c29ad553e8d875eac7b05f7aa6372d7f6dc4208ff781a7c7c1aa734caba15991c269cbc328118ab47cc8e8dea92
data/CHANGELOG.md CHANGED
@@ -1,6 +1,20 @@
1
1
  # Changelog
2
2
 
3
- ## [0.2.0] - 2026-08-10
3
+ ## [0.2.1] - 2026-08-10
4
+
5
+ ### Added
6
+
7
+ - **Declarative agents (ask-agent `agents/` convention).** Each workspace
8
+ can carry an `agents/<name>/` directory (`agent.rb` +
9
+ `instructions.md`): the harness lists them per workspace
10
+ (`GET /api/workspaces/:path/agents`), the composer has an agent picker,
11
+ and conversations remember their agent. When an agent is selected, the
12
+ session is built via `Ask::Agent.new` — the definition's tools, skills,
13
+ and model apply — and the agent's `instructions.md` becomes the system
14
+ prompt base (project context, guidelines, append, and footer still
15
+ apply, pi-style). Requires ask-coding-providers >= 0.3.2.
16
+
17
+
4
18
 
5
19
  ### Added
6
20
 
@@ -125,6 +125,19 @@ module Ask
125
125
  end
126
126
  end
127
127
 
128
+ # The system prompt for a workspace. When a declarative agent is
129
+ # selected, its instructions.md become the custom base prompt
130
+ # (project context, guidelines, append, and footer still apply).
131
+ # Adapters that don't accept a per-session prompt (external ACP
132
+ # agents) ignore the extra keywords.
133
+ def system_prompt_for(workspace, agent = nil)
134
+ Ask::CodingHarness::SystemPrompt.build(
135
+ workspace: workspace,
136
+ custom: @config.system_prompt || (agent_instructions(workspace, agent) if agent),
137
+ append: @config.system_prompt_append,
138
+ guidelines: @config.system_prompt_guidelines
139
+ )
140
+ end
128
141
  private
129
142
 
130
143
  def run_turn(conversation, prompt, model: nil, &on_event)
@@ -192,29 +205,56 @@ module Ask
192
205
 
193
206
  # One adapter session per conversation, created on first use. Each
194
207
  # session gets its workspace's system prompt (pi-style: default or
195
- # custom base + guidelines + AGENTS.md/CLAUDE.md project context).
208
+ # custom base + guidelines + AGENTS.md/CLAUDE.md project context),
209
+ # plus the conversation's declarative agent when one is selected.
210
+ # Runs inside the workspace (the mutex makes the chdir safe) so the
211
+ # ask-agent agents/ discovery finds this workspace's definitions.
196
212
  def session_for(conversation, workspace = nil, model: nil)
197
213
  workspace ||= conversation["directory"] || @config.workspace
198
214
  @mutex.synchronize do
199
- @sessions[conversation["id"]] ||= adapter.create_session(
200
- workspace,
201
- model: model || @config.model,
202
- system_prompt: system_prompt_for(workspace)
203
- )
215
+ Dir.chdir(workspace) do
216
+ @sessions[conversation["id"]] ||= adapter.create_session(
217
+ workspace,
218
+ model: model || @config.model,
219
+ system_prompt: system_prompt_for(workspace, conversation["agent"]),
220
+ agent: conversation["agent"]
221
+ )
222
+ end
204
223
  end
205
224
  end
206
225
 
207
- # The system prompt for a workspace. Adapters that don't accept a
208
- # per-session prompt (external ACP agents) ignore the extra keyword.
209
- def system_prompt_for(workspace)
210
- Ask::CodingHarness::SystemPrompt.build(
211
- workspace: workspace,
212
- custom: @config.system_prompt,
213
- append: @config.system_prompt_append,
214
- guidelines: @config.system_prompt_guidelines
215
- )
226
+
227
+ # Declarative agents in a workspace (ask-agent convention):
228
+ # [{name:, instructions:}] discovered without loading the
229
+ # definitions. Safe for listing in the UI.
230
+ def agent_definitions(workspace)
231
+ Dir.chdir(workspace) do
232
+ Ask::Agent.default_agent_paths.filter_map do |base|
233
+ next unless File.directory?(base)
234
+ Dir["#{base}/*/agent.rb"].sort.filter_map do |file|
235
+ dir = File.dirname(file)
236
+ name = File.basename(dir)
237
+ next if name == "shared"
238
+ instructions = File.file?(File.join(dir, "instructions.md")) ? File.read(File.join(dir, "instructions.md")) : nil
239
+ { "name" => name, "instructions" => instructions }
240
+ end
241
+ end.flatten
242
+ end
216
243
  end
217
244
 
245
+ # The instructions.md content of a named agent, loaded through the
246
+ # ask-agent registry (which also validates the definition).
247
+ def agent_instructions(workspace, agent)
248
+ Dir.chdir(workspace) do
249
+ Ask::Agent.rediscover!
250
+ klass = Ask::Agent.definitions[agent.to_s]&.first
251
+ klass&.instructions_content
252
+ end
253
+ end
254
+
255
+ # The server lists agents per workspace.
256
+ public :agent_definitions, :agent_instructions
257
+
218
258
  # Dispatch a control to the adapter, returning nil when the adapter
219
259
  # doesn't support it (e.g. external ACP agents without approvals).
220
260
  def send_adapter(conversation_id, method_name, *args)
@@ -124,6 +124,18 @@ module Ask
124
124
  { error: "Not a directory: #{dir}" }.to_json
125
125
  end
126
126
  end
127
+
128
+ # GET /api/workspaces/:encoded_path/agents — declarative agents
129
+ # (ask-agent convention: agents/<name>/agent.rb +
130
+ # instructions.md), listed without loading them.
131
+ r.get "agents" do
132
+ dir = URI.decode_www_form_component(encoded)
133
+ unless File.directory?(dir)
134
+ response.status = 404
135
+ next { error: "Not a directory: #{dir}" }.to_json
136
+ end
137
+ harness_runner.agent_definitions(dir).to_json
138
+ end
127
139
  end
128
140
 
129
141
  # POST /api/chat — streaming turn
@@ -148,7 +160,13 @@ module Ask
148
160
  store.register_workspace(workspace)
149
161
 
150
162
  existing = conversation_id && store.load(conversation_id)
151
- conversation = existing || store.build(directory: workspace)
163
+ conversation = existing || store.build(directory: workspace, agent: body["agent"])
164
+ # An explicit agent param updates the conversation (an agent
165
+ # picker can switch the persona for the next turn).
166
+ if existing && body["agent"]
167
+ conversation["agent"] = body["agent"]
168
+ conversation = store.save(conversation)
169
+ end
152
170
  new_conversation = existing.nil?
153
171
  conversation = store.save(conversation) if new_conversation
154
172
 
@@ -27,12 +27,15 @@ module Ask
27
27
  end
28
28
 
29
29
  # A fresh conversation record. Not persisted until {#save}.
30
- def build(directory: nil, title: "New conversation")
30
+ # @param agent [String, nil] declarative agent name (ask-agent
31
+ # convention) or nil for the default agent
32
+ def build(directory: nil, title: "New conversation", agent: nil)
31
33
  now = Time.now.iso8601
32
34
  {
33
35
  "id" => SecureRandom.uuid,
34
36
  "title" => title,
35
37
  "directory" => directory,
38
+ "agent" => agent,
36
39
  "archived" => false,
37
40
  "messages" => [],
38
41
  "created_at" => now,
@@ -120,6 +123,7 @@ module Ask
120
123
  "id" => data["id"],
121
124
  "title" => data["title"] || "New conversation",
122
125
  "directory" => data["directory"],
126
+ "agent" => data["agent"],
123
127
  "archived" => data["archived"] == true,
124
128
  "message_count" => data["messages"]&.length || 0,
125
129
  "created_at" => data["created_at"],
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ask
4
4
  module CodingHarness
5
- VERSION = "0.2.0"
5
+ VERSION = "0.2.1"
6
6
  end
7
7
  end
@@ -1 +1 @@
1
- :root{color-scheme:dark;--bg: #0b0b0c;--fg: #e5e5e5;--surface: #131316;--surface-muted: #161618;--border: #26262a;--border-strong: #3f3f46;--text-muted: #a3a3a3;--text-faint: #737373;--accent: #2f6feb;--danger: #dc2626;--font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif}html,body{margin:0;height:100%;background:var(--bg);color:var(--fg);font-family:var(--font);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}::selection{background:#2f6feb59}*{scrollbar-width:thin;scrollbar-color:#3f3f46 transparent}*::-webkit-scrollbar{width:8px;height:8px}*::-webkit-scrollbar-thumb{background:#3f3f46;border-radius:4px}*::-webkit-scrollbar-track{background:transparent}.tool-stream.svelte-1l486hy{display:flex;flex-direction:column;gap:.75rem;margin-top:.75rem}.block.svelte-1l486hy{display:flex;flex-direction:column;gap:.5rem}.tool.svelte-1l486hy{border:1px solid #26262a;border-radius:.625rem;background:#131316;overflow:hidden}.tool-head.svelte-1l486hy{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;font-size:.8125rem}.tool-icon.svelte-1l486hy{font-size:.875rem}.tool-name.svelte-1l486hy{font-weight:600;color:#d4d4d4;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.75rem}.tool-status.svelte-1l486hy{margin-left:auto;font-size:.6875rem;text-transform:uppercase;letter-spacing:.04em}.tool-status.running.svelte-1l486hy{color:#fbbf24;animation:svelte-1l486hy-pulse 1.2s infinite}.tool-status.done.svelte-1l486hy{color:#4ade80}.tool-status.failed.svelte-1l486hy{color:#f87171}@keyframes svelte-1l486hy-pulse{0%,to{opacity:1}50%{opacity:.4}}.tool-args.svelte-1l486hy{margin:0;padding:.375rem .75rem;border-top:1px solid #1f1f22;background:#0d0d0f;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.6875rem;line-height:1.6;color:#a3a3a3;white-space:pre-wrap;word-break:break-word;max-height:8rem;overflow-y:auto}.approvals.svelte-1l486hy{gap:.5rem}.approve-all.svelte-1l486hy{align-self:flex-start;font:inherit;font-size:.75rem;font-weight:600;padding:.375rem .75rem;border-radius:.5rem;border:1px solid #ea580c;background:#ea580c;color:#fff;cursor:pointer}.assistant.svelte-kpbn6d{max-width:46rem;margin:0 auto 1.5rem}.thinking.svelte-kpbn6d{margin-bottom:.75rem;border:1px solid #26262a;border-radius:.625rem;background:#131316}.thinking.svelte-kpbn6d summary:where(.svelte-kpbn6d){display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;cursor:pointer;list-style:none;font-size:.75rem}.thinking.svelte-kpbn6d summary:where(.svelte-kpbn6d)::-webkit-details-marker{display:none}.thinking-label.svelte-kpbn6d{color:#a3a3a3}.thinking-toggle.svelte-kpbn6d{margin-left:auto;font-size:.6875rem;color:#737373}.thinking-body.svelte-kpbn6d{padding:0 .75rem .75rem;color:#a3a3a3;font-size:.8125rem;line-height:1.6;white-space:pre-wrap}.markdown.svelte-kpbn6d{font-size:.9375rem;line-height:1.7;color:#e5e5e5;overflow-wrap:break-word}.markdown.svelte-kpbn6d p{margin:0 0 .75rem}.markdown.svelte-kpbn6d p:last-child{margin-bottom:0}.markdown.svelte-kpbn6d code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.8125rem;background:#1a1a1d;padding:.125rem .375rem;border-radius:.375rem;border:1px solid #26262a}.markdown.svelte-kpbn6d .code-block{margin:.75rem 0;padding:.75rem;border-radius:.625rem;background:#0d0d0f;border:1px solid #26262a;overflow-x:auto;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.8125rem;line-height:1.6;white-space:pre}.typing.svelte-kpbn6d{display:flex;gap:.25rem;padding:.5rem 0}.typing.svelte-kpbn6d span:where(.svelte-kpbn6d){width:.375rem;height:.375rem;border-radius:50%;background:#52525b;animation:svelte-kpbn6d-blink 1.2s infinite}.typing.svelte-kpbn6d span:where(.svelte-kpbn6d):nth-child(2){animation-delay:.2s}.typing.svelte-kpbn6d span:where(.svelte-kpbn6d):nth-child(3){animation-delay:.4s}@keyframes svelte-kpbn6d-blink{0%,to{opacity:.25}50%{opacity:1}}.user.svelte-10oznxe{display:flex;justify-content:flex-end;max-width:46rem;margin:0 auto 1.5rem}.bubble.svelte-10oznxe{max-width:85%;padding:.625rem .9375rem;border-radius:1rem 1rem .25rem;background:#1f4f8a;color:#f5f9ff;font-size:.9375rem;line-height:1.6;overflow-wrap:break-word}.bubble.svelte-10oznxe code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.8125rem;background:#ffffff26;padding:.125rem .375rem;border-radius:.375rem}.chat.svelte-xdaci2{flex:1;overflow-y:auto;padding:1.5rem 1rem 2rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch}.empty.svelte-xdaci2{max-width:30rem;margin:12vh auto 0;text-align:center;color:#a3a3a3;padding:0 1rem}.empty-logo.svelte-xdaci2{font-size:2.5rem;margin-bottom:.75rem}.empty.svelte-xdaci2 h1:where(.svelte-xdaci2){font-size:1.375rem;margin:0 0 .5rem;color:#e5e5e5}.empty.svelte-xdaci2 p:where(.svelte-xdaci2){font-size:.875rem;line-height:1.6;margin:0}.sidebar.svelte-181dlmc{display:flex;flex-direction:column;height:100%}.head.svelte-181dlmc{display:flex;align-items:center;gap:.5rem;padding:.75rem;border-bottom:1px solid #1f1f22}.ws-name.svelte-181dlmc{font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:#737373;padding:0 .125rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.new.svelte-181dlmc{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:.5rem;font:inherit;font-size:.8125rem;font-weight:600;padding:.5rem;border-radius:.625rem;border:1px solid #2a2a2e;background:#161618;color:#e5e5e5;cursor:pointer}.new.svelte-181dlmc:hover{background:#1f1f22}.new.svelte-181dlmc:disabled{opacity:.5;cursor:default}.close.svelte-181dlmc{display:none;width:2.25rem;height:2.25rem;border:none;border-radius:.5rem;background:transparent;color:#a3a3a3;cursor:pointer}@media(max-width:767px){.close.svelte-181dlmc{display:inline-flex;align-items:center;justify-content:center}}.search.svelte-181dlmc{padding:.625rem .75rem .25rem}.list.svelte-181dlmc{flex:1;overflow-y:auto;padding:.375rem .5rem .75rem;display:flex;flex-direction:column}.empty.svelte-181dlmc{padding:1rem .5rem;font-size:.8125rem;color:#737373;text-align:center}.rename-row.svelte-181dlmc{padding:.375rem .75rem}.rename-row.svelte-181dlmc input:where(.svelte-181dlmc){width:100%;font:inherit;font-size:.8125rem;padding:.25rem .5rem;border-radius:.375rem;border:1px solid #3f3f46;background:#0d0d0f;color:#e5e5e5;outline:none}.composer.svelte-1n8df3y{flex-shrink:0;padding:.75rem 1rem calc(.75rem + env(safe-area-inset-bottom));background:linear-gradient(transparent,#0b0b0c 40%)}.box.svelte-1n8df3y{display:flex;align-items:flex-end;gap:.5rem;max-width:46rem;margin:0 auto;padding:.5rem;background:#161618;border:1px solid #2a2a2e;border-radius:1rem;box-shadow:0 4px 24px #0006}.box.svelte-1n8df3y:focus-within{border-color:#3f3f46}textarea.svelte-1n8df3y{flex:1;resize:none;border:none;outline:none;background:transparent;color:#e5e5e5;font:inherit;font-size:.9375rem;line-height:1.5;padding:.375rem .5rem;max-height:180px}textarea.svelte-1n8df3y::placeholder{color:#737373}.send.svelte-1n8df3y{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border:none;border-radius:.75rem;background:#2f6feb;color:#fff;cursor:pointer;flex-shrink:0}.send.svelte-1n8df3y:disabled{background:#26262a;color:#737373;cursor:default}.send.stop.svelte-1n8df3y{background:#b91c1c}.hint.svelte-1n8df3y{display:flex;align-items:center;gap:.5rem;max-width:46rem;margin:.5rem auto 0;padding:0 .25rem;font-size:.6875rem;color:#737373}.model-chip.svelte-1n8df3y{color:#a3a3a3;border:1px solid #26262a;border-radius:999px;padding:.125rem .5rem;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.shortcut.svelte-1n8df3y{margin-left:auto}section.svelte-1u3w06f{padding:.75rem 1.25rem 1rem;border-top:1px solid #1f1f22}section.svelte-1u3w06f h3:where(.svelte-1u3w06f){margin:0 0 .5rem;font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:#a3a3a3}.row.svelte-1u3w06f{display:flex;gap:.75rem;padding:.25rem 0;font-size:.8125rem}.label.svelte-1u3w06f{color:#737373;width:6rem;flex-shrink:0}.value.svelte-1u3w06f{color:#e5e5e5;overflow-wrap:anywhere}.mono.svelte-1u3w06f{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.75rem}.models.svelte-1u3w06f{display:flex;flex-wrap:wrap;gap:.375rem}.model.svelte-1u3w06f{font:inherit;font-size:.75rem;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;padding:.375rem .625rem;border-radius:.5rem;border:1px solid #2a2a2e;background:#161618;color:#d4d4d4;cursor:pointer}.model.active.svelte-1u3w06f{border-color:#2f6feb;background:#1d3a63;color:#fff}.hint.svelte-1u3w06f{font-size:.75rem;color:#737373;margin:.5rem 0 0}.switcher.svelte-1xx308a{min-width:0;flex:1}.trigger-name.svelte-1xx308a{font-weight:600;font-size:.9375rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.menu-footer.svelte-1xx308a{padding:.25rem .125rem 0}.open-ws.svelte-1xx308a{width:100%;text-align:left;font:inherit;font-size:.8125rem;padding:.5rem .625rem;border:none;border-radius:.5rem;background:transparent;color:inherit;cursor:pointer}.open-ws.svelte-1xx308a:hover{background:var(--ask-surface-hover, #f5f5f5)}.hint.svelte-1xx308a{margin:0 0 .75rem;font-size:.75rem;line-height:1.5;color:var(--ask-text-muted, #a3a3a3)}.path-input.svelte-1xx308a{width:100%;font:inherit;font-size:.875rem;padding:.5rem .75rem;border-radius:.5rem;border:1px solid var(--ask-border-strong, #d4d4d4);background:var(--ask-surface-muted, #fafafa);color:inherit;outline:none}.path-input.svelte-1xx308a:focus{border-color:var(--ask-focus, #a3a3a3)}.error.svelte-1xx308a{margin-top:.5rem;font-size:.75rem;color:var(--ask-danger, #dc2626)}.btn.svelte-1xx308a{font:inherit;font-size:.8125rem;font-weight:600;padding:.5rem .875rem;border-radius:.5rem;cursor:pointer}.cancel.svelte-1xx308a{border:1px solid var(--ask-border-strong, #d4d4d4);background:transparent;color:inherit}.go.svelte-1xx308a{border:1px solid var(--ask-accent, #c2410c);background:var(--ask-accent, #c2410c);color:var(--ask-accent-text, #fafafa)}.go.svelte-1xx308a:disabled{opacity:.5;cursor:default}*{box-sizing:border-box}html,body{margin:0;height:100%;background:var(--bg, #0b0b0c);color:var(--fg, #e5e5e5);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;-webkit-font-smoothing:antialiased}#app{height:100%}.app.svelte-1n46o8q{display:flex;flex-direction:column;height:100dvh}.topbar.svelte-1n46o8q{display:flex;align-items:center;gap:.75rem;padding:.625rem 1rem;padding-top:calc(.625rem + env(safe-area-inset-top));background:#111113;border-bottom:1px solid #1f1f22;flex-shrink:0;-webkit-user-select:none;user-select:none}.workspace.svelte-1n46o8q{display:flex;align-items:center;gap:.5rem;min-width:0;flex:1}.topbar-actions.svelte-1n46o8q{display:flex;align-items:center;gap:.25rem}.icon-btn.svelte-1n46o8q{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border:none;border-radius:.5rem;background:transparent;color:#d4d4d4;cursor:pointer}.icon-btn.svelte-1n46o8q:hover{background:#1f1f22}.icon-btn.stop.svelte-1n46o8q{color:#f87171}.body.svelte-1n46o8q{display:flex;flex:1;min-height:0}.sidebar-wrap.svelte-1n46o8q{width:min(85vw,19rem);flex-shrink:0;border-right:1px solid #1f1f22;background:#0e0e10;z-index:20}@media(max-width:767px){.sidebar-wrap.svelte-1n46o8q{position:fixed;inset:0 auto 0 0;height:100dvh;box-shadow:0 0 40px #00000080}}.main.svelte-1n46o8q{flex:1;display:flex;flex-direction:column;min-width:0;position:relative}.banner-error.svelte-1n46o8q{margin:.75rem 1rem 0;padding:.625rem .875rem;border-radius:.625rem;background:#3f0d0d;color:#fca5a5;font-size:.8125rem;border:1px solid #7f1d1d}
1
+ :root{color-scheme:dark;--bg: #0b0b0c;--fg: #e5e5e5;--surface: #131316;--surface-muted: #161618;--border: #26262a;--border-strong: #3f3f46;--text-muted: #a3a3a3;--text-faint: #737373;--accent: #2f6feb;--danger: #dc2626;--font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif}html,body{margin:0;height:100%;background:var(--bg);color:var(--fg);font-family:var(--font);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}::selection{background:#2f6feb59}*{scrollbar-width:thin;scrollbar-color:#3f3f46 transparent}*::-webkit-scrollbar{width:8px;height:8px}*::-webkit-scrollbar-thumb{background:#3f3f46;border-radius:4px}*::-webkit-scrollbar-track{background:transparent}.tool-stream.svelte-1l486hy{display:flex;flex-direction:column;gap:.75rem;margin-top:.75rem}.block.svelte-1l486hy{display:flex;flex-direction:column;gap:.5rem}.tool.svelte-1l486hy{border:1px solid #26262a;border-radius:.625rem;background:#131316;overflow:hidden}.tool-head.svelte-1l486hy{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;font-size:.8125rem}.tool-icon.svelte-1l486hy{font-size:.875rem}.tool-name.svelte-1l486hy{font-weight:600;color:#d4d4d4;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.75rem}.tool-status.svelte-1l486hy{margin-left:auto;font-size:.6875rem;text-transform:uppercase;letter-spacing:.04em}.tool-status.running.svelte-1l486hy{color:#fbbf24;animation:svelte-1l486hy-pulse 1.2s infinite}.tool-status.done.svelte-1l486hy{color:#4ade80}.tool-status.failed.svelte-1l486hy{color:#f87171}@keyframes svelte-1l486hy-pulse{0%,to{opacity:1}50%{opacity:.4}}.tool-args.svelte-1l486hy{margin:0;padding:.375rem .75rem;border-top:1px solid #1f1f22;background:#0d0d0f;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.6875rem;line-height:1.6;color:#a3a3a3;white-space:pre-wrap;word-break:break-word;max-height:8rem;overflow-y:auto}.approvals.svelte-1l486hy{gap:.5rem}.approve-all.svelte-1l486hy{align-self:flex-start;font:inherit;font-size:.75rem;font-weight:600;padding:.375rem .75rem;border-radius:.5rem;border:1px solid #ea580c;background:#ea580c;color:#fff;cursor:pointer}.assistant.svelte-kpbn6d{max-width:46rem;margin:0 auto 1.5rem}.thinking.svelte-kpbn6d{margin-bottom:.75rem;border:1px solid #26262a;border-radius:.625rem;background:#131316}.thinking.svelte-kpbn6d summary:where(.svelte-kpbn6d){display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;cursor:pointer;list-style:none;font-size:.75rem}.thinking.svelte-kpbn6d summary:where(.svelte-kpbn6d)::-webkit-details-marker{display:none}.thinking-label.svelte-kpbn6d{color:#a3a3a3}.thinking-toggle.svelte-kpbn6d{margin-left:auto;font-size:.6875rem;color:#737373}.thinking-body.svelte-kpbn6d{padding:0 .75rem .75rem;color:#a3a3a3;font-size:.8125rem;line-height:1.6;white-space:pre-wrap}.markdown.svelte-kpbn6d{font-size:.9375rem;line-height:1.7;color:#e5e5e5;overflow-wrap:break-word}.markdown.svelte-kpbn6d p{margin:0 0 .75rem}.markdown.svelte-kpbn6d p:last-child{margin-bottom:0}.markdown.svelte-kpbn6d code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.8125rem;background:#1a1a1d;padding:.125rem .375rem;border-radius:.375rem;border:1px solid #26262a}.markdown.svelte-kpbn6d .code-block{margin:.75rem 0;padding:.75rem;border-radius:.625rem;background:#0d0d0f;border:1px solid #26262a;overflow-x:auto;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.8125rem;line-height:1.6;white-space:pre}.typing.svelte-kpbn6d{display:flex;gap:.25rem;padding:.5rem 0}.typing.svelte-kpbn6d span:where(.svelte-kpbn6d){width:.375rem;height:.375rem;border-radius:50%;background:#52525b;animation:svelte-kpbn6d-blink 1.2s infinite}.typing.svelte-kpbn6d span:where(.svelte-kpbn6d):nth-child(2){animation-delay:.2s}.typing.svelte-kpbn6d span:where(.svelte-kpbn6d):nth-child(3){animation-delay:.4s}@keyframes svelte-kpbn6d-blink{0%,to{opacity:.25}50%{opacity:1}}.user.svelte-10oznxe{display:flex;justify-content:flex-end;max-width:46rem;margin:0 auto 1.5rem}.bubble.svelte-10oznxe{max-width:85%;padding:.625rem .9375rem;border-radius:1rem 1rem .25rem;background:#1f4f8a;color:#f5f9ff;font-size:.9375rem;line-height:1.6;overflow-wrap:break-word}.bubble.svelte-10oznxe code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.8125rem;background:#ffffff26;padding:.125rem .375rem;border-radius:.375rem}.chat.svelte-xdaci2{flex:1;overflow-y:auto;padding:1.5rem 1rem 2rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch}.empty.svelte-xdaci2{max-width:30rem;margin:12vh auto 0;text-align:center;color:#a3a3a3;padding:0 1rem}.empty-logo.svelte-xdaci2{font-size:2.5rem;margin-bottom:.75rem}.empty.svelte-xdaci2 h1:where(.svelte-xdaci2){font-size:1.375rem;margin:0 0 .5rem;color:#e5e5e5}.empty.svelte-xdaci2 p:where(.svelte-xdaci2){font-size:.875rem;line-height:1.6;margin:0}.sidebar.svelte-181dlmc{display:flex;flex-direction:column;height:100%}.head.svelte-181dlmc{display:flex;align-items:center;gap:.5rem;padding:.75rem;border-bottom:1px solid #1f1f22}.ws-name.svelte-181dlmc{font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:#737373;padding:0 .125rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.new.svelte-181dlmc{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:.5rem;font:inherit;font-size:.8125rem;font-weight:600;padding:.5rem;border-radius:.625rem;border:1px solid #2a2a2e;background:#161618;color:#e5e5e5;cursor:pointer}.new.svelte-181dlmc:hover{background:#1f1f22}.new.svelte-181dlmc:disabled{opacity:.5;cursor:default}.close.svelte-181dlmc{display:none;width:2.25rem;height:2.25rem;border:none;border-radius:.5rem;background:transparent;color:#a3a3a3;cursor:pointer}@media(max-width:767px){.close.svelte-181dlmc{display:inline-flex;align-items:center;justify-content:center}}.search.svelte-181dlmc{padding:.625rem .75rem .25rem}.list.svelte-181dlmc{flex:1;overflow-y:auto;padding:.375rem .5rem .75rem;display:flex;flex-direction:column}.empty.svelte-181dlmc{padding:1rem .5rem;font-size:.8125rem;color:#737373;text-align:center}.rename-row.svelte-181dlmc{padding:.375rem .75rem}.rename-row.svelte-181dlmc input:where(.svelte-181dlmc){width:100%;font:inherit;font-size:.8125rem;padding:.25rem .5rem;border-radius:.375rem;border:1px solid #3f3f46;background:#0d0d0f;color:#e5e5e5;outline:none}.composer.svelte-1n8df3y{flex-shrink:0;padding:.75rem 1rem calc(.75rem + env(safe-area-inset-bottom));background:linear-gradient(transparent,#0b0b0c 40%)}.box.svelte-1n8df3y{display:flex;align-items:flex-end;gap:.5rem;max-width:46rem;margin:0 auto;padding:.5rem;background:#161618;border:1px solid #2a2a2e;border-radius:1rem;box-shadow:0 4px 24px #0006}.box.svelte-1n8df3y:focus-within{border-color:#3f3f46}textarea.svelte-1n8df3y{flex:1;resize:none;border:none;outline:none;background:transparent;color:#e5e5e5;font:inherit;font-size:.9375rem;line-height:1.5;padding:.375rem .5rem;max-height:180px}textarea.svelte-1n8df3y::placeholder{color:#737373}.send.svelte-1n8df3y{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border:none;border-radius:.75rem;background:#2f6feb;color:#fff;cursor:pointer;flex-shrink:0}.send.svelte-1n8df3y:disabled{background:#26262a;color:#737373;cursor:default}.send.stop.svelte-1n8df3y{background:#b91c1c}.hint.svelte-1n8df3y{display:flex;align-items:center;gap:.5rem;max-width:46rem;margin:.5rem auto 0;padding:0 .25rem;font-size:.6875rem;color:#737373}.model-chip.svelte-1n8df3y,.agent-chip.svelte-1n8df3y{color:#a3a3a3;border:1px solid #26262a;border-radius:999px;padding:.125rem .5rem;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.agent-chip.svelte-1n8df3y .trigger{padding:0;border:none;font-family:inherit;font-size:inherit}.agent-chip.svelte-1n8df3y .trigger:hover{background:transparent}.shortcut.svelte-1n8df3y{margin-left:auto}section.svelte-1u3w06f{padding:.75rem 1.25rem 1rem;border-top:1px solid #1f1f22}section.svelte-1u3w06f h3:where(.svelte-1u3w06f){margin:0 0 .5rem;font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:#a3a3a3}.row.svelte-1u3w06f{display:flex;gap:.75rem;padding:.25rem 0;font-size:.8125rem}.label.svelte-1u3w06f{color:#737373;width:6rem;flex-shrink:0}.value.svelte-1u3w06f{color:#e5e5e5;overflow-wrap:anywhere}.mono.svelte-1u3w06f{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.75rem}.models.svelte-1u3w06f{display:flex;flex-wrap:wrap;gap:.375rem}.model.svelte-1u3w06f{font:inherit;font-size:.75rem;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;padding:.375rem .625rem;border-radius:.5rem;border:1px solid #2a2a2e;background:#161618;color:#d4d4d4;cursor:pointer}.model.active.svelte-1u3w06f{border-color:#2f6feb;background:#1d3a63;color:#fff}.hint.svelte-1u3w06f{font-size:.75rem;color:#737373;margin:.5rem 0 0}.switcher.svelte-1xx308a{min-width:0;flex:1}.trigger-name.svelte-1xx308a{font-weight:600;font-size:.9375rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.menu-footer.svelte-1xx308a{padding:.25rem .125rem 0}.open-ws.svelte-1xx308a{width:100%;text-align:left;font:inherit;font-size:.8125rem;padding:.5rem .625rem;border:none;border-radius:.5rem;background:transparent;color:inherit;cursor:pointer}.open-ws.svelte-1xx308a:hover{background:var(--ask-surface-hover, #f5f5f5)}.hint.svelte-1xx308a{margin:0 0 .75rem;font-size:.75rem;line-height:1.5;color:var(--ask-text-muted, #a3a3a3)}.path-input.svelte-1xx308a{width:100%;font:inherit;font-size:.875rem;padding:.5rem .75rem;border-radius:.5rem;border:1px solid var(--ask-border-strong, #d4d4d4);background:var(--ask-surface-muted, #fafafa);color:inherit;outline:none}.path-input.svelte-1xx308a:focus{border-color:var(--ask-focus, #a3a3a3)}.error.svelte-1xx308a{margin-top:.5rem;font-size:.75rem;color:var(--ask-danger, #dc2626)}.btn.svelte-1xx308a{font:inherit;font-size:.8125rem;font-weight:600;padding:.5rem .875rem;border-radius:.5rem;cursor:pointer}.cancel.svelte-1xx308a{border:1px solid var(--ask-border-strong, #d4d4d4);background:transparent;color:inherit}.go.svelte-1xx308a{border:1px solid var(--ask-accent, #c2410c);background:var(--ask-accent, #c2410c);color:var(--ask-accent-text, #fafafa)}.go.svelte-1xx308a:disabled{opacity:.5;cursor:default}*{box-sizing:border-box}html,body{margin:0;height:100%;background:var(--bg, #0b0b0c);color:var(--fg, #e5e5e5);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;-webkit-font-smoothing:antialiased}#app{height:100%}.app.svelte-1n46o8q{display:flex;flex-direction:column;height:100dvh}.topbar.svelte-1n46o8q{display:flex;align-items:center;gap:.75rem;padding:.625rem 1rem;padding-top:calc(.625rem + env(safe-area-inset-top));background:#111113;border-bottom:1px solid #1f1f22;flex-shrink:0;-webkit-user-select:none;user-select:none}.workspace.svelte-1n46o8q{display:flex;align-items:center;gap:.5rem;min-width:0;flex:1}.topbar-actions.svelte-1n46o8q{display:flex;align-items:center;gap:.25rem}.icon-btn.svelte-1n46o8q{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border:none;border-radius:.5rem;background:transparent;color:#d4d4d4;cursor:pointer}.icon-btn.svelte-1n46o8q:hover{background:#1f1f22}.icon-btn.stop.svelte-1n46o8q{color:#f87171}.body.svelte-1n46o8q{display:flex;flex:1;min-height:0}.sidebar-wrap.svelte-1n46o8q{width:min(85vw,19rem);flex-shrink:0;border-right:1px solid #1f1f22;background:#0e0e10;z-index:20}@media(max-width:767px){.sidebar-wrap.svelte-1n46o8q{position:fixed;inset:0 auto 0 0;height:100dvh;box-shadow:0 0 40px #00000080}}.main.svelte-1n46o8q{flex:1;display:flex;flex-direction:column;min-width:0;position:relative}.banner-error.svelte-1n46o8q{margin:.75rem 1rem 0;padding:.625rem .875rem;border-radius:.625rem;background:#3f0d0d;color:#fca5a5;font-size:.8125rem;border:1px solid #7f1d1d}