@runfusion/fusion 0.36.0 → 0.37.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 (54) hide show
  1. package/dist/bin.js +164 -15
  2. package/dist/client/.vite/manifest.json +61 -61
  3. package/dist/client/assets/{AgentDetailView-CGycokdR.js → AgentDetailView-T_AHPxcG.js} +1 -1
  4. package/dist/client/assets/{AgentPermissionPolicyEditor-BoD6come.js → AgentPermissionPolicyEditor-niLSqGAE.js} +1 -1
  5. package/dist/client/assets/{AgentsView-B_afRRfc.js → AgentsView-CQhaLHz_.js} +3 -3
  6. package/dist/client/assets/{ChatView-IjNrSZSf.js → ChatView-B60kYfdk.js} +1 -1
  7. package/dist/client/assets/{DevServerView-Dd613aZ5.js → DevServerView-0Gb44WOb.js} +1 -1
  8. package/dist/client/assets/{DirectoryPicker-H-fUl2dF.js → DirectoryPicker-BSQA0XM9.js} +1 -1
  9. package/dist/client/assets/{DocumentsView-Dshc9e5K.js → DocumentsView-XZbaqEFF.js} +1 -1
  10. package/dist/client/assets/{EvalsView-50W0K5h7.js → EvalsView-CJNtXxX9.js} +1 -1
  11. package/dist/client/assets/{ExperimentalAgentOnboardingModal-BXBljPFj.js → ExperimentalAgentOnboardingModal-DR8E3i36.js} +1 -1
  12. package/dist/client/assets/GoalsView-CN1zQ_Ax.js +1 -0
  13. package/dist/client/assets/GoalsView-CtWi0fxE.css +1 -0
  14. package/dist/client/assets/{InsightsView-sVbGRKTl.js → InsightsView-D_jRaMyn.js} +1 -1
  15. package/dist/client/assets/{MemoryView-006a_sB0.js → MemoryView-D90vdPnp.js} +1 -1
  16. package/dist/client/assets/{NodesView-CiRPqgVx.js → NodesView-C1zuedAe.js} +1 -1
  17. package/dist/client/assets/{PiExtensionsManager-Y1ETuTxf.js → PiExtensionsManager-DBJDDVfM.js} +1 -1
  18. package/dist/client/assets/{PluginManager-Df_KHiXn.js → PluginManager-Ceg64P2Z.js} +1 -1
  19. package/dist/client/assets/{ResearchView-DU_QuS_-.js → ResearchView-XRwWdczc.js} +1 -1
  20. package/dist/client/assets/{SecretsView-D61Jvysn.js → SecretsView-TCrKyCme.js} +1 -1
  21. package/dist/client/assets/{SettingsModal-Cpur3WpT.js → SettingsModal-B8fRuWdQ.js} +3 -3
  22. package/dist/client/assets/{SettingsModal-BarzmqNb.js → SettingsModal-C1TczsEr.js} +1 -1
  23. package/dist/client/assets/{SetupWizardModal-BF3iRNq9.js → SetupWizardModal-D6moSTT3.js} +1 -1
  24. package/dist/client/assets/{SkillsView-tCKOFw3j.js → SkillsView-BDHLPVBi.js} +1 -1
  25. package/dist/client/assets/{StashRecoveryView-nGtypd10.js → StashRecoveryView-DZGa591R.js} +1 -1
  26. package/dist/client/assets/{TodoView-IyGPV6AO.js → TodoView-nr_SnCJv.js} +1 -1
  27. package/dist/client/assets/{dashboard-view-DiA5-hnb.js → dashboard-view-0XeZ1FTR.js} +1 -1
  28. package/dist/client/assets/{folder-open-Byqfi_N-.js → folder-open-iURwQbEg.js} +1 -1
  29. package/dist/client/assets/{index-B9Ro_NwC.js → index-CjuQj4qe.js} +14 -14
  30. package/dist/client/assets/index-DmrpDn7c.css +1 -0
  31. package/dist/client/assets/{upload-D6_BjqVi.js → upload-Beqg4S4L.js} +1 -1
  32. package/dist/client/assets/{users-CERYgInO.js → users-C2o86ZCR.js} +1 -1
  33. package/dist/client/index.html +2 -2
  34. package/dist/client/version.json +1 -1
  35. package/dist/droid-cli/package.json +1 -1
  36. package/dist/extension.js +195 -15
  37. package/dist/pi-claude-cli/package.json +1 -1
  38. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
  39. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  40. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  41. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  42. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  43. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  44. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  45. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  46. package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
  47. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  48. package/package.json +1 -1
  49. package/skill/fusion/SKILL.md +1 -1
  50. package/skill/fusion/references/extension-tools.md +16 -0
  51. package/skill/fusion/references/fusion-capabilities.md +1 -0
  52. package/dist/client/assets/GoalsView-Cg136Jcn.css +0 -1
  53. package/dist/client/assets/GoalsView-Dh508Z2s.js +0 -1
  54. package/dist/client/assets/index-DVFBXjGT.css +0 -1
