@runfusion/fusion 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/bin.js +1644 -509
  2. package/dist/client/assets/{AgentDetailView-DQBjJSPJ.js → AgentDetailView-B7j297GT.js} +4 -4
  3. package/dist/client/assets/AgentsView-Dvf_xUkx.js +522 -0
  4. package/dist/client/assets/{AgentsView-xm_3NO4M.css → AgentsView-V5GhlBYu.css} +1 -1
  5. package/dist/client/assets/ChatView-BgUt38ty.js +1 -0
  6. package/dist/client/assets/{DevServerView-BVixhlF0.js → DevServerView-C2qTJch7.js} +1 -1
  7. package/dist/client/assets/{DirectoryPicker-tvBgHxa7.js → DirectoryPicker-DRfhg9zz.js} +1 -1
  8. package/dist/client/assets/{DocumentsView-DVw_wT6V.js → DocumentsView-j8ic1xUw.js} +1 -1
  9. package/dist/client/assets/{InsightsView-G3MZhwSx.js → InsightsView-CpAz3o0i.js} +3 -3
  10. package/dist/client/assets/{MemoryView-Bl9gx2Dw.js → MemoryView-BcQsi_JK.js} +2 -2
  11. package/dist/client/assets/{NodesView-dwVhD4V2.js → NodesView-Bo_Yhr4N.js} +4 -4
  12. package/dist/client/assets/{PiExtensionsManager-CEHp6_Mj.js → PiExtensionsManager-DHt2zFg8.js} +3 -3
  13. package/dist/client/assets/{PluginManager-Dx0mcwat.js → PluginManager-BQhBHWrB.js} +1 -1
  14. package/dist/client/assets/ResearchView-BzRdUzNq.css +1 -0
  15. package/dist/client/assets/{ResearchView-BvlLYC_1.js → ResearchView-CLyyqAWE.js} +1 -1
  16. package/dist/client/assets/{RoadmapsView-DdYXssP2.js → RoadmapsView-tG7IdOoc.js} +2 -2
  17. package/dist/client/assets/{SettingsModal-CGWipm3s.js → SettingsModal-CXUGeZ0_.js} +1 -1
  18. package/dist/client/assets/{SettingsModal-CriZP5Lp.css → SettingsModal-DcGFm6NR.css} +1 -1
  19. package/dist/client/assets/SettingsModal-UziTDnLh.js +31 -0
  20. package/dist/client/assets/{SetupWizardModal-CKsJduYM.js → SetupWizardModal-BMJL6eNR.js} +1 -1
  21. package/dist/client/assets/SkillMultiselect-DDHJnrkn.css +1 -0
  22. package/dist/client/assets/SkillMultiselect-ILMft-Kz.js +1 -0
  23. package/dist/client/assets/SkillsView-x4_YwBz6.js +1 -0
  24. package/dist/client/assets/{TodoView-ByXJ90yL.js → TodoView-BBYcMbXE.js} +2 -2
  25. package/dist/client/assets/{folder-open-CxOUgHDf.js → folder-open-DDdJt8aE.js} +1 -1
  26. package/dist/client/assets/index-B15xwijw.css +1 -0
  27. package/dist/client/assets/index-DmSs2FGE.js +661 -0
  28. package/dist/client/assets/{list-checks--sf9u9ox.js → list-checks-DFxQ9biT.js} +1 -1
  29. package/dist/client/assets/{star-CF1f2iPu.js → star-BKs1bgJN.js} +1 -1
  30. package/dist/client/assets/{upload-rOBd4OhB.js → upload-Bb5Pidne.js} +1 -1
  31. package/dist/client/assets/{users-De-vFat1.js → users-BImNn91Q.js} +1 -1
  32. package/dist/client/index.html +2 -2
  33. package/dist/client/theme-data.css +1 -1
  34. package/dist/client/version.json +1 -1
  35. package/dist/extension.js +548 -96
  36. package/dist/pi-claude-cli/package.json +1 -1
  37. package/dist/pi-claude-cli/src/__tests__/prompt-builder.test.ts +36 -0
  38. package/dist/pi-claude-cli/src/prompt-builder.ts +19 -28
  39. package/package.json +1 -1
  40. package/skill/fusion/references/cli-commands.md +14 -0
  41. package/skill/fusion/references/engine-tools.md +1 -0
  42. package/dist/client/assets/AgentsView-DlA0yHBg.js +0 -522
  43. package/dist/client/assets/ChatView-DK5CmiAk.js +0 -1
  44. package/dist/client/assets/ResearchView-BVJFgfat.css +0 -1
  45. package/dist/client/assets/SettingsModal-Bgjg_4CD.js +0 -31
  46. package/dist/client/assets/SkillsView-C4Tz7CxC.js +0 -1
  47. package/dist/client/assets/index-BCz4ye4p.css +0 -1
  48. package/dist/client/assets/index-D7gT6mCr.js +0 -656
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion/pi-claude-cli",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Fusion vendored fork: pi coding-agent extension that routes LLM calls through the Claude Code CLI. Forked from rchern/pi-claude-cli (MIT). See UPSTREAM.md.",
5
5
  "license": "MIT",
