kimiflare 0.80.0 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -12236,6 +12236,8 @@ var init_supervisor = __esm({
12236
12236
  _phase = "idle";
12237
12237
  _killRequested = false;
12238
12238
  _activeWorkers = /* @__PURE__ */ new Map();
12239
+ /** Injectable LLM client for synthesis (overridable in tests). */
12240
+ _runKimi = runKimi;
12239
12241
  /** Coordinator-side MemoryManager for proxying memories to workers */
12240
12242
  memoryManager = null;
12241
12243
  /** Coordinator-side LspManager for proxying LSP context to workers */
@@ -12631,17 +12633,8 @@ ${w.context ?? ""}` : w.context ?? "",
12631
12633
  }
12632
12634
  return results;
12633
12635
  }
12634
- /** Synthesize findings from multiple workers into a unified execution plan.
12635
- *
12636
- * Steps:
12637
- * 1. Deduplicate findings by topic (case-insensitive), keeping the highest-confidence version.
12638
- * 2. Detect conflicts — same topic with different recommendations.
12639
- * 3. Tie-breaker: when conflicting recommendations exist, prefer the one from
12640
- * the worker with higher average confidence.
12641
- * 4. Produce a markdown execution plan the coordinator can present to the user
12642
- * or feed into an executor worker.
12643
- */
12644
- synthesizeFindings(results) {
12636
+ /** Heuristic synthesis exact legacy behavior, preserved as fallback. */
12637
+ synthesizeFindingsHeuristic(results) {
12645
12638
  const allFindings = results.flatMap((r) => r.findings);
12646
12639
  const allRecommendations = results.flatMap((r) => r.recommendations);
12647
12640
  const CONFIDENCE_SCORE = { high: 3, medium: 2, low: 1 };
@@ -12710,6 +12703,119 @@ ${w.context ?? ""}` : w.context ?? "",
12710
12703
  recommendations: resolvedRecommendations
12711
12704
  };
12712
12705
  }
