@runfusion/fusion 0.24.0 → 0.26.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 (167) hide show
  1. package/README.md +6 -0
  2. package/dist/bin.js +18646 -15669
  3. package/dist/client/assets/AgentDetailView-Cv-vgOj3.js +18 -0
  4. package/dist/client/assets/{AgentsView-BkB9FiMT.js → AgentsView-D6Zi5zfP.js} +4 -4
  5. package/dist/client/assets/ChatView-CAHjY9uO.js +1 -0
  6. package/dist/client/assets/{DevServerView-BkvtjZBa.js → DevServerView--_WBvIDQ.js} +1 -1
  7. package/dist/client/assets/{DirectoryPicker-BK-KbnhP.js → DirectoryPicker-xedtR-Rd.js} +1 -1
  8. package/dist/client/assets/{DocumentsView-BEg1CQAk.js → DocumentsView-Bg2oaZks.js} +1 -1
  9. package/dist/client/assets/{EvalsView-Berf9bQm.js → EvalsView-B3uOCXfr.js} +1 -1
  10. package/dist/client/assets/{ExperimentalAgentOnboardingModal-jcInE50G.js → ExperimentalAgentOnboardingModal-Bx6yXVS5.js} +1 -1
  11. package/dist/client/assets/{InsightsView-BX5bSF1J.js → InsightsView-Q1zvtF4F.js} +1 -1
  12. package/dist/client/assets/MemoryView-xcN_eouf.js +2 -0
  13. package/dist/client/assets/MemoryView-zaXewZzi.css +1 -0
  14. package/dist/client/assets/{NodesView-DLUOBLf6.js → NodesView-RxXg58_Q.js} +1 -1
  15. package/dist/client/assets/{PiExtensionsManager-COlJf0Kx.js → PiExtensionsManager-Cc8aAZXg.js} +2 -2
  16. package/dist/client/assets/PluginManager-BEkyBajl.js +1 -0
  17. package/dist/client/assets/{ResearchView-BzCcDAS4.css → ResearchView-BEI4ZSGs.css} +1 -1
  18. package/dist/client/assets/ResearchView-CERNf7sJ.js +1 -0
  19. package/dist/client/assets/{SettingsModal-yRqM4DV8.js → SettingsModal-B1r0yASu.js} +1 -1
  20. package/dist/client/assets/SettingsModal-BLsac7CJ.js +31 -0
  21. package/dist/client/assets/SettingsModal-Cis-4Lot.css +1 -0
  22. package/dist/client/assets/{SetupWizardModal-uUZk3TKT.js → SetupWizardModal-D1q548_L.js} +1 -1
  23. package/dist/client/assets/{SkillsView-CP8JX0P_.js → SkillsView-ClLM6u6p.js} +1 -1
  24. package/dist/client/assets/StashRecoveryView-B_8WIQEo.css +1 -0
  25. package/dist/client/assets/StashRecoveryView-ze0pEZ5U.js +1 -0
  26. package/dist/client/assets/{TodoView-DCRIkDZ-.js → TodoView-CTmIfy2M.js} +1 -1
  27. package/dist/client/assets/{dashboard-view-lR7YYmSC.js → dashboard-view-4xAN3yO5.js} +2 -2
  28. package/dist/client/assets/{folder-open-DHjELt8-.js → folder-open-BZuKESeq.js} +1 -1
  29. package/dist/client/assets/index-Bdw6llW6.js +692 -0
  30. package/dist/client/assets/index-CZGlyJuS.css +1 -0
  31. package/dist/client/assets/{star-DYesq1AV.js → star-D75YKEq-.js} +1 -1
  32. package/dist/client/assets/{upload-DTWF3Db5.js → upload-BYYTgWFj.js} +1 -1
  33. package/dist/client/assets/{users--syrel4l.js → users-RS90Aii3.js} +1 -1
  34. package/dist/client/index.html +2 -2
  35. package/dist/client/version.json +1 -1
  36. package/dist/droid-cli/package.json +1 -1
  37. package/dist/extension.js +5640 -3618
  38. package/dist/pi-claude-cli/package.json +1 -1
  39. package/dist/plugins/fusion-plugin-cli-printing-press/manifest.json +6 -0
  40. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +26 -0
  41. package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/manifest.test.ts +20 -0
  42. package/dist/plugins/fusion-plugin-cli-printing-press/src/index.ts +14 -0
  43. package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +9 -11
  44. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  45. package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +30 -0
  46. package/dist/plugins/fusion-plugin-dependency-graph/package.json +3 -28
  47. package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +899 -895
  48. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  49. package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +68 -71
  50. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  51. package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +47 -50
  52. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  53. package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +155 -109
  54. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  55. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  56. package/dist/plugins/fusion-plugin-reports/src/index.ts +49 -3
  57. package/dist/plugins/fusion-plugin-reports/src/report-schema.ts +38 -0
  58. package/dist/plugins/fusion-plugin-reports/src/store/__tests__/report-schema.test.ts +66 -0
  59. package/dist/plugins/fusion-plugin-reports/src/store/__tests__/report-store.test.ts +177 -0
  60. package/dist/plugins/fusion-plugin-reports/src/store/report-store.ts +341 -0
  61. package/dist/plugins/fusion-plugin-reports/src/store/report-types.ts +77 -0
  62. package/dist/plugins/fusion-plugin-roadmap/{src/dashboard/RoadmapsView.css → bundled.css} +13 -219
  63. package/dist/plugins/fusion-plugin-roadmap/bundled.js +29535 -0
  64. package/dist/plugins/fusion-plugin-roadmap/package.json +4 -41
  65. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  66. package/package.json +2 -3
  67. package/dist/client/assets/AgentDetailView-gy_5SUj2.js +0 -18
  68. package/dist/client/assets/ChatView-B_-B8fqu.js +0 -1
  69. package/dist/client/assets/MemoryView-CKElJY_3.js +0 -2
  70. package/dist/client/assets/MemoryView-DiajLXby.css +0 -1
  71. package/dist/client/assets/PluginManager-CfW55BF4.js +0 -1
  72. package/dist/client/assets/ResearchView-B256Lr8I.js +0 -1
  73. package/dist/client/assets/SettingsModal-BeA_nQtW.js +0 -31
  74. package/dist/client/assets/SettingsModal-DzsLquBu.css +0 -1
  75. package/dist/client/assets/index-CQyVRLOb.js +0 -692
  76. package/dist/client/assets/index-CxA2Nn0_.css +0 -1
  77. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraph.css +0 -58
  78. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraph.tsx +0 -301
  79. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphHighlight.css +0 -27
  80. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.css +0 -157
  81. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.tsx +0 -126
  82. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphToolbar.css +0 -35
  83. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphToolbar.tsx +0 -36
  84. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.highlighting.test.tsx +0 -112
  85. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.persistence.test.tsx +0 -115
  86. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.test.tsx +0 -128
  87. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphTaskNode.drag.test.tsx +0 -82
  88. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphTaskNode.test.tsx +0 -307
  89. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphToolbar.test.tsx +0 -60
  90. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/edges.test.tsx +0 -75
  91. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/filtering.test.tsx +0 -62
  92. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/filters.test.ts +0 -78
  93. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/graphPositionStorage.test.ts +0 -95
  94. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/host-integration.test.ts +0 -74
  95. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/index.test.ts +0 -58
  96. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/interactions.test.tsx +0 -121
  97. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/layout.test.ts +0 -70
  98. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/persistence.test.tsx +0 -89
  99. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphData.test.ts +0 -86
  100. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphInteraction.test.ts +0 -167
  101. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphPositions.test.ts +0 -66
  102. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useNodeDrag.test.ts +0 -81
  103. package/dist/plugins/fusion-plugin-dependency-graph/src/dashboard-interop.d.ts +0 -35
  104. package/dist/plugins/fusion-plugin-dependency-graph/src/dashboard-view.tsx +0 -19
  105. package/dist/plugins/fusion-plugin-dependency-graph/src/edges.tsx +0 -70
  106. package/dist/plugins/fusion-plugin-dependency-graph/src/filters.ts +0 -8
  107. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/__tests__/useDependencyChain.test.ts +0 -53
  108. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useDependencyChain.ts +0 -60
  109. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useGraphPositions.ts +0 -45
  110. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useNodeDrag.ts +0 -114
  111. package/dist/plugins/fusion-plugin-dependency-graph/src/index.ts +0 -24
  112. package/dist/plugins/fusion-plugin-dependency-graph/src/layout.ts +0 -91
  113. package/dist/plugins/fusion-plugin-dependency-graph/src/styles/drag.css +0 -15
  114. package/dist/plugins/fusion-plugin-dependency-graph/src/types.ts +0 -21
  115. package/dist/plugins/fusion-plugin-dependency-graph/src/useGraphData.ts +0 -17
  116. package/dist/plugins/fusion-plugin-dependency-graph/src/useGraphInteraction.ts +0 -292
  117. package/dist/plugins/fusion-plugin-dependency-graph/src/utils/graphPositionStorage.ts +0 -65
  118. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/api-client.test.ts +0 -101
  119. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/index.test.ts +0 -92
  120. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/roadmap-routes.test.ts +0 -48
  121. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/roadmap-suggestions.test.ts +0 -31
  122. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/RoadmapsView.tsx +0 -2559
  123. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/__tests__/RoadmapsView.test.tsx +0 -1144
  124. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/__tests__/useRoadmaps.test.ts +0 -1756
  125. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/api.ts +0 -70
  126. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/test-setup.ts +0 -7
  127. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/types.ts +0 -1
  128. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useConfirm.ts +0 -8
  129. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useRoadmaps.ts +0 -1188
  130. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useViewportMode.ts +0 -20
  131. package/dist/plugins/fusion-plugin-roadmap/src/dashboard-view.tsx +0 -6
  132. package/dist/plugins/fusion-plugin-roadmap/src/index.ts +0 -74
  133. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-routes.ts +0 -1
  134. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-schema.ts +0 -41
  135. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-suggestions.d.ts +0 -15
  136. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-suggestions.ts +0 -15
  137. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.d.ts +0 -283
  138. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.d.ts.map +0 -1
  139. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.js +0 -21
  140. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.js.map +0 -1
  141. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.ts +0 -310
  142. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.d.ts +0 -5
  143. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.d.ts.map +0 -1
  144. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.js +0 -361
  145. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.js.map +0 -1
  146. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.ts +0 -408
  147. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.d.ts +0 -68
  148. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.d.ts.map +0 -1
  149. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.js +0 -300
  150. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.js.map +0 -1
  151. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.ts +0 -381
  152. package/dist/plugins/fusion-plugin-roadmap/src/server/index.d.ts +0 -3
  153. package/dist/plugins/fusion-plugin-roadmap/src/server/index.ts +0 -1
  154. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-handoff.test.ts +0 -445
  155. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-ordering.test.ts +0 -334
  156. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-store.test.ts +0 -1318
  157. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-handoff.ts +0 -163
  158. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.d.ts +0 -37
  159. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.d.ts.map +0 -1
  160. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.js +0 -188
  161. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.js.map +0 -1
  162. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.ts +0 -311
  163. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.d.ts +0 -299
  164. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.d.ts.map +0 -1
  165. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.js +0 -765
  166. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.js.map +0 -1
  167. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.ts +0 -1001
@@ -16797,7 +16797,7 @@ var init_models = __esm({
16797
16797
  });
16798
16798
 
16799
16799
  // ../../node_modules/.pnpm/@mariozechner+pi-ai@0.72.1_@modelcontextprotocol+sdk@1.28.0_zod@4.3.6__ws@8.20.0_zod@4.3.6/node_modules/@mariozechner/pi-ai/dist/utils/event-stream.js