6
6
  "private": true,
@@ -1145,6 +1145,42 @@ describe("buildResumePrompt", () => {
1145
1145
  expect(buildResumePrompt(context)).toBe("Hello from blocks");
1146
1146
  });
1147
1147
 
1148
+ // Regression: multi-iteration tool loops re-anchor on the LAST assistant
1149
+ // turn, not the (only) user message at index 0. Previously this dumped the
1150
+ // entire transcript into a "user" prompt every iteration, ballooning the
1151
+ // resumed session.
1152
+ it("returns ONLY the trailing tool result during a multi-iteration tool loop", () => {
1153
+ const context = {
1154
+ messages: [
1155
+ { role: "user", content: "Find foo" },
1156
+ {
1157
+ role: "assistant",
1158
+ content: [{ type: "toolCall", name: "find", arguments: { pattern: "foo" } }],
1159
+ },
1160
+ { role: "toolResult", toolName: "find", content: "no matches (turn 1)" },
1161
+ {
1162
+ role: "assistant",
1163
+ content: [{ type: "toolCall", name: "find", arguments: { pattern: "foo" } }],
1164
+ },
1165
+ { role: "toolResult", toolName: "find", content: "no matches (turn 2)" },
1166
+ ],
1167
+ };
1168
+ const result = buildResumePrompt(context) as string;
1169
+ expect(result).toContain("no matches (turn 2)");
1170
+ expect(result).not.toContain("no matches (turn 1)");
1171
+ expect(result).not.toContain("Find foo");
1172
+ });
1173
+
1174
+ it("returns empty string mid-loop when only an assistant turn exists since the last delta", () => {
1175
+ const context = {
1176
+ messages: [
1177
+ { role: "user", content: "Hi" },
1178
+ { role: "assistant", content: "Working..." },
1179
+ ],
1180
+ };
1181
+ expect(buildResumePrompt(context)).toBe("");
1182
+ });
1183
+
1148
1184
  it("handles images in the final user message by returning ContentBlock[]", () => {
1149
1185
  const context = {
1150
1186
  messages: [
@@ -166,44 +166,36 @@ function buildCustomToolResultPrompt(messages: PiMessage[]): string | null {
166
166
  /**
167
167
  * Build a prompt for a resumed session.
168
168
  *
169
- * When resuming via --resume, the CLI already has the full conversation history.
170
- * We only need to send the new content since the last turn: the last assistant
171
- * response's tool results (if any) followed by the latest user message.
169
+ * When resuming via --resume, the CLI already has the full conversation history
170
+ * up through (and including) the most recent assistant turn that it produced.
171
+ * We only need to send the *delta* since that turn: any trailing tool results
172
+ * for the last assistant tool_use, and/or a new user message.
172
173
  *
173
- * For tool_use flows: pi sends [user, assistant(toolCall), toolResult, ...]
174
- * We need to include tool results so the resumed session sees them, plus the
175
- * final user message.
174
+ * Why anchor on the last assistant message (not the last user message)?
175
+ * Pi's tool-use loop appends `[user, assistant(toolUse), toolResult,
176
+ * assistant(toolUse), toolResult, ...]` — the only `user` entry stays at index
177
+ * 0 across many provider invocations. Anchoring on the last user message and
178
+ * walking forward (the prior implementation) re-sent the entire transcript on
179
+ * every tool-loop iteration, so each --resume turn appended a duplicate of the
180
+ * original query plus a growing stack of tool results to the on-disk session.
176
181
  *
177
- * Falls back to full prompt if the message structure is unexpected.
182
+ * Returns "" when there's nothing new to send (e.g. only an assistant message
183
+ * exists in the context — can happen mid-shutdown).
178
184
  */
179
185
  export function buildResumePrompt(context: PiContext): string | AnthropicContentBlock[] {
180
186
  const messages = context.messages;
181
187
  if (messages.length === 0) return "";
182
188
 
183
- // Find the last user message
184
- const finalUserIndex = findFinalUserMessageIndex(messages);
185
- if (finalUserIndex < 0) return "";
186
-
187
- // Collect new messages: everything from the last assistant turn onwards
188
- // (tool results from the last assistant + the new user message)
189
- const newMessages: PiMessage[] = [];
190
-
191
- // Walk backwards from finalUserIndex to find where new content starts.
192
- // Include trailing toolResult messages that follow the last assistant turn.
193
- let startIdx = finalUserIndex;
194
- for (let i = finalUserIndex - 1; i >= 0; i--) {
195
- if (messages[i].role === "toolResult") {
196
- startIdx = i;
197
- } else {
189
+ let lastAssistantIdx = -1;
190
+ for (let i = messages.length - 1; i >= 0; i--) {
191
+ if (messages[i].role === "assistant") {
192
+ lastAssistantIdx = i;
198
193
  break;
199
194
  }
200
195
  }
196
+ const newMessages = messages.slice(lastAssistantIdx + 1);
197
+ if (newMessages.length === 0) return "";
201
198
 
202
- for (let i = startIdx; i < messages.length; i++) {
203
- newMessages.push(messages[i]);
204
- }
205
-
206
- // If there are only tool results + one user message, build a combined prompt
207
199
  const parts: string[] = [];
208
200
  for (const msg of newMessages) {
209
201
  if (msg.role === "toolResult") {
@@ -217,7 +209,6 @@ export function buildResumePrompt(context: PiContext): string | AnthropicContent
217
209
  }
218
210
  parts.push(toolResultContentToText(msg.content));
219
211
  } else if (msg.role === "user") {
220
- // Check for images in the final user message
221
212
  if (contentHasImages(msg.content)) {
222
213
  const textSoFar = parts.join("\n");
223
214
  const userContent = buildFinalUserContent(msg.content);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runfusion/fusion",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
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",
@@ -40,6 +40,20 @@ fn task logs FN-001 --limit 50 # Limit log lines
40
40
  fn task logs FN-001 --type tool # Filter by log type
41
41
  ```
42
42
 
43
+ ## Research
44
+
45
+ ```bash
46
+ fn research create --query "question" # Create research run
47
+ fn research create --query "question" --wait # Wait for completion
48
+ fn research list # List runs
49
+ fn research ls --status failed --limit 20 # Filter by status
50
+ fn research show RR-001 # Show one run
51
+ fn research export RR-001 --format json # Export to JSON
52
+ fn research export RR-001 --output ./run.md # Export to specific path
53
+ fn research cancel RR-001 # Cancel active run
54
+ fn research retry RR-001 # Retry failed/cancelled run
55
+ ```
56
+
43
57
  ## Mission Management
44
58
 
45
59
  ```bash
@@ -55,4 +55,5 @@ These tools are **not** part of the pi extension's user-invokable `extension.ts`
55
55
 
56
56
  | Tool | Purpose | Parameters |
57
57
  |---|---|---|
58
+ | `fn_identity` | Return loaded soul/instructions/memory summary for this heartbeat tick (must be called first) | none |
58
59
  | `fn_heartbeat_done` | Signal end of heartbeat run with optional summary | `summary?` (string) |