12706
+ /** LLM-based synthesis with graceful fallback to heuristic. */
12707
+ async synthesizeFindingsLlm(results, opts2) {
12708
+ const MAX_RAW_OUTPUT = 2e3;
12709
+ const MAX_REASONING = 2e3;
12710
+ const workerBlocks = results.map((r, i) => {
12711
+ const findings = r.findings.map(
12712
+ (f) => ` - Topic: ${f.topic}
12713
+ Summary: ${f.summary}
12714
+ Confidence: ${f.confidence}
12715
+ Relevance: ${f.relevance}
12716
+ Sources: ${f.sources.join(", ") || "none"}`
12717
+ ).join("\n");
12718
+ const recs = r.recommendations.map((rec) => ` - ${rec}`).join("\n") || " (none)";
12719
+ const reasoning = r.reasoning ? r.reasoning.slice(0, MAX_REASONING) : "(none)";
12720
+ const rawOutput = r.rawOutput ? r.rawOutput.slice(0, MAX_RAW_OUTPUT) : "(none)";
12721
+ return [
12722
+ `--- Worker ${r.workerId || `w${i + 1}`} ---`,
12723
+ `Task: ${r.task}`,
12724
+ `Status: ${r.status}`,
12725
+ `Findings:
12726
+ ${findings || " (none)"}`,
12727
+ `Recommendations:
12728
+ ${recs}`,
12729
+ `Reasoning:
12730
+ ${reasoning}`,
12731
+ `Raw Output (truncated):
12732
+ ${rawOutput}`
12733
+ ].join("\n");
12734
+ });
12735
+ const userContent = [
12736
+ opts2.prompt ? `Original user request:
12737
+ ${opts2.prompt}` : "",
12738
+ "",
12739
+ "Worker outputs:",
12740
+ workerBlocks.join("\n\n"),
12741
+ "",
12742
+ "Instructions:",
12743
+ "1. Synthesize the worker findings into a coherent execution plan.",
12744
+ "2. Detect and resolve any conflicts between workers.",
12745
+ "3. Cite sources inline using [worker: <id>] notation.",
12746
+ "4. Return ONLY valid JSON in this exact shape (no markdown fences):",
12747
+ '{"plan":"markdown plan","conflicts":["string"],"recommendations":["string"],"reasoning":"optional string"}'
12748
+ ].filter(Boolean).join("\n");
12749
+ const messages = [
12750
+ {
12751
+ role: "system",
12752
+ content: "You are a synthesis engine. Combine findings from multiple research workers into a single coherent execution plan. Be concise. Return only valid JSON."
12753
+ },
12754
+ { role: "user", content: userContent }
12755
+ ];
12756
+ let text = "";
12757
+ const events = this._runKimi({
12758
+ accountId: opts2.accountId,
12759
+ apiToken: opts2.apiToken,
12760
+ model: opts2.model,
12761
+ messages,
12762
+ temperature: 0.2,
12763
+ maxCompletionTokens: 4096,
12764
+ reasoningEffort: "low",
12765
+ gateway: opts2.gateway,
12766
+ signal: opts2.signal
12767
+ });
12768
+ for await (const ev of events) {
12769
+ if (ev.type === "text") {
12770
+ text += ev.delta;
12771
+ opts2.onDelta?.(ev.delta);
12772
+ }
12773
+ }
12774
+ const cleaned = text.replace(/```(?:json)?\s*/gi, "").replace(/```\s*$/gi, "").trim();
12775
+ const parsed = JSON.parse(cleaned);
12776
+ if (!parsed.plan || !Array.isArray(parsed.conflicts) || !Array.isArray(parsed.recommendations)) {
12777
+ throw new Error("LLM synthesis returned malformed JSON");
12778
+ }
12779
+ return {
12780
+ plan: parsed.plan,
12781
+ conflicts: parsed.conflicts,
12782
+ recommendations: parsed.recommendations
12783
+ };
12784
+ }
12785
+ /** Synthesize findings from multiple workers into a unified execution plan.
12786
+ *
12787
+ * Uses LLM-based synthesis by default (configurable via synthesisStrategy).
12788
+ * Falls back to the heuristic path when credentials are missing, the strategy
12789
+ * demands it, or the LLM call fails.
12790
+ */
12791
+ async synthesizeFindings(results, opts2) {
12792
+ const strategy = opts2?.strategy ?? "llm";
12793
+ const disableLlm = opts2?.disableLlmSynthesis ?? false;
12794
+ const hasCreds = !!opts2?.accountId && !!opts2?.apiToken;
12795
+ const useHeuristic = !hasCreds || strategy === "heuristic" || disableLlm;
12796
+ if (useHeuristic) {
12797
+ return this.synthesizeFindingsHeuristic(results);
12798
+ }
12799
+ try {
12800
+ const llmResult = await this.synthesizeFindingsLlm(results, {
12801
+ prompt: opts2?.prompt,
12802
+ accountId: opts2.accountId,
12803
+ apiToken: opts2.apiToken,
12804
+ model: opts2?.model ?? "@cf/moonshotai/kimi-k2.5",
12805
+ gateway: opts2?.gateway,
12806
+ signal: opts2?.signal,
12807
+ onDelta: opts2?.onDelta
12808
+ });
12809
+ return llmResult;
12810
+ } catch (err) {
12811
+ const msg = err instanceof Error ? err.message : String(err);
12812
+ logger.warn("supervisor:synthesis_llm_failed", { error: msg });
12813
+ if (strategy === "hybrid") {
12814
+ return this.synthesizeFindingsHeuristic(results);
12815
+ }
12816
+ throw err;
12817
+ }
12818
+ }
12713
12819
  /** Automatically spawn research workers for a heavy prompt.
12714
12820
  *
12715
12821
  * Decomposes the prompt into 2-4 parallel research tasks using a simple
@@ -12735,7 +12841,22 @@ ${w.context ?? ""}` : w.context ?? "",
12735
12841
  try {
12736
12842
  const results = await this.spawnWorkers(workers, onUpdate, signal);
12737
12843
  onPhaseChange?.("synthesizing");
12738
- const synth = this.synthesizeFindings(results);
12844
+ const gateway = cfg?.aiGatewayId ? {
12845
+ id: cfg.aiGatewayId,
12846
+ cacheTtl: cfg.aiGatewayCacheTtl,
12847
+ skipCache: cfg.aiGatewaySkipCache,
12848
+ metadata: { feature: "synthesis", ...cfg.aiGatewayMetadata ?? {} }
12849
+ } : void 0;
12850
+ const synth = await this.synthesizeFindings(results, {
12851
+ prompt,
12852
+ accountId: cfg?.accountId,
12853
+ apiToken: cfg?.apiToken,
12854
+ model: cfg?.synthesisModel,
12855
+ gateway,
12856
+ signal,
12857
+ strategy: cfg?.synthesisStrategy,
12858
+ disableLlmSynthesis: cfg?.disableLlmSynthesis
12859
+ });
12739
12860
  const cfg2 = await loadConfig().catch(() => null);
12740
12861
  const autoExecute = cfg2?.autoExecute ?? /^(1|true|yes|on)$/i.test(process.env.KIMIFLARE_AUTO_EXECUTE ?? "");
12741
12862
  if (!autoExecute || synth.recommendations.length === 0) {
@@ -23620,8 +23741,9 @@ function useModalHost() {
23620
23741
  const [showGatewayPicker, setShowGatewayPicker] = useState15(false);
23621
23742
  const [showSkillsPicker, setShowSkillsPicker] = useState15(false);
23622
23743
  const [showShellPicker, setShowShellPicker] = useState15(false);
23744
+ const [showPlanCompletePicker, setShowPlanCompletePicker] = useState15(false);
23623
23745
  const flags = useMemo4(() => {
23624
- const hasFullscreenModal = commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || showThemePicker || showUiPicker || showModelPicker || showModePicker || keyEntryFor !== null || billingChooserFor !== null || unifiedProbeFor !== null || showRemoteDashboard || showInboxModal || showMultiAgentModal || showHooksDashboard || showHelpMenu || showMemoryPicker || showGatewayPicker || showSkillsPicker || showShellPicker;
23746
+ const hasFullscreenModal = commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || showThemePicker || showUiPicker || showModelPicker || showModePicker || keyEntryFor !== null || billingChooserFor !== null || unifiedProbeFor !== null || showRemoteDashboard || showInboxModal || showMultiAgentModal || showHooksDashboard || showHelpMenu || showMemoryPicker || showGatewayPicker || showSkillsPicker || showShellPicker || showPlanCompletePicker;
23625
23747
  const hasOverlayModal = limitModal !== null || loopModal !== null;
23626
23748
  return {
23627
23749
  hasFullscreenModal,
@@ -23650,6 +23772,7 @@ function useModalHost() {
23650
23772
  showGatewayPicker,
23651
23773
  showSkillsPicker,
23652
23774
  showShellPicker,
23775
+ showPlanCompletePicker,
23653
23776
  limitModal,
23654
23777
  loopModal
23655
23778
  ]);
@@ -23700,6 +23823,8 @@ function useModalHost() {
23700
23823
  setShowSkillsPicker,
23701
23824
  showShellPicker,
23702
23825
  setShowShellPicker,
23826
+ showPlanCompletePicker,
23827
+ setShowPlanCompletePicker,
23703
23828
  ...flags
23704
23829
  };
23705
23830
  }
@@ -27104,10 +27229,42 @@ var init_help_menu = __esm({
27104
27229
  }
27105
27230
  });
27106
27231
 
27107
- // src/ui/modal-host.tsx
27232
+ // src/ui/plan-complete-picker.tsx
27108
27233
  import { Box as Box38, Text as Text39 } from "ink";
27109
27234
  import SelectInput21 from "ink-select-input";
27110
27235
  import { jsx as jsx40, jsxs as jsxs38 } from "react/jsx-runtime";
27236
+ function PlanCompletePicker({ onPick }) {
27237
+ const theme = useTheme();
27238
+ const items = [
27239
+ { label: "\u25B8 Execute this plan and accept changes (auto mode)", value: "auto", key: "auto" },
27240
+ { label: "\u25B8 Start building and ask for permission (edit mode)", value: "edit", key: "edit" },
27241
+ { label: "\u25B8 Continue planning / ask a question", value: "continue", key: "continue" }
27242
+ ];
27243
+ return /* @__PURE__ */ jsxs38(Box38, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
27244
+ /* @__PURE__ */ jsx40(Text39, { color: theme.accent, bold: true, children: "Plan complete \u2014 what next?" }),
27245
+ /* @__PURE__ */ jsx40(Text39, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
27246
+ /* @__PURE__ */ jsx40(Box38, { marginTop: 1, children: /* @__PURE__ */ jsx40(
27247
+ SelectInput21,
27248
+ {
27249
+ items,
27250
+ onSelect: (item) => onPick(item.value),
27251
+ onHighlight: () => {
27252
+ }
27253
+ }
27254
+ ) })
27255
+ ] });
27256
+ }
27257
+ var init_plan_complete_picker = __esm({
27258
+ "src/ui/plan-complete-picker.tsx"() {
27259
+ "use strict";
27260
+ init_theme_context();
27261
+ }
27262
+ });
27263
+
27264
+ // src/ui/modal-host.tsx
27265
+ import { Box as Box39, Text as Text40 } from "ink";
27266
+ import SelectInput22 from "ink-select-input";
27267
+ import { jsx as jsx41, jsxs as jsxs39 } from "react/jsx-runtime";
27111
27268
  function ModalHost(props) {
27112
27269
  const {
27113
27270
  modals,
@@ -27140,7 +27297,7 @@ function ModalHost(props) {
27140
27297
  onInboxOpen
27141
27298
  } = props;
27142
27299
  if (modals.showRemoteDashboard) {
27143
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx40(
27300
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx41(
27144
27301
  RemoteSessionDetail,
27145
27302
  {
27146
27303
  session: selectedRemoteSession,
@@ -27149,7 +27306,7 @@ function ModalHost(props) {
27149
27306
  void onCancelRemoteSession(session);
27150
27307
  }
27151
27308
  }
27152
- ) : /* @__PURE__ */ jsx40(
27309
+ ) : /* @__PURE__ */ jsx41(
27153
27310
  RemoteDashboard,
27154
27311
  {
27155
27312
  onSelect: (session) => onSelectRemoteSession(session),
@@ -27158,7 +27315,7 @@ function ModalHost(props) {
27158
27315
  ) }) });
27159
27316
  }
27160
27317
  if (modals.showInboxModal) {
27161
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27318
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27162
27319
  InboxModal,
27163
27320
  {
27164
27321
  onDone: () => modals.setShowInboxModal(false),
@@ -27167,7 +27324,7 @@ function ModalHost(props) {
27167
27324
  ) }) });
