@runfusion/fusion 0.2.7 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +55392 -51635
- package/dist/client/assets/{AgentDetailView-BMrHuWGs.css → AgentDetailView-C1b9PC5l.css} +1 -1
- package/dist/client/assets/{AgentDetailView-B4lRk--v.js → AgentDetailView-DJwWfkpv.js} +1 -1
- package/dist/client/assets/{AgentsView-yCYBY2km.js → AgentsView-DegK8aw-.js} +5 -5
- package/dist/client/assets/ChatView-CYpEShLS.js +1 -0
- package/dist/client/assets/{DevServerView-jXXtoQUx.js → DevServerView-DfCTA9fx.js} +2 -2
- package/dist/client/assets/{DirectoryPicker-izgMlS27.js → DirectoryPicker-B0qNpfLW.js} +1 -1
- package/dist/client/assets/DirectoryPicker-DzKVmxOf.css +1 -0
- package/dist/client/assets/{DocumentsView-DkkoHRwL.js → DocumentsView-CsQxuyz3.js} +1 -1
- package/dist/client/assets/{InsightsView-DaRtUPHX.js → InsightsView-Bzs7A2jv.js} +2 -2
- package/dist/client/assets/MemoryView-Cl5ASqjW.js +2 -0
- package/dist/client/assets/MemoryView-DiajLXby.css +1 -0
- package/dist/client/assets/{NodesView-BsUk_oiU.js → NodesView-BpiqRlvc.js} +1 -1
- package/dist/client/assets/PiExtensionsManager-Cr6EoC7S.js +11 -0
- package/dist/client/assets/PiExtensionsManager-kgTOHPE9.css +1 -0
- package/dist/client/assets/PluginManager-DRiIqol2.css +1 -0
- package/dist/client/assets/PluginManager-DXtQdfns.js +1 -0
- package/dist/client/assets/{RoadmapsView-SQol126Y.js → RoadmapsView-CYPLTTB0.js} +2 -2
- package/dist/client/assets/SettingsModal-CDWvhvrd.css +1 -0
- package/dist/client/assets/SettingsModal-CNdVTVqD.js +1 -0
- package/dist/client/assets/SettingsModal-CyCC7MzL.js +31 -0
- package/dist/client/assets/SettingsModal-G0ESQXRD.css +1 -0
- package/dist/client/assets/{SetupWizardModal-CQc1uGSq.js → SetupWizardModal-BLiljNn7.js} +1 -1
- package/dist/client/assets/SetupWizardModal-BMa6p24b.css +1 -0
- package/dist/client/assets/SkillsView-Dlpw5LKI.js +1 -0
- package/dist/client/assets/{folder-open-CI4TCD7P.js → folder-open-B_38R5AA.js} +1 -1
- package/dist/client/assets/index-DQKtk17v.js +616 -0
- package/dist/client/assets/index-DjOxzdj3.css +1 -0
- package/dist/client/assets/{upload-CAlKC4qI.js → upload-DNQF7XCK.js} +1 -1
- package/dist/client/assets/users-CG2_rCdk.js +6 -0
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -0
- package/dist/extension.js +3222 -937
- package/dist/pi-claude-cli/index.ts +72 -28
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/pi-claude-cli/src/__tests__/event-bridge.test.ts +34 -0
- package/dist/pi-claude-cli/src/__tests__/mcp-config.test.ts +22 -0
- package/dist/pi-claude-cli/src/__tests__/prompt-builder.test.ts +72 -10
- package/dist/pi-claude-cli/src/__tests__/provider.test.ts +9 -9
- package/dist/pi-claude-cli/src/event-bridge.ts +17 -6
- package/dist/pi-claude-cli/src/mcp-config.ts +36 -3
- package/dist/pi-claude-cli/src/prompt-builder.ts +111 -7
- package/dist/pi-claude-cli/src/provider.ts +17 -2
- package/package.json +17 -16
- package/skill/fusion/SKILL.md +6 -1
- package/skill/fusion/references/engine-tools.md +54 -0
- package/skill/fusion/references/extension-tools.md +83 -84
- package/skill/fusion/references/fusion-capabilities.md +33 -31
- package/LICENSE +0 -21
- package/dist/client/assets/ChatView-CH9T0dDs.js +0 -1
- package/dist/client/assets/MemoryView-85NKuU3h.js +0 -2
- package/dist/client/assets/MemoryView-DhinauGs.css +0 -1
- package/dist/client/assets/PiExtensionsManager-BF5pxrSE.js +0 -11
- package/dist/client/assets/PiExtensionsManager-K7HQ08L4.css +0 -1
- package/dist/client/assets/PluginManager-ccq3uK50.css +0 -1
- package/dist/client/assets/PluginManager-s6btydh5.js +0 -1
- package/dist/client/assets/SkillsView-BtUhs_QW.js +0 -1
- package/dist/client/assets/index-Ct-OqLpP.css +0 -1
- package/dist/client/assets/index-rNf7s96d.js +0 -649
|
@@ -2,191 +2,187 @@
|
|
|
2
2
|
|
|
3
3
|
All tools are registered via the pi extension. They are available in any pi agent session when the Fusion extension is installed.
|
|
4
4
|
|
|
5
|
-
> Naming contract: all externally exposed Fusion extension tools are `fn_*` (for example `fn_task_create`).
|
|
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
|
+
|
|
7
|
+
<!-- BEGIN: extension-tools (auto-generated by scripts/sync-fusion-skill-tools.mjs — do not edit by hand) -->
|
|
6
8
|
|
|
7
9
|
## Task Tools
|
|
8
10
|
|
|
9
11
|
### fn_task_create
|
|
10
12
|
|
|
11
|
-
Create a new task on the Fusion board.
|
|
13
|
+
Create a new task on the Fusion task board. The task enters the triage column where the AI triage agent will specify it into a full prompt with steps, file scope, and acceptance criteria.
|
|
12
14
|
|
|
13
15
|
| Parameter | Type | Required | Description |
|
|
14
16
|
|-----------|------|----------|-------------|
|
|
15
17
|
| `description` | string | ✓ | What needs to be done — be descriptive |
|
|
16
|
-
| `depends` |
|
|
17
|
-
|
|
18
|
-
Returns: task ID, column, dependencies, path
|
|
18
|
+
| `depends` | array | — | Task IDs this depends on (e.g. ['FN-001', 'FN-002']) |
|
|
19
|
+
| `agentId` | string | — | Agent ID to assign this task to (e.g. 'agent-abc123') |
|
|
19
20
|
|
|
20
21
|
### fn_task_update
|
|
21
22
|
|
|
22
|
-
Update fields on an existing task
|
|
23
|
+
Update fields on an existing task. Supports modifying the title, description, dependencies, and assigned agent after task creation.
|
|
23
24
|
|
|
24
25
|
| Parameter | Type | Required | Description |
|
|
25
26
|
|-----------|------|----------|-------------|
|
|
26
|
-
| `id` | string | ✓ | Task ID (e.g
|
|
27
|
+
| `id` | string | ✓ | Task ID (e.g. FN-001) |
|
|
27
28
|
| `title` | string | — | New task title |
|
|
28
29
|
| `description` | string | — | New task description |
|
|
29
|
-
| `depends` |
|
|
30
|
-
|
|
31
|
-
Returns: task ID, list of updated fields
|
|
30
|
+
| `depends` | array | — | New dependency list — replaces existing dependencies (e.g. ['FN-001', 'FN-002']) |
|
|
31
|
+
| `agentId` | union | — | Agent ID to assign this task to, or null to clear (e.g. 'agent-abc123') |
|
|
32
32
|
|
|
33
33
|
### fn_task_list
|
|
34
34
|
|
|
35
|
-
List all tasks grouped by column.
|
|
35
|
+
List all tasks on the Fusion board, grouped by column.
|
|
36
36
|
|
|
37
37
|
| Parameter | Type | Required | Description |
|
|
38
38
|
|-----------|------|----------|-------------|
|
|
39
|
-
| `column` | string | — | Filter to specific column |
|
|
40
|
-
| `limit` | number | — | Max tasks per column (default: 10) |
|
|
41
|
-
|
|
42
|
-
Returns: formatted task list grouped by column
|
|
39
|
+
| `column` | string(enum) | — | Filter to a specific column |
|
|
40
|
+
| `limit` | number | — | Max tasks to show per column (default: 10) |
|
|
43
41
|
|
|
44
42
|
### fn_task_show
|
|
45
43
|
|
|
46
|
-
Show full task
|
|
44
|
+
Show full details for a task including steps, progress, and log entries.
|
|
47
45
|
|
|
48
46
|
| Parameter | Type | Required | Description |
|
|
49
47
|
|-----------|------|----------|-------------|
|
|
50
|
-
| `id` | string | ✓ | Task ID (e.g
|
|
51
|
-
|
|
52
|
-
Returns: task details with steps, prompt preview (500 chars), last 5 log entries
|
|
48
|
+
| `id` | string | ✓ | Task ID (e.g. FN-001) |
|
|
53
49
|
|
|
54
50
|
### fn_task_attach
|
|
55
51
|
|
|
56
|
-
Attach a file to a task.
|
|
52
|
+
Attach a file to a task. Supports images (png, jpg, gif, webp) and text files (txt, log, json, yaml, yml, toml, csv, xml).
|
|
57
53
|
|
|
58
54
|
| Parameter | Type | Required | Description |
|
|
59
55
|
|-----------|------|----------|-------------|
|
|
60
|
-
| `id` | string | ✓ | Task ID |
|
|
61
|
-
| `path` | string | ✓ | Path to file to attach |
|
|
62
|
-
|
|
63
|
-
Supported formats: png, jpg, jpeg, gif, webp, txt, log, json, yaml, yml, toml, csv, xml
|
|
56
|
+
| `id` | string | ✓ | Task ID (e.g. FN-001) |
|
|
57
|
+
| `path` | string | ✓ | Path to the file to attach |
|
|
64
58
|
|
|
65
59
|
### fn_task_pause
|
|
66
60
|
|
|
67
|
-
Pause
|
|
61
|
+
Pause a task — stops all automated agent and scheduler interaction for this task.
|
|
68
62
|
|
|
69
63
|
| Parameter | Type | Required | Description |
|
|
70
64
|
|-----------|------|----------|-------------|
|
|
71
|
-
| `id` | string | ✓ | Task ID |
|
|
65
|
+
| `id` | string | ✓ | Task ID (e.g. FN-001) |
|
|
72
66
|
|
|
73
67
|
### fn_task_unpause
|
|
74
68
|
|
|
75
|
-
|
|
69
|
+
Unpause a task — resumes automated agent and scheduler interaction.
|
|
76
70
|
|
|
77
71
|
| Parameter | Type | Required | Description |
|
|
78
72
|
|-----------|------|----------|-------------|
|
|
79
|
-
| `id` | string | ✓ | Task ID |
|
|
73
|
+
| `id` | string | ✓ | Task ID (e.g. FN-001) |
|
|
80
74
|
|
|
81
75
|
### fn_task_retry
|
|
82
76
|
|
|
83
|
-
Retry a failed task
|
|
77
|
+
Retry a failed task — clears the error state and moves it back to the todo column for re-execution.
|
|
84
78
|
|
|
85
79
|
| Parameter | Type | Required | Description |
|
|
86
80
|
|-----------|------|----------|-------------|
|
|
87
|
-
| `id` | string | ✓ | Task ID (
|
|
81
|
+
| `id` | string | ✓ | Task ID to retry (e.g. FN-001). Must be in 'failed' state. |
|
|
88
82
|
|
|
89
83
|
### fn_task_duplicate
|
|
90
84
|
|
|
91
|
-
Duplicate
|
|
85
|
+
Duplicate an existing task, creating a fresh copy in triage. Copies the title and description but resets all execution state. The AI triage agent will re-specify the new task.
|
|
92
86
|
|
|
93
87
|
| Parameter | Type | Required | Description |
|
|
94
88
|
|-----------|------|----------|-------------|
|
|
95
|
-
| `id` | string | ✓ | Source task ID to duplicate |
|
|
89
|
+
| `id` | string | ✓ | Source task ID to duplicate (e.g. FN-001) |
|
|
96
90
|
|
|
97
91
|
### fn_task_refine
|
|
98
92
|
|
|
99
|
-
|
|
93
|
+
Request a refinement of a completed or in-review task. Creates a new follow-up task in triage that references the original task as a dependency. Use this when a done or in-review task needs additional work, improvements, or follow-up changes.
|
|
100
94
|
|
|
101
95
|
| Parameter | Type | Required | Description |
|
|
102
96
|
|-----------|------|----------|-------------|
|
|
103
|
-
| `id` | string | ✓ | Task ID (
|
|
104
|
-
| `feedback` | string | ✓ |
|
|
97
|
+
| `id` | string | ✓ | Task ID to refine (e.g. FN-001). Must be in 'done' or 'in-review' column. |
|
|
98
|
+
| `feedback` | string | ✓ | Description of what needs to be refined or improved |
|
|
105
99
|
|
|
106
100
|
### fn_task_archive
|
|
107
101
|
|
|
108
|
-
Archive a done task
|
|
102
|
+
Archive a done task (move from done → archived). Archived tasks are preserved for historical reference but moved out of the main board view.
|
|
109
103
|
|
|
110
104
|
| Parameter | Type | Required | Description |
|
|
111
105
|
|-----------|------|----------|-------------|
|
|
112
|
-
| `id` | string | ✓ | Task ID (
|
|
106
|
+
| `id` | string | ✓ | Task ID to archive (e.g. FN-001). Must be in 'done' column. |
|
|
113
107
|
|
|
114
108
|
### fn_task_unarchive
|
|
115
109
|
|
|
116
|
-
|
|
110
|
+
Unarchive an archived task (move from archived → done). Restores the task to the done column.
|
|
117
111
|
|
|
118
112
|
| Parameter | Type | Required | Description |
|
|
119
113
|
|-----------|------|----------|-------------|
|
|
120
|
-
| `id` | string | ✓ | Task ID (
|
|
114
|
+
| `id` | string | ✓ | Task ID to unarchive (e.g. FN-001). Must be in 'archived' column. |
|
|
121
115
|
|
|
122
116
|
### fn_task_delete
|
|
123
117
|
|
|
124
|
-
Permanently delete a task.
|
|
118
|
+
Permanently delete a task from the Fusion board. Tasks are deleted immediately and cannot be recovered.
|
|
125
119
|
|
|
126
120
|
| Parameter | Type | Required | Description |
|
|
127
121
|
|-----------|------|----------|-------------|
|
|
128
|
-
| `id` | string | ✓ | Task ID |
|
|
122
|
+
| `id` | string | ✓ | Task ID to delete (e.g. FN-001) |
|
|
129
123
|
|
|
130
124
|
### fn_task_plan
|
|
131
125
|
|
|
132
|
-
Create a task via AI-guided planning mode
|
|
126
|
+
Create a task via AI-guided planning mode — interactive conversation to refine your idea into a well-specified task.
|
|
133
127
|
|
|
134
128
|
| Parameter | Type | Required | Description |
|
|
135
129
|
|-----------|------|----------|-------------|
|
|
136
|
-
| `description` | string | — | Initial plan description |
|
|
130
|
+
| `description` | string | — | Initial plan description (optional) — the AI will ask clarifying questions if not provided |
|
|
137
131
|
|
|
138
132
|
## GitHub Tools
|
|
139
133
|
|
|
140
134
|
### fn_task_import_github
|
|
141
135
|
|
|
142
|
-
|
|
136
|
+
Import GitHub issues as Fusion tasks. Fetches open issues from a repository and creates tasks in the triage column. Each task includes the issue title and body with a link to the source issue.
|
|
143
137
|
|
|
144
138
|
| Parameter | Type | Required | Description |
|
|
145
139
|
|-----------|------|----------|-------------|
|
|
146
|
-
| `ownerRepo` | string | ✓ | Repository (e.g.,
|
|
147
|
-
| `limit` | number | — | Max issues (default: 30, max: 100) |
|
|
148
|
-
| `labels` |
|
|
140
|
+
| `ownerRepo` | string | ✓ | Repository in owner/repo format (e.g., 'dustinbyrne/fusion') |
|
|
141
|
+
| `limit` | number | — | Max issues to import (default: 30, max: 100) |
|
|
142
|
+
| `labels` | array | — | Label names to filter by |
|
|
149
143
|
|
|
150
144
|
### fn_task_import_github_issue
|
|
151
145
|
|
|
152
|
-
Import a
|
|
146
|
+
Import a specific GitHub issue as a Fusion task. Fetches the issue by number and creates a single task in the triage column with the issue title and body.
|
|
153
147
|
|
|
154
148
|
| Parameter | Type | Required | Description |
|
|
155
149
|
|-----------|------|----------|-------------|
|
|
156
|
-
| `owner` | string | ✓ | Repository owner |
|
|
157
|
-
| `repo` | string | ✓ | Repository name |
|
|
158
|
-
| `issueNumber` | number | ✓ | GitHub issue number |
|
|
150
|
+
| `owner` | string | ✓ | Repository owner (e.g., 'dustinbyrne') |
|
|
151
|
+
| `repo` | string | ✓ | Repository name (e.g., 'fusion') |
|
|
152
|
+
| `issueNumber` | number | ✓ | GitHub issue number to import |
|
|
159
153
|
|
|
160
154
|
### fn_task_browse_github_issues
|
|
161
155
|
|
|
162
|
-
|
|
156
|
+
List open GitHub issues from a repository to browse before importing. Returns issue numbers, titles, and URLs for selection. Use with fn_task_import_github_issue to import specific issues by number.
|
|
163
157
|
|
|
164
158
|
| Parameter | Type | Required | Description |
|
|
165
159
|
|-----------|------|----------|-------------|
|
|
166
|
-
| `owner` | string | ✓ | Repository owner |
|
|
167
|
-
| `repo` | string | ✓ | Repository name |
|
|
168
|
-
| `limit` | number | — | Max issues (default: 30, max: 100) |
|
|
169
|
-
| `labels` |
|
|
160
|
+
| `owner` | string | ✓ | Repository owner (e.g., 'dustinbyrne') |
|
|
161
|
+
| `repo` | string | ✓ | Repository name (e.g., 'fusion') |
|
|
162
|
+
| `limit` | number | — | Max issues to show (default: 30, max: 100) |
|
|
163
|
+
| `labels` | array | — | Label names to filter by |
|
|
170
164
|
|
|
171
165
|
## Mission Tools
|
|
172
166
|
|
|
173
167
|
### fn_mission_create
|
|
174
168
|
|
|
175
|
-
Create a new mission — a high-level objective
|
|
169
|
+
Create a new mission — a high-level objective that can span multiple milestones. Missions contain milestones that break down work into phases.
|
|
176
170
|
|
|
177
171
|
| Parameter | Type | Required | Description |
|
|
178
172
|
|-----------|------|----------|-------------|
|
|
179
|
-
| `title` | string | ✓ | Mission title |
|
|
180
|
-
| `description` | string | — | Detailed objectives and context |
|
|
181
|
-
| `autoAdvance` | boolean | — |
|
|
173
|
+
| `title` | string | ✓ | Mission title — brief but descriptive |
|
|
174
|
+
| `description` | string | — | Detailed mission objectives and context |
|
|
175
|
+
| `autoAdvance` | boolean | — | Automatically activate the next pending slice when the current slice completes |
|
|
182
176
|
|
|
183
177
|
### fn_mission_list
|
|
184
178
|
|
|
185
|
-
List all missions with current status.
|
|
179
|
+
List all missions with their current status.
|
|
180
|
+
|
|
181
|
+
No parameters.
|
|
186
182
|
|
|
187
183
|
### fn_mission_show
|
|
188
184
|
|
|
189
|
-
Show mission details with full hierarchy.
|
|
185
|
+
Show mission details with full hierarchy: milestones → slices → features.
|
|
190
186
|
|
|
191
187
|
| Parameter | Type | Required | Description |
|
|
192
188
|
|-----------|------|----------|-------------|
|
|
@@ -194,63 +190,65 @@ Show mission details with full hierarchy.
|
|
|
194
190
|
|
|
195
191
|
### fn_mission_delete
|
|
196
192
|
|
|
197
|
-
Delete a mission and all
|
|
193
|
+
Delete a mission and all its milestones, slices, and features. Cannot be undone.
|
|
198
194
|
|
|
199
195
|
| Parameter | Type | Required | Description |
|
|
200
196
|
|-----------|------|----------|-------------|
|
|
201
|
-
| `id` | string | ✓ | Mission ID |
|
|
197
|
+
| `id` | string | ✓ | Mission ID to delete (e.g., M-001) |
|
|
202
198
|
|
|
203
199
|
### fn_milestone_add
|
|
204
200
|
|
|
205
|
-
Add a milestone to a mission.
|
|
201
|
+
Add a milestone to a mission. Milestones represent phases of work.
|
|
206
202
|
|
|
207
203
|
| Parameter | Type | Required | Description |
|
|
208
204
|
|-----------|------|----------|-------------|
|
|
209
|
-
| `missionId` | string | ✓ | Parent mission ID |
|
|
205
|
+
| `missionId` | string | ✓ | Parent mission ID (e.g., M-001) |
|
|
210
206
|
| `title` | string | ✓ | Milestone title |
|
|
211
207
|
| `description` | string | — | Milestone description |
|
|
212
208
|
|
|
213
209
|
### fn_slice_add
|
|
214
210
|
|
|
215
|
-
Add a slice to a milestone.
|
|
211
|
+
Add a slice to a milestone. Slices are work units that can be activated for implementation.
|
|
216
212
|
|
|
217
213
|
| Parameter | Type | Required | Description |
|
|
218
214
|
|-----------|------|----------|-------------|
|
|
219
|
-
| `milestoneId` | string | ✓ | Parent milestone ID |
|
|
215
|
+
| `milestoneId` | string | ✓ | Parent milestone ID (e.g., MS-001) |
|
|
220
216
|
| `title` | string | ✓ | Slice title |
|
|
221
217
|
| `description` | string | — | Slice description |
|
|
222
218
|
|
|
223
219
|
### fn_feature_add
|
|
224
220
|
|
|
225
|
-
Add a feature to a slice.
|
|
221
|
+
Add a feature to a slice. Features are deliverables that can be linked to tasks.
|
|
226
222
|
|
|
227
223
|
| Parameter | Type | Required | Description |
|
|
228
224
|
|-----------|------|----------|-------------|
|
|
229
|
-
| `sliceId` | string | ✓ | Parent slice ID |
|
|
225
|
+
| `sliceId` | string | ✓ | Parent slice ID (e.g., SL-001) |
|
|
230
226
|
| `title` | string | ✓ | Feature title |
|
|
231
227
|
| `description` | string | — | Feature description |
|
|
232
|
-
| `acceptanceCriteria` | string | — | Acceptance criteria |
|
|
228
|
+
| `acceptanceCriteria` | string | — | Acceptance criteria for completing the feature |
|
|
233
229
|
|
|
234
230
|
### fn_slice_activate
|
|
235
231
|
|
|
236
|
-
Activate a pending slice for implementation.
|
|
232
|
+
Activate a pending slice for implementation. Sets status to 'active' and enables task linking for its features.
|
|
237
233
|
|
|
238
234
|
| Parameter | Type | Required | Description |
|
|
239
235
|
|-----------|------|----------|-------------|
|
|
240
|
-
| `id` | string | ✓ | Slice ID (
|
|
236
|
+
| `id` | string | ✓ | Slice ID to activate (e.g., SL-001) |
|
|
241
237
|
|
|
242
238
|
### fn_feature_link_task
|
|
243
239
|
|
|
244
|
-
Link a feature to a
|
|
240
|
+
Link a feature to a fn task for implementation. Updates the feature status to 'triaged' and associates it with the task.
|
|
245
241
|
|
|
246
242
|
| Parameter | Type | Required | Description |
|
|
247
243
|
|-----------|------|----------|-------------|
|
|
248
|
-
| `featureId` | string | ✓ | Feature ID (e.g., F-001) |
|
|
249
|
-
| `taskId` | string | ✓ | Task ID (e.g., FN-001) |
|
|
244
|
+
| `featureId` | string | ✓ | Feature ID to link (e.g., F-001) |
|
|
245
|
+
| `taskId` | string | ✓ | Task ID to link to (e.g., FN-001) |
|
|
246
|
+
|
|
247
|
+
## Agent Tools
|
|
250
248
|
|
|
251
249
|
### fn_agent_stop
|
|
252
250
|
|
|
253
|
-
Stop
|
|
251
|
+
Stop a running agent — pauses its execution. Transitions the agent from running/active to paused state.
|
|
254
252
|
|
|
255
253
|
| Parameter | Type | Required | Description |
|
|
256
254
|
|-----------|------|----------|-------------|
|
|
@@ -258,7 +256,7 @@ Stop (pause) a running agent. Transitions the agent from running/active to pause
|
|
|
258
256
|
|
|
259
257
|
### fn_agent_start
|
|
260
258
|
|
|
261
|
-
Start
|
|
259
|
+
Start a stopped agent — resumes its execution. Transitions the agent from paused to active state.
|
|
262
260
|
|
|
263
261
|
| Parameter | Type | Required | Description |
|
|
264
262
|
|-----------|------|----------|-------------|
|
|
@@ -268,22 +266,23 @@ Start (resume) a stopped agent. Transitions the agent from paused to active stat
|
|
|
268
266
|
|
|
269
267
|
### fn_skills_search
|
|
270
268
|
|
|
271
|
-
Search the skills.sh directory for agent skills. Returns matching skills with names, sources, install counts, and install commands.
|
|
269
|
+
Search the skills.sh directory for agent skills. Returns matching skills with names, sources (owner/repo), install counts, and install commands. Use fn_skills_install to install a selected skill.
|
|
272
270
|
|
|
273
271
|
| Parameter | Type | Required | Description |
|
|
274
272
|
|-----------|------|----------|-------------|
|
|
275
|
-
| `query` | string | ✓ | Search query — framework, technology, or capability (e.g.,
|
|
276
|
-
| `limit` | number | — | Max results (default: 10, max: 50) |
|
|
273
|
+
| `query` | string | ✓ | Search query — framework name, technology, or capability (e.g., 'react', 'firebase', 'testing', 'docker') |
|
|
274
|
+
| `limit` | number | — | Max results to return (default: 10, max: 50) |
|
|
277
275
|
|
|
278
276
|
### fn_skills_install
|
|
279
277
|
|
|
280
|
-
Install an agent skill from skills.sh into the current project. Downloads skill files into the project's skill directories.
|
|
278
|
+
Install an agent skill from skills.sh into the current project. Downloads skill files into the project's skill directories (.fusion/skills/, legacy .pi/skills/, .agents/skills/). The skill becomes available to AI agents in subsequent sessions.
|
|
281
279
|
|
|
282
280
|
| Parameter | Type | Required | Description |
|
|
283
281
|
|-----------|------|----------|-------------|
|
|
284
|
-
| `source` | string | ✓ | GitHub source in owner/repo format (e.g.,
|
|
285
|
-
| `skill` | string | — | Specific skill name to install. Omit to install all skills from the source. |
|
|
282
|
+
| `source` | string | ✓ | GitHub source in owner/repo format (e.g., 'firebase/agent-skills') |
|
|
283
|
+
| `skill` | string | — | Specific skill name to install (e.g., 'firebase-basics'). Omit to install all skills from the source. |
|
|
286
284
|
|
|
285
|
+
<!-- END: extension-tools -->
|
|
287
286
|
## Dashboard Command
|
|
288
287
|
|
|
289
288
|
### /fn
|
|
@@ -7,40 +7,42 @@ Triage → Todo → In Progress → In Review → Done → Archived
|
|
|
7
7
|
|
|
8
8
|
## Pi Extension Tools (Available to Agents)
|
|
9
9
|
|
|
10
|
-
All skill/extension tool invocations in this catalog use the public `fn_*` namespace. Engine runtime
|
|
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
|
|
|
12
|
+
<!-- BEGIN: fusion-capabilities-tool-table (auto-generated by scripts/sync-fusion-skill-tools.mjs — do not edit by hand) -->
|
|
12
13
|
| Tool | Purpose |
|
|
13
14
|
|------|---------|
|
|
14
|
-
| `fn_task_create` | Create a new task
|
|
15
|
-
| `fn_task_update` | Update task title, description,
|
|
16
|
-
| `fn_task_list` | List all tasks grouped by column |
|
|
17
|
-
| `fn_task_show` | Show full task
|
|
18
|
-
| `fn_task_attach` | Attach a file to a task |
|
|
19
|
-
| `fn_task_pause` | Pause
|
|
20
|
-
| `fn_task_unpause` |
|
|
21
|
-
| `fn_task_retry` | Retry a failed task
|
|
22
|
-
| `fn_task_duplicate` | Duplicate
|
|
23
|
-
| `fn_task_refine` |
|
|
24
|
-
| `fn_task_archive` | Archive a done task |
|
|
25
|
-
| `fn_task_unarchive` |
|
|
26
|
-
| `fn_task_delete` | Permanently delete a task |
|
|
27
|
-
| `fn_task_import_github` |
|
|
28
|
-
| `fn_task_import_github_issue` | Import a
|
|
29
|
-
| `fn_task_browse_github_issues` |
|
|
30
|
-
| `fn_task_plan` | Create task via AI-guided planning mode |
|
|
31
|
-
| `fn_mission_create` | Create a new mission |
|
|
32
|
-
| `fn_mission_list` | List all missions |
|
|
33
|
-
| `fn_mission_show` | Show mission hierarchy |
|
|
34
|
-
| `fn_mission_delete` | Delete a mission |
|
|
35
|
-
| `fn_milestone_add` | Add a milestone to a mission |
|
|
36
|
-
| `fn_slice_add` | Add a slice to a milestone |
|
|
37
|
-
| `fn_feature_add` | Add a feature to a slice |
|
|
38
|
-
| `fn_slice_activate` | Activate a pending slice |
|
|
39
|
-
| `fn_feature_link_task` | Link a feature to a task |
|
|
40
|
-
| `fn_agent_stop` | Stop
|
|
41
|
-
| `fn_agent_start` | Start
|
|
42
|
-
| `fn_skills_search` | Search skills.sh for agent skills |
|
|
43
|
-
| `fn_skills_install` | Install
|
|
15
|
+
| `fn_task_create` | Create a new task on the Fusion task board. The task enters the triage column where the AI triage agent will specify it into a full prompt with steps, file scope, and acceptance criteria. |
|
|
16
|
+
| `fn_task_update` | Update fields on an existing task. Supports modifying the title, description, dependencies, and assigned agent after task creation. |
|
|
17
|
+
| `fn_task_list` | List all tasks on the Fusion board, grouped by column. |
|
|
18
|
+
| `fn_task_show` | Show full details for a task including steps, progress, and log entries. |
|
|
19
|
+
| `fn_task_attach` | Attach a file to a task. Supports images (png, jpg, gif, webp) and text files (txt, log, json, yaml, yml, toml, csv, xml). |
|
|
20
|
+
| `fn_task_pause` | Pause a task — stops all automated agent and scheduler interaction for this task. |
|
|
21
|
+
| `fn_task_unpause` | Unpause a task — resumes automated agent and scheduler interaction. |
|
|
22
|
+
| `fn_task_retry` | Retry a failed task — clears the error state and moves it back to the todo column for re-execution. |
|
|
23
|
+
| `fn_task_duplicate` | Duplicate an existing task, creating a fresh copy in triage. Copies the title and description but resets all execution state. The AI triage agent will re-specify the new task. |
|
|
24
|
+
| `fn_task_refine` | Request a refinement of a completed or in-review task. Creates a new follow-up task in triage that references the original task as a dependency. Use this when a done or in-review task needs additional work, improvements, or follow-up changes. |
|
|
25
|
+
| `fn_task_archive` | Archive a done task (move from done → archived). Archived tasks are preserved for historical reference but moved out of the main board view. |
|
|
26
|
+
| `fn_task_unarchive` | Unarchive an archived task (move from archived → done). Restores the task to the done column. |
|
|
27
|
+
| `fn_task_delete` | Permanently delete a task from the Fusion board. Tasks are deleted immediately and cannot be recovered. |
|
|
28
|
+
| `fn_task_import_github` | Import GitHub issues as Fusion tasks. Fetches open issues from a repository and creates tasks in the triage column. Each task includes the issue title and body with a link to the source issue. |
|
|
29
|
+
| `fn_task_import_github_issue` | Import a specific GitHub issue as a Fusion task. Fetches the issue by number and creates a single task in the triage column with the issue title and body. |
|
|
30
|
+
| `fn_task_browse_github_issues` | List open GitHub issues from a repository to browse before importing. Returns issue numbers, titles, and URLs for selection. Use with fn_task_import_github_issue to import specific issues by number. |
|
|
31
|
+
| `fn_task_plan` | Create a task via AI-guided planning mode — interactive conversation to refine your idea into a well-specified task. |
|
|
32
|
+
| `fn_mission_create` | Create a new mission — a high-level objective that can span multiple milestones. Missions contain milestones that break down work into phases. |
|
|
33
|
+
| `fn_mission_list` | List all missions with their current status. |
|
|
34
|
+
| `fn_mission_show` | Show mission details with full hierarchy: milestones → slices → features. |
|
|
35
|
+
| `fn_mission_delete` | Delete a mission and all its milestones, slices, and features. Cannot be undone. |
|
|
36
|
+
| `fn_milestone_add` | Add a milestone to a mission. Milestones represent phases of work. |
|
|
37
|
+
| `fn_slice_add` | Add a slice to a milestone. Slices are work units that can be activated for implementation. |
|
|
38
|
+
| `fn_feature_add` | Add a feature to a slice. Features are deliverables that can be linked to tasks. |
|
|
39
|
+
| `fn_slice_activate` | Activate a pending slice for implementation. Sets status to 'active' and enables task linking for its features. |
|
|
40
|
+
| `fn_feature_link_task` | Link a feature to a fn task for implementation. Updates the feature status to 'triaged' and associates it with the task. |
|
|
41
|
+
| `fn_agent_stop` | Stop a running agent — pauses its execution. Transitions the agent from running/active to paused state. |
|
|
42
|
+
| `fn_agent_start` | Start a stopped agent — resumes its execution. Transitions the agent from paused to active state. |
|
|
43
|
+
| `fn_skills_search` | Search the skills.sh directory for agent skills. Returns matching skills with names, sources (owner/repo), install counts, and install commands. Use fn_skills_install to install a selected skill. |
|
|
44
|
+
| `fn_skills_install` | Install an agent skill from skills.sh into the current project. Downloads skill files into the project's skill directories (.fusion/skills/, legacy .pi/skills/, .agents/skills/). The skill becomes available to AI agents in subsequent sessions. |
|
|
45
|
+
<!-- END: fusion-capabilities-tool-table -->
|
|
44
46
|
|
|
45
47
|
## CLI Commands (fn)
|
|
46
48
|
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Runfusion
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as s,j as e}from"./vendor-react-K0fH_qHe.js";import{i as Le,ax as lt,g as ct,ay as rt,a as ot,az as dt,aA as ut,aB as ht,aC as mt,aD as gt,aE as ft,s as pt,aF as xt,aG as St,f as vt,w as Pe,S as bt,I as Be,aj as wt,aH as Nt,B as Ce,aI as kt,aJ as Ct,aK as Mt,aL as jt,aM as yt,aN as Tt,h as At,j as $t}from"./index-rNf7s96d.js";import"./vendor-xterm-DzcZoU0P.js";const Re="kb-chat-active-session";function Dt(n){const i=n?.toolCalls;if(!Array.isArray(i))return;const r=i.map(l=>{if(!l||typeof l!="object")return null;const c=l,x=typeof c.toolName=="string"?c.toolName:"";if(!x)return null;const b=c.args;return{toolName:x,...b&&typeof b=="object"?{args:b}:{},isError:!!c.isError,result:c.result,status:"completed"}}).filter(l=>l!==null);return r.length>0?r:void 0}function He(n){return{id:n.id,sessionId:n.sessionId,role:n.role,content:n.content,thinkingOutput:n.thinkingOutput,toolCalls:Dt(n.metadata),createdAt:n.createdAt}}function Et(n){const[i,r]=s.useState([]),[l,c]=s.useState(null),[x,b]=s.useState(!0),[M,w]=s.useState([]),[X,z]=s.useState(!1),[O,L]=s.useState(!1),[re,D]=s.useState(""),[V,T]=s.useState(""),[pe,E]=s.useState([]),[S,P]=s.useState(""),[Z,U]=s.useState(""),[A,B]=s.useState(!0),[q,ne]=s.useState(new Map),k=s.useRef(null),J=s.useRef(!1),K=s.useRef(""),xe=s.useRef(i),H=s.useRef(l),we=s.useRef(O);xe.current=i,H.current=l,we.current=O,s.useEffect(()=>{K.current=S},[S]);const ae=s.useRef(new Set),ee=s.useRef(0),Ne=s.useRef(n);Ne.current!==n&&(Ne.current=n,ee.current++),s.useEffect(()=>{const o=ee.current;Le(void 0,n).then(h=>{if(ee.current!==o)return;const u=new Map;for(const N of h)u.set(N.id,N);ne(u)}).catch(()=>{})},[n]);const te=s.useCallback(async()=>{b(!0);try{const h=[...(await lt(n)).sessions].sort((u,N)=>new Date(N.updatedAt).getTime()-new Date(u.updatedAt).getTime());r(h)}catch{}finally{b(!1)}},[n]);s.useEffect(()=>{te()},[te]);const Q=s.useRef(()=>{});s.useEffect(()=>{if(x)return;const o=ct(Re,n);o&&i.find(u=>u.id===o)&&Q.current(o)},[x,i,n]);const I=s.useCallback(async(o,h)=>{z(!0);try{const u=await rt(o,{limit:50,...h},n),N=u.messages.map(He);h?.offset&&h.offset>0?w(W=>[...N,...W]):w(N),B(u.messages.length>=50)}catch{}finally{z(!1)}},[n]),oe=s.useCallback(o=>{k.current&&(k.current.close(),k.current=null);const h=i.find(u=>u.id===o);c(h||null),D(""),T(""),E([]),L(!1),B(!0),o?I(o):w([]),o?ot(Re,o,n):dt(Re,n)},[i,I,n]);Q.current=oe;const de=s.useCallback(async o=>{const h=await ut(o,n),u={id:h.session.id,title:h.session.title,agentId:h.session.agentId,status:h.session.status,modelProvider:h.session.modelProvider,modelId:h.session.modelId,createdAt:h.session.createdAt,updatedAt:h.session.updatedAt};return r(N=>[u,...N]),c(u),w([]),D(""),T(""),E([]),L(!1),B(!0),u},[n]),ue=s.useCallback(async o=>{await ht(o,{status:"archived"},n),r(h=>h.filter(u=>u.id!==o)),l?.id===o&&(c(null),w([]))},[l,n]),ie=s.useCallback(async o=>{l?.id===o&&k.current&&(k.current.close(),k.current=null),await mt(o,n),r(h=>h.filter(u=>u.id!==o)),l?.id===o&&(c(null),w([]))},[l,n]),he=s.useCallback(async()=>{!l||!A||await I(l.id,{offset:M.length})},[l,A,I,M.length]),se=s.useCallback(()=>{l&&(J.current=!0,k.current?.close(),k.current=null,gt(l.id,n).catch(()=>{}),L(!1),D(""),T(""),E([]))},[l,n]),_=s.useCallback(()=>{K.current="",P("")},[]),G=s.useCallback(o=>{if(!l)return;if(O){K.current=o,P(o);return}J.current=!1,k.current&&(k.current.close(),k.current=null);const h=`temp-${Date.now()}`,u={id:h,sessionId:l.id,role:"user",content:o,createdAt:new Date().toISOString()};w(p=>[...p,u]),D(""),T(""),E([]),L(!0);let N="",W="",R=[];const m={onThinking:p=>{W+=p,T(W)},onText:p=>{N+=p,D(N)},onToolStart:p=>{R=[...R,{toolName:p.toolName,args:p.args,isError:!1,status:"running"}],E(R)},onToolEnd:p=>{const C=[...R];for(let g=C.length-1;g>=0;g--){const v=C[g];if(v?.toolName===p.toolName&&v.status==="running"){C[g]={...v,status:"completed",isError:p.isError,result:p.result},R=C,E(C);return}}R=[...C,{toolName:p.toolName,isError:p.isError,result:p.result,status:"completed"}],E(R)},onDone:p=>{const C={id:p.messageId||`msg-${Date.now()}`,sessionId:l.id,role:"assistant",content:N,thinkingOutput:W,toolCalls:R.length>0?R:void 0,createdAt:new Date().toISOString()};ae.current.add(C.id),w(v=>[...v,C]),D(""),T(""),E([]),L(!1),k.current=null,setTimeout(()=>{ae.current.delete(C.id)},1e3),te();const g=K.current.trim();g&&(K.current="",P(""),G(g))},onError:p=>{if(w(C=>C.filter(g=>g.id!==h)),D(""),T(""),E([]),L(!1),k.current=null,console.error("[useChat] Stream error:",p),!J.current){const C=K.current.trim();C&&(K.current="",P(""),G(C))}}};k.current=ft(l.id,o,m,n)},[l,O,n,te]),Se=Z?i.filter(o=>o.title?.toLowerCase().includes(Z.toLowerCase())||o.agentId.toLowerCase().includes(Z.toLowerCase())):i;return s.useEffect(()=>{const o=ee.current,h=n?`?projectId=${encodeURIComponent(n)}`:"",u=()=>ee.current!==o,N=g=>{if(u())return;const v=JSON.parse(g.data);r(f=>f.some(j=>j.id===v.id)?f:[v,...f])},W=g=>{if(u())return;const v=JSON.parse(g.data);r(f=>[...f.map(ve=>ve.id===v.id?v:ve)]),H.current?.id===v.id&&c(v)},R=g=>{if(u())return;const{id:v}=JSON.parse(g.data);r(f=>f.filter(j=>j.id!==v)),H.current?.id===v&&(c(null),w([]))},m=g=>{if(u())return;const v=JSON.parse(g.data),f=He(v);ae.current.has(f.id)||H.current?.id===f.sessionId&&!we.current&&w(j=>j.some(ve=>ve.id===f.id)?j:[...j,f])},p=g=>{if(u())return;const{id:v}=JSON.parse(g.data);w(f=>f.filter(j=>j.id!==v))};return pt(`/api/events${h}`,{events:{"chat:session:created":N,"chat:session:updated":W,"chat:session:deleted":R,"chat:message:added":m,"chat:message:deleted":p}})},[n]),s.useEffect(()=>()=>{k.current&&(k.current.close(),k.current=null)},[]),{sessions:i,activeSession:l,sessionsLoading:x,messages:M,messagesLoading:X,isStreaming:O,streamingText:re,streamingThinking:V,streamingToolCalls:pe,pendingMessage:S,selectSession:oe,createSession:de,archiveSession:ue,deleteSession:ie,sendMessage:G,stopStreaming:se,clearPendingMessage:_,loadMoreMessages:he,hasMoreMessages:A,searchQuery:Z,setSearchQuery:U,filteredSessions:Se,refreshSessions:te,agentsMap:q}}function _e(n){const i=new Date(n),l=new Date().getTime()-i.getTime(),c=Math.floor(l/1e3),x=Math.floor(c/60),b=Math.floor(x/60),M=Math.floor(b/24);return c<60?"just now":x<60?`${x}m ago`:b<24?`${b}h ago`:M<7?`${M}d ago`:i.toLocaleDateString()}function Ge(n,i){if(!n||!i)return null;const r=i.toLowerCase();if(r.includes("claude")){let c=i.replace(/^claude[- ]/i,"Claude ").replace(/sonnet[- ](\d+)[- ](\d+)/i,"Sonnet $1.$2").replace(/sonnet[- ](\d+)/i,"Sonnet $1").replace(/haiku[- ](\d+)/i,"Haiku $1").replace(/opus[- ](\d+)/i,"Opus $1").replace(/sonnet/i,"Sonnet").replace(/haiku/i,"Haiku").replace(/opus/i,"Opus").replace(/-/g," ").trim();return c=c.replace(/\s+/g," "),c.length>30?c.slice(0,30)+"…":c}if(r.includes("gpt")||r.includes("openai")){const c=i.replace(/^gpt-4-turbo$/i,"GPT-4 Turbo").replace(/^gpt-4o-mini$/i,"GPT-4o Mini").replace(/^gpt-4o$/i,"GPT-4o").replace(/^gpt-4$/i,"GPT-4").replace(/^gpt-o1-preview$/i,"GPT-o1 Preview").replace(/^gpt-o1-mini$/i,"GPT-o1 Mini").replace(/^gpt-o1$/i,"GPT-o1").replace(/^gpt/i,"GPT").trim();return c.length>30?c.slice(0,30)+"…":c}if(r.includes("gemini")){const c=i.replace(/^gemini[- ]/i,"Gemini ").replace(/pro[- ](\d+)[- ](\d+)/i,"Pro $1.$2").replace(/pro[- ](\d+)/i,"Pro $1").replace(/-/g," ").replace(/\s+/g," ").trim();return c.length>30?c.slice(0,30)+"…":c}const l=i.replace(/-/g," ").replace(/^\w/,c=>c.toUpperCase()).replace(/\s+/g," ").trim();return l.length>30?l.slice(0,30)+"…":l}function Me(n,i){return n.length>i?`${n.slice(0,i)}…`:n}function Pt(n){if(!n)return null;const i=Object.entries(n);return i.length===0?null:i.map(([r,l])=>{let c="";if(typeof l=="string")c=l;else try{c=JSON.stringify(l)}catch{c=String(l)}return`${r}=${Me(c,50)}`}).join(", ")}function Rt(n){if(n===void 0)return null;if(typeof n=="string")return Me(n,200);try{return Me(JSON.stringify(n),200)}catch{return Me(String(n),200)}}function Ue(n){return!n||n.length===0?null:e.jsxs("div",{className:"chat-tool-calls","data-testid":"chat-tool-calls",children:[e.jsxs("div",{className:"chat-tool-calls-header",children:[e.jsx(Tt,{size:12,"aria-hidden":"true"}),e.jsx("span",{children:"Tool calls"})]}),n.map((i,r)=>{const l=i.status==="running",c=i.status==="completed"&&i.isError,x=Pt(i.args),b=Rt(i.result),M=l?x:b?`result: ${b}`:x?`args: ${x}`:null,w=l?"running":c?"error":"completed";return e.jsxs("details",{className:`chat-tool-call${l?" chat-tool-call--running":""}${c?" chat-tool-call--error":""}`,open:l,children:[e.jsxs("summary",{children:[e.jsx("span",{className:"chat-tool-call-status-dot","aria-hidden":"true"}),e.jsx("span",{className:"chat-tool-call-name",children:i.toolName}),M&&e.jsx("span",{className:"chat-tool-call-preview",title:M,children:M}),e.jsx("span",{className:"chat-tool-call-status-text",children:w})]}),e.jsxs("div",{className:"chat-tool-call-content",children:[x&&e.jsxs("div",{className:"chat-tool-call-row",children:[e.jsx("span",{className:"chat-tool-call-label",children:"args"}),e.jsx("span",{className:"chat-tool-call-value",children:x})]}),b&&e.jsxs("div",{className:`chat-tool-call-row${c?" chat-tool-call-row--error":""}`,children:[e.jsx("span",{className:"chat-tool-call-label",children:"result"}),e.jsx("span",{className:"chat-tool-call-value",children:b})]})]})]},`${i.toolName}-${r}`)})]})}const je="__fn_agent__";function qe(n){const i=/(^|[\s])\/([^\s]*)$/.exec(n);if(!i)return null;const r=i[1]??"",l=i[2]??"",c=i.index+r.length;return{filter:l,start:c,end:n.length}}function Lt(n,i){const r=n.slice(0,i),l=/(^|[\s\n])@([\w-]*)$/.exec(r);if(!l)return null;const c=l[2]??"",x=r.length-c.length-1;return{filter:c,start:x,end:i}}function It({projectId:n,onClose:i,onCreate:r}){const[l,c]=s.useState("agent"),[x,b]=s.useState([]),[M,w]=s.useState(!0),[X,z]=s.useState(""),[O,L]=s.useState([]),[re,D]=s.useState(!0),[V,T]=s.useState("");s.useEffect(()=>{let S=!1;return w(!0),Le(void 0,n).then(P=>{S||b(P)}).catch(()=>{S||b([])}).finally(()=>{S||w(!1)}),()=>{S=!0}},[n]),s.useEffect(()=>{D(!0),At().then(S=>{L(S.models)}).catch(()=>{L([])}).finally(()=>{D(!1)})},[]);const pe=S=>{if(S.preventDefault(),l==="agent"){if(!X)return;r({agentId:X});return}if(!V)return;const P=V.indexOf("/");if(P<=0)return;const Z=V.slice(0,P),U=V.slice(P+1);r({agentId:je,modelProvider:Z,modelId:U})},E=l==="agent"?!X:!V;return e.jsx("div",{className:"chat-new-dialog-backdrop",onClick:i,role:"dialog","aria-modal":"true",children:e.jsxs("div",{className:"chat-new-dialog",onClick:S=>S.stopPropagation(),children:[e.jsx("h3",{children:"New Chat"}),e.jsxs("div",{className:"chat-new-dialog-mode-toggle","data-testid":"chat-new-dialog-mode-toggle",children:[e.jsx("button",{type:"button",className:`chat-new-dialog-mode-btn${l==="agent"?" chat-new-dialog-mode-btn--active":""}`,"data-testid":"chat-new-dialog-mode-agent",onClick:()=>{c("agent"),T("")},children:"Agent"}),e.jsx("button",{type:"button",className:`chat-new-dialog-mode-btn${l==="model"?" chat-new-dialog-mode-btn--active":""}`,"data-testid":"chat-new-dialog-mode-model",onClick:()=>{c("model"),z("")},children:"Model"})]}),e.jsxs("form",{onSubmit:pe,children:[l==="agent"&&e.jsxs("label",{className:"chat-new-dialog-model-label",children:["Agent",M?e.jsx("div",{className:"chat-new-dialog-loading",children:"Loading agents..."}):x.length===0?e.jsx("div",{className:"chat-new-dialog-empty",children:"No agents available"}):e.jsx("div",{className:"chat-new-dialog-agent-list",children:x.map(S=>e.jsxs("button",{type:"button",className:`chat-new-dialog-agent-item${X===S.id?" chat-new-dialog-agent-item--selected":""}`,onClick:()=>z(S.id),"data-testid":`agent-option-${S.id}`,children:[e.jsx(Ce,{size:16}),e.jsx("span",{className:"chat-new-dialog-agent-name",children:S.name}),e.jsx("span",{className:"chat-new-dialog-agent-role",children:S.role})]},S.id))})]}),l==="model"&&e.jsx("div",{className:"chat-new-dialog-model-dropdown","data-testid":"chat-new-dialog-model-section",children:re?e.jsx("div",{className:"chat-new-dialog-loading",children:"Loading models..."}):e.jsx($t,{models:O,value:V,onChange:T,label:"Model",placeholder:"Select a model"})}),e.jsxs("div",{className:"chat-new-dialog-actions",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:i,children:"Cancel"}),e.jsx("button",{type:"submit",className:"btn btn-sm btn-primary",disabled:E,children:"Create"})]})]})]})})}function Vt({projectId:n,addToast:i}){const{activeSession:r,sessionsLoading:l,messages:c,messagesLoading:x,isStreaming:b,streamingText:M,streamingThinking:w,streamingToolCalls:X,selectSession:z,createSession:O,archiveSession:L,deleteSession:re,sendMessage:D,stopStreaming:V,pendingMessage:T,clearPendingMessage:pe,searchQuery:E,setSearchQuery:S,filteredSessions:P}=Et(n),[Z,U]=s.useState(!1),[A,B]=s.useState(""),[q,ne]=s.useState(null),[k,J]=s.useState(null),[K,xe]=s.useState(!0),[H,we]=s.useState(new Map),[ae,ee]=s.useState([]),[Ne,te]=s.useState(!0),[Q,I]=s.useState(!1),[oe,de]=s.useState(""),[ue,ie]=s.useState(0),[he,se]=s.useState(""),[_,G]=s.useState(!1),[Se,o]=s.useState(0),[h,u]=s.useState(-1),[,N]=s.useState(!1),[W,R]=s.useState({top:0,left:0}),m=xt({projectId:n}),p=s.useCallback(t=>{if(!t||!m.mentionActive)return;const a=t.getBoundingClientRect();R({top:a.top-260,left:a.left+8})},[m.mentionActive]),C=s.useRef(null),g=s.useRef(null),v=s.useRef(null),f=s.useRef(null),j=s.useRef(0),me=St()==="mobile",F=s.useMemo(()=>{const t=oe.trim().toLowerCase();return(t?ae.filter(d=>d.name.toLowerCase().includes(t)):ae).slice(0,10)},[ae,oe]),ge=s.useMemo(()=>Array.from(H.values()),[H]),le=s.useMemo(()=>{const t=he.trim().toLowerCase();return t?ge.filter(a=>a.name.toLowerCase().includes(t)):ge},[ge,he]),Ie=s.useMemo(()=>{const t=new Map;for(const a of ge)t.set(a.name.toLowerCase(),a);return t},[ge]);s.useEffect(()=>{ie(0)},[F]),s.useEffect(()=>{o(0)},[he,_]),s.useEffect(()=>()=>{g.current!==null&&window.clearTimeout(g.current)},[]),s.useEffect(()=>{C.current?.scrollIntoView({behavior:"smooth"})},[c,M]),s.useEffect(()=>{const t=()=>ne(null);if(q)return document.addEventListener("click",t),()=>document.removeEventListener("click",t)},[q]),s.useEffect(()=>{let t=!1;const a=n;return Le(void 0,n).then(d=>{if(t||a!==n)return;const y=new Map;for(const $ of d)y.set($.id,$);we(y)}).catch(()=>{}),()=>{t=!0}},[n]),s.useEffect(()=>{let t=!1;return te(!0),vt(n).then(a=>{t||ee(a)}).catch(()=>{t||ee([])}).finally(()=>{t||te(!1)}),()=>{t=!0}},[n]);const Je=s.useCallback(async t=>{try{await O(t),U(!1),me&&xe(!1)}catch{i("Failed to create chat session","error")}},[O,i,me]),ye=s.useCallback(()=>{const t=A.trim();!t||!r||(B(""),I(!1),de(""),G(!1),se(""),u(-1),D(t))},[A,r,D]),Te=s.useCallback(t=>{B(a=>{const d=qe(a);if(!d)return a;const y=`/skill:${t.name} `,$=a.slice(0,d.start)+y+a.slice(d.end);return window.requestAnimationFrame(()=>{f.current&&(f.current.style.height="auto",f.current.style.height=`${Math.min(f.current.scrollHeight,120)}px`,f.current.focus())}),$}),I(!1),de(""),ie(0)},[]),Ae=s.useCallback(t=>{const a=f.current;if(!a||h<0)return;const d=a.selectionStart??j.current,y=a.selectionEnd??d,$=Math.max(d,y),be=Math.min(h,$),ce=`${`@${t.name.replace(/\s+/g,"_")}`} `,Ee=A.slice(0,be)+ce+A.slice($),fe=be+ce.length;B(Ee),G(!1),se(""),o(0),u(-1),window.requestAnimationFrame(()=>{f.current&&(f.current.style.height="auto",f.current.style.height=`${Math.min(f.current.scrollHeight,120)}px`,f.current.focus(),f.current.setSelectionRange(fe,fe))})},[h,A]),Fe=s.useCallback(t=>{const a=/@([\w-]+)/g,d=[];let y=0,$=a.exec(t);for(;$;){const[be,Ve=""]=$,ce=$.index;ce>y&&d.push(t.slice(y,ce));const Ee=Ve.replace(/_/g," ").toLowerCase(),fe=Ie.get(Ee);fe?d.push(e.jsxs("span",{className:"chat-mention-chip",children:["@",fe.name.replace(/\s+/g,"_")]},`${fe.id}-${ce}`)):d.push(be),y=ce+be.length,$=a.exec(t)}return y<t.length&&d.push(t.slice(y)),d.length===0?t:d},[Ie]),Ke=s.useCallback(t=>{if(j.current=t.currentTarget.selectionStart??j.current,m.mentionActive&&m.files.length>0){if(m.handleKeyDown(t,A),t.key==="Enter"||t.key==="Tab"){const a=m.files[m.selectedIndex];if(a){const d=m.selectFile(a,A);B(d),m.dismissMention(),N(!1)}}return}if(_&&t.key==="ArrowDown"){t.preventDefault(),le.length>0&&o(a=>(a+1)%le.length);return}if(_&&t.key==="ArrowUp"){t.preventDefault(),le.length>0&&o(a=>a===0?le.length-1:a-1);return}if(_&&t.key==="Enter"){t.preventDefault();const a=le[Se]??le[0];a&&Ae(a);return}if(_&&t.key==="Escape"){t.preventDefault(),G(!1),se(""),u(-1);return}if(Q&&t.key==="ArrowDown"){t.preventDefault(),F.length>0&&ie(a=>(a+1)%F.length);return}if(Q&&t.key==="ArrowUp"){t.preventDefault(),F.length>0&&ie(a=>a===0?F.length-1:a-1);return}if(Q&&(t.key==="Enter"||t.key==="Tab")&&F.length>0){t.preventDefault();const a=F[ue]??F[0];a&&Te(a);return}if(Q&&t.key==="Escape"){t.preventDefault(),I(!1);return}t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),ye())},[_,le,Se,Ae,Q,F,ue,Te,ye,m,A]),ke=s.useCallback((t,a)=>{const d=Lt(t,a);if(d){G(!0),se(d.filter),u(d.start);return}G(!1),se(""),u(-1)},[]),Qe=s.useCallback(t=>{const a=t.target,d=a.value,y=a.selectionStart??d.length;j.current=y,B(d);const $=qe(d);$?(I(!0),de($.filter)):(I(!1),de("")),ke(d,y),m.detectMention(d,y),N(m.mentionActive),m.mentionActive&&p(a),a.style.height="auto",a.style.height=`${Math.min(a.scrollHeight,120)}px`},[ke]),$e=s.useCallback(t=>{const a=t.currentTarget,d=a.selectionStart??a.value.length;j.current=d,ke(a.value,d),m.detectMention(a.value,d),N(m.mentionActive),m.mentionActive&&p(a)},[ke,m,p]),We=s.useCallback(t=>{t.key!=="Escape"&&$e(t)},[$e]),Ye=s.useCallback(()=>{g.current!==null&&window.clearTimeout(g.current),g.current=window.setTimeout(()=>{I(!1),G(!1),se(""),u(-1),N(!1),m.dismissMention(),g.current=null},120)},[m]),Xe=s.useCallback(()=>{g.current!==null&&(window.clearTimeout(g.current),g.current=null)},[]),Ze=s.useCallback(async t=>{ne(null);try{await L(t),i("Conversation archived","success")}catch{i("Failed to archive conversation","error")}},[L,i]),et=s.useCallback(async t=>{J(null),ne(null);try{await re(t),i("Conversation deleted","success")}catch{i("Failed to delete conversation","error")}},[re,i]),tt=s.useCallback(t=>{z(t),me&&xe(!1)},[z,me]),st=s.useCallback(()=>{z(""),xe(!0)},[z]),nt=()=>e.jsxs("div",{className:"chat-empty-state",children:[e.jsx(yt,{size:48,strokeWidth:1.5}),e.jsx("h2",{children:"Start a new conversation"}),e.jsxs("button",{className:"btn btn-primary",onClick:()=>U(!0),children:[e.jsx(Pe,{size:16}),"New Chat"]})]}),Y=Ge(r?.modelProvider,r?.modelId),ze=r?.agentId===je?Y??"Fusion":r?.title||H.get(r?.agentId??"")?.name||r?.agentId||"Chat",at=!!(Y&&Y!==ze),De=H.get(r?.agentId??"")?.name||(r?.agentId===je?Y??"Fusion":r?.agentId?.slice(0,30)??"Fusion"),Oe=!!(Y&&Y!==De),it=T.length>50?`${T.slice(0,50)}…`:T;return e.jsxs("div",{className:"chat-view",children:[e.jsxs("div",{className:`chat-sidebar${K?"":" chat-sidebar--hidden"}`,children:[e.jsx("div",{className:"chat-sidebar-header",children:e.jsxs("button",{className:"btn btn-sm btn-primary",onClick:()=>U(!0),"data-testid":"chat-new-btn",children:[e.jsx(Pe,{size:14}),"New Chat"]})}),e.jsx("div",{className:"chat-sidebar-search",children:e.jsxs("div",{className:"chat-sidebar-search-wrapper",children:[e.jsx(bt,{size:14,className:"chat-sidebar-search-icon"}),e.jsx("input",{type:"text",className:"chat-sidebar-search",placeholder:"Search conversations...",value:E,onChange:t=>S(t.target.value),"data-testid":"chat-search-input"})]})}),e.jsx("div",{className:"chat-session-list chat-sidebar-list",children:l?e.jsx("div",{style:{padding:"12px",color:"var(--text-secondary)",fontSize:"13px"},children:"Loading..."}):P.length===0?e.jsx("div",{style:{padding:"12px",color:"var(--text-secondary)",fontSize:"13px"},children:"No conversations yet"}):P.map(t=>e.jsxs("div",{className:`chat-session-item${r?.id===t.id?" chat-session-item--active":""}`,onClick:()=>tt(t.id),onContextMenu:a=>{a.preventDefault(),ne({sessionId:t.id,x:a.clientX,y:a.clientY})},"data-testid":`chat-session-${t.id}`,children:[e.jsx("button",{className:"chat-session-delete-btn",onClick:a=>{a.stopPropagation(),J(t.id)},"data-testid":"chat-session-delete-btn","aria-label":"Delete conversation",children:e.jsx(Be,{size:14})}),e.jsx("div",{className:"chat-session-title",children:t.title||"Untitled"}),e.jsx("div",{className:"chat-session-preview",children:t.lastMessagePreview||"No messages"}),e.jsxs("div",{className:"chat-session-meta",children:[e.jsx("span",{children:H.get(t.agentId)?.name||(t.agentId===je?Ge(t.modelProvider,t.modelId)??"Fusion":t.agentId.slice(0,30))}),e.jsx("span",{children:t.updatedAt?_e(t.updatedAt):""})]})]},t.id))}),e.jsx("div",{className:"chat-sidebar-footer",children:e.jsxs("button",{className:"btn btn-sm btn-primary chat-sidebar-footer-btn",onClick:()=>U(!0),"data-testid":"chat-new-btn-mobile",children:[e.jsx(Pe,{size:14}),"New Chat"]})})]}),q&&e.jsxs("div",{className:"chat-session-context-menu",style:{top:q.y,left:q.x},onClick:t=>t.stopPropagation(),children:[e.jsxs("button",{onClick:()=>Ze(q.sessionId),"data-testid":"chat-context-archive",children:[e.jsx(wt,{size:14}),"Archive"]}),e.jsxs("button",{onClick:()=>{ne(null),J(q.sessionId)},"data-testid":"chat-context-delete",children:[e.jsx(Be,{size:14}),"Delete"]})]}),k&&e.jsx("div",{className:"chat-new-dialog-backdrop",onClick:()=>J(null),children:e.jsxs("div",{className:"chat-new-dialog",onClick:t=>t.stopPropagation(),children:[e.jsx("h3",{children:"Delete Conversation?"}),e.jsx("p",{style:{fontSize:"14px",color:"var(--text-secondary)",marginBottom:"16px"},children:"This action cannot be undone. All messages in this conversation will be permanently deleted."}),e.jsxs("div",{className:"chat-new-dialog-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:()=>J(null),children:"Cancel"}),e.jsx("button",{className:"btn btn-sm btn-danger",onClick:()=>void et(k),children:"Delete"})]})]})}),e.jsxs("div",{className:"chat-thread",children:[(r||!me)&&e.jsxs("div",{className:"chat-thread-header",children:[me&&r&&e.jsx("button",{className:"btn-icon",onClick:st,"data-testid":"chat-back-btn",children:e.jsx(Nt,{size:16})}),e.jsx(Ce,{size:16}),e.jsx("span",{className:"chat-thread-header-title",children:ze}),at&&e.jsx("span",{className:"chat-model-tag",children:Y})]}),e.jsxs("div",{className:"chat-messages",ref:v,children:[x?e.jsx("div",{style:{color:"var(--text-secondary)",fontSize:"13px"},children:"Loading messages..."}):c.length===0&&!r?nt():c.length===0&&r?e.jsx("div",{style:{color:"var(--text-secondary)",fontSize:"13px"},children:"No messages yet. Start the conversation!"}):e.jsxs(e.Fragment,{children:[c.map(t=>e.jsxs("div",{className:`chat-message chat-message--${t.role}`,"data-testid":`chat-message-${t.id}`,children:[t.role==="assistant"&&e.jsxs("div",{className:"chat-message-avatar",children:[e.jsx(Ce,{size:14}),e.jsx("span",{children:De}),Oe&&e.jsx("span",{className:"chat-model-tag",children:Y})]}),e.jsx("div",{className:"chat-message-content",children:Fe(t.content)}),Ue(t.toolCalls),t.thinkingOutput&&e.jsxs("details",{className:"chat-message-thinking",children:[e.jsx("summary",{children:"Thinking"}),e.jsx("pre",{className:"chat-message-thinking-content",children:t.thinkingOutput})]}),e.jsx("div",{className:"chat-message-time",children:_e(t.createdAt)})]},t.id)),b&&e.jsxs("div",{className:"chat-message chat-message--assistant chat-message--streaming",children:[e.jsxs("div",{className:"chat-message-avatar",children:[e.jsx(Ce,{size:14}),e.jsx("span",{children:De}),Oe&&e.jsx("span",{className:"chat-model-tag",children:Y})]}),M?e.jsx("div",{className:"chat-message-content",children:Fe(M)}):e.jsx("div",{className:"chat-message-content chat-message-content--waiting",children:w?"Thinking…":"Connecting…"}),Ue(X),w&&e.jsxs("details",{className:"chat-message-thinking",children:[e.jsx("summary",{children:"Thinking"}),e.jsx("pre",{className:"chat-message-thinking-content",children:w})]}),e.jsxs("div",{className:"chat-typing-indicator",children:[e.jsx("span",{}),e.jsx("span",{}),e.jsx("span",{})]})]})]}),e.jsx("div",{ref:C})]}),r&&e.jsxs("div",{className:"chat-input-area",children:[Q&&e.jsx("div",{className:"chat-skill-menu","data-testid":"chat-skill-menu",role:"listbox","aria-label":"Skill suggestions",children:Ne?e.jsx("div",{className:"chat-skill-menu-empty",children:"Loading skills…"}):F.length===0?e.jsx("div",{className:"chat-skill-menu-empty",children:oe?"No skills found":"No skills available"}):F.map((t,a)=>e.jsxs("button",{type:"button",role:"option","aria-selected":a===ue,className:`chat-skill-menu-item${a===ue?" chat-skill-menu-item--highlighted":""}`,onMouseDown:d=>d.preventDefault(),onMouseEnter:()=>ie(a),onClick:()=>Te(t),children:[e.jsx("span",{className:"chat-skill-menu-item-name",children:t.name}),e.jsx("span",{className:"chat-skill-menu-item-description",title:t.relativePath,children:t.relativePath})]},t.id))}),e.jsxs("div",{className:"chat-input-wrapper",children:[e.jsx("textarea",{ref:f,className:"chat-input-textarea",placeholder:"Type a message...",value:A,onChange:Qe,onKeyDown:Ke,onKeyUp:We,onClick:$e,onBlur:Ye,onFocus:Xe,rows:1,"data-testid":"chat-input"}),e.jsx(kt,{agents:ge,filter:he,highlightedIndex:Se,visible:_,onSelect:Ae,position:"below"}),e.jsx(Ct,{visible:m.mentionActive&&!_,position:W,files:m.files,selectedIndex:m.selectedIndex,onSelect:t=>{const a=m.selectFile(t,A);B(a),m.dismissMention(),N(!1),f.current?.focus()},loading:m.loading}),T&&e.jsxs("div",{className:"chat-pending-message","data-testid":"chat-pending-indicator",children:[e.jsx("span",{children:`Queued: ${it}`}),e.jsx("button",{type:"button",className:"chat-pending-message-dismiss","aria-label":"Dismiss queued message","data-testid":"chat-pending-dismiss",onClick:pe,children:"×"})]})]}),b?e.jsx("button",{className:"chat-input-stop",onClick:V,"aria-label":"Stop generation","data-testid":"chat-stop-btn",children:e.jsx(Mt,{size:14})}):e.jsx("button",{className:"chat-input-send",onClick:()=>void ye(),disabled:!A.trim(),"data-testid":"chat-send-btn",children:e.jsx(jt,{size:16})})]})]}),Z&&e.jsx(It,{projectId:n,onClose:()=>U(!1),onCreate:Je})]})}export{Vt as ChatView};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as a,j as e}from"./vendor-react-K0fH_qHe.js";import{b9 as Ae,ba as je,bb as Se,bc as Fe,o as ze,bd as De,be as Ie,bf as Le,bg as Ne,bh as Ce,bi as Re,bj as Te,bk as Ee,bl as We,n as qe,bm as Pe,L as w,bn as ke}from"./index-rNf7s96d.js";import"./vendor-xterm-DzcZoU0P.js";const U=".fusion/memory/MEMORY.md",_e=5e4,Oe="0 3 * * *",Ue="0 4 * * *";function oe(i){return{memoryEnabled:i.memoryEnabled!==!1,memoryAutoSummarizeEnabled:i.memoryAutoSummarizeEnabled??!1,memoryAutoSummarizeThresholdChars:i.memoryAutoSummarizeThresholdChars??_e,memoryAutoSummarizeSchedule:i.memoryAutoSummarizeSchedule??Oe,memoryDreamsEnabled:i.memoryDreamsEnabled??!1,memoryDreamsSchedule:i.memoryDreamsSchedule??Ue}}function Me(i,t){return i.some(m=>m.path===t)?t:i.find(m=>m.path===U)?.path??i[0]?.path??U}function Qe(i={}){const{projectId:t}=i,[m,x]=a.useState(""),[A,N]=a.useState(!0),[j,S]=a.useState(!1),[h,y]=a.useState(!1),[n,g]=a.useState(null),[Q,J]=a.useState(!0),[X,F]=a.useState(!1),[b,R]=a.useState(()=>oe({})),[C,ee]=a.useState(!0),[ce,B]=a.useState(!1),[c,f]=a.useState([]),[se,z]=a.useState(!0),[o,E]=a.useState(U),[T,u]=a.useState(""),[d,te]=a.useState(!1),[H,p]=a.useState(!1),[ae,$]=a.useState(!1),[ne,Y]=a.useState(!1),[G,W]=a.useState(null),[k,q]=a.useState(!0),[de,D]=a.useState(!1),[ue,V]=a.useState(!1),[re,Z]=a.useState(null),{status:K,loading:v,refresh:ie}=Ae({projectId:t}),I=a.useCallback(s=>{u(s),p(!0)},[]),P=a.useCallback(async s=>{te(!0);try{const{content:r}=await je(s,t);E(s),u(r),p(!1)}finally{te(!1)}},[t]),M=a.useCallback(async()=>{z(!0);try{const{files:s}=await Se(t);if(f(s),s.length===0){E(U),u(""),p(!1);return}const r=Me(s,o);r!==o&&await P(r)}finally{z(!1)}},[t,o,P]);a.useEffect(()=>{let s=!1;async function r(){try{const l=await We(t);s||(x(l.content),N(!1))}catch{s||(x(""),N(!1))}}return r(),()=>{s=!0}},[t]),a.useEffect(()=>{let s=!1;async function r(){try{const l=await Ce(t);s||(g(l.content),F(l.exists),J(!1))}catch{s||(g(null),F(!1),J(!1))}}return r(),()=>{s=!0}},[t]),a.useEffect(()=>{let s=!1;async function r(){ee(!0);try{const l=await qe(t);s||R(oe(l))}catch{s||R(oe({}))}finally{s||ee(!1)}}return r(),()=>{s=!0}},[t]),a.useEffect(()=>{let s=!1;async function r(){z(!0);try{const{files:l}=await Se(t);if(s)return;if(f(l),l.length===0){E(U),u(""),p(!1);return}const me=Me(l,o),{content:we}=await je(me,t);if(s)return;E(me),u(we),p(!1)}catch{s||(f([]),E(U),u(""),p(!1))}finally{s||z(!1)}}return r(),()=>{s=!0}},[t,o]),a.useEffect(()=>{let s=!1;async function r(){try{const l=await Ne(t);s||(W(l),q(!1))}catch{s||(W(null),q(!1))}}return r(),()=>{s=!0}},[t]),a.useEffect(()=>{let s=!1;async function r(){try{const l=await Pe(t);s||Z(l)}catch{s||Z(null)}}return r(),()=>{s=!0}},[t]);const le=a.useCallback(s=>{x(s),S(!0)},[]),he=a.useCallback(async()=>{if(j){y(!0);try{await Fe(m,t),S(!1)}finally{y(!1)}}},[m,j,t]),ye=a.useCallback(async s=>{B(!0);try{const r=await ze(s,t);R(oe(r))}finally{B(!1)}},[t]),ge=a.useCallback(async s=>{await P(s)},[P]),pe=a.useCallback(async()=>{if(H){$(!0);try{await De(o,T,t),p(!1),await M()}finally{$(!1)}}},[T,H,o,t,M]),xe=a.useCallback(async()=>{V(!0);try{const s=await Ie(t);return await ie(),s}finally{V(!1)}},[t,ie]),be=a.useCallback(async s=>Le(s,t),[t]),_=a.useCallback(async()=>{try{const s=await Ne(t);W(s)}catch{W(null)}},[t]),L=a.useCallback(async()=>{try{const s=await Ce(t);g(s.content),F(s.exists)}catch{g(null),F(!1)}},[t]),fe=a.useCallback(async s=>{await Re(s,t),await L()},[t,L]),ve=a.useCallback(async()=>{Y(!0);try{const s=await Te(t);return await Promise.all([L(),_()]),{success:s.success,summary:s.summary}}finally{Y(!1)}},[t,L,_]),O=a.useCallback(async s=>{D(!0);try{const r=s?await Ee(s,t):await Ee(t);if(s){const l=r.path??s;E(l),u(r.content),p(!1),await M();return}x(r.content),S(!0)}finally{D(!1)}},[t,M]);return{workingMemory:m,workingMemoryLoading:A,workingMemoryDirty:j,setWorkingMemory:le,saveWorkingMemory:he,savingWorkingMemory:h,insightsContent:n,insightsLoading:Q,insightsExists:X,refreshInsights:L,saveInsights:fe,memorySettings:b,settingsLoading:C,savingMemorySettings:ce,saveMemorySettings:ye,memoryFiles:c,memoryFilesLoading:se,selectedFilePath:o,selectedFileContent:T,selectedFileLoading:d,selectedFileDirty:H,setSelectedFileContent:I,selectFile:ge,saveSelectedFile:pe,savingSelectedFile:ae,reloadMemoryFiles:M,backendStatus:K,backendLoading:v,extractInsights:ve,extracting:ne,auditReport:G,auditLoading:k,refreshAudit:_,compactMemory:O,compacting:de,installQmdAction:xe,installingQmd:ue,testRetrieval:be,stats:re}}const Be={Patterns:"pattern",Principles:"principle",Conventions:"convention",Pitfalls:"pitfall",Context:"context"},He={"long-term":"Long-term",daily:"Daily",dreams:"Dreams"},$e={"long-term":"Curated durable decisions, conventions, constraints, and pitfalls promoted from dreams.",daily:"Raw daily observations, open loops, and running context for dream processing.",dreams:"Synthesized patterns and open loops promoted from daily memory."};function Ye(i){if(!i)return[];const t=[],m=i.split(/(?=^## )/m);for(const x of m){const A=x.trim();if(!A)continue;const N=A.match(/^##\s+(.+?)(\n|$)/);if(N){const j=N[1].trim(),S=Be[j]??j.toLowerCase(),h=A.slice(N[0].length).trim(),y=h.split(`
|
|
2
|
-
`).map(n=>n.replace(/^-\s+/,"").trim()).filter(n=>n.length>0&&(n.startsWith("- ")||n.startsWith("* ")));(y.length>0||h.length>0)&&t.push({name:j,key:S,items:y.length>0?y:h.length>0?[h]:[],expanded:!0})}}return t}function Ge(i){if(!i)return null;const t=i.match(/##\s+Last\s+Updated:\s*(\d{4}-\d{2}-\d{2})/i);return t?t[1]:null}function Ve(i){return i.reduce((t,m)=>t+m.items.length,0)}function Ze(i){switch(i){case"file":return"File (.fusion/memory/)";case"readonly":return"Read-Only";case"qmd":return"QMD (Quantized Memory Distillation)";default:return i}}function Ke(i){switch(i){case"healthy":return"Healthy";case"warning":return"Warning";case"issues":return"Issues Found"}}function ss({projectId:i,addToast:t}){const[m,x]=a.useState("working"),[A,N]=a.useState(new Set),[j,S]=a.useState(!1),[h,y]=a.useState(null),[n,g]=a.useState({memoryEnabled:!0,memoryAutoSummarizeEnabled:!1,memoryAutoSummarizeThresholdChars:5e4,memoryAutoSummarizeSchedule:"0 3 * * *",memoryDreamsEnabled:!1,memoryDreamsSchedule:"0 4 * * *"}),[Q,J]=a.useState(""),[X,F]=a.useState(!1),[b,R]=a.useState(null),{insightsContent:C,insightsLoading:ee,insightsExists:ce,saveInsights:B,memorySettings:c,settingsLoading:f,saveMemorySettings:se,savingMemorySettings:z,backendStatus:o,backendLoading:E,extractInsights:T,extracting:u,auditReport:d,auditLoading:te,refreshAudit:H,compactMemory:p,compacting:ae,installQmdAction:$,installingQmd:ne,testRetrieval:Y,memoryFiles:G,memoryFilesLoading:W,selectedFilePath:k,selectedFileContent:q,selectedFileLoading:de,selectedFileDirty:D,setSelectedFileContent:ue,selectFile:V,saveSelectedFile:re,savingSelectedFile:Z}=Qe({projectId:i});a.useEffect(()=>{g(c)},[c]);const K=a.useMemo(()=>n.memoryEnabled!==c.memoryEnabled||n.memoryAutoSummarizeEnabled!==c.memoryAutoSummarizeEnabled||n.memoryAutoSummarizeThresholdChars!==c.memoryAutoSummarizeThresholdChars||n.memoryAutoSummarizeSchedule!==c.memoryAutoSummarizeSchedule||n.memoryDreamsEnabled!==c.memoryDreamsEnabled||n.memoryDreamsSchedule!==c.memoryDreamsSchedule,[n,c]),v=a.useMemo(()=>G.find(s=>s.path===k),[G,k]),ie=v?$e[v.layer]:"Edits the selected memory file.",I=a.useMemo(()=>Ye(C),[C]),P=a.useMemo(()=>Ve(I),[I]),M=a.useMemo(()=>Ge(C),[C]),le=a.useCallback(s=>{N(r=>{const l=new Set(r);return l.has(s)?l.delete(s):l.add(s),l})},[]),he=a.useCallback(async s=>{try{await V(s)}catch{t("Failed to load memory file","error")}},[V,t]),ye=a.useCallback(async()=>{try{await re(),t("Memory saved","success")}catch{t("Failed to save memory","error")}},[re,t]),ge=a.useCallback(async()=>{if(!K)return;const s={};n.memoryEnabled!==c.memoryEnabled&&(s.memoryEnabled=n.memoryEnabled),n.memoryAutoSummarizeEnabled!==c.memoryAutoSummarizeEnabled&&(s.memoryAutoSummarizeEnabled=n.memoryAutoSummarizeEnabled),n.memoryAutoSummarizeThresholdChars!==c.memoryAutoSummarizeThresholdChars&&(s.memoryAutoSummarizeThresholdChars=n.memoryAutoSummarizeThresholdChars),n.memoryAutoSummarizeSchedule!==c.memoryAutoSummarizeSchedule&&(s.memoryAutoSummarizeSchedule=n.memoryAutoSummarizeSchedule),n.memoryDreamsEnabled!==c.memoryDreamsEnabled&&(s.memoryDreamsEnabled=n.memoryDreamsEnabled),n.memoryDreamsSchedule!==c.memoryDreamsSchedule&&(s.memoryDreamsSchedule=n.memoryDreamsSchedule);try{await se(s),t("Memory settings saved","success")}catch{t("Failed to save memory settings","error")}},[K,n,c,se,t]),pe=a.useCallback(async()=>{try{const s=await $();t(s.qmdAvailable?"qmd installed successfully":"qmd install finished, but qmd is still unavailable",s.qmdAvailable?"success":"info")}catch{t("Failed to install qmd","error")}},[$,t]),xe=a.useCallback(async()=>{F(!0),R(null);try{const s=await Y(Q);R(s),t(s.qmdAvailable?"Memory retrieval test complete":"qmd is not installed; local fallback was used",s.qmdAvailable?"success":"info")}catch{t("Failed to test memory retrieval","error")}finally{F(!1)}},[Q,Y,t]),be=a.useCallback(async()=>{try{await p(k),t("Memory file compacted","success")}catch{t("Failed to compact memory","error")}},[p,k,t]),_=a.useCallback(async()=>{try{const s=await T();t(s.summary,"success")}catch(s){t(s instanceof Error?s.message:"Failed to extract insights","error")}},[T,t]),L=a.useCallback(async()=>{if(h!==null)try{await B(h),S(!1),y(null),t("Insights saved","success")}catch{t("Failed to save insights","error")}},[h,B,t]),fe=a.useCallback(()=>{y(C??""),S(!0)},[C]),ve=a.useCallback(()=>{S(!1),y(null)},[]),O=o?.capabilities?.writable??!1;return e.jsxs("div",{className:"memory-view",children:[e.jsx("div",{className:"memory-view-header",children:e.jsxs("div",{children:[e.jsx("h2",{children:"Memory"}),e.jsx("p",{className:"memory-view-description",children:"Working memory, long-term insights, and engine status"})]})}),e.jsxs("div",{className:"memory-view-tabs",role:"tablist",children:[e.jsx("button",{type:"button",role:"tab","aria-selected":m==="working",className:`memory-view-tab${m==="working"?" memory-view-tab--active":""}`,onClick:()=>x("working"),"data-testid":"memory-tab-working",children:"Working Memory"}),e.jsx("button",{type:"button",role:"tab","aria-selected":m==="insights",className:`memory-view-tab${m==="insights"?" memory-view-tab--active":""}`,onClick:()=>x("insights"),"data-testid":"memory-tab-insights",children:"Insights"}),e.jsx("button",{type:"button",role:"tab","aria-selected":m==="engines",className:`memory-view-tab${m==="engines"?" memory-view-tab--active":""}`,onClick:()=>x("engines"),"data-testid":"memory-tab-engines",children:"Engines"})]}),e.jsxs("div",{className:"memory-view-content",children:[m==="working"&&e.jsxs("div",{className:"memory-working-tab",children:[!O&&e.jsx("div",{className:"memory-readonly-banner",children:"This memory backend is read-only. Changes cannot be saved."}),W||de?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading memory file…"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-editor-section",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryViewFilePath",children:"Memory File"}),e.jsx("select",{id:"memoryViewFilePath",className:"select",value:k,onChange:s=>{he(s.target.value)},disabled:D,children:G.map(s=>e.jsxs("option",{value:s.path,children:[s.label," - ",s.path]},s.path))}),e.jsx("small",{children:D?"Save or discard the current edits before switching files.":"Choose any project memory file to view or edit."})]}),v&&e.jsxs("div",{className:"memory-file-summary",children:[e.jsx("span",{children:He[v.layer]}),e.jsx("strong",{children:v.path}),e.jsxs("small",{children:[v.size.toLocaleString()," bytes · updated ",new Date(v.updatedAt).toLocaleString()]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:v?.label||"Memory Editor"}),e.jsx("small",{children:ie}),e.jsx("div",{className:"memory-editor-container",children:e.jsx(ke,{content:q,onChange:ue,readOnly:!O,filePath:k})})]})]}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsxs("span",{className:"memory-char-count",children:[q.length," characters"]}),e.jsx("div",{style:{flex:1}}),O&&q.length>0&&e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:be,disabled:ae||D,children:ae?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Compacting…"]}):"Compact Selected File"}),D&&O&&e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:ye,disabled:Z,children:Z?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Saving…"]}):"Save"})]}),e.jsxs("div",{className:"memory-config-section",children:[e.jsxs("div",{className:"memory-settings-group",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"memoryDreamsEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"memoryDreamsEnabled",type:"checkbox",checked:n.memoryDreamsEnabled,onChange:s=>{g(r=>({...r,memoryDreamsEnabled:s.target.checked}))},disabled:!n.memoryEnabled||f}),"Process dreams from daily memory"]}),e.jsx("small",{children:"Turns daily notes into DREAMS.md and promotes reusable lessons into MEMORY.md."})]}),n.memoryEnabled&&n.memoryDreamsEnabled&&e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryDreamsSchedule",children:"Dream Schedule"}),e.jsx("input",{id:"memoryDreamsSchedule",type:"text",className:"input",value:n.memoryDreamsSchedule,onChange:s=>{g(r=>({...r,memoryDreamsSchedule:s.target.value}))},placeholder:"0 4 * * *",disabled:f}),e.jsx("small",{children:"Cron expression for dream processing."})]})]}),e.jsxs("div",{className:"memory-settings-group",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"memoryAutoSummarizeEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"memoryAutoSummarizeEnabled",type:"checkbox",checked:n.memoryAutoSummarizeEnabled,onChange:s=>{g(r=>({...r,memoryAutoSummarizeEnabled:s.target.checked}))},disabled:!n.memoryEnabled||f}),"Auto-Summarize Memory"]}),e.jsx("small",{children:"Automatically compact memory when it exceeds the threshold on a schedule"})]}),n.memoryEnabled&&n.memoryAutoSummarizeEnabled&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryAutoSummarizeThresholdChars",children:"Compaction Threshold (chars)"}),e.jsx("input",{id:"memoryAutoSummarizeThresholdChars",type:"number",className:"input",value:n.memoryAutoSummarizeThresholdChars,onChange:s=>{g(r=>({...r,memoryAutoSummarizeThresholdChars:parseInt(s.target.value,10)||5e4}))},min:1e3,disabled:f}),e.jsx("small",{children:"Memory will be compacted when it exceeds this character count"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryAutoSummarizeSchedule",children:"Schedule (cron)"}),e.jsx("input",{id:"memoryAutoSummarizeSchedule",type:"text",className:"input",value:n.memoryAutoSummarizeSchedule,onChange:s=>{g(r=>({...r,memoryAutoSummarizeSchedule:s.target.value}))},placeholder:"0 3 * * *",disabled:f}),e.jsx("small",{children:"Cron expression for auto-summarize schedule (default: daily at 3 AM)"})]})]})]}),!n.memoryEnabled&&e.jsx("div",{className:"settings-empty-state memory-status-message",children:"Memory is currently disabled. Enable memory tools in Settings to edit these automations."}),K&&e.jsx("div",{className:"memory-action-bar",children:e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:ge,disabled:z||f,children:z?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Saving…"]}):"Save Settings"})})]})]})]}),m==="insights"&&e.jsx("div",{className:"memory-insights-tab",children:ee?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading insights…"})]}):j?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"memory-editor-container",children:e.jsx(ke,{content:h??"",onChange:y,readOnly:!1,filePath:".fusion/memory/INSIGHTS.md"})}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:ve,children:"Cancel"}),e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:L,children:"Save Insights"})]})]}):!ce||I.length===0?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx("p",{children:"No insights extracted yet."}),e.jsx("p",{children:'Insights are automatically extracted from working memory. Click "Extract Now" to trigger extraction manually.'}),e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:_,disabled:u,style:{marginTop:"var(--space-md)"},children:u?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Extracting…"]}):"Extract Now"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-stats-row",children:[e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value",children:P}),e.jsx("div",{className:"memory-stat-label",children:"Total Insights"})]}),e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value",children:I.length}),e.jsx("div",{className:"memory-stat-label",children:"Categories"})]}),M&&e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value",style:{fontSize:"16px"},children:M}),e.jsx("div",{className:"memory-stat-label",children:"Last Updated"})]})]}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:_,disabled:u,children:u?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Extracting…"]}):"Extract Now"}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:fe,children:"Edit Raw"})]}),e.jsx("div",{className:"memory-categories-list",children:I.map(s=>{const r=!A.has(s.key);return e.jsxs("div",{className:"memory-category-section",children:[e.jsxs("div",{className:"memory-category-header",onClick:()=>le(s.key),role:"button",tabIndex:0,onKeyDown:l=>{(l.key==="Enter"||l.key===" ")&&(l.preventDefault(),le(s.key))},children:[e.jsx("h4",{children:s.name}),e.jsx("span",{className:"memory-category-count",children:s.items.length})]}),r&&e.jsx("div",{className:"memory-category-items",children:s.items.map((l,me)=>e.jsx("div",{className:"memory-insight-item",children:l.replace(/^-\s+/,"").replace(/^\*\s+/,"")},me))})]},s.key)})})]})}),m==="engines"&&e.jsx("div",{className:"memory-engines-tab",children:E||te?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading engine status…"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-engine-card memory-qmd-card",children:[e.jsx("h3",{children:"QMD Integration"}),o?.qmdAvailable?e.jsxs("div",{className:"memory-engine-status",children:[e.jsx("span",{className:"memory-health-badge memory-health-badge--healthy",children:"Installed"}),e.jsx("span",{className:"memory-char-count",children:"qmd is available on PATH."})]}):e.jsxs("div",{className:"settings-empty-state memory-status-message",children:[e.jsxs("span",{children:["qmd is not installed. Search will use local files. Install indexed retrieval: ",e.jsx("code",{children:o?.qmdInstallCommand||"bun install -g @tobilu/qmd"})]}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:pe,disabled:ne,children:ne?"Installing…":"Install qmd"})]}),e.jsxs("div",{style:{display:"flex",gap:"var(--space-xs)",marginTop:"var(--space-sm)",flexWrap:"wrap"},children:[o?.capabilities?.readable&&e.jsx("span",{className:"memory-capability-badge",children:"Readable"}),o?.capabilities?.writable&&e.jsx("span",{className:"memory-capability-badge",children:"Writable"}),o?.capabilities?.supportsAtomicWrite&&e.jsx("span",{className:"memory-capability-badge",children:"Atomic Writes"}),o?.capabilities?.persistent&&e.jsx("span",{className:"memory-capability-badge",children:"Persistent"})]})]}),e.jsxs("div",{className:"memory-engine-card memory-retrieval-card",children:[e.jsx("h3",{children:"Test Memory Search"}),e.jsxs("div",{className:"memory-retrieval-input-row",children:[e.jsx("input",{type:"text",className:"input",value:Q,onChange:s=>J(s.target.value),placeholder:"Search memory with qmd"}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:xe,disabled:X,children:X?"Testing…":"Test Retrieval"})]}),e.jsx("small",{className:"settings-muted",children:"Runs the same qmd-backed memory_search path agents use."}),b&&e.jsxs("div",{className:"memory-test-result",children:[e.jsxs("strong",{children:[b.results.length," result",b.results.length===1?"":"s"," ",'for "',b.query,'"']}),e.jsxs("small",{children:["qmd ",b.qmdAvailable?"available":"missing"," · ",b.usedFallback?"local fallback used":"qmd path used"]}),b.results.length>0?e.jsx("ul",{children:b.results.map((s,r)=>e.jsxs("li",{children:[e.jsxs("span",{children:[s.path,":",s.lineStart]}),e.jsx("p",{children:s.snippet})]},`${s.path}-${s.lineStart}-${r}`))}):e.jsx("small",{children:"No matching memory found."})]})]}),e.jsxs("div",{className:"memory-engine-card",children:[e.jsx("h3",{children:"Current Backend"}),e.jsx("div",{className:"memory-engine-status",children:e.jsx("span",{style:{fontWeight:500},children:Ze(o?.currentBackend??"unknown")})}),e.jsxs("div",{style:{display:"flex",gap:"var(--space-xs)",marginTop:"var(--space-sm)",flexWrap:"wrap"},children:[o?.capabilities?.readable&&e.jsx("span",{className:"memory-capability-badge",children:"Readable"}),o?.capabilities?.writable&&e.jsx("span",{className:"memory-capability-badge",children:"Writable"}),o?.capabilities?.supportsAtomicWrite&&e.jsx("span",{className:"memory-capability-badge",children:"Atomic Writes"}),o?.capabilities?.persistent&&e.jsx("span",{className:"memory-capability-badge",children:"Persistent"})]})]}),d&&e.jsxs("div",{className:"memory-engine-card",children:[e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"var(--space-md)"},children:[e.jsx("h3",{children:"Health Status"}),e.jsx("span",{className:`memory-health-badge memory-health-badge--${d.health}`,children:Ke(d.health)})]}),e.jsxs("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"var(--space-md)"},children:[e.jsxs("div",{children:[e.jsx("div",{style:{fontSize:"12px",color:"var(--text-muted)",textTransform:"uppercase",marginBottom:"var(--space-xs)"},children:"Working Memory"}),e.jsxs("div",{style:{fontWeight:500},children:[d.workingMemory.size," chars"]}),e.jsxs("div",{style:{fontSize:"13px",color:"var(--text-muted)"},children:[d.workingMemory.sectionCount," sections"]})]}),e.jsxs("div",{children:[e.jsx("div",{style:{fontSize:"12px",color:"var(--text-muted)",textTransform:"uppercase",marginBottom:"var(--space-xs)"},children:"Insights Memory"}),e.jsxs("div",{style:{fontWeight:500},children:[d.insightsMemory.size," chars"]}),e.jsxs("div",{style:{fontSize:"13px",color:"var(--text-muted)"},children:[d.insightsMemory.insightCount," insights"]})]})]}),e.jsxs("div",{style:{marginTop:"var(--space-md)",paddingTop:"var(--space-md)",borderTop:"1px solid var(--border)"},children:[e.jsx("div",{style:{fontSize:"12px",color:"var(--text-muted)",textTransform:"uppercase",marginBottom:"var(--space-xs)"},children:"Last Extraction"}),e.jsx("div",{style:{fontWeight:500},children:d.extraction.success?e.jsx("span",{style:{color:"var(--color-success)"},children:"Success"}):e.jsx("span",{style:{color:"var(--color-error)"},children:"Failed"})}),e.jsx("div",{style:{fontSize:"13px",color:"var(--text-muted)"},children:d.extraction.summary||`${d.extraction.insightCount} insights extracted`})]}),e.jsxs("div",{style:{marginTop:"var(--space-md)",paddingTop:"var(--space-md)",borderTop:"1px solid var(--border)"},children:[e.jsx("div",{style:{fontSize:"12px",color:"var(--text-muted)",textTransform:"uppercase",marginBottom:"var(--space-xs)"},children:"Pruning"}),e.jsx("div",{style:{fontWeight:500},children:d.pruning.applied?e.jsx("span",{style:{color:"var(--color-warning)"},children:"Applied"}):e.jsx("span",{style:{color:"var(--text-muted)"},children:"Not needed"})}),d.pruning.applied&&e.jsx("div",{style:{fontSize:"13px",color:"var(--text-muted)"},children:d.pruning.reason})]})]}),d&&d.checks.length>0&&e.jsxs("div",{className:"memory-engine-card",children:[e.jsx("h3",{children:"Audit Checks"}),e.jsx("div",{children:d.checks.map(s=>e.jsxs("div",{className:"memory-audit-check",children:[e.jsx("span",{className:s.passed?"memory-audit-check-passed":"memory-audit-check-failed",children:s.passed?"✓":"✗"}),e.jsxs("div",{style:{flex:1},children:[e.jsx("div",{style:{fontWeight:500},children:s.name}),e.jsx("div",{style:{fontSize:"13px",color:"var(--text-muted)"},children:s.details})]})]},s.id))})]}),e.jsx("div",{className:"memory-action-bar",children:e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:()=>H(),children:"Run Audit"})}),e.jsxs("div",{style:{marginTop:"var(--space-lg)",fontSize:"13px",color:"var(--text-muted)"},children:["Note: Change backend type in"," ",e.jsx("span",{style:{cursor:"pointer",textDecoration:"underline"},onClick:()=>{t("Open Settings → Memory to change backend type","info")},children:"Settings → Memory"})]})]})})]})]})}export{ss as MemoryView};
|