@runfusion/fusion 0.16.0 → 0.17.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.
Files changed (62) hide show
  1. package/README.md +3 -19
  2. package/dist/bin.js +3368 -1162
  3. package/dist/client/assets/{AgentDetailView-KQz9dg0n.js → AgentDetailView-BmxnuM0D.js} +3 -3
  4. package/dist/client/assets/AgentDetailView-yu8Xltqk.css +1 -0
  5. package/dist/client/assets/AgentsView-1xSqjJxs.js +517 -0
  6. package/dist/client/assets/AgentsView-Bs03ptrd.css +1 -0
  7. package/dist/client/assets/ChatView-CkWkEwXL.js +1 -0
  8. package/dist/client/assets/DevServerView-DIrmWI5T.js +1 -0
  9. package/dist/client/assets/{DirectoryPicker-CFj7FOgn.js → DirectoryPicker-Sqwdifcb.js} +1 -1
  10. package/dist/client/assets/DocumentsView-Cx_02o_z.js +1 -0
  11. package/dist/client/assets/InsightsView-DAJSq4gV.js +11 -0
  12. package/dist/client/assets/{MemoryView-DDbr1DaJ.js → MemoryView-CCIBAre3.js} +2 -2
  13. package/dist/client/assets/NodesView-D02HxGCl.js +14 -0
  14. package/dist/client/assets/{NodesView-BprfihLf.css → NodesView-DuAXX_0j.css} +1 -1
  15. package/dist/client/assets/{PiExtensionsManager-QgzWFBAT.js → PiExtensionsManager-DD0fTQNf.js} +3 -3
  16. package/dist/client/assets/{PluginManager-KHiz9oLY.js → PluginManager-Cfl0VBX9.js} +1 -1
  17. package/dist/client/assets/ResearchView-B9RqOVbr.js +1 -0
  18. package/dist/client/assets/ResearchView-BzCcDAS4.css +1 -0
  19. package/dist/client/assets/{RoadmapsView-BlbAZTdi.js → RoadmapsView-DsH7Hicx.js} +2 -2
  20. package/dist/client/assets/{SettingsModal-D5EUFR2z.js → SettingsModal-Cn_CIPXu.js} +1 -1
  21. package/dist/client/assets/{SettingsModal-D0QA2W5K.css → SettingsModal-Dq4a5KSX.css} +1 -1
  22. package/dist/client/assets/SettingsModal-YH_rM1ZT.js +31 -0
  23. package/dist/client/assets/{SetupWizardModal-tTXAm1Wb.js → SetupWizardModal-k5vqrHZU.js} +1 -1
  24. package/dist/client/assets/SkillsView-BIdt5cfB.js +1 -0
  25. package/dist/client/assets/{folder-open-DObdkm5J.js → folder-open-B3TO7t7Z.js} +1 -1
  26. package/dist/client/assets/index-BIJgrHEn.css +1 -0
  27. package/dist/client/assets/index-BlkXZ4C5.js +682 -0
  28. package/dist/client/assets/{star-BkGA2L-k.js → star-DW-M-BD_.js} +1 -1
  29. package/dist/client/assets/{upload-B0NF4J5P.js → upload-BzG6fknr.js} +1 -1
  30. package/dist/client/assets/{users-DgomiHTd.js → users-DEicv0kj.js} +1 -1
  31. package/dist/client/index.html +2 -2
  32. package/dist/client/version.json +1 -1
  33. package/dist/extension.js +2252 -718
  34. package/dist/pi-claude-cli/package.json +1 -1
  35. package/dist/pi-claude-cli/src/__tests__/process-manager.test.ts +11 -0
  36. package/dist/pi-claude-cli/src/__tests__/provider.test.ts +25 -0
  37. package/dist/plugins/fusion-plugin-dependency-graph/package.json +7 -5
  38. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraphView.css +31 -0
  39. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraphView.tsx +156 -48
  40. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraphView.test.tsx +261 -0
  41. package/package.json +1 -1
  42. package/skill/fusion/SKILL.md +5 -5
  43. package/skill/fusion/references/engine-tools.md +2 -2
  44. package/skill/fusion/references/extension-tools.md +3 -3
  45. package/skill/fusion/references/fusion-capabilities.md +1 -1
  46. package/skill/fusion/references/skill-patterns.md +1 -1
  47. package/skill/fusion/workflows/dashboard-cli.md +3 -3
  48. package/skill/fusion/workflows/task-management.md +1 -1
  49. package/dist/client/assets/AgentDetailView-BoEpPOjM.css +0 -1
  50. package/dist/client/assets/AgentsView-8Xo-c04o.js +0 -517
  51. package/dist/client/assets/AgentsView-V5GhlBYu.css +0 -1
  52. package/dist/client/assets/ChatView-CjgOh8x7.js +0 -1
  53. package/dist/client/assets/DevServerView-BOPrzi-j.js +0 -1
  54. package/dist/client/assets/DocumentsView-CcJNmH06.js +0 -1
  55. package/dist/client/assets/InsightsView-B0DKRIYV.js +0 -11
  56. package/dist/client/assets/NodesView-BqtHfXsl.js +0 -14
  57. package/dist/client/assets/ResearchView-CVxPC1vz.css +0 -1
  58. package/dist/client/assets/ResearchView-s3SrjNBm.js +0 -1
  59. package/dist/client/assets/SettingsModal-c9MG4sxl.js +0 -31
  60. package/dist/client/assets/SkillsView-CS4ONN3D.js +0 -1
  61. package/dist/client/assets/index-BRaIPmpp.js +0 -682
  62. package/dist/client/assets/index-DeED_ky2.css +0 -1