27168
27325
  }
27169
27326
  if (modals.showMultiAgentModal) {
27170
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27327
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27171
27328
  MultiAgentModal,
27172
27329
  {
27173
27330
  initial: props.multiAgentSettings ?? {},
@@ -27180,7 +27337,7 @@ function ModalHost(props) {
27180
27337
  ) }) });
27181
27338
  }
27182
27339
  if (modals.showHooksDashboard) {
27183
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27340
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27184
27341
  HooksDashboard,
27185
27342
  {
27186
27343
  getConfigured: props.getConfiguredHooks,
@@ -27191,7 +27348,7 @@ function ModalHost(props) {
27191
27348
  ) }) });
27192
27349
  }
27193
27350
  if (modals.showHelpMenu) {
27194
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27351
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27195
27352
  HelpMenu,
27196
27353
  {
27197
27354
  customCommands: customCommands.map((c) => ({ name: c.name, description: c.description })),
@@ -27205,10 +27362,10 @@ function ModalHost(props) {
27205
27362
  ) }) });
27206
27363
  }
27207
27364
  if (modals.showShellPicker) {
27208
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(ShellPicker, { current: props.currentShell, onPick: props.onPickShell }) }) });
27365
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(ShellPicker, { current: props.currentShell, onPick: props.onPickShell }) }) });
27209
27366
  }