@@ -1,4 +1,4 @@
1
- import{c as a}from"./index-B9Ro_NwC.js";/**
1
+ import{c as a}from"./index-CjuQj4qe.js";/**
2
2
  * @license lucide-react v1.7.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-B9Ro_NwC.js";/**
1
+ import{c as e}from"./index-CjuQj4qe.js";/**
2
2
  * @license lucide-react v1.7.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -170,12 +170,12 @@
170
170
  </script>
171
171
  <!-- fusion:view-preload -->
172
172
 
173
- <script type="module" crossorigin src="/assets/index-B9Ro_NwC.js"></script>
173
+ <script type="module" crossorigin src="/assets/index-CjuQj4qe.js"></script>
174
174
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-K0fH_qHe.js">
175
175
  <link rel="modulepreload" crossorigin href="/assets/vendor-xterm-DzcZoU0P.js">
176
176
  <link rel="modulepreload" crossorigin href="/assets/vendor-codemirror-jBKmHyH0.js">
177
177
  <link rel="stylesheet" crossorigin href="/assets/vendor-xterm-LZoznX6r.css">
178
- <link rel="stylesheet" crossorigin href="/assets/index-DVFBXjGT.css">
178
+ <link rel="stylesheet" crossorigin href="/assets/index-DmrpDn7c.css">
179
179
  <link rel="stylesheet" href="/theme-data.css" id="theme-data" />
180
180
  </head>
181
181
  <body>
@@ -1 +1 @@
1
- {"version":"41ee33142-1a386595"}
1
+ {"version":"6e3006007-08bb4bab"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion/droid-cli",
3
- "version": "0.11.22",
3
+ "version": "0.11.23",
4
4
  "description": "First-party Fusion pi extension that routes LLM calls through the Droid CLI subprocess.",
5
5
  "license": "MIT",
6
6
  "private": true,
package/dist/extension.js CHANGED
@@ -70833,6 +70833,8 @@ var init_gating_classifications = __esm({
70833
70833
  "fn_insight_show",
70834
70834
  "fn_insight_run_list",
70835
70835
  "fn_insight_run_show",
70836
+ "fn_goal_list",
70837
+ "fn_goal_show",
70836
70838
  "fn_mission_list",
70837
70839
  "fn_mission_show",
70838
70840
  "fn_list_agents",
@@ -91675,6 +91677,7 @@ __export(merger_exports, {
91675
91677
  VERIFICATION_LOG_MAX_CHARS: () => VERIFICATION_LOG_MAX_CHARS,
91676
91678
  VerificationError: () => VerificationError,
91677
91679
  __executePostMergeScriptStepForTests: () => __executePostMergeScriptStepForTests,
91680
+ __testOnlyBuildDeterministicMergeMessage: () => buildDeterministicMergeMessage,
91678
91681
  __test__: () => __test__,
91679
91682
  aiMergeTask: () => aiMergeTask,
91680
91683
  applyAutostashBySha: () => applyAutostashBySha,
@@ -94410,7 +94413,7 @@ async function filterStagedGitignoredPaths(rootDir, taskId) {
94410
94413
  return { unstaged: [], remainingStaged };
94411
94414
  }
94412
94415
  }
94413
- async function commitOrAmendMergeWithFixes(rootDir, taskId, branch, commitLog, includeTaskId, preAttemptHeadSha, authorArg, diffStat, settings, signal, aiSummary, aiSubject, fixModifiedFiles = /* @__PURE__ */ new Set(), store, auditor) {
94416
+ async function commitOrAmendMergeWithFixes(rootDir, taskId, branch, commitLog, includeTaskId, preAttemptHeadSha, authorArg, diffStat, settings, signal, aiSummary, aiBody, aiSubject, fixModifiedFiles = /* @__PURE__ */ new Set(), store, auditor) {
94414
94417
  try {
94415
94418
  const { stdout: squashStagedOut } = await execAsync26("git diff --cached --name-only", {
94416
94419
  cwd: rootDir,
@@ -94710,7 +94713,7 @@ ${msg}`;
94710
94713
  diffStat: messageDiffStat,
94711
94714
  includeTaskId,
94712
94715
  aiSummary,
94713
- aiBody: void 0,
94716
+ aiBody,
94714
94717
  aiSubject
94715
94718
  });
94716
94719
  let lineageId;
@@ -98142,6 +98145,7 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
98142
98145
  settings,
98143
98146
  options.signal,
98144
98147
  aiMergeSummary,
98148
+ aiMergeBody,
98145
98149
  aiMergeSubject,
98146
98150
  verificationFixModifiedFiles,
98147
98151
  store,
@@ -98273,6 +98277,7 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
98273
98277
  settings,
98274
98278
  options.signal,
98275
98279
  aiMergeSummary,
98280
+ aiMergeBody,
98276
98281
  aiMergeSubject,
98277
98282
  buildFixModifiedFiles,
98278
98283
  store,
@@ -99187,6 +99192,7 @@ async function executeMergeAttempt(params, aiTracker) {
99187
99192
  diffStat,
99188
99193
  includeTaskId,
99189
99194
  aiSummary: safeBody,
99195
+ aiBody: aiBody?.trim().length ? aiBody : safeBody,
99190
99196
  aiSubject
99191
99197
  });
99192
99198
  await enforceSquashFileScopeInvariant({
@@ -99381,6 +99387,7 @@ async function executeMergeAttempt(params, aiTracker) {
99381
99387
  diffStat: actualContext.diffStat || diffStat,
99382
99388
  includeTaskId,
99383
99389
  aiSummary,
99390
+ aiBody,
99384
99391
  aiSubject
99385
99392
  });
99386
99393
  const trailerArg = buildTaskTrailerArgs(taskId);
@@ -114114,12 +114121,7 @@ ${summary}`,
114114
114121
  this.tokenUsageBaselines.delete(task.id);
114115
114122
  session.dispose();
114116
114123
  await this.persistTokenUsage(task.id);
114117
- await this.store.updateTask(task.id, {
114118
- status: "failed",
114119
- error: "executor-exit-while-review-pending"
114120
- });
114121
114124
  await this.handoffTaskToReview(task, "executor-exit-while-review-pending");
114122
- this.options.onError?.(task, new Error("executor-exit-while-review-pending"));
114123
114125
  pendingReviewParked = true;
114124
114126
  break;
114125
114127
  }
@@ -121942,7 +121944,10 @@ var init_mission_execution_loop = __esm({
121942
121944
  try {
121943
121945
  await this.missionStore.transitionLoopState(feature.id, "implementing");
121944
121946
  if (feature.taskId) {
121945
- await this.processTaskOutcome(feature.taskId);
121947
+ const linkedTask = await this.taskStore.getTask(feature.taskId).catch(() => null);
121948
+ if (linkedTask && (linkedTask.column === "done" || linkedTask.column === "archived")) {
121949
+ await this.processTaskOutcome(feature.taskId);
121950
+ }
121946
121951
  }
121947
121952
  recoveredCount++;
121948
121953
  } catch (err) {
@@ -121953,7 +121958,10 @@ var init_mission_execution_loop = __esm({
121953
121958
  loopLog.log(`Recovery: feature ${feature.id} awaiting fix implementation`);
121954
121959
  if (feature.taskId) {
121955
121960
  try {
121956
- await this.processTaskOutcome(feature.taskId);
121961
+ const linkedTask = await this.taskStore.getTask(feature.taskId).catch(() => null);
121962
+ if (linkedTask && (linkedTask.column === "done" || linkedTask.column === "archived")) {
121963
+ await this.processTaskOutcome(feature.taskId);
121964
+ }
121957
121965
  recoveredCount++;
121958
121966
  } catch (err) {
121959
121967
  loopLog.error(`Recovery failed for needs_fix feature ${feature.id}:`, err);
@@ -121995,10 +122003,17 @@ var init_mission_execution_loop = __esm({
121995
122003
  }
121996
122004
  if (feature.loopState !== "implementing") {
121997
122005
  loopLog.log(`Feature ${feature.id} loopState is "${feature.loopState}"; skipping validation`);
122006
+ this.logFeatureWarningEvent(feature.id, "validation_skipped_loop_state", `Validation skipped: feature ${feature.id} is in loopState "${feature.loopState}" (expected "implementing").`, {
122007
+ taskId,
122008
+ loopState: feature.loopState
122009
+ });
121998
122010
  return;
121999
122011
  }
122000
122012
  if (this.activeValidations.has(feature.id)) {
122001
122013
  loopLog.log(`Feature ${feature.id} already has an active validation; skipping duplicate trigger`);
122014
+ this.logFeatureWarningEvent(feature.id, "validation_deduplicated", `Validation already running for feature ${feature.id}; duplicate trigger ignored.`, {
122015
+ taskId
122016
+ });
122002
122017
  return;
122003
122018
  }
122004
122019
  const assertions = this.missionStore.listAssertionsForFeature(feature.id);
@@ -122466,6 +122481,10 @@ ${taskContext}` : ""}`;
122466
122481
  this.missionStore.completeValidatorRun(runId, "blocked", blockedReason);
122467
122482
  }
122468
122483
  loopLog.log(`Feature ${featureId} blocked: ${blockedReason}`);
122484
+ this.logFeatureErrorEvent(featureId, "validation_blocked", `Validation blocked for feature ${featureId}: ${blockedReason ?? "no reason provided"}`, {
122485
+ runId,
122486
+ blockedReason: blockedReason ?? null
122487
+ });
122469
122488
  if (this.missionAutopilot?.notifyValidationComplete) {
122470
122489
  await this.missionAutopilot.notifyValidationComplete(featureId, "blocked");
122471
122490
  }
@@ -122483,6 +122502,10 @@ ${taskContext}` : ""}`;
122483
122502
  this.missionStore.completeValidatorRun(runId, "error", error);
122484
122503
  }
122485
122504
  loopLog.error(`Feature ${featureId} validation error: ${error}`);
122505
+ this.logFeatureErrorEvent(featureId, "validation_error", `Validation error for feature ${featureId}: ${error}`, {
122506
+ runId,
122507
+ error
122508
+ });
122486
122509
  if (this.missionAutopilot?.notifyValidationComplete) {
122487
122510
  await this.missionAutopilot.notifyValidationComplete(featureId, "error");
122488
122511
  }
@@ -122491,6 +122514,31 @@ ${taskContext}` : ""}`;
122491
122514
  loopLog.error(`Error handling validation error for ${featureId}:`, err);
122492
122515
  }
122493
122516
  }
122517
+ logFeatureWarningEvent(featureId, code, description, metadata) {
122518
+ this.logFeatureMissionEvent(featureId, "warning", code, description, metadata);
122519
+ }
122520
+ logFeatureErrorEvent(featureId, code, description, metadata) {
122521
+ this.logFeatureMissionEvent(featureId, "error", code, description, metadata);
122522
+ }
122523
+ logFeatureMissionEvent(featureId, eventType, code, description, metadata) {
122524
+ const feature = this.missionStore.getFeature(featureId);
122525
+ if (!feature) return;
122526
+ const slice = this.missionStore.getSlice(feature.sliceId);
122527
+ if (!slice) return;
122528
+ const milestone = this.missionStore.getMilestone(slice.milestoneId);
122529
+ if (!milestone) return;
122530
+ try {
122531
+ this.missionStore.logMissionEvent?.(milestone.missionId, eventType, description, {
122532
+ code,
122533
+ featureId,
122534
+ sliceId: slice.id,
122535
+ milestoneId: milestone.id,
122536
+ ...metadata
122537
+ });
122538
+ } catch (err) {
122539
+ loopLog.warn(`Failed to log mission ${eventType} event for feature ${featureId}:`, err);
122540
+ }
122541
+ }
122494
122542
  };
122495
122543
  }
122496
122544
  });
@@ -126953,6 +127001,78 @@ var init_error_classifier = __esm({
126953
127001
  }
126954
127002
  });
126955
127003
 
127004
+ // ../engine/src/goal-context-injector.ts
127005
+ function normalizeTitle(title) {
127006
+ return title.replace(/\s*\n+\s*/g, " ").trim();
127007
+ }
127008
+ function renderGoalContext(goals) {
127009
+ const lines = goals.map((goal) => `- ${goal.id}: ${normalizeTitle(goal.title)}`);
127010
+ return `## Active Goals
127011
+
127012
+ ${lines.join("\n")}`;
127013
+ }
127014
+ function buildGoalContextSection(input) {
127015
+ const { activeGoals, onTruncated } = input;
127016
+ if (activeGoals.length === 0) {
127017
+ return { text: "", emittedGoalIds: [], truncated: null };
127018
+ }
127019
+ const sortedGoals = [...activeGoals].sort((a, b2) => {
127020
+ const byCreated = a.createdAt.localeCompare(b2.createdAt);
127021
+ if (byCreated !== 0) {
127022
+ return byCreated;
127023
+ }
127024
+ return a.id.localeCompare(b2.id);
127025
+ });
127026
+ const resolvedMaxGoals = Math.min(input.maxGoals ?? MAX_INJECTED_GOALS, MAX_INJECTED_GOALS);
127027
+ const charBudget = input.charBudget ?? DEFAULT_GOAL_INJECTION_CHAR_BUDGET;
127028
+ const droppedGoalIds = [];
127029
+ let selectedGoals = sortedGoals.slice(0, resolvedMaxGoals);
127030
+ if (sortedGoals.length > resolvedMaxGoals) {
127031
+ droppedGoalIds.push(...sortedGoals.slice(resolvedMaxGoals).map((goal) => goal.id));
127032
+ }
127033
+ let text = renderGoalContext(selectedGoals);
127034
+ let usedBudgetDrop = false;
127035
+ while (selectedGoals.length > 1 && text.length > charBudget) {
127036
+ const dropped = selectedGoals[selectedGoals.length - 1];
127037
+ selectedGoals = selectedGoals.slice(0, -1);
127038
+ droppedGoalIds.push(dropped.id);
127039
+ text = renderGoalContext(selectedGoals);
127040
+ usedBudgetDrop = true;
127041
+ }
127042
+ let truncated = null;
127043
+ if (droppedGoalIds.length > 0) {
127044
+ truncated = {
127045
+ reason: usedBudgetDrop ? "budget" : "cap",
127046
+ requested: activeGoals.length,
127047
+ emitted: selectedGoals.length,
127048
+ droppedGoalIds,
127049
+ charBudget,
127050
+ producedChars: text.length
127051
+ };
127052
+ onTruncated?.(truncated);
127053
+ }
127054
+ return {
127055
+ text,
127056
+ emittedGoalIds: selectedGoals.map((goal) => goal.id),
127057
+ truncated
127058
+ };
127059
+ }
127060
+ var MAX_INJECTED_GOALS, resolvedActiveGoalLimit, DEFAULT_GOAL_INJECTION_CHAR_BUDGET;
127061
+ var init_goal_context_injector = __esm({
127062
+ "../engine/src/goal-context-injector.ts"() {
127063
+ "use strict";
127064
+ init_src();
127065
+ MAX_INJECTED_GOALS = 5;
127066
+ resolvedActiveGoalLimit = "ACTIVE_GOAL_LIMIT" in src_exports && typeof ACTIVE_GOAL_LIMIT === "number" ? ACTIVE_GOAL_LIMIT : MAX_INJECTED_GOALS;
127067
+ if (MAX_INJECTED_GOALS > resolvedActiveGoalLimit) {
127068
+ throw new Error(
127069
+ `MAX_INJECTED_GOALS (${MAX_INJECTED_GOALS}) cannot exceed ACTIVE_GOAL_LIMIT (${resolvedActiveGoalLimit})`
127070
+ );
127071
+ }
127072
+ DEFAULT_GOAL_INJECTION_CHAR_BUDGET = 600;
127073
+ }
127074
+ });
127075
+
126956
127076
  // ../engine/src/experiment/benchmark-runner.ts
126957
127077
  import { spawn as spawn7 } from "node:child_process";
126958
127078
  import { mkdtemp, writeFile as writeFile17 } from "node:fs/promises";
@@ -132086,9 +132206,19 @@ var init_in_process_runtime = __esm({
132086
132206
  missionAutopilot: missionAutopilot ? {
132087
132207
  notifyValidationComplete: async (featureId) => {
132088
132208
  const feature = missionStore.getFeature(featureId);
132089
- if (feature?.taskId) {
132090
- await missionAutopilot.handleTaskCompletion(feature.taskId);
132209
+ if (!feature?.taskId) {
132210
+ return;
132091
132211
  }
132212
+ const slice = missionStore.getSlice(feature.sliceId);
132213
+ const milestone = slice ? missionStore.getMilestone(slice.milestoneId) : void 0;
132214
+ const missionId = milestone?.missionId;
132215
+ if (missionId) {
132216
+ const mission = missionStore.getMission(missionId);
132217
+ if (mission?.autopilotEnabled && !missionAutopilot.isWatching(missionId)) {
132218
+ missionAutopilot.watchMission(missionId);
132219
+ }
132220
+ }
132221
+ await missionAutopilot.handleTaskCompletion(feature.taskId);
132092
132222
  }
132093
132223
  } : void 0,
132094
132224
  rootDir: this.config.workingDirectory,
@@ -134807,6 +134937,10 @@ function buildMergeSystemPrompt2(agentPrompts) {
134807
134937
  " - The subject line must CONCISELY SUMMARIZE the squashed changes in",
134808
134938
  ' imperative mood (e.g. "add X", "fix Y") based on the actual diff \u2014 do',
134809
134939
  " not just restate the task title.",
134940
+ " - The commit BODY must include:",
134941
+ " 1) one short narrative summary line,",
134942
+ " 2) a bullet list of key changes, and",
134943
+ " 3) a `Files changed:` section populated from `git diff --stat`.",
134810
134944
  " - Include the task-id prefix and the trailer lines EXACTLY as given in the",
134811
134945
  " task instructions (they associate the commit with the board task)."
134812
134946
  ].filter((l) => l !== void 0).join("\n");
@@ -134820,11 +134954,15 @@ function buildMergePrompt2(input) {
134820
134954
  "Steps:",
134821
134955
  ` 1. Run: git merge --squash ${input.branch}`,
134822
134956
  " 2. If there are conflicts, resolve them (favor the task's intent), then `git add` the resolved files.",
134823
- " 3. Commit the staged result as a SINGLE commit whose subject summarizes the",
134824
- ` actual changes${input.taskTitle ? ` (task title hint: ${JSON.stringify(input.taskTitle)})` : ""}, including the required trailers:`,
134825
- ` git commit -m ${subjectShape}${trailerArgs}`,
134957
+ " 3. Build a merge body from the staged squash diff:",
134958
+ " - one short narrative summary line",
134959
+ " - bullet list of key changes",
134960
+ " - `Files changed:` + the output of `git diff --stat`",
134961
+ " 4. Commit the staged result as a SINGLE commit whose subject summarizes the",
134962
+ ` actual changes${input.taskTitle ? ` (task title hint: ${JSON.stringify(input.taskTitle)})` : ""}, including the body above and required trailers:`,
134963
+ ` git commit -m ${subjectShape} -m "<narrative + bullet list + Files changed: ...>"${trailerArgs}`,
134826
134964
  " Keep the trailer line(s) verbatim \u2014 they link the commit to the board task.",
134827
- " 4. Verify `git log --oneline ${tip}..HEAD` shows exactly one new commit and `git status` is clean.".replace("${tip}", short(input.tipSha)),
134965
+ " 5. Verify `git log --oneline ${tip}..HEAD` shows exactly one new commit and `git status` is clean.".replace("${tip}", short(input.tipSha)),
134828
134966
  "",
134829
134967
  "If `git merge --squash` reports the branch is already up to date (nothing to",
134830
134968
  "merge), do nothing and leave HEAD unchanged."
@@ -141288,6 +141426,7 @@ __export(src_exports2, {
141288
141426
  BranchConflictError: () => BranchConflictError,
141289
141427
  BranchCrossContaminationError: () => BranchCrossContaminationError,
141290
141428
  CronRunner: () => CronRunner,
141429
+ DEFAULT_GOAL_INJECTION_CHAR_BUDGET: () => DEFAULT_GOAL_INJECTION_CHAR_BUDGET,
141291
141430
  DEFAULT_NTFY_EVENTS: () => DEFAULT_NTFY_EVENTS,
141292
141431
  DiffVolumeRegressionError: () => DiffVolumeRegressionError,
141293
141432
  EngineAlreadyRunningError: () => EngineAlreadyRunningError,
@@ -141312,6 +141451,7 @@ __export(src_exports2, {
141312
141451
  KNOWN_EXTERNAL_INTEGRATIONS: () => KNOWN_EXTERNAL_INTEGRATIONS,
141313
141452
  LLMSynthesisProvider: () => LLMSynthesisProvider,
141314
141453
  LocalDocsProvider: () => LocalDocsProvider,
141454
+ MAX_INJECTED_GOALS: () => MAX_INJECTED_GOALS,
141315
141455
  MOCK_PROVIDER_ID: () => MOCK_PROVIDER_ID3,
141316
141456
  MOCK_SYNTHETIC_TOKEN_USAGE: () => MOCK_SYNTHETIC_TOKEN_USAGE,
141317
141457
  MergeAbortedError: () => MergeAbortedError,
@@ -141387,6 +141527,7 @@ __export(src_exports2, {
141387
141527
  assertSafeUrl: () => assertSafeUrl,
141388
141528
  auditSquashMerge: () => auditSquashMerge,
141389
141529
  buildAgentChatPrompt: () => buildAgentChatPrompt,
141530
+ buildGoalContextSection: () => buildGoalContextSection,
141390
141531
  buildNtfyClickUrl: () => buildNtfyClickUrl,
141391
141532
  buildRuntimeResolutionContext: () => buildRuntimeResolutionContext,
141392
141533
  buildSystemPromptWithInstructions: () => buildSystemPromptWithInstructions,
@@ -141529,6 +141670,7 @@ var init_src2 = __esm({
141529
141670
  init_external_integrations();
141530
141671
  init_web_fetch();
141531
141672
  init_error_classifier();
141673
+ init_goal_context_injector();
141532
141674
  init_worktrunk_installer();
141533
141675
  init_worktrunk_failure_handler();
141534
141676
  init_usage_limit_detector();
@@ -164265,6 +164407,44 @@ Status: ${goal.status}${softWarning ? `
164265
164407
  };
164266
164408
  }
164267
164409
  });
164410
+ pi2.registerTool({
164411
+ name: "fn_goal_show",
164412
+ label: "fn: Show Goal",
164413
+ description: "Show full details for a single goal by ID.",
164414
+ promptSnippet: "Show goal details by ID",
164415
+ promptGuidelines: [
164416
+ "Use to inspect a specific goal after listing or referencing its ID",
164417
+ "Cite the goal ID and status when summarizing or planning from this output",
164418
+ "Read-only retrieval; does not mutate goals"
164419
+ ],
164420
+ parameters: Type8.Object({
164421
+ id: Type8.String({ description: "Goal ID (G-\u2026)" })
164422
+ }),
164423
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
164424
+ const store = await getStore2(ctx.cwd);
164425
+ const goalStore = store.getGoalStore();
164426
+ const goal = goalStore.getGoal(params.id);
164427
+ if (!goal) {
164428
+ return {
164429
+ isError: true,
164430
+ content: [{ type: "text", text: `Goal ${params.id} not found` }],
164431
+ details: { code: "GOAL_NOT_FOUND", goalId: params.id }
164432
+ };
164433
+ }
164434
+ const lines = [];
164435
+ lines.push(`${goal.id}: ${goal.title}`);
164436
+ lines.push(`Status: ${goal.status}`);
164437
+ lines.push(`Created: ${goal.createdAt}`);
164438
+ lines.push(`Updated: ${goal.updatedAt}`);
164439
+ if (goal.description) {
164440
+ lines.push(`Description: ${goal.description}`);
164441
+ }
164442
+ return {
164443
+ content: [{ type: "text", text: lines.join("\n") }],
164444
+ details: { goal }
164445
+ };
164446
+ }
164447
+ });
164268
164448
  pi2.registerTool({
164269
164449
  name: "fn_mission_show",
164270
164450
  label: "fn: Show Mission",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion/pi-claude-cli",
3
- "version": "0.36.0",
3
+ "version": "0.37.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,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/cli-printing-press",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "type": "module",
5
5
  "description": "CLI Printing Press plugin package for Fusion",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/cursor-runtime",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/dependency-graph",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/droid-runtime",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/hermes-runtime",
3
- "version": "0.2.46",
3
+ "version": "0.2.47",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/openclaw-runtime",
3
- "version": "0.2.46",
3
+ "version": "0.2.47",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/paperclip-runtime",
3
- "version": "0.2.46",
3
+ "version": "0.2.47",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/reports",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "description": "Reports plugin for Fusion",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/roadmap",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/whatsapp-chat",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "description": "WhatsApp Web (Baileys) chat bridge for Fusion agents",
6
6
  "keywords": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runfusion/fusion",
3
- "version": "0.36.0",
3
+ "version": "0.37.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",
@@ -30,7 +30,7 @@ Mission → Milestone → Slice → Feature → Task
30
30
  - **Task tools** — `fn_task_create`, `fn_task_update`, `fn_task_list`, `fn_task_show`, `fn_task_attach`, `fn_task_pause`, `fn_task_unpause`, `fn_task_retry`, `fn_task_duplicate`, `fn_task_refine`, `fn_task_archive`, `fn_task_unarchive`, `fn_task_delete`, `fn_task_plan`
31
31
  - **GitHub tools** — `fn_task_import_github`, `fn_task_import_github_issue`, `fn_task_browse_github_issues`
32
32
  - **Mission tools** — `fn_mission_create`, `fn_mission_list`, `fn_mission_show`, `fn_mission_delete`, `fn_milestone_add`, `fn_slice_add`, `fn_feature_add`, `fn_slice_activate`, `fn_feature_link_task`, `fn_feature_update`, `fn_milestone_update`
33
- - **Goal tools** — `fn_goal_list`, `fn_goal_create`, `fn_goal_archive`
33
+ - **Goal tools** — `fn_goal_list`, `fn_goal_create`, `fn_goal_archive`, `fn_goal_show`
34
34
  - **Agent tools** — `fn_agent_stop`, `fn_agent_start`, `fn_agent_create`, `fn_agent_delete`, `fn_list_agents`, `fn_delegate_task`, `fn_agent_show`, `fn_agent_org_chart`
35
35
  - **Skills tools** — `fn_skills_search`, `fn_skills_install`
36
36
  - **Insight tools** — `fn_insight_list`, `fn_insight_show`, `fn_insight_run_list`, `fn_insight_run_show`
@@ -301,6 +301,14 @@ Archive a goal by ID.
301
301
  |-----------|------|----------|-------------|
302
302
  | `id` | string | ✓ | Goal ID (G-…) to archive |
303
303
 
304
+ ### fn_goal_show
305
+
306
+ Show full details for a single goal by ID.
307
+
308
+ | Parameter | Type | Required | Description |
309
+ |-----------|------|----------|-------------|
310
+ | `id` | string | ✓ | Goal ID (G-…) |
311
+
304
312
  ## Agent Tools
305
313
 
306
314
  ### fn_agent_stop
@@ -523,6 +531,14 @@ Group kept experiment runs into reviewable branches and finalize the session. Us
523
531
  | `summary` | string | — | Optional finalize summary |
524
532
 
525
533
  <!-- END: extension-tools -->
534
+
535
+ ## Goal retrieval contract notes
536
+
537
+ ### Goal-show response contract
538
+
539
+ - **Success:** returns `details.goal` as the complete goal JSON object (`id`, `title`, optional `description`, `status`, `createdAt`, `updatedAt`) and `content[0].text` with those same human-readable fields.
540
+ - **Not found:** returns `isError: true` with `details.code: "GOAL_NOT_FOUND"` and `details.goalId` set to the requested id.
541
+
526
542
  ## Dashboard Command
527
543
 
528
544
  ### /fn
@@ -46,6 +46,7 @@ All skill/extension tool invocations in this catalog use the public `fn_*` names
46
46
  | `fn_goal_list` | List goals by status with active-goal warning details. |
47
47
  | `fn_goal_create` | Create a new project goal. |
48
48
  | `fn_goal_archive` | Archive a goal by ID. |
49
+ | `fn_goal_show` | Show full details for a single goal by ID. |
49
50
  | `fn_mission_show` | Show mission details with full hierarchy: milestones → slices → features. |
50
51
  | `fn_mission_delete` | Delete a mission and all its milestones, slices, and features. Cannot be undone. |
51
52
  | `fn_milestone_add` | Add a milestone to a mission. Milestones represent phases of work. |
@@ -1 +0,0 @@
1
- .goals-view{display:flex;flex-direction:column;gap:var(--space-lg);padding:var(--space-lg)}.goals-header{display:flex;justify-content:space-between;align-items:center;gap:var(--space-md)}.goals-title{margin:0;color:var(--text);font-size:calc(var(--space-lg) + var(--space-xs))}.goals-count{margin:0;color:var(--text-muted)}.goals-add-button{display:inline-flex;align-items:center;gap:var(--space-sm)}.goals-add-button:focus-visible,.goals-card:focus-visible,.goals-activate-button:focus-visible{outline:none;box-shadow:var(--focus-ring-strong)}.goals-warning{margin:0;padding:var(--space-md);border-radius:var(--radius-md);border:calc(var(--space-xs) / 4) solid var(--color-warning);background:color-mix(in srgb,var(--color-warning) 10%,transparent);color:var(--color-warning)}.goals-error{margin:0}.goals-list{display:flex;flex-direction:column;gap:var(--space-md)}.goals-card{display:flex;align-items:center;justify-content:space-between;gap:var(--space-md)}.goals-card-main{min-width:0}.goals-card-title{margin:0;color:var(--text);font-size:calc(var(--space-md) + var(--space-xs))}.goals-card-status{margin:var(--space-xs) 0 0;color:var(--text-muted)}.goals-activate-button{min-width:calc(var(--space-2xl) * 2)}.goals-empty{color:var(--text-muted)}@media(max-width:768px){.goals-header{flex-direction:column;align-items:stretch}.goals-add-button,.goals-card,.goals-activate-button{min-height:calc(var(--space-xl) + var(--space-md))}.goals-card{flex-direction:column;align-items:stretch}}
@@ -1 +0,0 @@
1
- import{j as t,r as g}from"./vendor-react-K0fH_qHe.js";import{J as h}from"./index-B9Ro_NwC.js";import"./vendor-xterm-DzcZoU0P.js";import"./vendor-codemirror-jBKmHyH0.js";const v=5,p=3,x=[{id:"goal-1",title:"Reduce mean review turnaround",status:"active",createdAt:"2026-05-14T09:30:00.000Z"},{id:"goal-2",title:"Raise merge reliability coverage",status:"active",createdAt:"2026-05-15T12:00:00.000Z"},{id:"goal-3",title:"Ship dashboard quality audit",status:"inactive",createdAt:"2026-05-16T08:15:00.000Z"}];function j(n){const[s,i]=g.useState(()=>n??x),[c,o]=g.useState(null),l=g.useMemo(()=>s.filter(e=>e.status==="active").length,[s]);function r(){if(l>=v){o("Cannot activate more than 5 goals. Resolve an active goal before adding another active goal.");return}o(null),i(e=>[...e,{id:`goal-${e.length+1}`,title:`New Goal ${e.length+1}`,status:"active",createdAt:new Date().toISOString()}])}function a(e){const m=s.find(d=>d.id===e);if(!(!m||m.status==="active")){if(l>=v){o("Cannot activate more than 5 goals. Resolve an active goal before activating another.");return}o(null),i(d=>d.map(u=>u.id===e?{...u,status:"active"}:u))}}return{goals:s,activeCount:l,errorMessage:c,addGoal:r,activateGoal:a}}function A({initialGoals:n}){const{goals:s,activeCount:i,errorMessage:c,addGoal:o,activateGoal:l}=j(n),r=i>=p&&i<=v;return t.jsxs("section",{className:"goals-view","data-testid":"goals-view",children:[t.jsxs("header",{className:"goals-header",children:[t.jsxs("div",{children:[t.jsx("h2",{className:"goals-title",children:"Goals"}),t.jsxs("p",{className:"goals-count","data-testid":"goals-active-count",children:[i," active goals"]})]}),t.jsxs("button",{type:"button",className:"btn btn-primary goals-add-button",onClick:o,"data-testid":"goals-add-button",children:[t.jsx(h,{"aria-hidden":"true"}),"Add Goal"]})]}),r?t.jsx("p",{className:"goals-warning",role:"status",children:"Approaching the 5-active goal cap. Keep active goals focused."}):null,c?t.jsx("p",{className:"form-error goals-error",role:"alert",children:c}):null,s.length===0?t.jsx("div",{className:"goals-empty card","data-testid":"goals-empty-state",children:"No goals yet. Add one to begin tracking strategic outcomes."}):t.jsx("div",{className:"goals-list","data-testid":"goals-list",children:s.map(a=>t.jsxs("article",{className:"card goals-card","data-testid":`goal-card-${a.id}`,children:[t.jsxs("div",{className:"goals-card-main",children:[t.jsx("h3",{className:"goals-card-title",children:a.title}),t.jsxs("p",{className:"goals-card-status",children:["Status: ",a.status]})]}),t.jsx("button",{type:"button",className:"btn goals-activate-button",disabled:a.status==="active",onClick:()=>l(a.id),"data-testid":`goal-activate-${a.id}`,children:a.status==="active"?"Active":"Activate"})]},a.id))})]})}export{A as GoalsView};