16800
- var EventStream, AssistantMessageEventStream2;
16800
+ var EventStream, AssistantMessageEventStream;
16801
16801
  var init_event_stream = __esm({
16802
16802
  "../../node_modules/.pnpm/@mariozechner+pi-ai@0.72.1_@modelcontextprotocol+sdk@1.28.0_zod@4.3.6__ws@8.20.0_zod@4.3.6/node_modules/@mariozechner/pi-ai/dist/utils/event-stream.js"() {
16803
16803
  EventStream = class {
@@ -16857,7 +16857,7 @@ var init_event_stream = __esm({
16857
16857
  return this.finalResultPromise;
16858
16858
  }
16859
16859
  };
16860
- AssistantMessageEventStream2 = class extends EventStream {
16860
+ AssistantMessageEventStream = class extends EventStream {
16861
16861
  constructor() {
16862
16862
  super((event) => event.type === "done" || event.type === "error", (event) => {
16863
16863
  if (event.type === "done") {
@@ -18600,7 +18600,7 @@ var init_openai_codex_responses = __esm({
18600
18600
  "in_progress"
18601
18601
  ]);
18602
18602
  streamOpenAICodexResponses = (model, context, options) => {
18603
- const stream2 = new AssistantMessageEventStream2();
18603
+ const stream2 = new AssistantMessageEventStream();
18604
18604
  (async () => {
18605
18605
  const output = {
18606
18606
  role: "assistant",
@@ -26131,7 +26131,7 @@ var init_anthropic = __esm({
26131
26131
  "content_block_stop"
26132
26132
  ]);
26133
26133
  streamAnthropic = (model, context, options) => {
26134
- const stream2 = new AssistantMessageEventStream2();
26134
+ const stream2 = new AssistantMessageEventStream();
26135
26135
  (async () => {
26136
26136
  const output = {
26137
26137
  role: "assistant",
@@ -34474,7 +34474,7 @@ var init_azure_openai_responses = __esm({
34474
34474
  DEFAULT_AZURE_API_VERSION = "v1";
34475
34475
  AZURE_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set(["openai", "openai-codex", "opencode", "azure-openai-responses"]);
34476
34476
  streamAzureOpenAIResponses = (model, context, options) => {
34477
- const stream2 = new AssistantMessageEventStream2();
34477
+ const stream2 = new AssistantMessageEventStream();
34478
34478
  (async () => {
34479
34479
  const deploymentName = resolveDeploymentName(model, options);
34480
34480
  const output = {
@@ -74649,7 +74649,7 @@ var init_google = __esm({
74649
74649
  init_simple_options();
74650
74650
  toolCallCounter = 0;
74651
74651
  streamGoogle = (model, context, options) => {
74652
- const stream2 = new AssistantMessageEventStream2();
74652
+ const stream2 = new AssistantMessageEventStream();
74653
74653
  (async () => {
74654
74654
  const output = {
74655
74655
  role: "assistant",
@@ -75078,7 +75078,7 @@ var init_google_vertex = __esm({
75078
75078
  };
75079
75079
  toolCallCounter2 = 0;
75080
75080
  streamGoogleVertex = (model, context, options) => {
75081
- const stream2 = new AssistantMessageEventStream2();
75081
+ const stream2 = new AssistantMessageEventStream();
75082
75082
  (async () => {
75083
75083
  const output = {
75084
75084
  role: "assistant",
@@ -127353,7 +127353,7 @@ var init_mistral = __esm({
127353
127353
  MISTRAL_TOOL_CALL_ID_LENGTH = 9;
127354
127354
  MAX_MISTRAL_ERROR_BODY_CHARS = 4e3;
127355
127355
  streamMistral = (model, context, options) => {
127356
- const stream2 = new AssistantMessageEventStream2();
127356
+ const stream2 = new AssistantMessageEventStream();
127357
127357
  (async () => {
127358
127358
  const output = createOutput(model);
127359
127359
  try {
@@ -127946,7 +127946,7 @@ var init_openai_completions = __esm({
127946
127946
  init_simple_options();
127947
127947
  init_transform_messages();
127948
127948
  streamOpenAICompletions = (model, context, options) => {
127949
- const stream2 = new AssistantMessageEventStream2();
127949
+ const stream2 = new AssistantMessageEventStream();
127950
127950
  (async () => {
127951
127951
  const output = {
127952
127952
  role: "assistant",
@@ -128337,7 +128337,7 @@ var init_openai_responses = __esm({
128337
128337
  init_simple_options();
128338
128338
  OPENAI_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set(["openai", "openai-codex", "opencode"]);
128339
128339
  streamOpenAIResponses = (model, context, options) => {
128340
- const stream2 = new AssistantMessageEventStream2();
128340
+ const stream2 = new AssistantMessageEventStream();
128341
128341
  (async () => {
128342
128342
  const output = {
128343
128343
  role: "assistant",
@@ -128415,645 +128415,21 @@ var init_openai_responses = __esm({
128415
128415
  }
128416
128416
  });
128417
128417
 
128418
- // ../plugin-sdk/dist/index.js
128418
+ // ../plugin-sdk/src/index.ts
128419
128419
  function definePlugin(plugin2) {
128420
128420
  return plugin2;
128421
128421
  }
128422
128422
 
128423
- // ../../plugins/fusion-plugin-droid-runtime/dist/cli-spawn.js
128423
+ // ../../plugins/fusion-plugin-droid-runtime/src/cli-spawn.ts
128424
128424
  function resolveCliSettings(settings2) {
128425
128425
  const binaryPath = typeof settings2?.droidBinaryPath === "string" && settings2.droidBinaryPath.trim().length > 0 ? settings2.droidBinaryPath.trim() : "droid";
128426
128426
  const model = typeof settings2?.droidModel === "string" ? settings2.droidModel : void 0;
128427
128427
  return { binaryPath, model };
128428
128428
  }
128429
128429
 
128430
- // ../../plugins/fusion-plugin-droid-runtime/dist/provider.js
128430
+ // ../../plugins/fusion-plugin-droid-runtime/src/provider.ts
128431
128431
  import { createInterface } from "node:readline";
128432
128432
 
128433
- // ../../plugins/fusion-plugin-droid-runtime/dist/prompt-builder.js
128434
- import { existsSync, readFileSync } from "node:fs";
128435
- import { resolve, join, dirname } from "node:path";
128436
- import { homedir } from "node:os";
128437
-
128438
- // ../../plugins/fusion-plugin-droid-runtime/dist/tool-mapping.js
128439
- var TOOL_MAPPINGS = [
128440
- { claude: "Read", pi: "read", args: { file_path: "path" } },
128441
- { claude: "Write", pi: "write", args: { file_path: "path" } },
128442
- {
128443
- claude: "Edit",
128444
- pi: "edit",
128445
- args: { file_path: "path", old_string: "oldText", new_string: "newText" }
128446
- },
128447
- { claude: "Bash", pi: "bash", args: {} },
128448
- { claude: "Grep", pi: "grep", args: { head_limit: "limit" } },
128449
- { claude: "Glob", pi: "find", args: {} }
128450
- ];
128451
- var CUSTOM_TOOLS_MCP_PREFIX = "mcp__custom-tools__";
128452
- var BUILT_IN_PI_NAMES = new Set(TOOL_MAPPINGS.map((m2) => m2.pi));
128453
- function isCustomToolName(piName) {
128454
- return !BUILT_IN_PI_NAMES.has(piName);
128455
- }
128456
- function isPiKnownDroidTool(claudeName) {
128457
- if (claudeName.startsWith(CUSTOM_TOOLS_MCP_PREFIX))
128458
- return true;
128459
- return claudeName.toLowerCase() in DROID_TO_PI_NAME;
128460
- }
128461
- var DROID_TO_PI_NAME = {};
128462
- var PI_TO_DROID_NAME = {};
128463
- var DROID_TO_PI_ARGS = {};
128464
- var PI_TO_DROID_ARGS = {};
128465
- for (const m2 of TOOL_MAPPINGS) {
128466
- DROID_TO_PI_NAME[m2.claude.toLowerCase()] = m2.pi;
128467
- PI_TO_DROID_NAME[m2.pi] = m2.claude;
128468
- DROID_TO_PI_ARGS[m2.claude.toLowerCase()] = m2.args;
128469
- const reverseArgs = {};
128470
- for (const [from, to] of Object.entries(m2.args)) {
128471
- reverseArgs[to] = from;
128472
- }
128473
- PI_TO_DROID_ARGS[m2.pi] = reverseArgs;
128474
- }
128475
- PI_TO_DROID_NAME["glob"] = "Glob";
128476
- function mapDroidToolNameToPi(claudeName) {
128477
- if (claudeName.startsWith(CUSTOM_TOOLS_MCP_PREFIX)) {
128478
- return claudeName.slice(CUSTOM_TOOLS_MCP_PREFIX.length);
128479
- }
128480
- return DROID_TO_PI_NAME[claudeName.toLowerCase()] ?? claudeName;
128481
- }
128482
- function mapPiToolNameToDroid(piName) {
128483
- return PI_TO_DROID_NAME[piName] ?? piName;
128484
- }
128485
- function translateDroidArgsToPi(claudeToolName, args) {
128486
- const renames = DROID_TO_PI_ARGS[claudeToolName.toLowerCase()];
128487
- if (!renames || Object.keys(renames).length === 0)
128488
- return args;
128489
- const result = {};
128490
- for (const [key, value] of Object.entries(args)) {
128491
- const newKey = renames[key] ?? key;
128492
- result[newKey] = value;
128493
- }
128494
- return result;
128495
- }
128496
- function translatePiArgsToDroid(piToolName, args) {
128497
- const renames = PI_TO_DROID_ARGS[piToolName];
128498
- if (!renames || Object.keys(renames).length === 0)
128499
- return args;
128500
- const result = {};
128501
- for (const [key, value] of Object.entries(args)) {
128502
- const newKey = renames[key] ?? key;
128503
- result[newKey] = value;
128504
- }
128505
- return result;
128506
- }
128507
-
128508
- // ../../plugins/fusion-plugin-droid-runtime/dist/prompt-builder.js
128509
- var placeholderImageCount = 0;
128510
- function translateImageBlock(piBlock) {
128511
- const block = piBlock;
128512
- if (typeof block.data === "string" && typeof block.mimeType === "string") {
128513
- return {
128514
- type: "image",
128515
- source: {
128516
- type: "base64",
128517
- media_type: block.mimeType,
128518
- data: block.data
128519
- }
128520
- };
128521
- }
128522
- return null;
128523
- }
128524
- function buildFinalUserContent(content) {
128525
- if (typeof content === "string") {
128526
- return [{ type: "text", text: content }];
128527
- }
128528
- if (!Array.isArray(content)) {
128529
- return [{ type: "text", text: "" }];
128530
- }
128531
- const blocks = [];
128532
- for (const rawBlock of content) {
128533
- const block = rawBlock;
128534
- if (block.type === "text") {
128535
- blocks.push({ type: "text", text: typeof block.text === "string" ? block.text : "" });
128536
- } else if (block.type === "image") {
128537
- const translated = translateImageBlock(block);
128538
- if (translated) {
128539
- blocks.push(translated);
128540
- } else {
128541
- blocks.push({
128542
- type: "text",
128543
- text: "[An image was shared here but could not be included]"
128544
- });
128545
- placeholderImageCount++;
128546
- }
128547
- }
128548
- }
128549
- return blocks;
128550
- }
128551
- function contentHasImages(content) {
128552
- if (typeof content === "string" || !Array.isArray(content))
128553
- return false;
128554
- return content.some((block) => block.type === "image");
128555
- }
128556
- function buildCustomToolResultPrompt(messages) {
128557
- if (messages.length < 3)
128558
- return null;
128559
- const last = messages[messages.length - 1];
128560
- if (last.role !== "toolResult")
128561
- return null;
128562
- if (!last.toolName || !isCustomToolName(last.toolName))
128563
- return null;
128564
- let userMessage = null;
128565
- for (let i2 = messages.length - 3; i2 >= 0; i2--) {
128566
- const msg = messages[i2];
128567
- if (msg.role === "user") {
128568
- userMessage = userContentToText(msg.content);
128569
- break;
128570
- }
128571
- }
128572
- if (!userMessage)
128573
- return null;
128574
- const toolResult = toolResultContentToText(last.content);
128575
- return `${userMessage}
128576
-
128577
- [The ${last.toolName} tool was called and returned the following result]
128578
- ${toolResult}
128579
-
128580
- Respond to the user using the tool result above.`;
128581
- }
128582
- function buildResumePrompt(context) {
128583
- const messages = context.messages;
128584
- if (messages.length === 0)
128585
- return "";
128586
- let lastAssistantIdx = -1;
128587
- for (let i2 = messages.length - 1; i2 >= 0; i2--) {
128588
- if (messages[i2].role === "assistant") {
128589
- lastAssistantIdx = i2;
128590
- break;
128591
- }
128592
- }
128593
- const newMessages = messages.slice(lastAssistantIdx + 1);
128594
- if (newMessages.length === 0)
128595
- return "";
128596
- const parts = [];
128597
- for (const msg of newMessages) {
128598
- if (msg.role === "toolResult") {
128599
- if (msg.toolName && isCustomToolName(msg.toolName)) {
128600
- parts.push(`TOOL RESULT (${msg.toolName}):`);
128601
- } else {
128602
- const claudeToolName = msg.toolName ? mapPiToolNameToDroid(msg.toolName) : "unknown";
128603
- parts.push(`TOOL RESULT (${claudeToolName}):`);
128604
- }
128605
- parts.push(toolResultContentToText(msg.content));
128606
- } else if (msg.role === "user") {
128607
- if (contentHasImages(msg.content)) {
128608
- const textSoFar = parts.join("\n");
128609
- const userContent = buildFinalUserContent(msg.content);
128610
- const result = [];
128611
- if (textSoFar) {
128612
- result.push({ type: "text", text: textSoFar });
128613
- }
128614
- result.push(...userContent);
128615
- return result;
128616
- }
128617
- parts.push(userContentToText(msg.content));
128618
- }
128619
- }
128620
- return parts.join("\n") || "";
128621
- }
128622
- function buildPrompt(context) {
128623
- placeholderImageCount = 0;
128624
- const customToolPrompt = buildCustomToolResultPrompt(context.messages);
128625
- if (customToolPrompt) {
128626
- if (placeholderImageCount > 0) {
128627
- console.warn(`[droid-cli] ${placeholderImageCount} image(s) in conversation history could not be included in the prompt`);
128628
- }
128629
- return customToolPrompt;
128630
- }
128631
- const finalUserIndex = findFinalUserMessageIndex(context.messages);
128632
- const finalUserMsg = finalUserIndex >= 0 ? context.messages[finalUserIndex] : void 0;
128633
- const finalUserHasImages = finalUserMsg !== void 0 && finalUserMsg.role === "user" && contentHasImages(finalUserMsg.content);
128634
- const anyToolResultHasImages = context.messages.some((m2) => m2.role === "toolResult" && toolResultHasImages(m2.content));
128635
- if (finalUserHasImages || anyToolResultHasImages) {
128636
- const historyParts = [];
128637
- const toolResultImageBlocks = [];
128638
- for (let i2 = 0; i2 < context.messages.length; i2++) {
128639
- if (i2 === finalUserIndex)
128640
- continue;
128641
- const message = context.messages[i2];
128642
- if (message.role === "user") {
128643
- historyParts.push("USER:");
128644
- historyParts.push(userContentToText(message.content));
128645
- } else if (message.role === "assistant") {
128646
- historyParts.push("ASSISTANT:");
128647
- historyParts.push(contentToText(message.content));
128648
- } else if (message.role === "toolResult") {
128649
- if (message.toolName && isCustomToolName(message.toolName)) {
128650
- historyParts.push(`TOOL RESULT (${message.toolName}):`);
128651
- } else {
128652
- const claudeToolName = message.toolName ? mapPiToolNameToDroid(message.toolName) : "unknown";
128653
- historyParts.push(`TOOL RESULT (${claudeToolName}):`);
128654
- }
128655
- historyParts.push(toolResultContentToText(message.content));
128656
- if (Array.isArray(message.content)) {
128657
- for (const rawBlock of message.content) {
128658
- const block = rawBlock;
128659
- if (block.type === "image") {
128660
- const translated = translateImageBlock(block);
128661
- if (translated) {
128662
- toolResultImageBlocks.push(translated);
128663
- placeholderImageCount--;
128664
- }
128665
- }
128666
- }
128667
- }
128668
- }
128669
- }
128670
- const finalUserContent = finalUserMsg?.role === "user" ? buildFinalUserContent(finalUserMsg.content) : [];
128671
- const result = [];
128672
- const historyText = historyParts.join("\n");
128673
- if (historyText) {
128674
- result.push({ type: "text", text: historyText });
128675
- }
128676
- result.push(...toolResultImageBlocks);
128677
- result.push(...finalUserContent);
128678
- if (placeholderImageCount > 0) {
128679
- console.warn(`[droid-cli] ${placeholderImageCount} image(s) in conversation history could not be included in the prompt`);
128680
- }
128681
- return result;
128682
- }
128683
- const parts = [];
128684
- for (const message of context.messages) {
128685
- if (message.role === "user") {
128686
- parts.push("USER:");
128687
- parts.push(userContentToText(message.content));
128688
- } else if (message.role === "assistant") {
128689
- parts.push("ASSISTANT:");
128690
- parts.push(contentToText(message.content));
128691
- } else if (message.role === "toolResult") {
128692
- if (message.toolName && isCustomToolName(message.toolName)) {
128693
- parts.push(`TOOL RESULT (${message.toolName}):`);
128694
- } else {
128695
- const claudeToolName = message.toolName ? mapPiToolNameToDroid(message.toolName) : "unknown";
128696
- parts.push(`TOOL RESULT (${claudeToolName}):`);
128697
- }
128698
- parts.push(toolResultContentToText(message.content));
128699
- }
128700
- }
128701
- if (placeholderImageCount > 0) {
128702
- console.warn(`[droid-cli] ${placeholderImageCount} image(s) in conversation history could not be included in the prompt`);
128703
- }
128704
- return parts.join("\n") || "";
128705
- }
128706
- function findFinalUserMessageIndex(messages) {
128707
- for (let i2 = messages.length - 1; i2 >= 0; i2--) {
128708
- if (messages[i2].role === "user")
128709
- return i2;
128710
- }
128711
- return -1;
128712
- }
128713
- function buildSystemPrompt(context, cwd) {
128714
- const parts = [];
128715
- if (context.systemPrompt) {
128716
- parts.push(rewriteCustomToolReferences(context.systemPrompt, context.tools));
128717
- }
128718
- const agentsPath = resolveAgentsMdPath(cwd);
128719
- if (agentsPath) {
128720
- try {
128721
- const content = readFileSync(agentsPath, "utf-8");
128722
- const sanitized = sanitizeAgentsContent(content);
128723
- parts.push(sanitized);
128724
- } catch {
128725
- }
128726
- }
128727
- if (context.messages?.some((m2) => m2.role === "toolResult")) {
128728
- parts.push("IMPORTANT: The conversation history below contains tool results from previously executed tools. Use these results to answer the user's question. Do NOT attempt to re-call tools that already have results.");
128729
- }
128730
- const customToolsAddendum = buildCustomToolsAddendum(context.tools);
128731
- if (customToolsAddendum) {
128732
- parts.push(customToolsAddendum);
128733
- }
128734
- return parts.join("\n\n");
128735
- }
128736
- var BUILT_IN_PI_TOOLS = /* @__PURE__ */ new Set([
128737
- "read",
128738
- "write",
128739
- "edit",
128740
- "bash",
128741
- "grep",
128742
- "find"
128743
- ]);
128744
- function rewriteCustomToolReferences(prompt, tools) {
128745
- if (!prompt || !tools || tools.length === 0) {
128746
- return prompt;
128747
- }
128748
- let result = prompt;
128749
- for (const tool of tools) {
128750
- if (BUILT_IN_PI_TOOLS.has(tool.name))
128751
- continue;
128752
- const escaped = tool.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
128753
- const pattern = new RegExp(`(?<![A-Za-z0-9_])(?<!mcp__custom-tools__)${escaped}(?![A-Za-z0-9_])`, "g");
128754
- result = result.replace(pattern, `mcp__custom-tools__${tool.name}`);
128755
- }
128756
- return result;
128757
- }
128758
- function buildCustomToolsAddendum(tools) {
128759
- if (!tools || tools.length === 0)
128760
- return "";
128761
- const customNames = tools.map((t2) => t2.name).filter((name) => !BUILT_IN_PI_TOOLS.has(name));
128762
- if (customNames.length === 0)
128763
- return "";
128764
- const lines = customNames.sort().map((name) => `- \`${name}\` is exposed as \`mcp__custom-tools__${name}\``);
128765
- return [
128766
- "## Custom tool naming (MCP)",
128767
- "",
128768
- "The following pi extension tools are available under MCP-prefixed",
128769
- "names. When a system prompt or task instruction asks you to call one",
128770
- "of these by its short name, call the MCP-prefixed name directly.",
128771
- "",
128772
- ...lines
128773
- ].join("\n");
128774
- }
128775
- function userContentToText(content) {
128776
- if (typeof content === "string")
128777
- return content;
128778
- if (!Array.isArray(content))
128779
- return "";
128780
- const texts = [];
128781
- for (const rawBlock of content) {
128782
- const block = rawBlock;
128783
- if (block.type === "text") {
128784
- texts.push(typeof block.text === "string" ? block.text : "");
128785
- } else if (block.type === "image") {
128786
- texts.push("[An image was shared here but could not be included]");
128787
- placeholderImageCount++;
128788
- }
128789
- }
128790
- return texts.join("\n");
128791
- }
128792
- function contentToText(content) {
128793
- if (typeof content === "string")
128794
- return content;
128795
- if (!Array.isArray(content))
128796
- return "";
128797
- return content.map((rawBlock) => {
128798
- const block = rawBlock;
128799
- if (block.type === "text")
128800
- return typeof block.text === "string" ? block.text : "";
128801
- if (block.type === "thinking")
128802
- return "";
128803
- if (block.type === "toolCall") {
128804
- const name = typeof block.name === "string" ? block.name : "";
128805
- const rawArgs = block.arguments;
128806
- const argsObject = rawArgs && typeof rawArgs === "object" ? rawArgs : void 0;
128807
- const isCustom = isCustomToolName(name);
128808
- if (isCustom) {
128809
- const argsStr2 = argsObject ? JSON.stringify(argsObject) : typeof rawArgs === "string" ? JSON.stringify(rawArgs) : "{}";
128810
- return `[Used ${name} tool with args: ${argsStr2}]`;
128811
- }
128812
- const claudeName = mapPiToolNameToDroid(name);
128813
- const claudeArgs = argsObject ? translatePiArgsToDroid(name, argsObject) : void 0;
128814
- const argsStr = claudeArgs ? JSON.stringify(claudeArgs) : typeof rawArgs === "string" ? JSON.stringify(rawArgs) : "{}";
128815
- return `[Prior tool call \u2014 already executed; result follows in TOOL RESULT (${claudeName}):] args=${argsStr}`;
128816
- }
128817
- return `[${String(block.type)}]`;
128818
- }).join("\n");
128819
- }
128820
- function toolResultContentToText(content) {
128821
- if (typeof content === "string")
128822
- return content;
128823
- if (!Array.isArray(content))
128824
- return "";
128825
- const texts = [];
128826
- for (const rawBlock of content) {
128827
- const block = rawBlock;
128828
- if (block.type === "text") {
128829
- texts.push(typeof block.text === "string" ? block.text : "");
128830
- } else if (block.type === "image") {
128831
- texts.push("[An image was shared here but could not be included]");
128832
- placeholderImageCount++;
128833
- }
128834
- }
128835
- return texts.join("\n");
128836
- }
128837
- function toolResultHasImages(content) {
128838
- if (typeof content === "string" || !Array.isArray(content))
128839
- return false;
128840
- return content.some((block) => block.type === "image");
128841
- }
128842
- function resolveAgentsMdPath(cwd) {
128843
- let current = resolve(cwd);
128844
- while (true) {
128845
- const candidate = join(current, "AGENTS.md");
128846
- if (existsSync(candidate))
128847
- return candidate;
128848
- const parent = dirname(current);
128849
- if (parent === current)
128850
- break;
128851
- current = parent;
128852
- }
128853
- const globalHome = process.env.HOME || process.env.USERPROFILE || homedir();
128854
- const globalPath = join(globalHome, ".pi", "agent", "AGENTS.md");
128855
- if (existsSync(globalPath))
128856
- return globalPath;
128857
- return void 0;
128858
- }
128859
- function sanitizeAgentsContent(content) {
128860
- let sanitized = content;
128861
- sanitized = sanitized.replace(/~\/\.pi\b/gi, "~/.claude");
128862
- sanitized = sanitized.replace(/(^|[\s'"`])\.pi\//g, "$1.claude/");
128863
- sanitized = sanitized.replace(/\b\.pi\b/gi, ".claude");
128864
- return sanitized;
128865
- }
128866
-
128867
- // ../../plugins/fusion-plugin-droid-runtime/dist/process-manager.js
128868
- import { execSync, spawn } from "node:child_process";
128869
- import { writeFileSync, unlinkSync } from "node:fs";
128870
- import { join as join2 } from "node:path";
128871
- import { tmpdir } from "node:os";
128872
- function debugLog(message) {
128873
- if (process.env.PI_DROID_CLI_DEBUG !== "1")
128874
- return;
128875
- console.error(`[droid-cli] ${message}`);
128876
- }
128877
- function buildDroidSpawnArgs(modelId, systemPrompt, options) {
128878
- const args = [
128879
- "-p",
128880
- "--input-format",
128881
- "stream-json",
128882
- "--output-format",
128883
- "stream-json",
128884
- "--verbose",
128885
- "--include-partial-messages",
128886
- "--model",
128887
- modelId
128888
- ];
128889
- if (options?.resumeSessionId) {
128890
- args.push("--resume", options.resumeSessionId);
128891
- } else if (options?.newSessionId) {
128892
- args.push("--session-id", options.newSessionId);
128893
- }
128894
- if (systemPrompt) {
128895
- const tmpFile = join2(tmpdir(), `droid-cli-sysprompt-${process.pid}.txt`);
128896
- writeFileSync(tmpFile, systemPrompt, "utf-8");
128897
- args.push("--append-system-prompt", tmpFile);
128898
- }
128899
- if (options?.effort) {
128900
- args.push("--effort", options.effort);
128901
- }
128902
- if (options?.mcpConfigPath) {
128903
- args.push("--mcp-config", options.mcpConfigPath);
128904
- }
128905
- return args;
128906
- }
128907
- function spawnDroid(modelId, systemPrompt, options) {
128908
- const args = buildDroidSpawnArgs(modelId, systemPrompt, {
128909
- effort: options?.effort,
128910
- mcpConfigPath: options?.mcpConfigPath,
128911
- resumeSessionId: options?.resumeSessionId,
128912
- newSessionId: options?.newSessionId
128913
- });
128914
- const proc = spawn("droid", args, {
128915
- stdio: ["pipe", "pipe", "pipe"],
128916
- cwd: options?.cwd ?? process.cwd()
128917
- });
128918
- debugLog(`spawnDroid: pid=${proc.pid} model=${modelId}`);
128919
- return proc;
128920
- }
128921
- function cleanupSystemPromptFile() {
128922
- try {
128923
- unlinkSync(join2(tmpdir(), `droid-cli-sysprompt-${process.pid}.txt`));
128924
- } catch {
128925
- }
128926
- }
128927
- function writeUserMessage(proc, prompt) {
128928
- const message = {
128929
- type: "user",
128930
- message: {
128931
- role: "user",
128932
- content: prompt
128933
- }
128934
- };
128935
- proc.stdin.write(JSON.stringify(message) + "\n");
128936
- proc.stdin.end();
128937
- }
128938
- function forceKillProcess(proc) {
128939
- if (proc.killed || proc.exitCode !== null)
128940
- return;
128941
- proc.kill("SIGKILL");
128942
- }
128943
- var activeProcesses = /* @__PURE__ */ new Set();
128944
- function registerProcess(proc) {
128945
- activeProcesses.add(proc);
128946
- proc.on("exit", () => activeProcesses.delete(proc));
128947
- }
128948
- function killAllProcesses() {
128949
- for (const proc of activeProcesses) {
128950
- forceKillProcess(proc);
128951
- }
128952
- activeProcesses.clear();
128953
- }
128954
- function cleanupProcess(proc) {
128955
- setTimeout(() => {
128956
- forceKillProcess(proc);
128957
- }, 500);
128958
- }
128959
- function captureStderr(proc) {
128960
- let buffer = "";
128961
- proc.stderr.on("data", (data) => {
128962
- buffer += data.toString();
128963
- });
128964
- return () => buffer;
128965
- }
128966
- function runDroidProbe(args, timeoutMs = 45e3) {
128967
- return new Promise((resolve2) => {
128968
- const proc = spawn("droid", args, { stdio: "ignore" });
128969
- const timer = setTimeout(() => {
128970
- try {
128971
- proc.kill("SIGKILL");
128972
- } catch {
128973
- }
128974
- resolve2(124);
128975
- }, timeoutMs);
128976
- proc.once("error", () => {
128977
- clearTimeout(timer);
128978
- resolve2(127);
128979
- });
128980
- proc.once("exit", (code) => {
128981
- clearTimeout(timer);
128982
- resolve2(code ?? 1);
128983
- });
128984
- });
128985
- }
128986
- async function validateCliPresenceAsync() {
128987
- const code = await runDroidProbe(["--version"]);
128988
- if (code === 0)
128989
- return { ok: true };
128990
- return {
128991
- ok: false,
128992
- error: new Error("Droid CLI not found on PATH. Install Droid CLI and then run: droid auth login")
128993
- };
128994
- }
128995
- async function validateCliAuthAsync() {
128996
- const code = await runDroidProbe(["auth", "status"]);
128997
- if (code === 0)
128998
- return true;
128999
- console.warn("[droid-cli] Droid CLI is not authenticated. Run 'droid auth login' to authenticate.");
129000
- return false;
129001
- }
129002
- async function discoverDroidModels() {
129003
- const attempts = [["models", "--json"], ["model", "list", "--json"], ["models"]];
129004
- for (const args of attempts) {
129005
- const models = await new Promise((resolve2) => {
129006
- const proc = spawn("droid", args, { stdio: ["ignore", "pipe", "ignore"] });
129007
- let out = "";
129008
- proc.stdout?.on("data", (chunk) => {
129009
- out += chunk.toString();
129010
- });
129011
- proc.once("error", () => resolve2(null));
129012
- proc.once("exit", (code) => {
129013
- if (code !== 0)
129014
- return resolve2(null);
129015
- const trimmed = out.trim();
129016
- if (!trimmed)
129017
- return resolve2([]);
129018
- try {
129019
- const parsed = JSON.parse(trimmed);
129020
- if (Array.isArray(parsed)) {
129021
- return resolve2(parsed.map((entry) => typeof entry === "string" ? entry : typeof entry?.id === "string" ? entry.id : typeof entry?.name === "string" ? entry.name : void 0).filter((id) => Boolean(id)));
129022
- }
129023
- } catch {
129024
- }
129025
- resolve2(trimmed.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
129026
- });
129027
- });
129028
- if (models && models.length > 0) {
129029
- return Array.from(new Set(models));
129030
- }
129031
- }
129032
- return [];
129033
- }
129034
-
129035
- // ../../plugins/fusion-plugin-droid-runtime/dist/stream-parser.js
129036
- function parseLine(line) {
129037
- const trimmed = line.trim();
129038
- if (!trimmed) {
129039
- return null;
129040
- }
129041
- if (!trimmed.startsWith("{")) {
129042
- return null;
129043
- }
129044
- let parsed;
129045
- try {
129046
- parsed = JSON.parse(trimmed);
129047
- } catch {
129048
- console.error("Failed to parse NDJSON line:", trimmed);
129049
- return null;
129050
- }
129051
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
129052
- return null;
129053
- }
129054
- return parsed;
129055
- }
129056
-
129057
128433
  // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/system/memory/memory.mjs
129058
128434
  var memory_exports = {};
129059
128435
  __export(memory_exports, {
@@ -132523,7 +131899,7 @@ function createLazyLoadErrorMessage(model, error40) {
132523
131899
  }
132524
131900
  function createLazyStream(loadModule) {
132525
131901
  return (model, context, options) => {
132526
- const outer = new AssistantMessageEventStream2();
131902
+ const outer = new AssistantMessageEventStream();
132527
131903
  loadModule().then((module) => {
132528
131904
  const inner = module.stream(model, context, options);
132529
131905
  forwardStream(outer, inner);
@@ -132537,7 +131913,7 @@ function createLazyStream(loadModule) {
132537
131913
  }
132538
131914
  function createLazySimpleStream(loadModule) {
132539
131915
  return (model, context, options) => {
132540
- const outer = new AssistantMessageEventStream2();
131916
+ const outer = new AssistantMessageEventStream();
132541
131917
  loadModule().then((module) => {
132542
131918
  const inner = module.streamSimple(model, context, options);
132543
131919
  forwardStream(outer, inner);
@@ -135648,249 +135024,866 @@ function Encode3(direction, context, type, value) {
135648
135024
  for (let i2 = 0; i2 < exterior.length; i2++) {
135649
135025
  exterior[i2] = FromType22(direction, context, type.items, exterior[i2]);
135650
135026
  }
135651
- return exterior;
135652
- }
135653
- function FromArray11(direction, context, type, value) {
135654
- return guard_exports.IsEqual(direction, "Decode") ? Decode4(direction, context, type, value) : Encode3(direction, context, type, value);
135027
+ return exterior;
135028
+ }
135029
+ function FromArray11(direction, context, type, value) {
135030
+ return guard_exports.IsEqual(direction, "Decode") ? Decode4(direction, context, type, value) : Encode3(direction, context, type, value);
135031
+ }
135032
+
135033
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-cyclic.mjs
135034
+ function FromCyclic9(direction, context, type, value) {
135035
+ value = FromType22(direction, { ...context, ...type.$defs }, Ref(type.$ref), value);
135036
+ return Callback(direction, context, type, value);
135037
+ }
135038
+
135039
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-intersect.mjs
135040
+ function MergeInteriors(interiors) {
135041
+ return interiors.reduce((results, interior) => ({ ...results, ...interior }), {});
135042
+ }
135043
+ function NonMatchingInterior(value, interiors) {
135044
+ for (const interior of interiors)
135045
+ if (!guard_exports.IsDeepEqual(value, interior))
135046
+ return interior;
135047
+ return value;
135048
+ }
135049
+ function Decode5(direction, context, type, value) {
135050
+ if (guard_exports.IsEqual(type.allOf.length, 0))
135051
+ return Callback(direction, context, type, value);
135052
+ const interiors = type.allOf.map((schema) => FromType22(direction, context, schema, Clean(schema, Clone2(value))));
135053
+ const structural = interiors.every((result) => guard_exports.IsObject(result));
135054
+ const exterior = structural ? MergeInteriors(interiors) : NonMatchingInterior(value, interiors);
135055
+ return Callback(direction, context, type, exterior);
135056
+ }
135057
+ function Encode4(direction, context, type, value) {
135058
+ if (guard_exports.IsEqual(type.allOf.length, 0))
135059
+ return Callback(direction, context, type, value);
135060
+ const exterior = Callback(direction, context, type, value);
135061
+ const interiors = type.allOf.map((schema) => FromType22(direction, context, schema, Clean(schema, Clone2(exterior))));
135062
+ const structural = interiors.every((result) => guard_exports.IsObject(result));
135063
+ if (structural)
135064
+ return MergeInteriors(interiors);
135065
+ return NonMatchingInterior(exterior, interiors);
135066
+ }
135067
+ function FromIntersect9(direction, context, type, value) {
135068
+ return guard_exports.IsEqual(direction, "Decode") ? Decode5(direction, context, type, value) : Encode4(direction, context, type, value);
135069
+ }
135070
+
135071
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-object.mjs
135072
+ function Decode6(direction, context, type, value) {
135073
+ if (!guard_exports.IsObjectNotArray(value))
135074
+ return Unreachable();
135075
+ for (const key of guard_exports.Keys(type.properties)) {
135076
+ if (!guard_exports.HasPropertyKey(value, key) || IsOptionalUndefined(type.properties[key], key, value))
135077
+ continue;
135078
+ value[key] = FromType22(direction, context, type.properties[key], value[key]);
135079
+ }
135080
+ return Callback(direction, context, type, value);
135081
+ }
135082
+ function Encode5(direction, context, type, value) {
135083
+ const exterior = Callback(direction, context, type, value);
135084
+ if (!guard_exports.IsObjectNotArray(exterior))
135085
+ return exterior;
135086
+ for (const key of guard_exports.Keys(type.properties)) {
135087
+ if (!guard_exports.HasPropertyKey(exterior, key) || IsOptionalUndefined(type.properties[key], key, exterior))
135088
+ continue;
135089
+ exterior[key] = FromType22(direction, context, type.properties[key], exterior[key]);
135090
+ }
135091
+ return exterior;
135092
+ }
135093
+ function FromObject14(direction, context, type, value) {
135094
+ return guard_exports.IsEqual(direction, "Decode") ? Decode6(direction, context, type, value) : Encode5(direction, context, type, value);
135095
+ }
135096
+
135097
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-record.mjs
135098
+ function Decode7(direction, context, type, value) {
135099
+ if (!guard_exports.IsObjectNotArray(value))
135100
+ return Unreachable();
135101
+ const regexp = new RegExp(RecordPattern(type));
135102
+ for (const key of guard_exports.Keys(value)) {
135103
+ if (!regexp.test(key))
135104
+ Unreachable();
135105
+ value[key] = FromType22(direction, context, RecordValue(type), value[key]);
135106
+ }
135107
+ return Callback(direction, context, type, value);
135108
+ }
135109
+ function Encode6(direction, context, type, value) {
135110
+ const exterior = Callback(direction, context, type, value);
135111
+ if (!guard_exports.IsObjectNotArray(exterior))
135112
+ return exterior;
135113
+ const regexp = new RegExp(RecordPattern(type));
135114
+ for (const key of guard_exports.Keys(exterior)) {
135115
+ if (!regexp.test(key))
135116
+ continue;
135117
+ exterior[key] = FromType22(direction, context, RecordValue(type), exterior[key]);
135118
+ }
135119
+ return exterior;
135120
+ }
135121
+ function FromRecord5(direction, context, type, value) {
135122
+ return guard_exports.IsEqual(direction, "Decode") ? Decode7(direction, context, type, value) : Encode6(direction, context, type, value);
135123
+ }
135124
+
135125
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-ref.mjs
135126
+ function ResolveRef(direction, context, type, value) {
135127
+ return guard_exports.HasPropertyKey(context, type.$ref) ? FromType22(direction, context, context[type.$ref], value) : value;
135128
+ }
135129
+ function FromRef8(direction, context, type, value) {
135130
+ return guard_exports.IsEqual(direction, "Decode") ? Callback(direction, context, type, ResolveRef(direction, context, type, value)) : ResolveRef(direction, context, type, Callback(direction, context, type, value));
135131
+ }
135132
+
135133
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-tuple.mjs
135134
+ function Decode8(direction, context, type, value) {
135135
+ if (!guard_exports.IsArray(value))
135136
+ return Unreachable();
135137
+ for (let i2 = 0; i2 < Math.min(type.items.length, value.length); i2++) {
135138
+ value[i2] = FromType22(direction, context, type.items[i2], value[i2]);
135139
+ }
135140
+ return Callback(direction, context, type, value);
135141
+ }
135142
+ function Encode7(direction, context, type, value) {
135143
+ const exterior = Callback(direction, context, type, value);
135144
+ if (!guard_exports.IsArray(exterior))
135145
+ return value;
135146
+ for (let i2 = 0; i2 < Math.min(type.items.length, exterior.length); i2++) {
135147
+ exterior[i2] = FromType22(direction, context, type.items[i2], exterior[i2]);
135148
+ }
135149
+ return exterior;
135150
+ }
135151
+ function FromTuple8(direction, context, type, value) {
135152
+ return guard_exports.IsEqual(direction, "Decode") ? Decode8(direction, context, type, value) : Encode7(direction, context, type, value);
135153
+ }
135154
+
135155
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-union.mjs
135156
+ function Decode9(direction, context, type, value) {
135157
+ for (const schema of UnionPrioritySort(type.anyOf, 1)) {
135158
+ if (!Check2(context, schema, value))
135159
+ continue;
135160
+ const variant = FromType22(direction, context, schema, value);
135161
+ return Callback(direction, context, type, variant);
135162
+ }
135163
+ return value;
135164
+ }
135165
+ function Encode8(direction, context, type, value) {
135166
+ const exterior = Callback(direction, context, type, value);
135167
+ for (const schema of UnionPrioritySort(type.anyOf, -1)) {
135168
+ const variant = FromType22(direction, context, schema, Clone2(exterior));
135169
+ if (!Check2(context, schema, variant))
135170
+ continue;
135171
+ return variant;
135172
+ }
135173
+ return exterior;
135174
+ }
135175
+ function FromUnion12(direction, context, type, value) {
135176
+ return guard_exports.IsEqual(direction, "Decode") ? Decode9(direction, context, type, value) : Encode8(direction, context, type, value);
135177
+ }
135178
+
135179
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-type.mjs
135180
+ function FromType22(direction, context, type, value) {
135181
+ return IsArray2(type) ? FromArray11(direction, context, type, value) : IsCyclic(type) ? FromCyclic9(direction, context, type, value) : IsIntersect(type) ? FromIntersect9(direction, context, type, value) : IsObject2(type) ? FromObject14(direction, context, type, value) : IsRecord(type) ? FromRecord5(direction, context, type, value) : IsRef(type) ? FromRef8(direction, context, type, value) : IsTuple(type) ? FromTuple8(direction, context, type, value) : IsUnion(type) ? FromUnion12(direction, context, type, value) : Callback(direction, context, type, value);
135182
+ }
135183
+
135184
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/decode.mjs
135185
+ var DecodeError = class extends AssertError {
135186
+ constructor(value, errors) {
135187
+ super("Decode", value, errors);
135188
+ }
135189
+ };
135190
+ function Assert(context, type, value) {
135191
+ if (!Check2(context, type, value))
135192
+ throw new DecodeError(value, Errors2(context, type, value));
135193
+ return value;
135194
+ }
135195
+ function DecodeUnsafe(context, type, value) {
135196
+ return FromType22("Decode", context, type, value);
135197
+ }
135198
+ var Decoder = Pipeline([
135199
+ (_context, _type, value) => Clone2(value),
135200
+ (context, type, value) => Default(context, type, value),
135201
+ (context, type, value) => Convert(context, type, value),
135202
+ (context, type, value) => Clean(context, type, value),
135203
+ (context, type, value) => Assert(context, type, value),
135204
+ (context, type, value) => DecodeUnsafe(context, type, value)
135205
+ ]);
135206
+
135207
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/encode.mjs
135208
+ var EncodeError = class extends AssertError {
135209
+ constructor(value, errors) {
135210
+ super("Encode", value, errors);
135211
+ }
135212
+ };
135213
+ function Assert2(context, type, value) {
135214
+ if (!Check2(context, type, value))
135215
+ throw new EncodeError(value, Errors2(context, type, value));
135216
+ return value;
135217
+ }
135218
+ function EncodeUnsafe(context, type, value) {
135219
+ return FromType22("Encode", context, type, value);
135220
+ }
135221
+ var Encoder = Pipeline([
135222
+ (_context, _type, value) => Clone2(value),
135223
+ (context, type, value) => EncodeUnsafe(context, type, value),
135224
+ (context, type, value) => Default(context, type, value),
135225
+ (context, type, value) => Convert(context, type, value),
135226
+ (context, type, value) => Clean(context, type, value),
135227
+ (context, type, value) => Assert2(context, type, value)
135228
+ ]);
135229
+
135230
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/parse/parse.mjs
135231
+ var ParseError2 = class extends AssertError {
135232
+ constructor(value, errors) {
135233
+ super("Parse", value, errors);
135234
+ }
135235
+ };
135236
+ function Assert3(context, type, value) {
135237
+ if (!Check2(context, type, value))
135238
+ throw new ParseError2(value, Errors2(context, type, value));
135239
+ return value;
135240
+ }
135241
+ var Parser = Pipeline([
135242
+ (_context, _type, value) => Clone2(value),
135243
+ (context, type, value) => Default(context, type, value),
135244
+ (context, type, value) => Convert(context, type, value),
135245
+ (context, type, value) => Clean(context, type, value),
135246
+ (context, type, value) => Assert3(context, type, value)
135247
+ ]);
135248
+
135249
+ // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/delta/edit.mjs
135250
+ var Insert = _Object_({
135251
+ type: Literal("insert"),
135252
+ path: String2(),
135253
+ value: Unknown()
135254
+ });
135255
+ var Update2 = Object({
135256
+ type: Literal("update"),
135257
+ path: String2(),
135258
+ value: Unknown()
135259
+ });
135260
+ var Delete2 = _Object_({
135261
+ type: Literal("delete"),
135262
+ path: String2()
135263
+ });
135264
+ var Edit = Union([Insert, Update2, Delete2]);
135265
+
135266
+ // ../../node_modules/.pnpm/@mariozechner+pi-ai@0.72.1_@modelcontextprotocol+sdk@1.28.0_zod@4.3.6__ws@8.20.0_zod@4.3.6/node_modules/@mariozechner/pi-ai/dist/utils/validation.js
135267
+ var TYPEBOX_KIND = Symbol.for("TypeBox.Kind");
135268
+
135269
+ // ../../plugins/fusion-plugin-droid-runtime/src/prompt-builder.ts
135270
+ import { existsSync, readFileSync } from "node:fs";
135271
+ import { resolve, join, dirname } from "node:path";
135272
+ import { homedir } from "node:os";
135273
+
135274
+ // ../../plugins/fusion-plugin-droid-runtime/src/tool-mapping.ts
135275
+ var TOOL_MAPPINGS = [
135276
+ { claude: "Read", pi: "read", args: { file_path: "path" } },
135277
+ { claude: "Write", pi: "write", args: { file_path: "path" } },
135278
+ {
135279
+ claude: "Edit",
135280
+ pi: "edit",
135281
+ args: { file_path: "path", old_string: "oldText", new_string: "newText" }
135282
+ },
135283
+ { claude: "Bash", pi: "bash", args: {} },
135284
+ { claude: "Grep", pi: "grep", args: { head_limit: "limit" } },
135285
+ { claude: "Glob", pi: "find", args: {} }
135286
+ ];
135287
+ var CUSTOM_TOOLS_MCP_PREFIX = "mcp__custom-tools__";
135288
+ var BUILT_IN_PI_NAMES = new Set(TOOL_MAPPINGS.map((m2) => m2.pi));
135289
+ function isCustomToolName(piName) {
135290
+ return !BUILT_IN_PI_NAMES.has(piName);
135291
+ }
135292
+ function isPiKnownDroidTool(claudeName) {
135293
+ if (claudeName.startsWith(CUSTOM_TOOLS_MCP_PREFIX)) return true;
135294
+ return claudeName.toLowerCase() in DROID_TO_PI_NAME;
135295
+ }
135296
+ var DROID_TO_PI_NAME = {};
135297
+ var PI_TO_DROID_NAME = {};
135298
+ var DROID_TO_PI_ARGS = {};
135299
+ var PI_TO_DROID_ARGS = {};
135300
+ for (const m2 of TOOL_MAPPINGS) {
135301
+ DROID_TO_PI_NAME[m2.claude.toLowerCase()] = m2.pi;
135302
+ PI_TO_DROID_NAME[m2.pi] = m2.claude;
135303
+ DROID_TO_PI_ARGS[m2.claude.toLowerCase()] = m2.args;
135304
+ const reverseArgs = {};
135305
+ for (const [from, to] of Object.entries(m2.args)) {
135306
+ reverseArgs[to] = from;
135307
+ }
135308
+ PI_TO_DROID_ARGS[m2.pi] = reverseArgs;
135309
+ }
135310
+ PI_TO_DROID_NAME["glob"] = "Glob";
135311
+ function mapDroidToolNameToPi(claudeName) {
135312
+ if (claudeName.startsWith(CUSTOM_TOOLS_MCP_PREFIX)) {
135313
+ return claudeName.slice(CUSTOM_TOOLS_MCP_PREFIX.length);
135314
+ }
135315
+ return DROID_TO_PI_NAME[claudeName.toLowerCase()] ?? claudeName;
135316
+ }
135317
+ function mapPiToolNameToDroid(piName) {
135318
+ return PI_TO_DROID_NAME[piName] ?? piName;
135319
+ }
135320
+ function translateDroidArgsToPi(claudeToolName, args) {
135321
+ const renames = DROID_TO_PI_ARGS[claudeToolName.toLowerCase()];
135322
+ if (!renames || Object.keys(renames).length === 0) return args;
135323
+ const result = {};
135324
+ for (const [key, value] of Object.entries(args)) {
135325
+ const newKey = renames[key] ?? key;
135326
+ result[newKey] = value;
135327
+ }
135328
+ return result;
135329
+ }
135330
+ function translatePiArgsToDroid(piToolName, args) {
135331
+ const renames = PI_TO_DROID_ARGS[piToolName];
135332
+ if (!renames || Object.keys(renames).length === 0) return args;
135333
+ const result = {};
135334
+ for (const [key, value] of Object.entries(args)) {
135335
+ const newKey = renames[key] ?? key;
135336
+ result[newKey] = value;
135337
+ }
135338
+ return result;
135339
+ }
135340
+
135341
+ // ../../plugins/fusion-plugin-droid-runtime/src/prompt-builder.ts
135342
+ var placeholderImageCount = 0;
135343
+ function translateImageBlock(piBlock) {
135344
+ const block = piBlock;
135345
+ if (typeof block.data === "string" && typeof block.mimeType === "string") {
135346
+ return {
135347
+ type: "image",
135348
+ source: {
135349
+ type: "base64",
135350
+ media_type: block.mimeType,
135351
+ data: block.data
135352
+ }
135353
+ };
135354
+ }
135355
+ return null;
135356
+ }
135357
+ function buildFinalUserContent(content) {
135358
+ if (typeof content === "string") {
135359
+ return [{ type: "text", text: content }];
135360
+ }
135361
+ if (!Array.isArray(content)) {
135362
+ return [{ type: "text", text: "" }];
135363
+ }
135364
+ const blocks = [];
135365
+ for (const rawBlock of content) {
135366
+ const block = rawBlock;
135367
+ if (block.type === "text") {
135368
+ blocks.push({ type: "text", text: typeof block.text === "string" ? block.text : "" });
135369
+ } else if (block.type === "image") {
135370
+ const translated = translateImageBlock(block);
135371
+ if (translated) {
135372
+ blocks.push(translated);
135373
+ } else {
135374
+ blocks.push({
135375
+ type: "text",
135376
+ text: "[An image was shared here but could not be included]"
135377
+ });
135378
+ placeholderImageCount++;
135379
+ }
135380
+ }
135381
+ }
135382
+ return blocks;
135383
+ }
135384
+ function contentHasImages(content) {
135385
+ if (typeof content === "string" || !Array.isArray(content)) return false;
135386
+ return content.some((block) => block.type === "image");
135387
+ }
135388
+ function buildCustomToolResultPrompt(messages) {
135389
+ if (messages.length < 3) return null;
135390
+ const last = messages[messages.length - 1];
135391
+ if (last.role !== "toolResult") return null;
135392
+ if (!last.toolName || !isCustomToolName(last.toolName)) return null;
135393
+ let userMessage = null;
135394
+ for (let i2 = messages.length - 3; i2 >= 0; i2--) {
135395
+ const msg = messages[i2];
135396
+ if (msg.role === "user") {
135397
+ userMessage = userContentToText(msg.content);
135398
+ break;
135399
+ }
135400
+ }
135401
+ if (!userMessage) return null;
135402
+ const toolResult = toolResultContentToText(last.content);
135403
+ return `${userMessage}
135404
+
135405
+ [The ${last.toolName} tool was called and returned the following result]
135406
+ ${toolResult}
135407
+
135408
+ Respond to the user using the tool result above.`;
135409
+ }
135410
+ function buildResumePrompt(context) {
135411
+ const messages = context.messages;
135412
+ if (messages.length === 0) return "";
135413
+ let lastAssistantIdx = -1;
135414
+ for (let i2 = messages.length - 1; i2 >= 0; i2--) {
135415
+ if (messages[i2].role === "assistant") {
135416
+ lastAssistantIdx = i2;
135417
+ break;
135418
+ }
135419
+ }
135420
+ const newMessages = messages.slice(lastAssistantIdx + 1);
135421
+ if (newMessages.length === 0) return "";
135422
+ const parts = [];
135423
+ for (const msg of newMessages) {
135424
+ if (msg.role === "toolResult") {
135425
+ if (msg.toolName && isCustomToolName(msg.toolName)) {
135426
+ parts.push(`TOOL RESULT (${msg.toolName}):`);
135427
+ } else {
135428
+ const claudeToolName = msg.toolName ? mapPiToolNameToDroid(msg.toolName) : "unknown";
135429
+ parts.push(`TOOL RESULT (${claudeToolName}):`);
135430
+ }
135431
+ parts.push(toolResultContentToText(msg.content));
135432
+ } else if (msg.role === "user") {
135433
+ if (contentHasImages(msg.content)) {
135434
+ const textSoFar = parts.join("\n");
135435
+ const userContent = buildFinalUserContent(msg.content);
135436
+ const result = [];
135437
+ if (textSoFar) {
135438
+ result.push({ type: "text", text: textSoFar });
135439
+ }
135440
+ result.push(...userContent);
135441
+ return result;
135442
+ }
135443
+ parts.push(userContentToText(msg.content));
135444
+ }
135445
+ }
135446
+ return parts.join("\n") || "";
135447
+ }
135448
+ function buildPrompt(context) {
135449
+ placeholderImageCount = 0;
135450
+ const customToolPrompt = buildCustomToolResultPrompt(context.messages);
135451
+ if (customToolPrompt) {
135452
+ if (placeholderImageCount > 0) {
135453
+ console.warn(
135454
+ `[droid-cli] ${placeholderImageCount} image(s) in conversation history could not be included in the prompt`
135455
+ );
135456
+ }
135457
+ return customToolPrompt;
135458
+ }
135459
+ const finalUserIndex = findFinalUserMessageIndex(context.messages);
135460
+ const finalUserMsg = finalUserIndex >= 0 ? context.messages[finalUserIndex] : void 0;
135461
+ const finalUserHasImages = finalUserMsg !== void 0 && finalUserMsg.role === "user" && contentHasImages(finalUserMsg.content);
135462
+ const anyToolResultHasImages = context.messages.some(
135463
+ (m2) => m2.role === "toolResult" && toolResultHasImages(m2.content)
135464
+ );
135465
+ if (finalUserHasImages || anyToolResultHasImages) {
135466
+ const historyParts = [];
135467
+ const toolResultImageBlocks = [];
135468
+ for (let i2 = 0; i2 < context.messages.length; i2++) {
135469
+ if (i2 === finalUserIndex) continue;
135470
+ const message = context.messages[i2];
135471
+ if (message.role === "user") {
135472
+ historyParts.push("USER:");
135473
+ historyParts.push(userContentToText(message.content));
135474
+ } else if (message.role === "assistant") {
135475
+ historyParts.push("ASSISTANT:");
135476
+ historyParts.push(contentToText(message.content));
135477
+ } else if (message.role === "toolResult") {
135478
+ if (message.toolName && isCustomToolName(message.toolName)) {
135479
+ historyParts.push(`TOOL RESULT (${message.toolName}):`);
135480
+ } else {
135481
+ const claudeToolName = message.toolName ? mapPiToolNameToDroid(message.toolName) : "unknown";
135482
+ historyParts.push(`TOOL RESULT (${claudeToolName}):`);
135483
+ }
135484
+ historyParts.push(toolResultContentToText(message.content));
135485
+ if (Array.isArray(message.content)) {
135486
+ for (const rawBlock of message.content) {
135487
+ const block = rawBlock;
135488
+ if (block.type === "image") {
135489
+ const translated = translateImageBlock(block);
135490
+ if (translated) {
135491
+ toolResultImageBlocks.push(translated);
135492
+ placeholderImageCount--;
135493
+ }
135494
+ }
135495
+ }
135496
+ }
135497
+ }
135498
+ }
135499
+ const finalUserContent = finalUserMsg?.role === "user" ? buildFinalUserContent(finalUserMsg.content) : [];
135500
+ const result = [];
135501
+ const historyText = historyParts.join("\n");
135502
+ if (historyText) {
135503
+ result.push({ type: "text", text: historyText });
135504
+ }
135505
+ result.push(...toolResultImageBlocks);
135506
+ result.push(...finalUserContent);
135507
+ if (placeholderImageCount > 0) {
135508
+ console.warn(
135509
+ `[droid-cli] ${placeholderImageCount} image(s) in conversation history could not be included in the prompt`
135510
+ );
135511
+ }
135512
+ return result;
135513
+ }
135514
+ const parts = [];
135515
+ for (const message of context.messages) {
135516
+ if (message.role === "user") {
135517
+ parts.push("USER:");
135518
+ parts.push(userContentToText(message.content));
135519
+ } else if (message.role === "assistant") {
135520
+ parts.push("ASSISTANT:");
135521
+ parts.push(contentToText(message.content));
135522
+ } else if (message.role === "toolResult") {
135523
+ if (message.toolName && isCustomToolName(message.toolName)) {
135524
+ parts.push(`TOOL RESULT (${message.toolName}):`);
135525
+ } else {
135526
+ const claudeToolName = message.toolName ? mapPiToolNameToDroid(message.toolName) : "unknown";
135527
+ parts.push(`TOOL RESULT (${claudeToolName}):`);
135528
+ }
135529
+ parts.push(toolResultContentToText(message.content));
135530
+ }
135531
+ }
135532
+ if (placeholderImageCount > 0) {
135533
+ console.warn(
135534
+ `[droid-cli] ${placeholderImageCount} image(s) in conversation history could not be included in the prompt`
135535
+ );
135536
+ }
135537
+ return parts.join("\n") || "";
135655
135538
  }
135656
-
135657
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-cyclic.mjs
135658
- function FromCyclic9(direction, context, type, value) {
135659
- value = FromType22(direction, { ...context, ...type.$defs }, Ref(type.$ref), value);
135660
- return Callback(direction, context, type, value);
135539
+ function findFinalUserMessageIndex(messages) {
135540
+ for (let i2 = messages.length - 1; i2 >= 0; i2--) {
135541
+ if (messages[i2].role === "user") return i2;
135542
+ }
135543
+ return -1;
135661
135544
  }
135662
-
135663
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-intersect.mjs
135664
- function MergeInteriors(interiors) {
135665
- return interiors.reduce((results, interior) => ({ ...results, ...interior }), {});
135545
+ function buildSystemPrompt(context, cwd) {
135546
+ const parts = [];
135547
+ if (context.systemPrompt) {
135548
+ parts.push(rewriteCustomToolReferences(context.systemPrompt, context.tools));
135549
+ }
135550
+ const agentsPath = resolveAgentsMdPath(cwd);
135551
+ if (agentsPath) {
135552
+ try {
135553
+ const content = readFileSync(agentsPath, "utf-8");
135554
+ const sanitized = sanitizeAgentsContent(content);
135555
+ parts.push(sanitized);
135556
+ } catch {
135557
+ }
135558
+ }
135559
+ if (context.messages?.some((m2) => m2.role === "toolResult")) {
135560
+ parts.push(
135561
+ "IMPORTANT: The conversation history below contains tool results from previously executed tools. Use these results to answer the user's question. Do NOT attempt to re-call tools that already have results."
135562
+ );
135563
+ }
135564
+ const customToolsAddendum = buildCustomToolsAddendum(context.tools);
135565
+ if (customToolsAddendum) {
135566
+ parts.push(customToolsAddendum);
135567
+ }
135568
+ return parts.join("\n\n");
135666
135569
  }
135667
- function NonMatchingInterior(value, interiors) {
135668
- for (const interior of interiors)
135669
- if (!guard_exports.IsDeepEqual(value, interior))
135670
- return interior;
135671
- return value;
135570
+ var BUILT_IN_PI_TOOLS = /* @__PURE__ */ new Set([
135571
+ "read",
135572
+ "write",
135573
+ "edit",
135574
+ "bash",
135575
+ "grep",
135576
+ "find"
135577
+ ]);
135578
+ function rewriteCustomToolReferences(prompt, tools) {
135579
+ if (!prompt || !tools || tools.length === 0) {
135580
+ return prompt;
135581
+ }
135582
+ let result = prompt;
135583
+ for (const tool of tools) {
135584
+ if (BUILT_IN_PI_TOOLS.has(tool.name)) continue;
135585
+ const escaped = tool.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
135586
+ const pattern = new RegExp(
135587
+ `(?<![A-Za-z0-9_])(?<!mcp__custom-tools__)${escaped}(?![A-Za-z0-9_])`,
135588
+ "g"
135589
+ );
135590
+ result = result.replace(pattern, `mcp__custom-tools__${tool.name}`);
135591
+ }
135592
+ return result;
135672
135593
  }
135673
- function Decode5(direction, context, type, value) {
135674
- if (guard_exports.IsEqual(type.allOf.length, 0))
135675
- return Callback(direction, context, type, value);
135676
- const interiors = type.allOf.map((schema) => FromType22(direction, context, schema, Clean(schema, Clone2(value))));
135677
- const structural = interiors.every((result) => guard_exports.IsObject(result));
135678
- const exterior = structural ? MergeInteriors(interiors) : NonMatchingInterior(value, interiors);
135679
- return Callback(direction, context, type, exterior);
135594
+ function buildCustomToolsAddendum(tools) {
135595
+ if (!tools || tools.length === 0) return "";
135596
+ const customNames = tools.map((t2) => t2.name).filter((name) => !BUILT_IN_PI_TOOLS.has(name));
135597
+ if (customNames.length === 0) return "";
135598
+ const lines = customNames.sort().map((name) => `- \`${name}\` is exposed as \`mcp__custom-tools__${name}\``);
135599
+ return [
135600
+ "## Custom tool naming (MCP)",
135601
+ "",
135602
+ "The following pi extension tools are available under MCP-prefixed",
135603
+ "names. When a system prompt or task instruction asks you to call one",
135604
+ "of these by its short name, call the MCP-prefixed name directly.",
135605
+ "",
135606
+ ...lines
135607
+ ].join("\n");
135680
135608
  }
135681
- function Encode4(direction, context, type, value) {
135682
- if (guard_exports.IsEqual(type.allOf.length, 0))
135683
- return Callback(direction, context, type, value);
135684
- const exterior = Callback(direction, context, type, value);
135685
- const interiors = type.allOf.map((schema) => FromType22(direction, context, schema, Clean(schema, Clone2(exterior))));
135686
- const structural = interiors.every((result) => guard_exports.IsObject(result));
135687
- if (structural)
135688
- return MergeInteriors(interiors);
135689
- return NonMatchingInterior(exterior, interiors);
135609
+ function userContentToText(content) {
135610
+ if (typeof content === "string") return content;
135611
+ if (!Array.isArray(content)) return "";
135612
+ const texts = [];
135613
+ for (const rawBlock of content) {
135614
+ const block = rawBlock;
135615
+ if (block.type === "text") {
135616
+ texts.push(typeof block.text === "string" ? block.text : "");
135617
+ } else if (block.type === "image") {
135618
+ texts.push("[An image was shared here but could not be included]");
135619
+ placeholderImageCount++;
135620
+ }
135621
+ }
135622
+ return texts.join("\n");
135690
135623
  }
135691
- function FromIntersect9(direction, context, type, value) {
135692
- return guard_exports.IsEqual(direction, "Decode") ? Decode5(direction, context, type, value) : Encode4(direction, context, type, value);
135624
+ function contentToText(content) {
135625
+ if (typeof content === "string") return content;
135626
+ if (!Array.isArray(content)) return "";
135627
+ return content.map((rawBlock) => {
135628
+ const block = rawBlock;
135629
+ if (block.type === "text") return typeof block.text === "string" ? block.text : "";
135630
+ if (block.type === "thinking") return "";
135631
+ if (block.type === "toolCall") {
135632
+ const name = typeof block.name === "string" ? block.name : "";
135633
+ const rawArgs = block.arguments;
135634
+ const argsObject = rawArgs && typeof rawArgs === "object" ? rawArgs : void 0;
135635
+ const isCustom = isCustomToolName(name);
135636
+ if (isCustom) {
135637
+ const argsStr2 = argsObject ? JSON.stringify(argsObject) : typeof rawArgs === "string" ? JSON.stringify(rawArgs) : "{}";
135638
+ return `[Used ${name} tool with args: ${argsStr2}]`;
135639
+ }
135640
+ const claudeName = mapPiToolNameToDroid(name);
135641
+ const claudeArgs = argsObject ? translatePiArgsToDroid(name, argsObject) : void 0;
135642
+ const argsStr = claudeArgs ? JSON.stringify(claudeArgs) : typeof rawArgs === "string" ? JSON.stringify(rawArgs) : "{}";
135643
+ return `[Prior tool call \u2014 already executed; result follows in TOOL RESULT (${claudeName}):] args=${argsStr}`;
135644
+ }
135645
+ return `[${String(block.type)}]`;
135646
+ }).join("\n");
135693
135647
  }
135694
-
135695
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-object.mjs
135696
- function Decode6(direction, context, type, value) {
135697
- if (!guard_exports.IsObjectNotArray(value))
135698
- return Unreachable();
135699
- for (const key of guard_exports.Keys(type.properties)) {
135700
- if (!guard_exports.HasPropertyKey(value, key) || IsOptionalUndefined(type.properties[key], key, value))
135701
- continue;
135702
- value[key] = FromType22(direction, context, type.properties[key], value[key]);
135648
+ function toolResultContentToText(content) {
135649
+ if (typeof content === "string") return content;
135650
+ if (!Array.isArray(content)) return "";
135651
+ const texts = [];
135652
+ for (const rawBlock of content) {
135653
+ const block = rawBlock;
135654
+ if (block.type === "text") {
135655
+ texts.push(typeof block.text === "string" ? block.text : "");
135656
+ } else if (block.type === "image") {
135657
+ texts.push("[An image was shared here but could not be included]");
135658
+ placeholderImageCount++;
135659
+ }
135703
135660
  }
135704
- return Callback(direction, context, type, value);
135661
+ return texts.join("\n");
135705
135662
  }
135706
- function Encode5(direction, context, type, value) {
135707
- const exterior = Callback(direction, context, type, value);
135708
- if (!guard_exports.IsObjectNotArray(exterior))
135709
- return exterior;
135710
- for (const key of guard_exports.Keys(type.properties)) {
135711
- if (!guard_exports.HasPropertyKey(exterior, key) || IsOptionalUndefined(type.properties[key], key, exterior))
135712
- continue;
135713
- exterior[key] = FromType22(direction, context, type.properties[key], exterior[key]);
135663
+ function toolResultHasImages(content) {
135664
+ if (typeof content === "string" || !Array.isArray(content)) return false;
135665
+ return content.some((block) => block.type === "image");
135666
+ }
135667
+ function resolveAgentsMdPath(cwd) {
135668
+ let current = resolve(cwd);
135669
+ while (true) {
135670
+ const candidate = join(current, "AGENTS.md");
135671
+ if (existsSync(candidate)) return candidate;
135672
+ const parent = dirname(current);
135673
+ if (parent === current) break;
135674
+ current = parent;
135714
135675
  }
135715
- return exterior;
135676
+ const globalHome = process.env.HOME || process.env.USERPROFILE || homedir();
135677
+ const globalPath = join(globalHome, ".pi", "agent", "AGENTS.md");
135678
+ if (existsSync(globalPath)) return globalPath;
135679
+ return void 0;
135716
135680
  }
135717
- function FromObject14(direction, context, type, value) {
135718
- return guard_exports.IsEqual(direction, "Decode") ? Decode6(direction, context, type, value) : Encode5(direction, context, type, value);
135681
+ function sanitizeAgentsContent(content) {
135682
+ let sanitized = content;
135683
+ sanitized = sanitized.replace(/~\/\.pi\b/gi, "~/.claude");
135684
+ sanitized = sanitized.replace(/(^|[\s'"`])\.pi\//g, "$1.claude/");
135685
+ sanitized = sanitized.replace(/\b\.pi\b/gi, ".claude");
135686
+ return sanitized;
135719
135687
  }
135720
135688
 
135721
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-record.mjs
135722
- function Decode7(direction, context, type, value) {
135723
- if (!guard_exports.IsObjectNotArray(value))
135724
- return Unreachable();
135725
- const regexp = new RegExp(RecordPattern(type));
135726
- for (const key of guard_exports.Keys(value)) {
135727
- if (!regexp.test(key))
135728
- Unreachable();
135729
- value[key] = FromType22(direction, context, RecordValue(type), value[key]);
135730
- }
135731
- return Callback(direction, context, type, value);
135689
+ // ../../plugins/fusion-plugin-droid-runtime/src/process-manager.ts
135690
+ import { execSync, spawn } from "node:child_process";
135691
+ import { writeFileSync, unlinkSync } from "node:fs";
135692
+ import { join as join2 } from "node:path";
135693
+ import { tmpdir } from "node:os";
135694
+ function debugLog(message) {
135695
+ if (process.env.PI_DROID_CLI_DEBUG !== "1") return;
135696
+ console.error(`[droid-cli] ${message}`);
135732
135697
  }
135733
- function Encode6(direction, context, type, value) {
135734
- const exterior = Callback(direction, context, type, value);
135735
- if (!guard_exports.IsObjectNotArray(exterior))
135736
- return exterior;
135737
- const regexp = new RegExp(RecordPattern(type));
135738
- for (const key of guard_exports.Keys(exterior)) {
135739
- if (!regexp.test(key))
135740
- continue;
135741
- exterior[key] = FromType22(direction, context, RecordValue(type), exterior[key]);
135698
+ function buildDroidSpawnArgs(modelId, systemPrompt, options) {
135699
+ const args = [
135700
+ "-p",
135701
+ "--input-format",
135702
+ "stream-json",
135703
+ "--output-format",
135704
+ "stream-json",
135705
+ "--verbose",
135706
+ "--include-partial-messages",
135707
+ "--model",
135708
+ modelId
135709
+ ];
135710
+ if (options?.resumeSessionId) {
135711
+ args.push("--resume", options.resumeSessionId);
135712
+ } else if (options?.newSessionId) {
135713
+ args.push("--session-id", options.newSessionId);
135742
135714
  }
135743
- return exterior;
135744
- }
135745
- function FromRecord5(direction, context, type, value) {
135746
- return guard_exports.IsEqual(direction, "Decode") ? Decode7(direction, context, type, value) : Encode6(direction, context, type, value);
135747
- }
135748
-
135749
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-ref.mjs
135750
- function ResolveRef(direction, context, type, value) {
135751
- return guard_exports.HasPropertyKey(context, type.$ref) ? FromType22(direction, context, context[type.$ref], value) : value;
135715
+ if (systemPrompt) {
135716
+ const tmpFile = join2(
135717
+ tmpdir(),
135718
+ `droid-cli-sysprompt-${process.pid}.txt`
135719
+ );
135720
+ writeFileSync(tmpFile, systemPrompt, "utf-8");
135721
+ args.push("--append-system-prompt", tmpFile);
135722
+ }
135723
+ if (options?.effort) {
135724
+ args.push("--effort", options.effort);
135725
+ }
135726
+ if (options?.mcpConfigPath) {
135727
+ args.push("--mcp-config", options.mcpConfigPath);
135728
+ }
135729
+ return args;
135752
135730
  }
135753
- function FromRef8(direction, context, type, value) {
135754
- return guard_exports.IsEqual(direction, "Decode") ? Callback(direction, context, type, ResolveRef(direction, context, type, value)) : ResolveRef(direction, context, type, Callback(direction, context, type, value));
135731
+ function spawnDroid(modelId, systemPrompt, options) {
135732
+ const args = buildDroidSpawnArgs(modelId, systemPrompt, {
135733
+ effort: options?.effort,
135734
+ mcpConfigPath: options?.mcpConfigPath,
135735
+ resumeSessionId: options?.resumeSessionId,
135736
+ newSessionId: options?.newSessionId
135737
+ });
135738
+ const proc = spawn("droid", args, {
135739
+ stdio: ["pipe", "pipe", "pipe"],
135740
+ cwd: options?.cwd ?? process.cwd()
135741
+ });
135742
+ debugLog(`spawnDroid: pid=${proc.pid} model=${modelId}`);
135743
+ return proc;
135755
135744
  }
135756
-
135757
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-tuple.mjs
135758
- function Decode8(direction, context, type, value) {
135759
- if (!guard_exports.IsArray(value))
135760
- return Unreachable();
135761
- for (let i2 = 0; i2 < Math.min(type.items.length, value.length); i2++) {
135762
- value[i2] = FromType22(direction, context, type.items[i2], value[i2]);
135745
+ function cleanupSystemPromptFile() {
135746
+ try {
135747
+ unlinkSync(join2(tmpdir(), `droid-cli-sysprompt-${process.pid}.txt`));
135748
+ } catch {
135763
135749
  }
135764
- return Callback(direction, context, type, value);
135765
135750
  }
135766
- function Encode7(direction, context, type, value) {
135767
- const exterior = Callback(direction, context, type, value);
135768
- if (!guard_exports.IsArray(exterior))
135769
- return value;
135770
- for (let i2 = 0; i2 < Math.min(type.items.length, exterior.length); i2++) {
135771
- exterior[i2] = FromType22(direction, context, type.items[i2], exterior[i2]);
135772
- }
135773
- return exterior;
135751
+ function writeUserMessage(proc, prompt) {
135752
+ const message = {
135753
+ type: "user",
135754
+ message: {
135755
+ role: "user",
135756
+ content: prompt
135757
+ }
135758
+ };
135759
+ proc.stdin.write(JSON.stringify(message) + "\n");
135760
+ proc.stdin.end();
135774
135761
  }
135775
- function FromTuple8(direction, context, type, value) {
135776
- return guard_exports.IsEqual(direction, "Decode") ? Decode8(direction, context, type, value) : Encode7(direction, context, type, value);
135762
+ function forceKillProcess(proc) {
135763
+ if (proc.killed || proc.exitCode !== null) return;
135764
+ proc.kill("SIGKILL");
135777
135765
  }
135778
-
135779
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-union.mjs
135780
- function Decode9(direction, context, type, value) {
135781
- for (const schema of UnionPrioritySort(type.anyOf, 1)) {
135782
- if (!Check2(context, schema, value))
135783
- continue;
135784
- const variant = FromType22(direction, context, schema, value);
135785
- return Callback(direction, context, type, variant);
135786
- }
135787
- return value;
135766
+ var activeProcesses = /* @__PURE__ */ new Set();
135767
+ function registerProcess(proc) {
135768
+ activeProcesses.add(proc);
135769
+ proc.on("exit", () => activeProcesses.delete(proc));
135788
135770
  }
135789
- function Encode8(direction, context, type, value) {
135790
- const exterior = Callback(direction, context, type, value);
135791
- for (const schema of UnionPrioritySort(type.anyOf, -1)) {
135792
- const variant = FromType22(direction, context, schema, Clone2(exterior));
135793
- if (!Check2(context, schema, variant))
135794
- continue;
135795
- return variant;
135771
+ function killAllProcesses() {
135772
+ for (const proc of activeProcesses) {
135773
+ forceKillProcess(proc);
135796
135774
  }
135797
- return exterior;
135775
+ activeProcesses.clear();
135798
135776
  }
135799
- function FromUnion12(direction, context, type, value) {
135800
- return guard_exports.IsEqual(direction, "Decode") ? Decode9(direction, context, type, value) : Encode8(direction, context, type, value);
135777
+ function cleanupProcess(proc) {
135778
+ setTimeout(() => {
135779
+ forceKillProcess(proc);
135780
+ }, 500);
135801
135781
  }
135802
-
135803
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/from-type.mjs
135804
- function FromType22(direction, context, type, value) {
135805
- return IsArray2(type) ? FromArray11(direction, context, type, value) : IsCyclic(type) ? FromCyclic9(direction, context, type, value) : IsIntersect(type) ? FromIntersect9(direction, context, type, value) : IsObject2(type) ? FromObject14(direction, context, type, value) : IsRecord(type) ? FromRecord5(direction, context, type, value) : IsRef(type) ? FromRef8(direction, context, type, value) : IsTuple(type) ? FromTuple8(direction, context, type, value) : IsUnion(type) ? FromUnion12(direction, context, type, value) : Callback(direction, context, type, value);
135782
+ function captureStderr(proc) {
135783
+ let buffer = "";
135784
+ proc.stderr.on("data", (data) => {
135785
+ buffer += data.toString();
135786
+ });
135787
+ return () => buffer;
135806
135788
  }
135807
-
135808
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/decode.mjs
135809
- var DecodeError = class extends AssertError {
135810
- constructor(value, errors) {
135811
- super("Decode", value, errors);
135812
- }
135813
- };
135814
- function Assert(context, type, value) {
135815
- if (!Check2(context, type, value))
135816
- throw new DecodeError(value, Errors2(context, type, value));
135817
- return value;
135789
+ function runDroidProbe(args, timeoutMs = 45e3) {
135790
+ return new Promise((resolve2) => {
135791
+ const proc = spawn("droid", args, { stdio: "ignore" });
135792
+ const timer = setTimeout(() => {
135793
+ try {
135794
+ proc.kill("SIGKILL");
135795
+ } catch {
135796
+ }
135797
+ resolve2(124);
135798
+ }, timeoutMs);
135799
+ proc.once("error", () => {
135800
+ clearTimeout(timer);
135801
+ resolve2(127);
135802
+ });
135803
+ proc.once("exit", (code) => {
135804
+ clearTimeout(timer);
135805
+ resolve2(code ?? 1);
135806
+ });
135807
+ });
135818
135808
  }
135819
- function DecodeUnsafe(context, type, value) {
135820
- return FromType22("Decode", context, type, value);
135809
+ async function validateCliPresenceAsync() {
135810
+ const code = await runDroidProbe(["--version"]);
135811
+ if (code === 0) return { ok: true };
135812
+ return {
135813
+ ok: false,
135814
+ error: new Error(
135815
+ "Droid CLI not found on PATH. Install Droid CLI and then run: droid auth login"
135816
+ )
135817
+ };
135821
135818
  }
135822
- var Decoder = Pipeline([
135823
- (_context, _type, value) => Clone2(value),
135824
- (context, type, value) => Default(context, type, value),
135825
- (context, type, value) => Convert(context, type, value),
135826
- (context, type, value) => Clean(context, type, value),
135827
- (context, type, value) => Assert(context, type, value),
135828
- (context, type, value) => DecodeUnsafe(context, type, value)
135829
- ]);
135830
-
135831
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/codec/encode.mjs
135832
- var EncodeError = class extends AssertError {
135833
- constructor(value, errors) {
135834
- super("Encode", value, errors);
135835
- }
135836
- };
135837
- function Assert2(context, type, value) {
135838
- if (!Check2(context, type, value))
135839
- throw new EncodeError(value, Errors2(context, type, value));
135840
- return value;
135819
+ async function validateCliAuthAsync() {
135820
+ const code = await runDroidProbe(["auth", "status"]);
135821
+ if (code === 0) return true;
135822
+ console.warn(
135823
+ "[droid-cli] Droid CLI is not authenticated. Run 'droid auth login' to authenticate."
135824
+ );
135825
+ return false;
135841
135826
  }
135842
- function EncodeUnsafe(context, type, value) {
135843
- return FromType22("Encode", context, type, value);
135827
+ async function discoverDroidModels() {
135828
+ const attempts = [["models", "--json"], ["model", "list", "--json"], ["models"]];
135829
+ for (const args of attempts) {
135830
+ const models = await new Promise((resolve2) => {
135831
+ const proc = spawn("droid", args, { stdio: ["ignore", "pipe", "ignore"] });
135832
+ let out = "";
135833
+ proc.stdout?.on("data", (chunk) => {
135834
+ out += chunk.toString();
135835
+ });
135836
+ proc.once("error", () => resolve2(null));
135837
+ proc.once("exit", (code) => {
135838
+ if (code !== 0) return resolve2(null);
135839
+ const trimmed = out.trim();
135840
+ if (!trimmed) return resolve2([]);
135841
+ try {
135842
+ const parsed = JSON.parse(trimmed);
135843
+ if (Array.isArray(parsed)) {
135844
+ return resolve2(
135845
+ parsed.map(
135846
+ (entry) => typeof entry === "string" ? entry : typeof entry?.id === "string" ? entry.id : typeof entry?.name === "string" ? entry.name : void 0
135847
+ ).filter((id) => Boolean(id))
135848
+ );
135849
+ }
135850
+ } catch {
135851
+ }
135852
+ resolve2(
135853
+ trimmed.split(/\r?\n/).map((line) => line.trim()).filter(Boolean)
135854
+ );
135855
+ });
135856
+ });
135857
+ if (models && models.length > 0) {
135858
+ return Array.from(new Set(models));
135859
+ }
135860
+ }
135861
+ return [];
135844
135862
  }
135845
- var Encoder = Pipeline([
135846
- (_context, _type, value) => Clone2(value),
135847
- (context, type, value) => EncodeUnsafe(context, type, value),
135848
- (context, type, value) => Default(context, type, value),
135849
- (context, type, value) => Convert(context, type, value),
135850
- (context, type, value) => Clean(context, type, value),
135851
- (context, type, value) => Assert2(context, type, value)
135852
- ]);
135853
135863
 
135854
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/parse/parse.mjs
135855
- var ParseError2 = class extends AssertError {
135856
- constructor(value, errors) {
135857
- super("Parse", value, errors);
135864
+ // ../../plugins/fusion-plugin-droid-runtime/src/stream-parser.ts
135865
+ function parseLine(line) {
135866
+ const trimmed = line.trim();
135867
+ if (!trimmed) {
135868
+ return null;
135858
135869
  }
135859
- };
135860
- function Assert3(context, type, value) {
135861
- if (!Check2(context, type, value))
135862
- throw new ParseError2(value, Errors2(context, type, value));
135863
- return value;
135870
+ if (!trimmed.startsWith("{")) {
135871
+ return null;
135872
+ }
135873
+ let parsed;
135874
+ try {
135875
+ parsed = JSON.parse(trimmed);
135876
+ } catch {
135877
+ console.error("Failed to parse NDJSON line:", trimmed);
135878
+ return null;
135879
+ }
135880
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
135881
+ return null;
135882
+ }
135883
+ return parsed;
135864
135884
  }
135865
- var Parser = Pipeline([
135866
- (_context, _type, value) => Clone2(value),
135867
- (context, type, value) => Default(context, type, value),
135868
- (context, type, value) => Convert(context, type, value),
135869
- (context, type, value) => Clean(context, type, value),
135870
- (context, type, value) => Assert3(context, type, value)
135871
- ]);
135872
-
135873
- // ../../node_modules/.pnpm/typebox@1.1.32/node_modules/typebox/build/value/delta/edit.mjs
135874
- var Insert = _Object_({
135875
- type: Literal("insert"),
135876
- path: String2(),
135877
- value: Unknown()
135878
- });
135879
- var Update2 = Object({
135880
- type: Literal("update"),
135881
- path: String2(),
135882
- value: Unknown()
135883
- });
135884
- var Delete2 = _Object_({
135885
- type: Literal("delete"),
135886
- path: String2()
135887
- });
135888
- var Edit = Union([Insert, Update2, Delete2]);
135889
135885
 
135890
- // ../../node_modules/.pnpm/@mariozechner+pi-ai@0.72.1_@modelcontextprotocol+sdk@1.28.0_zod@4.3.6__ws@8.20.0_zod@4.3.6/node_modules/@mariozechner/pi-ai/dist/utils/validation.js
135891
- var TYPEBOX_KIND = Symbol.for("TypeBox.Kind");
135892
-
135893
- // ../../plugins/fusion-plugin-droid-runtime/dist/event-bridge.js
135886
+ // ../../plugins/fusion-plugin-droid-runtime/src/event-bridge.ts
135894
135887
  function mapStopReason5(reason) {
135895
135888
  switch (reason) {
135896
135889
  case "tool_use":
@@ -136025,8 +136018,7 @@ function createEventBridge(stream2, model) {
136025
136018
  const deltaType = event.delta?.type;
136026
136019
  if (deltaType === "text_delta" && event.delta.text != null) {
136027
136020
  const idx = blocks.findIndex((b) => b.index === event.index);
136028
- if (idx === -1)
136029
- return;
136021
+ if (idx === -1) return;
136030
136022
  const block = blocks[idx];
136031
136023
  if (block.type === "text") {
136032
136024
  block.text += event.delta.text;
@@ -136041,8 +136033,7 @@ function createEventBridge(stream2, model) {
136041
136033
  }
136042
136034
  } else if (deltaType === "thinking_delta" && event.delta.thinking != null) {
136043
136035
  const idx = blocks.findIndex((b) => b.index === event.index);
136044
- if (idx === -1)
136045
- return;
136036
+ if (idx === -1) return;
136046
136037
  const block = blocks[idx];
136047
136038
  if (block.type === "thinking") {
136048
136039
  block.text += event.delta.thinking;
@@ -136057,8 +136048,7 @@ function createEventBridge(stream2, model) {
136057
136048
  }
136058
136049
  } else if (deltaType === "input_json_delta" && event.delta.partial_json != null) {
136059
136050
  const idx = blocks.findIndex((b) => b.index === event.index);
136060
- if (idx === -1)
136061
- return;
136051
+ if (idx === -1) return;
136062
136052
  const block = blocks[idx];
136063
136053
  if (block.type === "tool_use") {
136064
136054
  block.partialJson += event.delta.partial_json;
@@ -136076,8 +136066,7 @@ function createEventBridge(stream2, model) {
136076
136066
  }
136077
136067
  } else if (deltaType === "signature_delta" && event.delta.signature != null) {
136078
136068
  const idx = blocks.findIndex((b) => b.index === event.index);
136079
- if (idx === -1)
136080
- return;
136069
+ if (idx === -1) return;
136081
136070
  const block = blocks[idx];
136082
136071
  if (block.type === "thinking") {
136083
136072
  const contentBlock = output.content[idx];
@@ -136087,8 +136076,7 @@ function createEventBridge(stream2, model) {
136087
136076
  }
136088
136077
  function handleContentBlockStop(event) {
136089
136078
  const idx = blocks.findIndex((b) => b.index === event.index);
136090
- if (idx === -1)
136091
- return;
136079
+ if (idx === -1) return;
136092
136080
  const block = blocks[idx];
136093
136081
  delete block.index;
136094
136082
  if (block.type === "text") {
@@ -136140,8 +136128,7 @@ function createEventBridge(stream2, model) {
136140
136128
  }
136141
136129
  const usage = event.usage;
136142
136130
  if (usage) {
136143
- if (usage.input_tokens != null)
136144
- output.usage.input = usage.input_tokens;
136131
+ if (usage.input_tokens != null) output.usage.input = usage.input_tokens;
136145
136132
  if (usage.output_tokens != null)
136146
136133
  output.usage.output = usage.output_tokens;
136147
136134
  output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
@@ -136156,7 +136143,7 @@ function createEventBridge(stream2, model) {
136156
136143
  };
136157
136144
  }
136158
136145
 
136159
- // ../../plugins/fusion-plugin-droid-runtime/dist/thinking-config.js
136146
+ // ../../plugins/fusion-plugin-droid-runtime/src/thinking-config.ts
136160
136147
  var STANDARD_EFFORT_MAP = {
136161
136148
  minimal: "low",
136162
136149
  low: "low",
@@ -136183,22 +136170,23 @@ function mapThinkingEffort(reasoning, modelId, thinkingBudgets) {
136183
136170
  return void 0;
136184
136171
  }
136185
136172
  if (thinkingBudgets && Object.keys(thinkingBudgets).length > 0) {
136186
- console.warn("[droid-cli] Custom thinkingBudgets are not supported with CLI subprocess. The CLI uses --effort levels instead of token budgets. Budgets will be ignored.");
136173
+ console.warn(
136174
+ "[droid-cli] Custom thinkingBudgets are not supported with CLI subprocess. The CLI uses --effort levels instead of token budgets. Budgets will be ignored."
136175
+ );
136187
136176
  }
136188
136177
  const isOpus = modelId ? isOpusModel(modelId) : false;
136189
136178
  const map2 = isOpus ? OPUS_EFFORT_MAP : STANDARD_EFFORT_MAP;
136190
136179
  return map2[reasoning];
136191
136180
  }
136192
136181
 
136193
- // ../../plugins/fusion-plugin-droid-runtime/dist/provider.js
136182
+ // ../../plugins/fusion-plugin-droid-runtime/src/provider.ts
136194
136183
  var INACTIVITY_TIMEOUT_MS = 30 * 6e4;
136195
136184
  var FIRST_LINE_TIMEOUT_MS = 6e4;
136196
136185
  function isDebugStreamEnabled() {
136197
136186
  return process.env.PI_DROID_CLI_DEBUG === "1";
136198
136187
  }
136199
136188
  function debugLog2(message) {
136200
- if (!isDebugStreamEnabled())
136201
- return;
136189
+ if (!isDebugStreamEnabled()) return;
136202
136190
  console.error(`[droid-cli] ${message}`);
136203
136191
  }
136204
136192
  function streamViaCli(model, context, options) {
@@ -136208,8 +136196,7 @@ function streamViaCli(model, context, options) {
136208
136196
  let abortHandler;
136209
136197
  try {
136210
136198
  let endStreamWithError2 = function(errMsg) {
136211
- if (streamEnded || broken)
136212
- return;
136199
+ if (streamEnded || broken) return;
136213
136200
  streamEnded = true;
136214
136201
  const output = bridge.getOutput();
136215
136202
  const errorMessage = {
@@ -136224,11 +136211,12 @@ function streamViaCli(model, context, options) {
136224
136211
  });
136225
136212
  stream2.end();
136226
136213
  }, resetInactivityTimer2 = function() {
136227
- if (inactivityTimer !== void 0)
136228
- clearTimeout(inactivityTimer);
136214
+ if (inactivityTimer !== void 0) clearTimeout(inactivityTimer);
136229
136215
  inactivityTimer = setTimeout(() => {
136230
136216
  forceKillProcess(proc);
136231
- endStreamWithError2(`Droid CLI subprocess timed out: no output for ${INACTIVITY_TIMEOUT_MS / 1e3} seconds`);
136217
+ endStreamWithError2(
136218
+ `Droid CLI subprocess timed out: no output for ${INACTIVITY_TIMEOUT_MS / 1e3} seconds`
136219
+ );
136232
136220
  }, INACTIVITY_TIMEOUT_MS);
136233
136221
  };
136234
136222
  var endStreamWithError = endStreamWithError2, resetInactivityTimer = resetInactivityTimer2;
@@ -136236,7 +136224,11 @@ function streamViaCli(model, context, options) {
136236
136224
  const resumeSessionId = options?.sessionId && context.messages.length > 1 ? options.sessionId : void 0;
136237
136225
  const prompt = resumeSessionId ? buildResumePrompt(context) : buildPrompt(context);
136238
136226
  const systemPrompt = resumeSessionId ? void 0 : buildSystemPrompt(context, cwd);
136239
- const effort = mapThinkingEffort(options?.reasoning, model.id, options?.thinkingBudgets);
136227
+ const effort = mapThinkingEffort(
136228
+ options?.reasoning,
136229
+ model.id,
136230
+ options?.thinkingBudgets
136231
+ );
136240
136232
  const spawnOptions = {
136241
136233
  cwd,
136242
136234
  signal: options?.signal,
@@ -136254,7 +136246,9 @@ function streamViaCli(model, context, options) {
136254
136246
  resumeSessionId,
136255
136247
  newSessionId: !resumeSessionId ? options?.sessionId : void 0
136256
136248
  });
136257
- debugLog2(`spawned droid subprocess pid=${proc.pid ?? "unknown"} args=${JSON.stringify(spawnArgs)}`);
136249
+ debugLog2(
136250
+ `spawned droid subprocess pid=${proc.pid ?? "unknown"} args=${JSON.stringify(spawnArgs)}`
136251
+ );
136258
136252
  writeUserMessage(proc, prompt);
136259
136253
  debugLog2("user message written to stdin, stdin.end() called");
136260
136254
  const bridge = createEventBridge(stream2, model);
@@ -136281,16 +136275,14 @@ function streamViaCli(model, context, options) {
136281
136275
  terminal: false
136282
136276
  });
136283
136277
  proc.on("error", (err) => {
136284
- if (broken)
136285
- return;
136278
+ if (broken) return;
136286
136279
  const stderr = getStderr();
136287
136280
  endStreamWithError2(stderr || err.message);
136288
136281
  });
136289
136282
  proc.on("close", (code, _signal) => {
136290
136283
  clearTimeout(inactivityTimer);
136291
136284
  debugLog2(`subprocess closed: code=${code} signal=${_signal}`);
136292
- if (broken)
136293
- return;
136285
+ if (broken) return;
136294
136286
  const stderr = getStderr().trim();
136295
136287
  if (stderr) {
136296
136288
  console.warn(`[droid-cli] Droid CLI stderr on close: ${stderr}`);
@@ -136302,10 +136294,11 @@ function streamViaCli(model, context, options) {
136302
136294
  });
136303
136295
  resetInactivityTimer2();
136304
136296
  const firstLineTimer = setTimeout(() => {
136305
- if (firstLineReceived)
136306
- return;
136297
+ if (firstLineReceived) return;
136307
136298
  forceKillProcess(proc);
136308
- endStreamWithError2(`Droid CLI produced no output within ${FIRST_LINE_TIMEOUT_MS / 1e3}s \u2014 likely binary hang or auth failure (try \`droid --version\` and \`droid auth status\`)`);
136299
+ endStreamWithError2(
136300
+ `Droid CLI produced no output within ${FIRST_LINE_TIMEOUT_MS / 1e3}s \u2014 likely binary hang or auth failure (try \`droid --version\` and \`droid auth status\`)`
136301
+ );
136309
136302
  }, FIRST_LINE_TIMEOUT_MS);
136310
136303
  proc.on("close", () => clearTimeout(firstLineTimer));
136311
136304
  rl.on("line", (line) => {
@@ -136313,12 +136306,10 @@ function streamViaCli(model, context, options) {
136313
136306
  firstLineReceived = true;
136314
136307
  debugLog2("first stdout line received from Droid CLI");
136315
136308
  }
136316
- if (broken)
136317
- return;
136309
+ if (broken) return;
136318
136310
  resetInactivityTimer2();
136319
136311
  const msg = parseLine(line);
136320
- if (!msg)
136321
- return;
136312
+ if (!msg) return;
136322
136313
  if (msg.type === "stream_event") {
136323
136314
  const isTopLevel = !msg.parent_tool_use_id;
136324
136315
  if (isTopLevel) {
@@ -136328,7 +136319,9 @@ function streamViaCli(model, context, options) {
136328
136319
  const toolName = msg.event.content_block.name;
136329
136320
  if (toolName) {
136330
136321
  const piKnownTool = isPiKnownDroidTool(toolName);
136331
- debugLog2(`top-level tool_use seen: ${toolName} (piKnown=${piKnownTool ? "yes" : "no"})`);
136322
+ debugLog2(
136323
+ `top-level tool_use seen: ${toolName} (piKnown=${piKnownTool ? "yes" : "no"})`
136324
+ );
136332
136325
  if (piKnownTool) {
136333
136326
  sawBuiltInOrCustomTool = true;
136334
136327
  }
@@ -136344,7 +136337,9 @@ function streamViaCli(model, context, options) {
136344
136337
  return;
136345
136338
  }
136346
136339
  } else if (msg.type === "control_request") {
136347
- debugLog2(`unexpected control_request received (stdin already closed): ${msg.request_id}`);
136340
+ debugLog2(
136341
+ `unexpected control_request received (stdin already closed): ${msg.request_id}`
136342
+ );
136348
136343
  } else if (msg.type === "result") {
136349
136344
  if (msg.subtype === "error") {
136350
136345
  endStreamWithError2(msg.error ?? "Unknown error from Droid CLI");
@@ -136369,9 +136364,13 @@ function streamViaCli(model, context, options) {
136369
136364
  const output = bridge.getOutput();
136370
136365
  const contentEvents = output.content || [];
136371
136366
  if (contentEvents.length === 0) {
136372
- console.warn(`[droid-cli] Droid CLI closed without content events (model=${model.id}, sessionId=${options?.sessionId ?? "none"})`);
136367
+ console.warn(
136368
+ `[droid-cli] Droid CLI closed without content events (model=${model.id}, sessionId=${options?.sessionId ?? "none"})`
136369
+ );
136373
136370
  }
136374
- const piToolCalls = (output.content || []).filter((c) => c.type === "toolCall");
136371
+ const piToolCalls = (output.content || []).filter(
136372
+ (c) => c.type === "toolCall"
136373
+ );
136375
136374
  const effectiveReason = output.stopReason === "toolUse" && piToolCalls.length === 0 ? "stop" : output.stopReason;
136376
136375
  streamEnded = true;
136377
136376
  stream2.push({
@@ -136408,7 +136407,7 @@ function streamViaCli(model, context, options) {
136408
136407
  return stream2;
136409
136408
  }
136410
136409
 
136411
- // ../../plugins/fusion-plugin-droid-runtime/dist/runtime-adapter.js
136410
+ // ../../plugins/fusion-plugin-droid-runtime/src/runtime-adapter.ts
136412
136411
  var DroidRuntimeAdapter = class {
136413
136412
  id = "droid";
136414
136413
  name = "Droid Runtime";
@@ -136459,7 +136458,7 @@ var DroidRuntimeAdapter = class {
136459
136458
  }
136460
136459
  };
136461
136460
 
136462
- // ../../plugins/fusion-plugin-droid-runtime/dist/probe.js
136461
+ // ../../plugins/fusion-plugin-droid-runtime/src/probe.ts
136463
136462
  import { spawn as spawn2 } from "node:child_process";
136464
136463
  function resolveDroidBinaryPath(settings2) {
136465
136464
  if (typeof settings2?.droidBinaryPath === "string" && settings2.droidBinaryPath.trim().length > 0) {
@@ -136516,7 +136515,7 @@ async function probeDroidBinary(options) {
136516
136515
  };
136517
136516
  }
136518
136517
 
136519
- // ../../plugins/fusion-plugin-droid-runtime/dist/mcp-config.js
136518
+ // ../../plugins/fusion-plugin-droid-runtime/src/mcp-config.ts
136520
136519
  import { writeFileSync as writeFileSync2 } from "node:fs";
136521
136520
  import { join as join3, dirname as dirname2 } from "node:path";
136522
136521
  import { tmpdir as tmpdir2 } from "node:os";
@@ -136541,8 +136540,7 @@ function getCustomToolDefs(pi) {
136541
136540
  }));
136542
136541
  }
136543
136542
  function toolsFromContext(contextTools) {
136544
- if (!Array.isArray(contextTools))
136545
- return [];
136543
+ if (!Array.isArray(contextTools)) return [];
136546
136544
  return contextTools.filter((tool) => !BUILT_IN_TOOL_NAMES.has(tool.name)).map((tool) => ({
136547
136545
  name: tool.name,
136548
136546
  description: tool.description,
@@ -136551,7 +136549,10 @@ function toolsFromContext(contextTools) {
136551
136549
  }
136552
136550
  function writeMcpConfig(toolDefs, cacheKey) {
136553
136551
  const suffix = cacheKey ? `${process.pid}-${cacheKey}` : `${process.pid}`;
136554
- const schemaFilePath = join3(tmpdir2(), `droid-cli-mcp-schemas-${suffix}.json`);
136552
+ const schemaFilePath = join3(
136553
+ tmpdir2(),
136554
+ `droid-cli-mcp-schemas-${suffix}.json`
136555
+ );
136555
136556
  writeFileSync2(schemaFilePath, JSON.stringify(toolDefs));
136556
136557
  const __filename = fileURLToPath(import.meta.url);
136557
136558
  const __dirname = dirname2(__filename);
@@ -136564,12 +136565,15 @@ function writeMcpConfig(toolDefs, cacheKey) {
136564
136565
  }
136565
136566
  }
136566
136567
  };
136567
- const configFilePath = join3(tmpdir2(), `droid-cli-mcp-config-${suffix}.json`);
136568
+ const configFilePath = join3(
136569
+ tmpdir2(),
136570
+ `droid-cli-mcp-config-${suffix}.json`
136571
+ );
136568
136572
  writeFileSync2(configFilePath, JSON.stringify(config2));
136569
136573
  return configFilePath;
136570
136574
  }
136571
136575
 
136572
- // ../../plugins/fusion-plugin-droid-runtime/dist/index.js
136576
+ // ../../plugins/fusion-plugin-droid-runtime/src/index.ts
136573
136577
  var DROID_RUNTIME_ID = "droid";
136574
136578
  var DROID_RUNTIME_VERSION = "0.1.0";
136575
136579
  var droidRuntimeMetadata = {