27210
27367
  if (modals.showMemoryPicker) {
27211
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27368
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27212
27369
  MemoryPicker,
27213
27370
  {
27214
27371
  enabled: props.memoryEnabled,
@@ -27219,7 +27376,7 @@ function ModalHost(props) {
27219
27376
  ) }) });
27220
27377
  }
27221
27378
  if (modals.showGatewayPicker) {
27222
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27379
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27223
27380
  GatewayPicker,
27224
27381
  {
27225
27382
  gatewayId: props.gatewayId,
@@ -27232,10 +27389,10 @@ function ModalHost(props) {
27232
27389
  ) }) });
27233
27390
  }
27234
27391
  if (modals.showSkillsPicker) {
27235
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(SkillsPicker, { onAction: props.onSkillsAction, onDone: props.onSkillsDone }) }) });
27392
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(SkillsPicker, { onAction: props.onSkillsAction, onDone: props.onSkillsDone }) }) });
27236
27393
  }
27237
27394
  if (modals.showLspWizard) {
27238
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27395
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27239
27396
  LspWizard,
27240
27397
  {
27241
27398
  servers: lspServers,
@@ -27247,7 +27404,7 @@ function ModalHost(props) {
27247
27404
  ) }) });
27248
27405
  }
27249
27406
  if (modals.commandWizard) {
27250
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27407
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27251
27408
  CommandWizard,
27252
27409
  {
27253
27410
  mode: modals.commandWizard.mode,
@@ -27261,7 +27418,7 @@ function ModalHost(props) {
27261
27418
  }
27262
27419
  if (modals.commandPicker) {
27263
27420
  const pickerMode = modals.commandPicker.mode;
27264
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27421
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27265
27422
  CommandPicker,
27266
27423
  {
27267
27424
  commands: customCommands,
@@ -27280,15 +27437,15 @@ function ModalHost(props) {
27280
27437
  }
27281
27438
  if (modals.commandToDelete) {
27282
27439
  const cmd = modals.commandToDelete;
27283
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs38(Box38, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
27284
- /* @__PURE__ */ jsxs38(Text39, { color: theme.accent, bold: true, children: [
27440
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs39(Box39, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
27441
+ /* @__PURE__ */ jsxs39(Text40, { color: theme.accent, bold: true, children: [
27285
27442
  "Delete /",
27286
27443
  cmd.name,
27287
27444
  "?"
27288
27445
  ] }),
27289
- /* @__PURE__ */ jsx40(Text39, { color: theme.info.color, children: cmd.filepath }),
27290
- /* @__PURE__ */ jsx40(Box38, { marginTop: 1, children: /* @__PURE__ */ jsx40(
27291
- SelectInput21,
27446
+ /* @__PURE__ */ jsx41(Text40, { color: theme.info.color, children: cmd.filepath }),
27447
+ /* @__PURE__ */ jsx41(Box39, { marginTop: 1, children: /* @__PURE__ */ jsx41(
27448
+ SelectInput22,
27292
27449
  {
27293
27450
  items: [
27294
27451
  { label: "Yes, delete", value: "yes", key: "yes" },
@@ -27306,7 +27463,7 @@ function ModalHost(props) {
27306
27463
  ] }) });
27307
27464
  }
27308
27465
  if (modals.showCommandList) {
27309
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27466
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27310
27467
  CommandList,
27311
27468
  {
27312
27469
  commands: customCommands,
@@ -27315,24 +27472,27 @@ function ModalHost(props) {
27315
27472
  ) }) });
27316
27473
  }
27317
27474
  if (modals.showThemePicker) {
27318
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(ThemePicker, { themes, onPick: onPickTheme }) }) });
27475
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(ThemePicker, { themes, onPick: onPickTheme }) }) });
27319
27476
  }
27320
27477
  if (modals.showUiPicker) {
27321
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(UiPicker, { current: currentUiEngine, onPick: onPickUi }) }) });
27478
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(UiPicker, { current: currentUiEngine, onPick: onPickUi }) }) });
27322
27479
  }