@@ -0,0 +1,261 @@
1
+ import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
2
+ import { render, fireEvent, screen, act, cleanup } from "@testing-library/react";
3
+ import * as React from "react";
4
+ import { DependencyGraphView } from "../DependencyGraphView";
5
+ import type { DependencyGraphHostContext, PluginDashboardViewComponentProps } from "../DependencyGraphView";
6
+ import type { Task } from "@fusion/core";
7
+
8
+ // Mock storage to avoid localStorage dependency
9
+ vi.mock("../storage", () => ({
10
+ loadPositions: () => ({}),
11
+ savePositions: () => {},
12
+ }));
13
+
14
+ // Helper to create a minimal Task
15
+ function createTask(overrides: Partial<Task> & { id: string; column: Task["column"] }): Task {
16
+ return {
17
+ description: overrides.description ?? `Task ${overrides.id}`,
18
+ column: overrides.column,
19
+ dependencies: overrides.dependencies ?? [],
20
+ steps: overrides.steps ?? [],
21
+ currentStep: overrides.currentStep ?? 0,
22
+ log: overrides.log ?? [],
23
+ ...overrides,
24
+ } as Task;
25
+ }
26
+
27
+ function createMockContext(tasks: Task[] = []): DependencyGraphHostContext {
28
+ return {
29
+ projectId: "test-project",
30
+ tasks,
31
+ openTaskDetail: vi.fn(),
32
+ renderTaskCard: (task: Task) => React.createElement("div", { "data-testid": "task-card" }, task.id),
33
+ };
34
+ }
35
+
36
+ function renderView(context?: DependencyGraphHostContext) {
37
+ const props: PluginDashboardViewComponentProps = {
38
+ context: context ?? createMockContext(),
39
+ };
40
+ return render(React.createElement(DependencyGraphView, props));
41
+ }
42
+
43
+ describe("DependencyGraphView", () => {
44
+ beforeEach(() => {
45
+ // Mock getComputedStyle for rem calculations
46
+ vi.spyOn(window, "getComputedStyle").mockImplementation((() => {
47
+ return { fontSize: "16px" } as CSSStyleDeclaration;
48
+ }) as typeof window.getComputedStyle);
49
+
50
+ // Mock matchMedia to default to desktop
51
+ window.matchMedia = vi.fn().mockImplementation((query: string) => ({
52
+ matches: false,
53
+ media: query,
54
+ onchange: null,
55
+ addListener: vi.fn(),
56
+ removeListener: vi.fn(),
57
+ addEventListener: vi.fn(),
58
+ removeEventListener: vi.fn(),
59
+ dispatchEvent: vi.fn(),
60
+ }));
61
+ });
62
+
63
+ afterEach(() => {
64
+ cleanup();
65
+ vi.restoreAllMocks();
66
+ });
67
+
68
+ it("renders empty state when no active-column tasks provided", () => {
69
+ const { container } = renderView(createMockContext([]));
70
+ const empty = container.querySelector(".dependency-graph-empty");
71
+ expect(empty).toBeTruthy();
72
+ expect(empty?.textContent).toContain("No tasks to display");
73
+ });
74
+
75
+ it("renders nodes for active-column tasks", () => {
76
+ const tasks = [
77
+ createTask({ id: "FN-001", column: "todo" }),
78
+ createTask({ id: "FN-002", column: "in-progress" }),
79
+ ];
80
+ const { container } = renderView(createMockContext(tasks));
81
+ const nodes = container.querySelectorAll(".dependency-graph-node");
82
+ expect(nodes.length).toBe(2);
83
+ });
84
+
85
+ it("filters out tasks not in active columns", () => {
86
+ const tasks = [
87
+ createTask({ id: "FN-001", column: "todo" }),
88
+ createTask({ id: "FN-002", column: "done" }),
89
+ createTask({ id: "FN-003", column: "archived" }),
90
+ ];
91
+ const { container } = renderView(createMockContext(tasks));
92
+ const nodes = container.querySelectorAll(".dependency-graph-node");
93
+ expect(nodes.length).toBe(1);
94
+ });
95
+
96
+ it("renders edges for tasks with dependencies in the active set", () => {
97
+ const tasks = [
98
+ createTask({ id: "FN-001", column: "todo" }),
99
+ createTask({ id: "FN-002", column: "todo", dependencies: ["FN-001"] }),
100
+ ];
101
+ const { container } = renderView(createMockContext(tasks));
102
+ const edges = container.querySelectorAll(".dependency-graph-edge");
103
+ expect(edges.length).toBe(1);
104
+ });
105
+
106
+ it("does not render edges for dependencies not in the active set", () => {
107
+ const tasks = [
108
+ createTask({ id: "FN-002", column: "todo", dependencies: ["FN-999"] }),
109
+ ];
110
+ const { container } = renderView(createMockContext(tasks));
111
+ const edges = container.querySelectorAll(".dependency-graph-edge");
112
+ expect(edges.length).toBe(0);
113
+ });
114
+
115
+ it("zoom-in button increases scale", () => {
116
+ const tasks = [createTask({ id: "FN-001", column: "todo" })];
117
+ const { container, unmount } = renderView(createMockContext(tasks));
118
+ const zoomInBtn = Array.from(container.querySelectorAll("button")).find((b) => b.textContent === "Zoom In")!;
119
+ fireEvent.click(zoomInBtn);
120
+ const scene = container.querySelector(".dependency-graph-scene") as HTMLElement;
121
+ expect(scene).toBeTruthy();
122
+ const transform = scene.style.transform;
123
+ expect(transform).toMatch(/scale\([1-9]/);
124
+ });
125
+
126
+ it("zoom-out button decreases scale", () => {
127
+ const tasks = [createTask({ id: "FN-001", column: "todo" })];
128
+ const { container, unmount } = renderView(createMockContext(tasks));
129
+ const zoomOutBtn = Array.from(container.querySelectorAll("button")).find((b) => b.textContent === "Zoom Out")!;
130
+ fireEvent.click(zoomOutBtn);
131
+ const scene = container.querySelector(".dependency-graph-scene") as HTMLElement;
132
+ expect(scene).toBeTruthy();
133
+ const transform = scene.style.transform;
134
+ expect(transform).toMatch(/scale\(0\./);
135
+ });
136
+
137
+ it("fit-to-graph button produces a valid scale", () => {
138
+ const tasks = [createTask({ id: "FN-001", column: "todo" })];
139
+ const { container, unmount } = renderView(createMockContext(tasks));
140
+
141
+ // Mock canvas dimensions for fitToGraph
142
+ const canvas = container.querySelector(".dependency-graph-canvas") as HTMLElement;
143
+ if (canvas) {
144
+ Object.defineProperty(canvas, "clientWidth", { value: 800, configurable: true });
145
+ Object.defineProperty(canvas, "clientHeight", { value: 600, configurable: true });
146
+ }
147
+
148
+ const fitBtn = Array.from(container.querySelectorAll("button")).find((b) => b.textContent === "Fit")!;
149
+ fireEvent.click(fitBtn);
150
+
151
+ const scene = container.querySelector(".dependency-graph-scene") as HTMLElement;
152
+ expect(scene).toBeTruthy();
153
+ const transform = scene.style.transform;
154
+ const scaleMatch = transform.match(/scale\(([\d.]+)\)/);
155
+ expect(scaleMatch).toBeTruthy();
156
+ const scaleValue = parseFloat(scaleMatch![1]);
157
+ expect(scaleValue).toBeGreaterThanOrEqual(0.4);
158
+ expect(scaleValue).toBeLessThanOrEqual(2);
159
+ });
160
+
161
+ it("wheel event zooms the graph", () => {
162
+ const tasks = [createTask({ id: "FN-001", column: "todo" })];
163
+ const { container } = renderView(createMockContext(tasks));
164
+ const canvas = container.querySelector(".dependency-graph-canvas") as HTMLElement;
165
+
166
+ expect(canvas).toBeTruthy();
167
+
168
+ // Mock getBoundingClientRect on the canvas
169
+ canvas.getBoundingClientRect = vi.fn().mockReturnValue({
170
+ left: 0, top: 0, right: 800, bottom: 600, width: 800, height: 600, x: 0, y: 0,
171
+ });
172
+
173
+ const initialScene = container.querySelector(".dependency-graph-scene") as HTMLElement;
174
+ const initialTransform = initialScene.style.transform;
175
+
176
+ // Negative deltaY = zoom in
177
+ fireEvent.wheel(canvas, { deltaY: -100, clientX: 400, clientY: 300 });
178
+
179
+ const updatedScene = container.querySelector(".dependency-graph-scene") as HTMLElement;
180
+ const updatedTransform = updatedScene.style.transform;
181
+
182
+ expect(updatedTransform).not.toBe(initialTransform);
183
+ const scaleMatch = updatedTransform.match(/scale\(([\d.]+)\)/);
184
+ expect(scaleMatch).toBeTruthy();
185
+ expect(parseFloat(scaleMatch![1])).toBeGreaterThan(1);
186
+ });
187
+
188
+ it("pinch gesture changes scale", () => {
189
+ const tasks = [createTask({ id: "FN-001", column: "todo" })];
190
+ const { container } = renderView(createMockContext(tasks));
191
+ const canvas = container.querySelector(".dependency-graph-canvas") as HTMLElement;
192
+
193
+ expect(canvas).toBeTruthy();
194
+
195
+ // First pointer down (finger 1)
196
+ fireEvent.pointerDown(canvas, {
197
+ pointerId: 1,
198
+ pointerType: "touch",
199
+ button: 0,
200
+ clientX: 200,
201
+ clientY: 300,
202
+ });
203
+
204
+ // Second pointer down (finger 2) — starts pinch
205
+ fireEvent.pointerDown(canvas, {
206
+ pointerId: 2,
207
+ pointerType: "touch",
208
+ button: 0,
209
+ clientX: 600,
210
+ clientY: 300,
211
+ });
212
+
213
+ // Move fingers apart (increasing distance)
214
+ fireEvent.pointerMove(canvas, {
215
+ pointerId: 1,
216
+ pointerType: "touch",
217
+ clientX: 100,
218
+ clientY: 300,
219
+ });
220
+
221
+ fireEvent.pointerMove(canvas, {
222
+ pointerId: 2,
223
+ pointerType: "touch",
224
+ clientX: 700,
225
+ clientY: 300,
226
+ });
227
+
228
+ const scene = container.querySelector(".dependency-graph-scene") as HTMLElement;
229
+ const transform = scene.style.transform;
230
+ const scaleMatch = transform.match(/scale\(([\d.]+)\)/);
231
+ expect(scaleMatch).toBeTruthy();
232
+ expect(parseFloat(scaleMatch![1])).toBeGreaterThan(1);
233
+ });
234
+
235
+ it("scale is clamped between MIN_SCALE and MAX_SCALE", () => {
236
+ const tasks = [createTask({ id: "FN-001", column: "todo" })];
237
+ const { container, unmount } = renderView(createMockContext(tasks));
238
+
239
+ // Try to zoom in beyond MAX_SCALE (2.0)
240
+ const zoomInBtn = Array.from(container.querySelectorAll("button")).find((b) => b.textContent === "Zoom In")!;
241
+ for (let i = 0; i < 50; i++) {
242
+ fireEvent.click(zoomInBtn);
243
+ }
244
+
245
+ const scene = container.querySelector(".dependency-graph-scene") as HTMLElement;
246
+ let scaleMatch = scene.style.transform.match(/scale\(([\d.]+)\)/);
247
+ expect(scaleMatch).toBeTruthy();
248
+ expect(parseFloat(scaleMatch![1])).toBeLessThanOrEqual(2);
249
+
250
+ // Try to zoom out beyond MIN_SCALE (0.4)
251
+ const zoomOutBtn = Array.from(container.querySelectorAll("button")).find((b) => b.textContent === "Zoom Out")!;
252
+ for (let i = 0; i < 100; i++) {
253
+ fireEvent.click(zoomOutBtn);
254
+ }
255
+
256
+ const updatedScene = container.querySelector(".dependency-graph-scene") as HTMLElement;
257
+ scaleMatch = updatedScene.style.transform.match(/scale\(([\d.]+)\)/);
258
+ expect(scaleMatch).toBeTruthy();
259
+ expect(parseFloat(scaleMatch![1])).toBeGreaterThanOrEqual(0.4);
260
+ });
261
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runfusion/fusion",
3
- "version": "0.16.0",
3
+ "version": "0.17.1",
4
4
  "license": "MIT",
5
5
  "description": "Fusion CLI: HTTP API server, daemon, dashboard launcher, and task tooling for the Fusion AI coding agent.",
6
6
  "homepage": "https://github.com/Runfusion/Fusion#readme",
@@ -19,11 +19,11 @@ Fusion is an AI-orchestrated task board. You throw in rough ideas; AI specifies,
19
19
  **Missions** provide hierarchical planning above tasks:
20
20
  Mission → Milestone → Slice → Feature → Task
21
21
 
22
- **Available tools:** Fusion registers tools via the pi extension (prefixed `fn_*`). No CLI commands or Bash needed — use the registered tools directly.
22
+ **Available tools:** Fusion registers tools (prefixed `fn_*`). No CLI commands or Bash needed — use the registered tools directly.
23
23
 
24
- **Naming boundary:** The published pi-extension skill surface uses `fn_*` tool names (for example `fn_task_create`, `fn_mission_create`). Engine runtime sessions also inject additional `fn_*` tools (for example `fn_review_spec`, `fn_review_step`, `fn_spawn_agent`) that are not user-invokable extension tools.
24
+ **Naming boundary:** The published skill surface uses `fn_*` tool names (for example `fn_task_create`, `fn_mission_create`). Engine runtime sessions also inject additional `fn_*` tools (for example `fn_review_spec`, `fn_review_step`, `fn_spawn_agent`) that are not part of the published skill surface.
25
25
 
26
- **Engine runtime tools:** Triage/executor/merger/heartbeat sessions include auto-injected engine tools that do not come from the pi extension registration list. See `references/engine-tools.md` for the canonical runtime-only catalog and usage boundaries.
26
+ **Engine runtime tools:** Triage/executor/merger/heartbeat sessions include auto-injected engine tools that are not part of the published skill surface. See `references/engine-tools.md` for the canonical runtime-only catalog and usage boundaries.
27
27
 
28
28
  **Tool categories:**
29
29
  <!-- BEGIN: tool-categories (auto-generated by scripts/sync-fusion-skill-tools.mjs — do not edit by hand) -->
@@ -85,7 +85,7 @@ Use `fn_mission_create` for high-level objectives, then add milestones, slices,
85
85
 
86
86
  <known_limitations>
87
87
 
88
- These operations are **not available** via pi extension tools and require the dashboard or CLI:
88
+ These operations are **not available** via extension tools and require the dashboard or CLI:
89
89
 
90
90
  - **Moving tasks between columns** — No tool for column moves (handled by the AI engine)
91
91
  - **Workflow steps** — Creating/managing workflow step definitions requires the dashboard
@@ -103,7 +103,7 @@ For these operations, guide the user to the dashboard (`/fn`) or CLI commands do
103
103
  |-----------|-------------|
104
104
  | references/cli-commands.md | Full CLI command reference |
105
105
  | references/task-structure.md | Task file structure and storage |
106
- | references/extension-tools.md | All pi extension tools with parameters |
106
+ | references/extension-tools.md | All extension tools with parameters |
107
107
  | references/best-practices.md | Tips for effective Fusion usage |
108
108
  | references/fusion-capabilities.md | Complete feature catalog |
109
109
  | references/engine-tools.md | Engine session-scoped runtime tools (not extension-invokable) |
@@ -1,10 +1,10 @@
1
1
  # Engine Session-Scoped Tools
2
2
 
3
- These tools are **not** part of the pi extension's user-invokable `extension.ts` surface. They are injected by the engine at runtime for specific agent session types.
3
+ These tools are **not** part of the user-invokable extension surface. They are injected by the engine at runtime for specific agent session types.
4
4
 
5
5
  - Source files: `packages/engine/src/agent-tools.ts`, `triage.ts`, `executor.ts`, `merger.ts`, `agent-heartbeat.ts`
6
6
  - Availability: only when the engine creates a session for the matching agent role
7
- - Important: do not tell users to call these directly from the generic pi extension tool list
7
+ - Important: do not tell users to call these directly from the generic extension tool list
8
8
 
9
9
  ## Shared runtime tools (`agent-tools.ts`)
10
10
 
@@ -1,6 +1,6 @@
1
- # Fusion Pi Extension Tools
1
+ # Fusion Extension Tools
2
2
 
3
- All tools are registered via the pi extension. They are available in any pi agent session when the Fusion extension is installed.
3
+ All tools are registered via the Fusion extension. They are available in any agent session when Fusion is configured.
4
4
 
5
5
  > Naming contract: all externally exposed Fusion extension tools are `fn_*` (for example `fn_task_create`). Engine runtime sessions also inject additional `fn_*` tools (for example `fn_review_step`, `fn_spawn_agent`, `fn_task_document_write`) that are separate from this extension surface and documented in `engine-tools.md`.
6
6
 
@@ -364,7 +364,7 @@ Cancel a research run.
364
364
 
365
365
  ### /fn
366
366
 
367
- Start or stop the Fusion dashboard from within a pi session.
367
+ Start or stop the Fusion dashboard from within an agent session.
368
368
 
369
369
  | Command | Description |
370
370
  |---------|-------------|
@@ -5,7 +5,7 @@
5
5
  Fusion is an AI-orchestrated task board. Tasks flow through columns:
6
6
  Triage → Todo → In Progress → In Review → Done → Archived
7
7
 
8
- ## Pi Extension Tools (Available to Agents)
8
+ ## Extension Tools (Available to Agents)
9
9
 
10
10
  All skill/extension tool invocations in this catalog use the public `fn_*` namespace. Engine runtime sessions also have additional runtime-only `fn_*` tools that are intentionally not listed here (see `references/engine-tools.md`).
11
11
 
@@ -30,7 +30,7 @@
30
30
  ## Key Takeaways for Fusion Skill
31
31
 
32
32
  1. **Use router pattern** — Fusion has multiple distinct workflows (task management, lifecycle, specs, dashboard/CLI)
33
- 2. **No `allowed-tools` needed** — Fusion tools are registered via pi extension, not Bash CLI
33
+ 2. **No `allowed-tools` needed** — Fusion tools are registered via the extension, not Bash CLI
34
34
  3. **Inline essential concepts** — Task columns, workflow overview in SKILL.md
35
35
  4. **Progressive disclosure** — SKILL.md routes to workflows, workflows reference detailed docs
36
36
  5. **Pure XML structure** — No markdown headings (#, ##, ###) in body
@@ -3,14 +3,14 @@
3
3
  </required_reading>
4
4
 
5
5
  <objective>
6
- Guide the agent through using the Fusion dashboard and CLI for operations not available via pi extension tools.
6
+ Guide the agent through using the Fusion dashboard and CLI for operations not available via extension tools.
7
7
  </objective>
8
8
 
9
9
  <process>
10
10
 
11
11
  **Starting the dashboard:**
12
12
 
13
- Use the `/fn` command (registered by the pi extension):
13
+ Use the `/fn` command (registered by the Fusion extension):
14
14
  - `/fn` or `/fn 4040` — Start dashboard + AI engine on specified port (default 4040)
15
15
  - `/fn stop` — Stop the dashboard
16
16
  - `/fn status` — Check if dashboard is running
@@ -28,7 +28,7 @@ The dashboard provides:
28
28
 
29
29
  **Operations that require CLI or dashboard:**
30
30
 
31
- These cannot be done with pi extension tools:
31
+ These cannot be done with extension tools:
32
32
 
33
33
  | Operation | CLI Command | Dashboard |
34
34
  |-----------|-------------|-----------|
@@ -4,7 +4,7 @@
4
4
  </required_reading>
5
5
 
6
6
  <objective>
7
- Guide the agent through creating, viewing, and managing tasks on the Fusion board using pi extension tools.
7
+ Guide the agent through creating, viewing, and managing tasks on the Fusion board using extension tools.
8
8
 
9
9
  Use only the public `fn_*` extension tools in this workflow. Do not substitute internal engine runtime tools like `task_create`, `task_update`, `task_log`, or `task_done`.
10
10
  </objective>
@@ -1 +0,0 @@
1
- .agent-detail-overlay{position:fixed;inset:0;background:color-mix(in srgb,var(--bg) 60%,transparent);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:100;padding:var(--space-lg)}.agent-detail-modal{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-lg);width:100%;min-width:calc(var(--space-xl) * 20);max-width:calc(100vw - var(--space-2xl) - var(--space-xs) * 2);min-height:calc(var(--space-xl) * 13 + var(--space-sm));max-height:calc(100dvh - var(--space-2xl) - var(--space-xs) * 2);display:flex;flex-direction:column;overflow:hidden;resize:both;box-shadow:var(--shadow-lg)}.agent-detail-modal:not([style*=width]){width:min(calc(var(--space-xl) * 37 + var(--space-md)),calc(100vw - var(--space-2xl) - var(--space-xs) * 2))}.agent-detail-modal:not([style*=height]){height:min(85vh,calc(100dvh - var(--space-2xl) - var(--space-xs) * 2))}.agent-detail-inline-shell{width:100%;height:100%;min-height:0;display:flex;flex-direction:column;overflow:hidden}.agent-detail-inline{width:100%;height:100%;min-height:0;display:flex;flex-direction:column;overflow:hidden;background:var(--surface);border:1px solid var(--border)}.agent-detail-inline-loading{width:100%;height:100%;min-height:0;display:flex;align-items:center;justify-content:center;overflow:hidden}.agent-detail-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-md);padding:calc(var(--space-xl) * 2 + var(--space-md));color:var(--text-muted)}.agent-detail-header{display:flex;align-items:center;justify-content:space-between;gap:var(--space-md);padding:var(--space-md) calc(var(--space-lg) + var(--space-xs));border-bottom:1px solid var(--border);background:var(--bg-secondary)}.agent-detail-identity{display:flex;align-items:center;gap:var(--space-md);flex-shrink:0;min-width:0}.agent-detail-icon{width:calc(var(--space-lg) * 2 + var(--space-xs));height:calc(var(--space-lg) * 2 + var(--space-xs));border-radius:var(--radius-md);background:var(--todo);display:flex;align-items:center;justify-content:center;color:var(--text);flex-shrink:0}.agent-detail-info{min-width:0}.agent-detail-info h2{font-size:calc(var(--space-md) + var(--space-xs));font-weight:600;margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.agent-detail-badges{display:flex;gap:var(--space-xs);margin-top:calc(var(--space-xs) * .5)}.agent-detail-controls{display:flex;align-items:center;gap:calc(var(--space-xs) + var(--space-sm) * .25);flex-shrink:0}.btn--compact{padding:calc(var(--space-xs) + var(--space-xs) * .25) calc(var(--space-sm) + var(--space-xs) * .5);font-size:var(--space-md);gap:var(--space-xs)}.agent-detail-utility-actions{display:flex;align-items:center;gap:var(--space-xs);flex-shrink:0}.agent-detail-title{display:flex;align-items:center;gap:var(--space-lg)}.agent-detail-actions{display:flex;align-items:center;gap:var(--space-sm)}.agent-detail-tabs{display:flex;gap:var(--space-xs);padding:0 calc(var(--space-lg) + var(--space-xs));border-bottom:1px solid var(--border);background:var(--bg-secondary)}.agent-detail-tab{display:flex;align-items:center;gap:var(--space-xs);padding:calc(var(--space-sm) + var(--space-xs) * .5) var(--space-md);background:none;border:none;border-bottom:calc(var(--space-xs) * .5) solid transparent;color:var(--text-muted);font-size:calc(var(--space-sm) + var(--space-xs) + var(--space-xs) * .25);cursor:pointer;transition:all var(--transition-fast)}.agent-detail-tab:hover{color:var(--text);background:var(--card-hover)}.agent-detail-tab.active{color:var(--todo);border-bottom-color:var(--todo)}.agent-detail-tab:focus-visible{outline:none;box-shadow:var(--focus-ring-strong);background:color-mix(in srgb,var(--todo) 12%,transparent);color:var(--text);border-radius:var(--radius-sm)}.agent-detail-content{flex:1;overflow-y:auto;padding:var(--space-xl)}.agent-detail-footer{display:flex;align-items:center;gap:var(--space-sm);padding:var(--space-md) var(--space-xl);border-top:1px solid var(--border);background:var(--bg-secondary);font-size:var(--space-md);color:var(--text-muted)}.agent-detail-id{font-family:var(--font-mono);cursor:pointer}.agent-detail-id:hover{color:var(--text)}.dashboard-tab{display:flex;flex-direction:column;gap:var(--space-xl)}.dashboard-summary-layout{padding-bottom:var(--space-md)}.dashboard-summary-card{background:var(--card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:var(--space-lg);display:flex;flex-direction:column;gap:var(--space-md)}.budget-warning-banner{display:flex;gap:var(--space-sm);align-items:flex-start;border:1px solid var(--color-warning);background:color-mix(in srgb,var(--color-warning) 12%,transparent);border-radius:var(--radius-md);padding:var(--space-md)}.dashboard-summary-hero__heading{display:flex;align-items:center;gap:var(--space-sm)}.dashboard-summary-hero__heading h3{margin:0;font-size:calc(var(--space-lg) + var(--space-xs) * .5);font-weight:600}.dashboard-summary-hero__meta{display:flex;flex-wrap:wrap;gap:var(--space-md);color:var(--text-muted)}.dashboard-summary-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(calc(var(--space-xl) * 6 + var(--space-sm)),1fr));gap:var(--space-md)}.dashboard-summary-grid p{margin:0}.dashboard-summary-label{font-size:calc(var(--space-sm) + var(--space-xs) * .5);color:var(--text-muted)}.dashboard-summary-health-row{display:inline-flex;align-items:center;gap:var(--space-xs)}.runs-list{display:flex;flex-direction:column;gap:var(--space-sm)}.run-item{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--space-sm)}.dashboard-section{background:var(--bg-secondary);border-radius:var(--radius-md);padding:calc(var(--space-lg) + var(--space-xs))}.dashboard-section h3{font-size:calc(var(--space-md) + var(--space-xs) * .5);font-weight:600;margin:0 0 var(--space-lg) 0;color:var(--text-muted);text-transform:uppercase;letter-spacing:calc(var(--space-xs) * .125)}.info-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(calc(var(--space-xl) * 7 + var(--space-sm)),1fr));gap:var(--space-lg)}.info-item{display:flex;flex-direction:column;gap:var(--space-xs)}.info-label{font-size:var(--space-md);color:var(--text-muted)}.info-value{font-size:calc(var(--space-md) + var(--space-xs) * .5);font-weight:500}.inline-badge{display:inline-block;padding:calc(var(--space-xs) * .5) var(--space-sm);border-radius:var(--radius-sm);font-size:var(--space-md);text-transform:capitalize}.stats-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--space-lg)}.stat-card{background:var(--surface);border-radius:var(--radius-md);padding:var(--space-lg);text-align:center}.stat-value{font-size:calc(var(--space-lg) + var(--space-xs) * .5);font-weight:700;color:var(--todo)}.stat-label{font-size:calc(var(--space-sm) + var(--space-xs) * .5);color:var(--text-muted);margin-top:var(--space-xs)}.current-task{display:flex;align-items:center;gap:var(--space-md)}.task-badge{font-family:var(--font-mono);background:var(--surface);padding:var(--space-sm) var(--space-md);border-radius:var(--radius-sm);font-size:calc(var(--space-md) + var(--space-xs) * .25)}.metadata-json{background:var(--surface);padding:var(--space-md);border-radius:var(--radius-sm);font-size:var(--space-md);overflow-x:auto;margin:0}.logs-tab{display:flex;flex-direction:column;height:100%}.logs-header{display:flex;align-items:center;justify-content:space-between;padding-bottom:var(--space-md);margin-bottom:var(--space-md);border-bottom:1px solid var(--border)}.logs-count{font-size:var(--space-md);color:var(--text-muted)}.streaming-indicator{display:flex;align-items:center;gap:calc(var(--space-xs) + var(--space-sm) * .25);font-size:var(--space-md);color:var(--color-success)}.streaming-dot{width:var(--space-sm);height:var(--space-sm);background:var(--color-success);border-radius:50%;animation:pulse 1.5s infinite}.logs-container{flex:1;overflow-y:auto;font-family:var(--font-mono);font-size:calc(var(--space-md) + var(--space-xs) * .25);line-height:1.6;max-height:calc(var(--space-2xl) * 12 + var(--space-lg))}.logs-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:calc(var(--space-2xl) + var(--space-lg));color:var(--text-muted);text-align:center}.logs-empty p{margin:var(--space-sm) 0 0 0}.log-entry{display:flex;gap:var(--space-sm);padding:var(--space-xs) var(--space-sm);margin:calc(var(--space-xs) * .5) 0;border-radius:var(--radius-sm)}.log-timestamp{color:var(--text-muted);font-size:calc(var(--space-sm) + var(--space-xs) * .75);flex-shrink:0}.log-agent{color:var(--text-muted);font-size:calc(var(--space-sm) + var(--space-xs) * .75);font-weight:600;text-transform:uppercase;flex-shrink:0}.log-icon{flex-shrink:0}.log-text{word-break:break-word}.log-detail{color:var(--text-muted);font-size:var(--space-md)}.runs-tab{display:flex;flex-direction:column;gap:var(--space-md)}.runs-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:calc(var(--space-2xl) + var(--space-lg));color:var(--text-muted);text-align:center}.runs-empty p{margin:var(--space-sm) 0 0 0}.run-card{background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius-md);padding:var(--space-lg)}.run-card--active{border-color:var(--in-progress);background:color-mix(in srgb,var(--in-progress) 5%,transparent)}.run-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-sm)}.run-live-indicator{display:flex;align-items:center;gap:calc(var(--space-xs) + var(--space-sm) * .25);font-weight:600;color:var(--in-progress)}.live-dot{width:var(--space-sm);height:var(--space-sm);background:var(--in-progress);border-radius:50%;animation:pulse 1.5s infinite}.run-id{font-family:var(--font-mono);font-size:calc(var(--space-md) + var(--space-xs) * .25);color:var(--text-muted)}.run-status{display:flex;align-items:center;gap:calc(var(--space-xs) + var(--space-sm) * .25);font-size:calc(var(--space-md) + var(--space-xs) * .25);text-transform:capitalize}.run-status.active{color:var(--in-progress)}.run-status.completed{color:var(--color-success)}.run-status.failed{color:var(--color-error)}.run-status.terminated{color:var(--text-muted)}.run-details{display:flex;gap:var(--space-sm);font-size:var(--space-md);color:var(--text-muted)}.run-logs-container{padding:var(--space-md);background:var(--bg-secondary);border-top:1px solid var(--border);border-bottom:1px solid var(--border)}.run-details-loading-state{display:flex;align-items:center;gap:var(--space-sm);padding:var(--space-sm) 0}.run-output-sections{margin-bottom:var(--space-md)}.run-output-section{margin-bottom:var(--space-sm)}.run-output-label{margin-bottom:var(--space-xs);color:var(--text-muted);font-size:calc(var(--space-sm) + var(--space-xs));font-weight:600;letter-spacing:calc(var(--space-xs) * .1);text-transform:uppercase}.run-output-label--error{color:var(--color-error)}.run-output-panel{margin:0;max-height:calc(var(--space-2xl) * 6.25);overflow:auto;border-radius:var(--radius-sm);padding:var(--space-sm) var(--space-md);background:var(--surface);border:1px solid var(--border);white-space:pre-wrap;word-break:break-word;font-size:calc(var(--space-sm) + var(--space-xs));line-height:1.5}.run-output-panel--error{color:var(--color-error);border-color:color-mix(in srgb,var(--color-error) 35%,var(--border));background:color-mix(in srgb,var(--color-error) 10%,transparent)}.run-context-grid{display:flex;flex-wrap:wrap;gap:var(--space-xs) var(--space-md);font-size:calc(var(--space-sm) + var(--space-xs))}.run-context-item{line-height:1.5}.run-output-empty{padding:var(--space-sm) 0;font-style:italic;font-size:calc(var(--space-sm) + var(--space-xs))}.run-agent-logs-section{margin-top:var(--space-xs);padding-top:var(--space-sm);border-top:1px solid var(--border)}.agent-tasks-list{display:flex;flex-direction:column;gap:var(--space-sm)}.agent-task-item{display:flex;flex-direction:column;gap:calc(var(--space-xs) + var(--space-sm) * .25);padding:var(--space-md) calc(var(--space-md) + var(--space-xs) * .5);border:1px solid var(--border);border-radius:var(--radius-md);background:var(--bg-secondary);text-decoration:none;transition:background var(--transition-fast),border-color var(--transition-fast)}.agent-task-item:hover{background:var(--card-hover);border-color:var(--text-dim)}.agent-task-row{display:flex;align-items:center;justify-content:space-between;gap:var(--space-sm)}.agent-task-id{font-family:var(--font-mono);font-size:var(--space-md);font-weight:600;color:var(--todo)}.agent-task-title{font-size:calc(var(--space-md) + var(--space-xs) * .5);font-weight:500;color:var(--text);line-height:1.4}.agent-task-status{font-size:var(--space-md);color:var(--text-muted)}.agent-task-column{display:inline-flex;align-items:center;padding:calc(var(--space-xs) * .5) var(--space-sm);border-radius:var(--radius-pill);font-size:calc(var(--space-sm) + var(--space-xs) * .5);font-weight:700;text-transform:uppercase;letter-spacing:calc(var(--space-xs) * .1)}.agent-task-column.column-triage{color:var(--triage);background:color-mix(in srgb,var(--triage) 18%,transparent)}.agent-task-column.column-todo{color:var(--todo);background:color-mix(in srgb,var(--todo) 18%,transparent)}.agent-task-column.column-in-progress{color:var(--in-progress);background:color-mix(in srgb,var(--in-progress) 18%,transparent)}.agent-task-column.column-in-review{color:var(--in-review);background:color-mix(in srgb,var(--in-review) 18%,transparent)}.agent-task-column.column-done{color:var(--done);background:color-mix(in srgb,var(--done) 18%,transparent)}.agent-task-column.column-archived{color:var(--text-muted);background:color-mix(in srgb,var(--text-muted) 18%,transparent)}.agent-tasks-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-sm);padding:calc(var(--space-2xl) + var(--space-lg));color:var(--text-muted);text-align:center}.agent-tasks-empty p{margin:0}.config-tab{display:flex;flex-direction:column;gap:var(--space-xl)}.config-section{background:var(--bg-secondary);border-radius:var(--radius-md);padding:calc(var(--space-md) + var(--space-sm))}.config-section h3{font-size:calc(var(--space-md) + var(--space-xs));font-weight:600;margin:0 0 var(--space-sm) 0}.config-section--danger{border:1px solid color-mix(in srgb,var(--color-error) 40%,transparent)}.config-danger-note{font-size:calc(var(--space-sm) + var(--space-xs) * .75);color:var(--text-muted)}.agent-content-toolbar{display:flex;align-items:center;gap:var(--space-md);padding:var(--space-sm) var(--space-lg);border-bottom:1px solid var(--border);background:var(--surface);flex-shrink:0}.agent-content-mode-toggle{display:flex;align-items:center;gap:var(--space-xs)}.agent-content-mode-toggle .btn{display:inline-flex;align-items:center;gap:calc(var(--space-xs) + var(--space-sm) * .25)}.agent-content-preview{overflow-y:auto;padding:var(--space-lg);min-height:150px}.agent-content-placeholder{color:var(--text-muted);text-align:center;padding:var(--space-xl);min-height:150px;display:flex;align-items:center;justify-content:center}.config-description{font-size:calc(var(--space-md) + var(--space-xs) * .5);color:var(--text-muted);margin:0 0 calc(var(--space-md) + var(--space-sm)) 0}.config-fields{display:flex;flex-direction:column;gap:var(--space-lg)}.config-field{display:flex;flex-direction:column;gap:calc(var(--space-xs) + var(--space-sm) * .25)}.config-field label{font-size:calc(var(--space-md) + var(--space-xs) * .25);font-weight:500}.config-runtime-tabs{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-sm);margin-bottom:var(--space-md)}.config-runtime-tab{border:1px solid var(--border);border-radius:var(--radius-md);background:var(--card);color:var(--text-muted);padding:var(--space-sm) var(--space-md);font-size:calc(var(--space-sm) + var(--space-xs));font-weight:600;cursor:pointer;transition:border-color var(--transition-fast),background var(--transition-fast),color var(--transition-fast),box-shadow var(--transition-fast)}.config-runtime-tab:hover{border-color:var(--todo);color:var(--text);background:var(--card-hover)}.config-runtime-tab:focus-visible{outline:none;border-color:var(--todo);box-shadow:var(--focus-ring-strong)}.config-runtime-tab.active{border-color:var(--todo);color:var(--text);background:color-mix(in srgb,var(--todo) 12%,transparent)}.config-hint{font-size:calc(var(--space-sm) + var(--space-xs) * .75);color:var(--text-muted);font-style:italic}.config-error{font-size:calc(var(--space-sm) + var(--space-xs) * .75);color:var(--color-error)}.input--error{border-color:var(--color-error)!important}.config-actions{display:flex;align-items:center;gap:var(--space-md);margin-top:calc(var(--space-md) + var(--space-sm));padding-top:var(--space-lg);border-top:1px solid var(--border)}.config-saved-indicator{display:flex;align-items:center;gap:calc(var(--space-sm) - var(--space-xs) * .5);font-size:calc(var(--space-md) + var(--space-xs) * .25);color:var(--color-success)}.heartbeat-procedure-actions{margin-top:var(--space-sm)}.heartbeat-procedure-viewer{margin-top:var(--space-lg)}.heartbeat-procedure-status{display:inline-flex;align-items:center;gap:var(--space-xs);margin-left:auto}.heartbeat-procedure-status--warning{color:var(--color-warning)}.rating-summary-card{background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius-md);padding:calc(var(--space-md) + var(--space-sm));display:flex;flex-direction:column;gap:var(--space-md)}.rating-score-display{display:flex;align-items:center;gap:var(--space-md)}.rating-average{font-size:var(--space-2xl);font-weight:700;line-height:1}.rating-stats{display:flex;align-items:center;gap:var(--space-md)}.rating-count{font-size:calc(var(--space-md) + var(--space-xs) * .5);color:var(--text-muted)}.rating-trend-badge{font-size:var(--space-md);padding:var(--space-xs) calc(var(--space-md) - var(--space-xs) * .5);border-radius:var(--radius-lg);font-weight:500}.trend-improving{background:color-mix(in srgb,var(--color-success) 15%,transparent);color:var(--color-success)}.trend-declining{background:color-mix(in srgb,var(--color-error) 15%,transparent);color:var(--color-error)}.trend-stable{background:color-mix(in srgb,var(--color-warning) 15%,transparent);color:var(--color-warning)}.trend-insufficient{background:var(--bg-tertiary);color:var(--text-muted)}.category-breakdown{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:var(--space-lg)}.category-breakdown h4{margin:0 0 var(--space-md) 0;font-size:calc(var(--space-md) + var(--space-xs) * .25);font-weight:600}.category-breakdown .category-item{display:flex;justify-content:space-between;align-items:center;padding:var(--space-sm) 0;border-bottom:1px solid var(--border)}.category-breakdown .category-item:last-child{border-bottom:none}.category-name{text-transform:capitalize;font-size:calc(var(--space-md) + var(--space-xs) * .25)}.category-score{font-weight:600;font-size:calc(var(--space-md) + var(--space-xs) * .25)}.add-rating-form{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:var(--space-lg);display:flex;flex-direction:column;gap:var(--space-md)}.add-rating-form h4{margin:0;font-size:calc(var(--space-md) + var(--space-xs) * .25);font-weight:600}.star-selector{display:flex;gap:var(--space-xs)}.star-btn{background:none;border:none;padding:var(--space-xs);cursor:pointer;border-radius:var(--radius-sm);color:var(--text-muted);transition:background-color var(--transition-fast),color var(--transition-fast)}.star-btn:hover{background:var(--card-hover)}.star-btn:focus-visible{outline:none;box-shadow:var(--focus-ring-strong)}.rating-stars{display:inline-flex;gap:var(--space-xs)}.rating-stars .star-filled{color:var(--color-warning)}.rating-stars .star-empty{color:var(--text-muted)}.add-rating-form .add-rating-category-select,.add-rating-form .add-rating-comment-input{width:100%}.add-rating-form .add-rating-comment-input{resize:vertical;min-height:calc(var(--space-xl) + var(--space-2xl))}.rating-history{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:var(--space-lg);max-height:calc(var(--space-xl) * 12 + var(--space-md));overflow-y:auto}.rating-history h4{margin:0 0 var(--space-md) 0;font-size:calc(var(--space-md) + var(--space-xs) * .25);font-weight:600}.rating-history .no-ratings{color:var(--text-muted);font-size:calc(var(--space-md) + var(--space-xs) * .25);text-align:center;padding:var(--space-lg)}.rating-history-item{padding:var(--space-md) 0;border-bottom:1px solid var(--border)}.rating-history-item:last-child{border-bottom:none}.rating-item-header{display:flex;align-items:center;gap:var(--space-sm);flex-wrap:wrap}.rating-category-badge{font-size:calc(var(--space-sm) + var(--space-xs) * .5);padding:calc(var(--space-xs) * .5) var(--space-sm);background:var(--card-hover);border-radius:var(--radius-pill);text-transform:capitalize}.rating-time{font-size:calc(var(--space-sm) + var(--space-xs) * .5);color:var(--text-muted);margin-left:auto}.rating-delete-btn{background:none;border:none;padding:var(--space-xs);cursor:pointer;color:var(--text-muted);border-radius:var(--radius-sm);transition:color var(--transition-fast),background-color var(--transition-fast)}.rating-delete-btn:hover{color:var(--color-error);background:color-mix(in srgb,var(--color-error) 10%,transparent)}.rating-comment{margin:var(--space-sm) 0 0 0;font-size:calc(var(--space-sm) + var(--space-xs));color:var(--text-muted);line-height:1.4}.runs-loading-row{display:flex;align-items:center;justify-content:center;gap:var(--space-sm);padding:var(--space-xl)}.runs-toolbar{padding:var(--space-sm) var(--space-lg);border-bottom:1px solid var(--border)}.runs-toolbar--between{display:flex;justify-content:space-between;align-items:center}.runs-toolbar-meta{font-size:calc(var(--space-sm) + var(--space-xs));color:var(--text-muted)}.run-card--clickable{cursor:pointer}.run-card--clickable:focus-visible{outline:none;box-shadow:var(--focus-ring-strong)}.run-header-group{display:flex;align-items:center;gap:var(--space-sm)}.run-badge--compact{font-size:calc(var(--space-sm) + var(--space-xs) * .5);padding:calc(var(--space-xs) * .25) calc(var(--space-sm) * .75)}.run-output-summary{cursor:pointer;user-select:none}.run-live-indicator--with-margin{margin-left:var(--space-sm)}.detail-section-body--loading{display:flex;align-items:center;gap:var(--space-sm)}.agent-empty--padded{padding:var(--space-xl)}.logs-fallback-label{font-size:calc(var(--space-sm) + var(--space-xs))}.config-textarea-mono{font-family:var(--font-mono);font-size:calc(var(--space-md) + var(--space-xs) * .25);resize:vertical}.config-textarea-top-spacing{margin-top:var(--space-sm)}.config-hint--block-spacing{margin-bottom:var(--space-md)}.config-hint--block{display:block;margin-bottom:var(--space-sm)}.config-hint--top-spacing{margin-top:var(--space-sm)}.config-hint--inline-loader{display:inline-flex;gap:var(--space-xs);margin-top:var(--space-sm)}.config-inline-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--space-sm)}.config-hint--inline-tight{display:flex;align-items:center;gap:var(--space-xs)}.config-hint--warning{color:var(--color-warning)}@media(max-width:768px){.config-runtime-tabs{grid-template-columns:1fr}.agent-detail-overlay{padding:0;align-items:stretch}.agent-detail-modal{min-width:0!important;min-height:0!important;width:100vw!important;height:100dvh!important;max-width:100vw!important;max-height:100dvh;margin:0;border-radius:0;border:none;resize:none}.agent-detail-header{flex-wrap:wrap;gap:var(--space-sm);padding:var(--space-md);padding-top:max(var(--space-md),env(safe-area-inset-top,0))}.agent-detail-identity{flex:1 1 auto;min-width:0;gap:var(--space-sm)}.agent-detail-icon{width:calc(var(--space-lg) * 2);height:calc(var(--space-lg) * 2);flex-shrink:0}.agent-detail-icon svg{width:calc(var(--space-sm) + var(--space-xs) * 2);height:calc(var(--space-sm) + var(--space-xs) * 2)}.agent-detail-info h2{font-size:calc(var(--space-md) + var(--space-xs) * .75);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.agent-detail-badges{flex-wrap:wrap}.agent-detail-controls{flex:1 1 100%;flex-wrap:wrap;gap:calc(var(--space-xs) + var(--space-sm) * .25);order:3}.agent-detail-controls .btn--compact{padding:calc(var(--space-sm) - var(--space-xs) * .5) calc(var(--space-md) - var(--space-xs) * .5);font-size:var(--space-md);min-height:calc(var(--space-lg) + var(--space-md) + var(--space-xs))}.agent-detail-controls .btn--compact svg{width:calc(var(--space-md) + var(--space-xs) * .5);height:calc(var(--space-md) + var(--space-xs) * .5)}.agent-detail-utility-actions{flex-shrink:0}.agent-detail-utility-actions .btn-icon{min-height:calc(var(--space-lg) + var(--space-md) + var(--space-xs));min-width:calc(var(--space-lg) + var(--space-md) + var(--space-xs))}.agent-detail-title{flex:1 1 auto;min-width:0;gap:var(--space-md)}.agent-detail-actions{flex:1 1 100%;flex-wrap:wrap;gap:calc(var(--space-xs) + var(--space-sm) * .25)}.agent-detail-actions .btn{padding:calc(var(--space-sm) - var(--space-xs) * .5) calc(var(--space-md) - var(--space-xs) * .5);font-size:calc(var(--space-md) + var(--space-xs) * .25);min-height:calc(var(--space-lg) + var(--space-md) + var(--space-xs))}.agent-detail-actions .btn svg{width:calc(var(--space-sm) + var(--space-xs) * 1.5);height:calc(var(--space-sm) + var(--space-xs) * 1.5)}.agent-detail-actions .btn-icon{min-height:calc(var(--space-lg) + var(--space-md) + var(--space-xs));min-width:calc(var(--space-lg) + var(--space-md) + var(--space-xs))}.agent-detail-tabs{padding:0;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}.agent-detail-tabs::-webkit-scrollbar{display:none}.agent-detail-tab{padding:var(--space-md) calc(var(--space-md) + var(--space-xs) * .5);font-size:calc(var(--space-md) + var(--space-xs) * .25);white-space:nowrap;min-height:calc(var(--space-lg) + var(--space-md) + var(--space-xs))}.agent-detail-content{padding:var(--space-lg)}.agent-detail-footer{flex-wrap:wrap;gap:var(--space-sm);padding:var(--space-sm) var(--space-lg);padding-bottom:max(var(--space-sm),env(safe-area-inset-bottom,0));font-size:calc(var(--space-sm) + var(--space-xs) * .75)}.agent-detail-id{max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dashboard-tab{gap:var(--space-lg)}.dashboard-section{padding:var(--space-lg)}.info-grid{grid-template-columns:repeat(2,1fr);gap:var(--space-md)}.stats-grid{grid-template-columns:repeat(3,1fr);gap:var(--space-md)}.stat-value{font-size:calc(var(--space-lg) + var(--space-xs) * .5)}.logs-container{max-height:50vh}.logs-empty{padding:var(--space-2xl) var(--space-lg)}.log-entry{padding:var(--space-xs) calc(var(--space-xs) * .5);font-size:var(--space-md)}.log-text{min-width:0;overflow-wrap:anywhere}.run-card{padding:var(--space-md)}.run-header{flex-wrap:wrap;gap:calc(var(--space-xs) + var(--space-sm) * .25)}.run-details{flex-wrap:wrap}.run-logs-container{padding:var(--space-sm)}.run-output-panel{max-height:calc(var(--space-2xl) * 5)}.run-context-grid{flex-direction:column;gap:var(--space-xs)}.run-details .text-muted{min-width:0;overflow-wrap:anywhere}.config-tab{gap:var(--space-lg)}.config-section{padding:var(--space-lg)}.config-section .input,.config-section .select,.config-section textarea{font-size:calc(var(--space-md) + var(--space-xs));min-height:calc(var(--space-lg) + var(--space-md) + var(--space-xs))}.config-actions{flex-direction:column;align-items:stretch;gap:var(--space-sm)}.config-actions .btn{width:100%;justify-content:center}.heartbeat-procedure-status{margin-left:0}}@media(max-width:480px){.info-grid,.stats-grid{grid-template-columns:1fr}.agent-detail-actions{flex-direction:column;width:100%}.agent-detail-actions .btn{width:100%;justify-content:center}.agent-detail-actions .btn-icon{align-self:flex-end}.agent-detail-footer .divider,.agent-detail-footer .text-muted,.agent-detail-footer .link{display:none}}@media(max-width:768px){.agent-dialog-overlay{padding:0;align-items:stretch}.agent-dialog{width:100vw!important;height:100dvh;max-width:100%!important;max-height:100dvh;border-radius:0;border:none}.agent-dialog-header{padding:max(var(--space-md),env(safe-area-inset-top,0px)) var(--space-lg) var(--space-md) var(--space-lg);flex-shrink:0}.agent-dialog-body{padding:var(--space-lg);-webkit-overflow-scrolling:touch}.agent-dialog-footer{padding:var(--space-md) var(--space-lg);padding-bottom:max(var(--space-md),env(safe-area-inset-bottom,0px));flex-wrap:wrap;gap:var(--space-sm)}.agent-dialog-field .input,.agent-dialog-field .select,.agent-dialog-field textarea{font-size:calc(var(--space-md) + var(--space-xs));min-height:calc(var(--space-lg) * 2 + var(--space-xs))}.agent-dialog-summary-row{flex-direction:column;gap:calc(var(--space-xs) * .5)}.agent-dialog-summary-row>span:first-child,.agent-dialog-summary-row-label{width:auto}.agent-dialog-steps{padding:var(--space-sm) var(--space-lg)}.agent-dialog-step{flex:1;width:auto;height:calc(var(--space-xs) - var(--space-xs) * .25)}.agent-dialog-tabs{grid-template-columns:1fr;gap:calc(var(--space-sm) - var(--space-xs) * .5);margin-bottom:var(--space-md)}.agent-dialog-tab{min-height:calc(var(--space-lg) * 2 + var(--space-xs));text-align:left}.agent-import-file-upload{flex-direction:column;align-items:stretch;gap:var(--space-sm)}.agent-import-textarea{font-size:calc(var(--space-md) + var(--space-xs));min-height:calc(var(--space-xl) * 4 + var(--space-xs))}.agent-import-agent-list{max-height:calc(100dvh - (var(--space-xl) * 10 + var(--space-lg)))}.agent-import-result-stats{flex-direction:column;gap:var(--space-sm);align-items:center}.agent-import-browse-list{max-height:calc(100dvh - (var(--space-xl) * 10 + var(--space-lg)))}.agent-import-skill-list{max-height:calc(100dvh - (var(--space-xl) * 15 + var(--space-md)))}}@media(max-width:480px){.agent-dialog-body{padding:var(--space-md)}.agent-dialog-footer{flex-direction:column}.agent-dialog-footer .btn{width:100%;justify-content:center}}.reflections-tab{padding:var(--space-lg);display:flex;flex-direction:column;gap:var(--space-lg)}.reflections-header{display:flex;align-items:center;justify-content:space-between;gap:var(--space-md)}.reflections-header h3{display:flex;align-items:center;gap:var(--space-sm);font-size:1rem;font-weight:600;color:var(--text)}.reflections-stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:var(--space-md)}.reflections-stat-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:var(--space-md);text-align:center}.reflections-stat-card .stat-value{display:flex;align-items:center;justify-content:center;gap:var(--space-sm);font-size:1.5rem;font-weight:700;color:var(--text);margin-bottom:var(--space-xs)}.reflections-stat-card .stat-label{font-size:.75rem;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.05em}.reflections-no-data{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-sm);padding:var(--space-xl);color:var(--text-secondary);text-align:center}.reflections-list{display:flex;flex-direction:column;gap:var(--space-md)}.reflections-loading-indicator{display:flex;align-items:center;justify-content:center;gap:var(--space-sm);padding:var(--space-lg)}.reflections-ratings-section{display:flex;flex-direction:column;gap:var(--space-md)}.reflections-ratings-section>h4,.reflections-list h4{font-size:.875rem;font-weight:600;color:var(--text);margin-bottom:var(--space-xs)}.reflection-cards{display:flex;flex-direction:column;gap:var(--space-sm)}.reflection-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:var(--space-md);cursor:pointer;transition:border-color .15s,background-color .15s}.reflection-card:hover{border-color:var(--border-active);background:var(--card-hover)}.reflection-card:focus-visible{outline:none;box-shadow:var(--focus-ring-strong)}.reflection-card--expanded{border-color:var(--color-primary)}.reflection-card-header{display:flex;align-items:center;gap:var(--space-sm);margin-bottom:var(--space-sm)}.reflection-trigger-badge{font-size:.7rem;font-weight:600;padding:2px 6px;border-radius:var(--radius-sm);text-transform:uppercase;letter-spacing:.05em}.reflection-trigger-periodic{background:color-mix(in srgb,var(--color-info) 15%,transparent);color:var(--color-info)}.reflection-trigger-post-task{background:color-mix(in srgb,var(--color-success) 15%,transparent);color:var(--color-success)}.reflection-trigger-manual{background:color-mix(in srgb,var(--color-primary) 15%,transparent);color:var(--color-primary)}.reflection-trigger-user-requested{background:color-mix(in srgb,var(--color-warning) 15%,transparent);color:var(--color-warning)}.reflection-timestamp{font-size:.75rem;color:var(--text-muted);flex:1}.reflection-chevron{color:var(--text-muted)}.reflection-summary{font-size:.875rem;color:var(--text);line-height:1.5}.reflection-details{margin-top:var(--space-md);padding-top:var(--space-md);border-top:1px solid var(--border);display:flex;flex-direction:column;gap:var(--space-md)}.reflection-insights h5,.reflection-suggestions h5{display:flex;align-items:center;gap:var(--space-xs);font-size:.8rem;font-weight:600;color:var(--text);margin-bottom:var(--space-xs)}.reflection-insights ul,.reflection-suggestions ul{list-style:none;display:flex;flex-direction:column;gap:var(--space-xs)}.reflection-insights li,.reflection-suggestions li{font-size:.8rem;color:var(--text-secondary);padding-left:var(--space-md);position:relative}.reflection-insights li:before{content:"•";position:absolute;left:4px;color:var(--color-success)}.reflection-suggestions li:before{content:"→";position:absolute;left:0;color:var(--color-primary)}.reflection-metrics{background:var(--bg);border-radius:var(--radius-sm);padding:var(--space-sm)}.reflection-metrics h5{font-size:.75rem;font-weight:600;color:var(--text-muted);margin-bottom:var(--space-xs)}.metrics-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(100px,1fr));gap:var(--space-sm)}.metric{display:flex;flex-direction:column;gap:2px}.metric-label{font-size:.7rem;color:var(--text-muted)}.metric-value{font-size:.875rem;font-weight:600;color:var(--text)}.reflection-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-sm);padding:var(--space-2xl);color:var(--text-secondary);text-align:center}.reflection-empty p{font-size:.875rem}@media(max-width:768px){.reflections-header{flex-wrap:wrap;align-items:flex-start}.reflections-header .btn{width:100%;justify-content:center}}.budget-progress-container{margin-top:4px}.budget-progress-bar{width:100%;height:8px;background:var(--bg-secondary, #161b22);border-radius:4px;overflow:hidden;margin-top:4px}.budget-progress-bar__fill{height:100%;border-radius:4px;transition:width .3s ease,background-color .3s ease}.budget-progress-bar__fill--green{background:var(--state-active-text, #3fb950)}.budget-progress-bar__fill--amber{background:var(--state-paused-text, #e3b541)}.budget-progress-bar__fill--red{background:var(--state-error-text, #f85149)}.budget-progress-label{font-size:.75rem;color:var(--text-secondary, #8b949e);margin-top:4px;display:block}.budget-badge{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:12px;font-size:.75rem;font-weight:500}.budget-warning-banner{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:6px;background:var(--state-error-bg, rgba(248,81,73,.15));color:var(--state-error-text, #f85149);border:1px solid var(--state-error-border, #f85149);font-size:.875rem;margin-bottom:12px}.btn-reset-budget{margin-top:8px}.chat-sidebar-footer{display:none}@media(max-width:768px){.chat-view{flex-direction:column}.chat-sidebar{width:100%;min-width:100%;height:100%;max-height:none;border-right:none;border-bottom:1px solid var(--border);flex-direction:column}.chat-sidebar-header,.chat-sidebar-search{display:none}.chat-sidebar-list{flex:1;min-height:0;overflow-y:auto}.chat-sidebar-footer{display:flex;padding:var(--space-md);border-top:1px solid var(--border);background:var(--bg-secondary)}.chat-sidebar-footer-btn{flex:1;justify-content:center}.chat-sidebar--hidden{display:none}.chat-message{max-width:90%}.chat-new-dialog{width:95vw;margin:16px}.chat-thread-header{padding:8px 12px}.chat-skill-menu{left:var(--space-md);right:calc(var(--space-md) + var(--mobile-nav-height));min-width:0;max-width:none}}@media(max-width:768px){.file-mention-popup{max-height:200px}.file-mention-popup-item{min-height:36px;padding:10px 12px}.agent-mention-popup{max-width:280px;min-width:200px}}.skill-multiselect{display:flex;flex-direction:column;gap:var(--space-sm)}.skill-multiselect-label{font-size:13px;font-weight:500;color:var(--text-secondary)}.skill-multiselect-chips{display:flex;flex-wrap:wrap;gap:4px}.skill-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 6px;background:var(--bg-tertiary);color:var(--text-secondary);border-radius:4px;font-size:12px;line-height:1.4}.skill-chip-name{max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.skill-chip-remove{display:inline-flex;align-items:center;justify-content:center;width:14px;height:14px;padding:0;background:transparent;border:none;border-radius:2px;color:var(--text-muted);font-size:14px;line-height:1;cursor:pointer;transition:color .15s,background .15s}.skill-chip-remove:hover:not(:disabled){color:var(--text-primary);background:var(--bg-hover)}.skill-chip-remove:disabled{opacity:.5;cursor:not-allowed}.skill-multiselect-add{min-height:32px}.skill-multiselect-loading,.skill-multiselect-empty{font-size:13px;color:var(--text-muted);padding:4px 0}.skill-multiselect-dropdown{width:100%;font-size:13px}.agent-dialog-skills-hint{margin-top:4px;font-size:12px}.skill-badge-row{display:flex;flex-wrap:wrap;gap:4px}.skill-badge{display:inline-block;padding:2px 6px;background:var(--bg-tertiary);color:var(--text-secondary);border-radius:4px;font-size:11px;line-height:1.4}.badge-skill{background:var(--bg-tertiary);color:var(--text-secondary)}.agent-board-skills{display:flex;flex-wrap:wrap;gap:4px;padding:4px 8px}.skill-badge-sm{display:inline-block;padding:1px 5px;background:var(--bg-tertiary);color:var(--text-secondary);border-radius:3px;font-size:10px;line-height:1.4}.skill-badge-extra{background:var(--bg-secondary)}.agent-tree__skill{display:inline-block;padding:1px 5px;background:var(--bg-tertiary);color:var(--text-secondary);border-radius:3px;font-size:10px;line-height:1.4;margin-left:6px}.org-chart-node__skill{display:inline-block;padding:1px 5px;background:var(--bg-tertiary);color:var(--text-secondary);border-radius:3px;font-size:10px;line-height:1.4}.divider{color:var(--border)}.text-muted{color:var(--text-muted)}.link{display:inline-flex;align-items:center;gap:4px;color:var(--todo);text-decoration:none}.link:hover{text-decoration:underline}.text-secondary{color:var(--text-muted)}