27323
27480
  if (modals.showModelPicker) {
27324
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(ModelPicker, { current: currentModel, onPick: onPickModel }) }) });
27481
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(ModelPicker, { current: currentModel, onPick: onPickModel }) }) });
27325
27482
  }
27326
27483
  if (modals.showModePicker) {
27327
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(ModePicker, { current: props.currentMode, onPick: props.onPickMode, multiAgentEnabled: props.multiAgentEnabled }) }) });
27484
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(ModePicker, { current: props.currentMode, onPick: props.onPickMode, multiAgentEnabled: props.multiAgentEnabled }) }) });
27485
+ }
27486
+ if (modals.showPlanCompletePicker) {
27487
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(PlanCompletePicker, { onPick: props.onPlanCompletePick }) }) });
27328
27488
  }
27329
27489
  if (modals.billingChooserFor) {
27330
27490
  const model = modals.billingChooserFor;
27331
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(BillingChooser, { model, onPick: (choice) => onPickBilling(model, choice) }) }) });
27491
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(BillingChooser, { model, onPick: (choice) => onPickBilling(model, choice) }) }) });
27332
27492
  }
27333
27493
  if (modals.unifiedProbeFor) {
27334
27494
  const model = modals.unifiedProbeFor;
27335
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27495
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27336
27496
  UnifiedBillingStatus,
27337
27497
  {
27338
27498
  model,
@@ -27345,7 +27505,7 @@ function ModalHost(props) {
27345
27505
  }
27346
27506
  if (modals.keyEntryFor) {
27347
27507
  const model = modals.keyEntryFor;
27348
- return /* @__PURE__ */ jsx40(ThemeProvider, { theme, children: /* @__PURE__ */ jsx40(Box38, { flexDirection: "column", children: /* @__PURE__ */ jsx40(
27508
+ return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
27349
27509
  KeyEntryModal,
27350
27510
  {
27351
27511
  model,
@@ -27366,7 +27526,7 @@ function ModalOverlay({
27366
27526
  }) {
27367
27527
  if (modals.limitModal) {
27368
27528
  const m = modals.limitModal;
27369
- return /* @__PURE__ */ jsx40(
27529
+ return /* @__PURE__ */ jsx41(
27370
27530
  LimitModal,
27371
27531
  {
27372
27532
  limit: m.limit,
@@ -27380,7 +27540,7 @@ function ModalOverlay({
27380
27540
  }
27381
27541
  if (modals.loopModal) {
27382
27542
  const m = modals.loopModal;
27383
- return /* @__PURE__ */ jsx40(
27543
+ return /* @__PURE__ */ jsx41(
27384
27544
  LimitModal,
27385
27545
  {
27386
27546
  limit: 50,
@@ -27425,6 +27585,7 @@ var init_modal_host = __esm({
27425
27585
  init_multi_agent_modal();
27426
27586
  init_hooks_dashboard();
27427
27587
  init_help_menu();
27588
+ init_plan_complete_picker();
27428
27589
  }
27429
27590
  });
27430
27591
 
@@ -30397,10 +30558,10 @@ __export(app_exports, {
30397
30558
  renderApp: () => renderApp
30398
30559
  });
30399
30560
  import React23, { useState as useState27, useRef as useRef7, useEffect as useEffect11, useCallback as useCallback10, useMemo as useMemo6 } from "react";
30400
- import { Box as Box39, Text as Text40, useApp, useInput as useInput19, render } from "ink";
30561
+ import { Box as Box40, Text as Text41, useApp, useInput as useInput19, render } from "ink";
30401
30562
  import { existsSync as existsSync8 } from "fs";
30402
30563
  import { join as join37 } from "path";
30403
- import { jsx as jsx41, jsxs as jsxs39 } from "react/jsx-runtime";
30564
+ import { jsx as jsx42, jsxs as jsxs40 } from "react/jsx-runtime";
30404
30565
  function App({
30405
30566
  initialCfg,
30406
30567
  initialUpdateResult,
@@ -30530,6 +30691,8 @@ function App({
30530
30691
  setShowSkillsPicker,
30531
30692
  showShellPicker,
30532
30693
  setShowShellPicker,
30694
+ showPlanCompletePicker,
30695
+ setShowPlanCompletePicker,
30533
30696
  hasFullscreenModal,
30534
30697
  hasAnyModal
30535
30698
  } = modals;
@@ -31287,6 +31450,60 @@ ${wcagWarnings.join("\n")}` }
31287
31450
  },
31288
31451
  [mkKey, setShowUiPicker]
31289
31452
  );
31453
+ const handlePlanCompletePick = useCallback10(
31454
+ (picked) => {
31455
+ setShowPlanCompletePicker(false);
31456
+ if (!picked || picked === "continue") return;
31457
+ const plan = distillSessionPlan(messagesRef.current);
31458
+ if (!plan) {
31459
+ setEvents((e) => [
31460
+ ...e,
31461
+ { kind: "error", key: mkKey(), text: "No plan found to start fresh with." }
31462
+ ]);
31463
+ setMode(picked);
31464
+ return;
31465
+ }
31466
+ const clipResult = writeToClipboard(plan);
31467
+ if (cacheStableRef.current && messagesRef.current.length >= 2) {
31468
+ messagesRef.current = [messagesRef.current[0], messagesRef.current[1]];
31469
+ } else {
31470
+ messagesRef.current = [messagesRef.current[0]];
31471
+ }
31472
+ resetSession();
31473
+ executorRef.current.clearArtifacts();
31474
+ if (flushTimeoutRef.current) {
31475
+ clearTimeout(flushTimeoutRef.current);
31476
+ flushTimeoutRef.current = null;
31477
+ }
31478
+ pendingTextRef.current.clear();
31479
+ activeAsstIdRef.current = null;
31480
+ pendingToolCallsRef.current.clear();
31481
+ usageRef.current = null;
31482
+ turnCounterRef.current = 0;
31483
+ setEvents([]);
31484
+ setUsage(null);
31485
+ setSessionUsage(null);
31486
+ gatewayMetaRef.current = null;
31487
+ setGatewayMeta(null);
31488
+ clearTaskTracking();
31489
+ compactSuggestedRef.current = false;
31490
+ updateNudgedRef.current = false;
31491
+ messagesRef.current.push({ role: "user", content: plan });
31492
+ setEvents((e) => [
31493
+ ...e,
31494
+ {
31495
+ kind: "info",
31496
+ key: mkKey(),
31497
+ text: clipResult.success ? `Plan copied to clipboard. Starting fresh session in ${picked} mode with plan only\u2026` : `Clipboard unavailable. Starting fresh session in ${picked} mode with plan only\u2026`
31498
+ }
31499
+ ]);
31500
+ if (!clipResult.success) {
31501
+ setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "--- Plan ---\n" + plan }]);
31502
+ }
31503
+ setMode(picked);
31504
+ },
31505
+ [mkKey, setShowPlanCompletePicker, setMode, setEvents, setUsage, setSessionUsage, setGatewayMeta, clearTaskTracking, resetSession]
31506
+ );
31290
31507
  const handleModelPick = useCallback10(
31291
31508
  (picked) => {
31292
31509
  setShowModelPicker(false);
@@ -32149,6 +32366,12 @@ ${conflicts.join("\n")}` }
32149
32366
  }
32150
32367
  })();
32151
32368
  cleanupTurn();
32369
+ if (modeRef.current === "plan") {
32370
+ const plan = distillSessionPlan(messagesRef.current);
32371
+ if (plan) {
32372
+ setShowPlanCompletePicker(true);
32373
+ }
32374
+ }
32152
32375
  },
32153
32376
  onError: async (e) => {
32154
32377
  if (e.name === "AbortError") {
@@ -32182,7 +32405,7 @@ ${conflicts.join("\n")}` }
32182
32405
  }
32183
32406
  );
32184
32407
  },
32185
- [cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateGatewayMeta]
32408
+ [cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateGatewayMeta, setShowPlanCompletePicker]
32186
32409
  );
32187
32410
  useEffect11(() => {
32188
32411
  if (!busy && queue2.length > 0 && supervisorRef.current.phase === "idle") {
@@ -32243,7 +32466,7 @@ ${conflicts.join("\n")}` }
32243
32466
  });
32244
32467
  }, [usage, modelContextLimit, busy, runCompact2]);
32245
32468
  if (!cfg) {
32246
- return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(
32469
+ return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(
32247
32470
  Onboarding,
32248
32471
  {
32249
32472
  onCancel: () => exit(),
@@ -32258,7 +32481,7 @@ ${conflicts.join("\n")}` }
32258
32481
  ) });
32259
32482
  }
32260
32483
  if (checkpointSession !== null) {
32261
- return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(
32484
+ return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
32262
32485
  CheckpointPicker,
32263
32486
  {
32264
32487
  session: checkpointSession,
@@ -32268,10 +32491,10 @@ ${conflicts.join("\n")}` }
32268
32491
  ) }) });
32269
32492
  }
32270
32493
  if (resumeSessions !== null) {
32271
- return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", children: /* @__PURE__ */ jsx41(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
32494
+ return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
32272
32495
  }
32273
32496
  if (hasFullscreenModal) {
32274
- return /* @__PURE__ */ jsx41(
32497
+ return /* @__PURE__ */ jsx42(
32275
32498
  ModalHost,
32276
32499
  {
32277
32500
  modals,
@@ -32410,14 +32633,15 @@ ${conflicts.join("\n")}` }
32410
32633
  }
32411
32634
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: `Type /skills ${action} <name> to ${action} a skill.` }]);
32412
32635
  },
32413
- onSkillsDone: () => setShowSkillsPicker(false)
32636
+ onSkillsDone: () => setShowSkillsPicker(false),
32637
+ onPlanCompletePick: handlePlanCompletePick
32414
32638
  }
32415
32639
  );
32416
32640
  }
32417
32641
  const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
32418
- return /* @__PURE__ */ jsx41(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs39(Box39, { flexDirection: "column", children: [
32419
- !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx41(Welcome, {}) : /* @__PURE__ */ jsx41(ChatView, { events, showReasoning, verbose, intentTier: intentTier ?? void 0 }),
32420
- perm ? /* @__PURE__ */ jsx41(
32642
+ return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs40(Box40, { flexDirection: "column", children: [
32643
+ !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx42(Welcome, {}) : /* @__PURE__ */ jsx42(ChatView, { events, showReasoning, verbose, intentTier: intentTier ?? void 0 }),
32644
+ perm ? /* @__PURE__ */ jsx42(
32421
32645
  PermissionModal,
32422
32646
  {
32423
32647
  tool: perm.tool,
@@ -32427,7 +32651,7 @@ ${conflicts.join("\n")}` }
32427
32651
  submitRef.current(text);
32428
32652
  }
32429
32653
  }
32430
- ) : limitModal || loopModal ? /* @__PURE__ */ jsx41(
32654
+ ) : limitModal || loopModal ? /* @__PURE__ */ jsx42(
32431
32655
  ModalOverlay,
32432
32656
  {
32433
32657
  modals,
@@ -32438,9 +32662,9 @@ ${conflicts.join("\n")}` }
32438
32662
  loopResolveRef.current = null;
32439
32663
  }
32440
32664
  }
32441
- ) : /* @__PURE__ */ jsxs39(Box39, { flexDirection: "column", marginTop: 1, children: [
32442
- (activeWorkers.length > 0 || coordinatorNarration) && /* @__PURE__ */ jsx41(WorkerList, { workers: activeWorkers, isSynthesizing, narration: coordinatorNarration }),
32443
- tasks.length > 0 && /* @__PURE__ */ jsx41(
32665
+ ) : /* @__PURE__ */ jsxs40(Box40, { flexDirection: "column", marginTop: 1, children: [
32666
+ (activeWorkers.length > 0 || coordinatorNarration) && /* @__PURE__ */ jsx42(WorkerList, { workers: activeWorkers, isSynthesizing, narration: coordinatorNarration }),
32667
+ tasks.length > 0 && /* @__PURE__ */ jsx42(
32444
32668
  TaskList,
32445
32669
  {
32446
32670
  tasks,
@@ -32448,11 +32672,11 @@ ${conflicts.join("\n")}` }
32448
32672
  tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
32449
32673
  }
32450
32674
  ),
32451
- queue2.length > 0 && /* @__PURE__ */ jsx41(Box39, { flexDirection: "column", marginBottom: 1, children: queue2.map((q, i) => /* @__PURE__ */ jsxs39(Text40, { color: theme.info.color, dimColor: theme.info.dim, children: [
32675
+ queue2.length > 0 && /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", marginBottom: 1, children: queue2.map((q, i) => /* @__PURE__ */ jsxs40(Text41, { color: theme.info.color, dimColor: theme.info.dim, children: [
32452
32676
  "\u23F3 ",
32453
32677
  q.display
32454
32678
  ] }, `queue_${i}`)) }),
32455
- /* @__PURE__ */ jsx41(
32679
+ /* @__PURE__ */ jsx42(
32456
32680
  StatusBar,
32457
32681
  {
32458
32682
  usage,
@@ -32474,7 +32698,7 @@ ${conflicts.join("\n")}` }
32474
32698
  intentTier: intentTier ?? void 0
32475
32699
  }
32476
32700
  ),
32477
- picker.active?.kind === "file" && /* @__PURE__ */ jsx41(
32701
+ picker.active?.kind === "file" && /* @__PURE__ */ jsx42(
32478
32702
  FilePicker,
32479
32703
  {
32480
32704
  items: picker.fileItems,
@@ -32483,7 +32707,7 @@ ${conflicts.join("\n")}` }
32483
32707
  recentFiles: new Set(recentFilesRef.current.keys())
32484
32708
  }
32485
32709
  ),
32486
- picker.active?.kind === "slash" && /* @__PURE__ */ jsx41(
32710
+ picker.active?.kind === "slash" && /* @__PURE__ */ jsx42(
32487
32711
  SlashPicker,
32488
32712
  {
32489
32713
  items: picker.slashItems,
@@ -32491,9 +32715,9 @@ ${conflicts.join("\n")}` }
32491
32715
  query: picker.query
32492
32716
  }
32493
32717
  ),
32494
- /* @__PURE__ */ jsxs39(Box39, { marginTop: 1, children: [
32495
- /* @__PURE__ */ jsx41(Text40, { color: theme.prompt ?? theme.accent, children: "\u203A " }),
32496
- /* @__PURE__ */ jsx41(
32718
+ /* @__PURE__ */ jsxs40(Box40, { marginTop: 1, children: [
32719
+ /* @__PURE__ */ jsx42(Text41, { color: theme.prompt ?? theme.accent, children: "\u203A " }),
32720
+ /* @__PURE__ */ jsx42(
32497
32721
  CustomTextInput,
32498
32722
  {
32499
32723
  value: input,
@@ -32550,7 +32774,7 @@ ${conflicts.join("\n")}` }
32550
32774
  }
32551
32775
  async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null) {
32552
32776
  const instance = render(
32553
- /* @__PURE__ */ jsx41(
32777
+ /* @__PURE__ */ jsx42(
32554
32778
  App,
32555
32779
  {
32556
32780
  initialCfg: cfg,
@@ -32631,6 +32855,8 @@ var init_app = __esm({
32631
32855
  init_run_startup_tasks();
32632
32856
  init_manager_init();
32633
32857
  init_run_compact();
32858
+ init_distill();
32859
+ init_clipboard();
32634
32860
  init_command_handlers();
32635
32861
  init_app_helpers();
32636
32862
  }