flavor-code 1.4.0-beta.1 → 1.4.0-beta.11

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 (169) hide show
  1. package/README.md +2 -0
  2. package/README.zh-CN.md +2 -0
  3. package/dist/agent/loop.d.ts +7 -2
  4. package/dist/{app-C5ZQUOKJ.js → app-PXXQOEWP.js} +312 -40
  5. package/dist/{chunk-ODRWR4KK.js → chunk-26T23AKR.js} +180 -14253
  6. package/dist/{chunk-6MNOZ2TX.js → chunk-BYHO2CA5.js} +1925 -765
  7. package/dist/{chunk-URUVFECH.js → chunk-EXOSMO57.js} +12 -7
  8. package/dist/chunk-N5MXHJKD.js +107 -0
  9. package/dist/{chunk-2BF7CVWZ.js → chunk-RAYH6K2H.js} +2 -2
  10. package/dist/{chunk-FOTMP4ZS.js → chunk-UO4DLWU5.js} +8 -2
  11. package/dist/{chunk-3WCDZ6ZL.js → chunk-ZJCAQXA7.js} +2 -1
  12. package/dist/{claude-ink-LP32NSX5.js → claude-ink-C24UQAL7.js} +2 -2
  13. package/dist/cli-main.js +56 -25
  14. package/dist/cli.js +54 -10
  15. package/dist/config/schema.d.ts +8 -0
  16. package/dist/context/manager.d.ts +9 -0
  17. package/dist/desktop/main.js +2318 -1071
  18. package/dist/desktop-renderer/assets/index-RNe5Gtum.js +154 -0
  19. package/dist/desktop-renderer/assets/{interactive-terminal-C4o7MNPO.js → interactive-terminal-DestMQ2z.js} +1 -1
  20. package/dist/desktop-renderer/index.html +1 -1
  21. package/dist/git/service.d.ts +3 -3
  22. package/dist/git/tools.d.ts +1 -1
  23. package/dist/goal/classifier.d.ts +2 -0
  24. package/dist/goal/orchestrator.d.ts +23 -2
  25. package/dist/goal/planner.d.ts +2 -0
  26. package/dist/goal/store.d.ts +2 -0
  27. package/dist/goal/types.d.ts +14 -0
  28. package/dist/harness/journal.d.ts +2 -0
  29. package/dist/harness/local.d.ts +2 -0
  30. package/dist/init/project.d.ts +0 -6
  31. package/dist/jobs/registry.d.ts +7 -1
  32. package/dist/{load-V2UIYYQI.js → load-EW56Q2MM.js} +1 -1
  33. package/dist/loop/orchestrator.d.ts +20 -0
  34. package/dist/loop/types.d.ts +7 -0
  35. package/dist/loop/verifier.d.ts +2 -0
  36. package/dist/models/openai.d.ts +1 -1
  37. package/dist/models/structured.d.ts +7 -0
  38. package/dist/models/types.d.ts +1 -1
  39. package/dist/production.d.ts +17 -0
  40. package/dist/sdk/index.js +5 -5
  41. package/dist/session/tree.d.ts +2 -0
  42. package/dist/tools/lsp.d.ts +15 -10
  43. package/dist/tools/runtime.d.ts +2 -1
  44. package/dist/tools/search.d.ts +1 -0
  45. package/dist/tools/types.d.ts +1 -1
  46. package/dist/ui/session.d.ts +11 -0
  47. package/dist/ui/transcript.d.ts +9 -0
  48. package/dist/utils/abort.d.ts +20 -0
  49. package/dist/utils/execFileNoThrow.d.ts +1 -0
  50. package/dist/utils/heap.d.ts +58 -0
  51. package/dist/utils/memory-restart.d.ts +42 -3
  52. package/dist/utils/process-tree.d.ts +2 -0
  53. package/dist/utils/rotation-census.d.ts +36 -0
  54. package/package.json +3 -2
  55. package//346/212/200/346/234/257/346/226/271/346/241/210/346/212/245/345/221/212.md +7 -7
  56. package/dist/astgraph/db.mjs +0 -237
  57. package/dist/astgraph/extract.mjs +0 -239
  58. package/dist/astgraph/flavor-plugin.json +0 -25
  59. package/dist/astgraph/grammars.mjs +0 -68
  60. package/dist/astgraph/index.js +0 -301
  61. package/dist/astgraph/indexer.mjs +0 -175
  62. package/dist/astgraph/query.mjs +0 -165
  63. package/dist/astgraph/resolve.mjs +0 -93
  64. package/dist/astgraph/vendor/tree-sitter-javascript.wasm +0 -0
  65. package/dist/astgraph/vendor/tree-sitter-tsx.wasm +0 -0
  66. package/dist/astgraph/vendor/tree-sitter-typescript.wasm +0 -0
  67. package/dist/astgraph/vendor/tree-sitter.js +0 -3980
  68. package/dist/astgraph/vendor/tree-sitter.wasm +0 -0
  69. package/dist/astgraph/vendor/zod/LICENSE +0 -21
  70. package/dist/astgraph/vendor/zod/index.js +0 -4
  71. package/dist/astgraph/vendor/zod/locales/index.js +0 -1
  72. package/dist/astgraph/vendor/zod/locales/package.json +0 -7
  73. package/dist/astgraph/vendor/zod/package.json +0 -135
  74. package/dist/astgraph/vendor/zod/v4/classic/checks.js +0 -1
  75. package/dist/astgraph/vendor/zod/v4/classic/coerce.js +0 -17
  76. package/dist/astgraph/vendor/zod/v4/classic/compat.js +0 -31
  77. package/dist/astgraph/vendor/zod/v4/classic/errors.js +0 -48
  78. package/dist/astgraph/vendor/zod/v4/classic/external.js +0 -20
  79. package/dist/astgraph/vendor/zod/v4/classic/from-json-schema.js +0 -599
  80. package/dist/astgraph/vendor/zod/v4/classic/index.js +0 -4
  81. package/dist/astgraph/vendor/zod/v4/classic/iso.js +0 -30
  82. package/dist/astgraph/vendor/zod/v4/classic/package.json +0 -7
  83. package/dist/astgraph/vendor/zod/v4/classic/parse.js +0 -15
  84. package/dist/astgraph/vendor/zod/v4/classic/schemas.js +0 -1395
  85. package/dist/astgraph/vendor/zod/v4/core/api.js +0 -1087
  86. package/dist/astgraph/vendor/zod/v4/core/checks.js +0 -575
  87. package/dist/astgraph/vendor/zod/v4/core/core.js +0 -78
  88. package/dist/astgraph/vendor/zod/v4/core/doc.js +0 -35
  89. package/dist/astgraph/vendor/zod/v4/core/errors.js +0 -185
  90. package/dist/astgraph/vendor/zod/v4/core/index.js +0 -16
  91. package/dist/astgraph/vendor/zod/v4/core/json-schema-generator.js +0 -95
  92. package/dist/astgraph/vendor/zod/v4/core/json-schema-processors.js +0 -601
  93. package/dist/astgraph/vendor/zod/v4/core/json-schema.js +0 -1
  94. package/dist/astgraph/vendor/zod/v4/core/package.json +0 -7
  95. package/dist/astgraph/vendor/zod/v4/core/parse.js +0 -93
  96. package/dist/astgraph/vendor/zod/v4/core/regexes.js +0 -139
  97. package/dist/astgraph/vendor/zod/v4/core/registries.js +0 -51
  98. package/dist/astgraph/vendor/zod/v4/core/schemas.js +0 -2239
  99. package/dist/astgraph/vendor/zod/v4/core/standard-schema.js +0 -1
  100. package/dist/astgraph/vendor/zod/v4/core/to-json-schema.js +0 -448
  101. package/dist/astgraph/vendor/zod/v4/core/util.js +0 -674
  102. package/dist/astgraph/vendor/zod/v4/core/versions.js +0 -5
  103. package/dist/astgraph/vendor/zod/v4/index.js +0 -3
  104. package/dist/astgraph/vendor/zod/v4/locales/ar.js +0 -106
  105. package/dist/astgraph/vendor/zod/v4/locales/az.js +0 -105
  106. package/dist/astgraph/vendor/zod/v4/locales/be.js +0 -156
  107. package/dist/astgraph/vendor/zod/v4/locales/bg.js +0 -120
  108. package/dist/astgraph/vendor/zod/v4/locales/ca.js +0 -107
  109. package/dist/astgraph/vendor/zod/v4/locales/cs.js +0 -111
  110. package/dist/astgraph/vendor/zod/v4/locales/da.js +0 -115
  111. package/dist/astgraph/vendor/zod/v4/locales/de.js +0 -108
  112. package/dist/astgraph/vendor/zod/v4/locales/el.js +0 -109
  113. package/dist/astgraph/vendor/zod/v4/locales/en.js +0 -113
  114. package/dist/astgraph/vendor/zod/v4/locales/eo.js +0 -109
  115. package/dist/astgraph/vendor/zod/v4/locales/es.js +0 -132
  116. package/dist/astgraph/vendor/zod/v4/locales/fa.js +0 -114
  117. package/dist/astgraph/vendor/zod/v4/locales/fi.js +0 -112
  118. package/dist/astgraph/vendor/zod/v4/locales/fr-CA.js +0 -107
  119. package/dist/astgraph/vendor/zod/v4/locales/fr.js +0 -125
  120. package/dist/astgraph/vendor/zod/v4/locales/he.js +0 -214
  121. package/dist/astgraph/vendor/zod/v4/locales/hr.js +0 -122
  122. package/dist/astgraph/vendor/zod/v4/locales/hu.js +0 -108
  123. package/dist/astgraph/vendor/zod/v4/locales/hy.js +0 -147
  124. package/dist/astgraph/vendor/zod/v4/locales/id.js +0 -106
  125. package/dist/astgraph/vendor/zod/v4/locales/index.js +0 -52
  126. package/dist/astgraph/vendor/zod/v4/locales/is.js +0 -109
  127. package/dist/astgraph/vendor/zod/v4/locales/it.js +0 -108
  128. package/dist/astgraph/vendor/zod/v4/locales/ja.js +0 -107
  129. package/dist/astgraph/vendor/zod/v4/locales/ka.js +0 -112
  130. package/dist/astgraph/vendor/zod/v4/locales/kh.js +0 -5
  131. package/dist/astgraph/vendor/zod/v4/locales/km.js +0 -110
  132. package/dist/astgraph/vendor/zod/v4/locales/ko.js +0 -111
  133. package/dist/astgraph/vendor/zod/v4/locales/lt.js +0 -203
  134. package/dist/astgraph/vendor/zod/v4/locales/mk.js +0 -109
  135. package/dist/astgraph/vendor/zod/v4/locales/ms.js +0 -107
  136. package/dist/astgraph/vendor/zod/v4/locales/nl.js +0 -110
  137. package/dist/astgraph/vendor/zod/v4/locales/no.js +0 -108
  138. package/dist/astgraph/vendor/zod/v4/locales/ota.js +0 -109
  139. package/dist/astgraph/vendor/zod/v4/locales/package.json +0 -7
  140. package/dist/astgraph/vendor/zod/v4/locales/pl.js +0 -109
  141. package/dist/astgraph/vendor/zod/v4/locales/ps.js +0 -114
  142. package/dist/astgraph/vendor/zod/v4/locales/pt.js +0 -108
  143. package/dist/astgraph/vendor/zod/v4/locales/ro.js +0 -119
  144. package/dist/astgraph/vendor/zod/v4/locales/ru.js +0 -156
  145. package/dist/astgraph/vendor/zod/v4/locales/sl.js +0 -109
  146. package/dist/astgraph/vendor/zod/v4/locales/sv.js +0 -110
  147. package/dist/astgraph/vendor/zod/v4/locales/ta.js +0 -110
  148. package/dist/astgraph/vendor/zod/v4/locales/th.js +0 -110
  149. package/dist/astgraph/vendor/zod/v4/locales/tr.js +0 -105
  150. package/dist/astgraph/vendor/zod/v4/locales/ua.js +0 -5
  151. package/dist/astgraph/vendor/zod/v4/locales/uk.js +0 -108
  152. package/dist/astgraph/vendor/zod/v4/locales/ur.js +0 -110
  153. package/dist/astgraph/vendor/zod/v4/locales/uz.js +0 -110
  154. package/dist/astgraph/vendor/zod/v4/locales/vi.js +0 -108
  155. package/dist/astgraph/vendor/zod/v4/locales/yo.js +0 -107
  156. package/dist/astgraph/vendor/zod/v4/locales/zh-CN.js +0 -109
  157. package/dist/astgraph/vendor/zod/v4/locales/zh-TW.js +0 -107
  158. package/dist/astgraph/vendor/zod/v4/mini/checks.js +0 -1
  159. package/dist/astgraph/vendor/zod/v4/mini/coerce.js +0 -22
  160. package/dist/astgraph/vendor/zod/v4/mini/external.js +0 -14
  161. package/dist/astgraph/vendor/zod/v4/mini/index.js +0 -3
  162. package/dist/astgraph/vendor/zod/v4/mini/iso.js +0 -34
  163. package/dist/astgraph/vendor/zod/v4/mini/package.json +0 -7
  164. package/dist/astgraph/vendor/zod/v4/mini/parse.js +0 -1
  165. package/dist/astgraph/vendor/zod/v4/mini/schemas.js +0 -961
  166. package/dist/astgraph/vendor/zod/v4/package.json +0 -7
  167. package/dist/chunk-CIVPKHF4.js +0 -53
  168. package/dist/desktop-renderer/assets/index-CqRIr-hz.js +0 -154
  169. package/dist/devtools-4QTPKBKK.js +0 -2
package/README.md CHANGED
@@ -178,6 +178,8 @@ Common commands:
178
178
 
179
179
  You can submit steering or queue follow-ups while a run is in progress; once the current model response finishes, the task picks up new instructions at safe boundaries.
180
180
 
181
+ During planned work, a wide CLI shows the main task plan and sub-agent exploration side by side; if only one track exists it uses the full row, and narrow terminals stack both tracks. Long streamed responses keep a live `Writing response` activity below the latest output. LSP tools locate the nearest nested project configuration for each target file, so monorepos and sandbox/worktree projects do not need a `tsconfig.json` or `jsconfig.json` at the Flavor workspace root; JavaScript and CommonJS files are supported by the bundled TypeScript server as well.
182
+
181
183
  `/commit` and `/review` use the cheap sub-agent model and degrade gracefully when it is unavailable. Session checkpoints are tagged with the current git state (`branch@sha`), so `/tree` shows what the workspace looked like at each node. `/explain <symbol>` runs on the same cheap model: it assembles call relations from the code graph, the symbol's real source slice, and recent commits touching the file, then generates a five-part newcomer walkthrough (what it does / key implementation points / call flow / why it is written this way / gotchas); an interactive picker disambiguates multiple matches, and a missing graph degrades to a `/ast init` hint instead of an error.
182
184
 
183
185
  #### CLI pals and cross-project work
package/README.zh-CN.md CHANGED
@@ -178,6 +178,8 @@ OAuth PKCE 的运行时行为与配置约定见 [PKCE 规范](./docs/specs/pkce-
178
178
 
179
179
  运行中可以提交 steering 或排队 follow-up;当前模型响应结束后,任务会在安全边界处接收新指令。
180
180
 
181
+ 有任务规划时,宽终端会把主任务计划与子 Agent 探索左右并排展示;只有一类工作时占满整行,窄终端则自动纵向排列。长内容流式输出期间,最新内容下方会持续显示 `Writing response` 动作。LSP 工具会从目标文件向上寻找最近的嵌套项目配置,因此 monorepo、sandbox 或 worktree 项目无需在 Flavor 工作区根部额外放置 `tsconfig.json` / `jsconfig.json`;内置 TypeScript 服务也支持 JavaScript 与 CommonJS 文件。
182
+
181
183
  `/commit` 与 `/review` 使用廉价子 Agent 模型,模型不可用时优雅降级。会话 checkpoint 会标记当前 git 状态(`branch@sha`),`/tree` 可以看到每个节点对应的工作区现场。`/explain <符号>` 同样走廉价模型:它把代码图中的调用关系、符号的真实源码切片和该文件的近期提交历史组装成证据,生成面向新人的五段式讲解(做什么 / 关键实现点 / 调用关系 / 为什么这样写 / 注意事项);多个符号命中时弹出选择卡片,可方向键选择或直接输入更精确的名字;代码图未建立时提示 `/ast init`,不会抛错。
182
184
 
183
185
  #### CLI Pals 与跨项目协作
@@ -2,6 +2,7 @@ import type { ContextManager } from "../context/manager.js";
2
2
  import type { HallucinationGuard } from "../hallucination/guard.js";
3
3
  import type { HookBus } from "../hooks/bus.js";
4
4
  import type { ModelRegistry } from "../models/registry.js";
5
+ import { MEMORY_PRESSURE_HEAP_RATIO } from "../utils/heap.js";
5
6
  import { type ModelMessage, type ModelTool } from "../models/types.js";
6
7
  import type { ToolRuntime } from "../tools/runtime.js";
7
8
  import type { AgentError, AgentEvent, AgentRunRequest } from "./types.js";
@@ -10,9 +11,10 @@ import type { AgentError, AgentEvent, AgentRunRequest } from "./types.js";
10
11
  * leak otherwise ends in a native OOM crash with no recovery; tripping this
11
12
  * watermark saves the session and lets the launcher relaunch on a fresh heap.
12
13
  * 0.8 keeps headroom for compaction payloads and the GC death spiral that
13
- * starts near ~0.95.
14
+ * starts near ~0.95. The reading is GC-verified: uncollected garbage alone
15
+ * must not stop a turn.
14
16
  */
15
- export declare const MEMORY_PRESSURE_HEAP_RATIO = 0.8;
17
+ export { MEMORY_PRESSURE_HEAP_RATIO };
16
18
  export declare function memoryPressureError(heapUsed: number, heapLimit: number): AgentError | undefined;
17
19
  export interface AgentLoopOptions {
18
20
  registry: ModelRegistry;
@@ -46,6 +48,9 @@ export declare class AgentLoop {
46
48
  constructor(options: AgentLoopOptions);
47
49
  get modelId(): string;
48
50
  get iterationLimitMode(): "standard" | "d2c";
51
+ get maxIterations(): number;
52
+ get softLimitFactor(): number;
53
+ get extendIterations(): number;
49
54
  setModel(modelId: string): void;
50
55
  setFallbackModel(modelId: string): void;
51
56
  /** D2C keeps a hard cap, but may automatically expand it up to ten times. */
@@ -2,7 +2,7 @@
2
2
  import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
3
3
  import {
4
4
  statusPresentation
5
- } from "./chunk-2BF7CVWZ.js";
5
+ } from "./chunk-RAYH6K2H.js";
6
6
  import {
7
7
  COMMAND_DESCRIPTIONS,
8
8
  MVP_COMMANDS,
@@ -19,9 +19,9 @@ import {
19
19
  thinkingWindow,
20
20
  transcriptReducer,
21
21
  withTimeout
22
- } from "./chunk-6MNOZ2TX.js";
23
- import "./chunk-CIVPKHF4.js";
24
- import "./chunk-URUVFECH.js";
22
+ } from "./chunk-BYHO2CA5.js";
23
+ import "./chunk-N5MXHJKD.js";
24
+ import "./chunk-EXOSMO57.js";
25
25
  import {
26
26
  Box_default,
27
27
  ClockContext,
@@ -34,14 +34,16 @@ import {
34
34
  instances_default,
35
35
  osc,
36
36
  shiftAnchor,
37
+ stringWidth,
37
38
  stripAnsi,
38
39
  useStdout,
39
40
  use_app_default,
40
41
  use_input_default
41
- } from "./chunk-ODRWR4KK.js";
42
+ } from "./chunk-26T23AKR.js";
42
43
  import {
43
- execFileNoThrow
44
- } from "./chunk-3WCDZ6ZL.js";
44
+ execFileNoThrow,
45
+ getGraphemeSegmenter
46
+ } from "./chunk-ZJCAQXA7.js";
45
47
  import "./chunk-S32JRDZK.js";
46
48
 
47
49
  // src/ui/app.tsx
@@ -969,7 +971,12 @@ function wrapPromptInput(input, codePointCursor, options) {
969
971
  // src/ui/task-progress.tsx
970
972
  import { useRef as useRef3 } from "react";
971
973
  import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
972
- function TaskStatusLine({ block, interactive }) {
974
+ function TaskStatusLine({
975
+ block,
976
+ interactive,
977
+ textWidth,
978
+ maxTextLines
979
+ }) {
973
980
  const running = block.state === "running";
974
981
  const { stdout } = useStdout();
975
982
  const foreground = interactive && (block.activity === "model" || block.task?.role === "main");
@@ -1007,8 +1014,20 @@ function TaskStatusLine({ block, interactive }) {
1007
1014
  thinkingScroll.current = { start: state.start, lastTime: time };
1008
1015
  return state.text;
1009
1016
  })() : void 0;
1010
- return /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "column", children: [
1011
- /* @__PURE__ */ jsxs2(Box_default, { ref, flexDirection: "row", children: [
1017
+ const textSegments = [
1018
+ { text: `${presentation.glyph} `, color: presentation.color },
1019
+ ...presentation.badge ? [{ text: `${presentation.badge} `, color: presentation.badgeColor }] : [],
1020
+ { text: before, color: presentation.color },
1021
+ ...statusLabel === void 0 ? [] : [
1022
+ { text: " \xB7 ", color: presentation.color },
1023
+ { text: statusLabel, color: statusColor ?? presentation.color }
1024
+ ],
1025
+ ...after ? [{ text: after, color: presentation.color }] : [],
1026
+ ...metaLabel === void 0 ? [] : [{ text: ` ${metaLabel}`, color: metaColor ?? "ansi:blackBright" }]
1027
+ ];
1028
+ const boundedText = textWidth === void 0 || maxTextLines === void 0 ? void 0 : limitTaskTextSegments(textSegments, textWidth, maxTextLines).segments;
1029
+ return /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "column", width: "100%", children: [
1030
+ /* @__PURE__ */ jsx3(Box_default, { ref, flexDirection: "row", width: "100%", children: boundedText === void 0 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1012
1031
  /* @__PURE__ */ jsxs2(Text, { ...presentation.color === void 0 ? {} : { color: presentation.color }, children: [
1013
1032
  presentation.glyph,
1014
1033
  " "
@@ -1027,10 +1046,69 @@ function TaskStatusLine({ block, interactive }) {
1027
1046
  " ",
1028
1047
  metaLabel
1029
1048
  ] })
1030
- ] }),
1049
+ ] }) : /* @__PURE__ */ jsx3(Text, { children: boundedText.map((segment, index) => /* @__PURE__ */ jsx3(Text, { ...segment.color === void 0 ? {} : { color: segment.color }, children: segment.text }, index)) }) }),
1031
1050
  thinkingLine === void 0 ? null : /* @__PURE__ */ jsx3(ThinkingLineView, { text: thinkingLine })
1032
1051
  ] });
1033
1052
  }
1053
+ function limitTaskTextSegments(segments, width, maxLines = 3) {
1054
+ const lineWidth = Math.max(3, Math.floor(width));
1055
+ const lineLimit = Math.max(1, Math.floor(maxLines));
1056
+ const lines = [[]];
1057
+ const widths = [0];
1058
+ let truncated = false;
1059
+ outer: for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex += 1) {
1060
+ const segment = segments[segmentIndex];
1061
+ for (const { segment: grapheme } of getGraphemeSegmenter().segment(segment.text)) {
1062
+ if (grapheme === "\n" || grapheme === "\r" || grapheme === "\r\n") {
1063
+ if (lines.length >= lineLimit) {
1064
+ truncated = true;
1065
+ break outer;
1066
+ }
1067
+ lines.push([]);
1068
+ widths.push(0);
1069
+ continue;
1070
+ }
1071
+ const glyphWidth = stringWidth(grapheme);
1072
+ const lineIndex = lines.length - 1;
1073
+ if (glyphWidth > 0 && widths[lineIndex] + glyphWidth > lineWidth && lines[lineIndex].length > 0) {
1074
+ if (lines.length >= lineLimit) {
1075
+ truncated = true;
1076
+ break outer;
1077
+ }
1078
+ lines.push([]);
1079
+ widths.push(0);
1080
+ }
1081
+ const target = lines.length - 1;
1082
+ lines[target].push({ value: grapheme, width: glyphWidth, segmentIndex });
1083
+ widths[target] = widths[target] + glyphWidth;
1084
+ }
1085
+ }
1086
+ if (truncated) {
1087
+ const lastIndex = lines.length - 1;
1088
+ const last = lines[lastIndex];
1089
+ while (last.length > 0 && widths[lastIndex] > lineWidth - 3) {
1090
+ widths[lastIndex] = widths[lastIndex] - last.pop().width;
1091
+ }
1092
+ while (last.length > 0 && /^\s$/u.test(last.at(-1).value)) {
1093
+ widths[lastIndex] = widths[lastIndex] - last.pop().width;
1094
+ }
1095
+ last.push({ value: "...", width: 3, segmentIndex: last.at(-1)?.segmentIndex ?? 0 });
1096
+ }
1097
+ const output = [];
1098
+ const append = (value, segmentIndex) => {
1099
+ const previous = output.at(-1);
1100
+ if (previous?.segmentIndex === segmentIndex) previous.text += value;
1101
+ else output.push({ text: value, color: segments[segmentIndex]?.color, segmentIndex });
1102
+ };
1103
+ lines.forEach((line, lineIndex) => {
1104
+ if (lineIndex > 0) append("\n", line[0]?.segmentIndex ?? output.at(-1)?.segmentIndex ?? 0);
1105
+ for (const token of line) append(token.value, token.segmentIndex);
1106
+ });
1107
+ return {
1108
+ truncated,
1109
+ segments: output.map(({ text, color }) => ({ text, ...color === void 0 ? {} : { color } }))
1110
+ };
1111
+ }
1034
1112
  var THINKING_RAIL = "#416f84";
1035
1113
  var THINKING_TEXT = "#91a0a8";
1036
1114
  function ThinkingLineView({ text }) {
@@ -1039,38 +1117,220 @@ function ThinkingLineView({ text }) {
1039
1117
  /* @__PURE__ */ jsx3(Text, { color: THINKING_TEXT, wrap: "truncate-end", children: text })
1040
1118
  ] });
1041
1119
  }
1120
+ var SPLIT_TRACK_MIN_COLUMNS = 72;
1042
1121
  function TaskProgressPanel({
1043
1122
  blocks,
1044
1123
  interactive,
1045
1124
  maxHeight = 8,
1046
- scrollRef,
1125
+ columns = 80,
1126
+ mainScrollRef,
1127
+ subagentScrollRef,
1047
1128
  onHoverChange
1048
1129
  }) {
1049
1130
  if (blocks.length === 0 || maxHeight <= 0) return null;
1050
- return /* @__PURE__ */ jsxs2(
1131
+ const taskBlocks = blocks.filter((block) => block.task?.role === "main");
1132
+ const subagentBlocks = blocks.filter((block) => block.task?.role === "subagent");
1133
+ const hasTasks = taskBlocks.length > 0;
1134
+ const hasSubagents = subagentBlocks.length > 0;
1135
+ const split = hasTasks && hasSubagents && columns >= SPLIT_TRACK_MIN_COLUMNS;
1136
+ const hoverProps = (track) => ({
1137
+ onMouseEnter: () => onHoverChange?.(track)
1138
+ });
1139
+ return /* @__PURE__ */ jsx3(
1051
1140
  Box_default,
1052
1141
  {
1053
1142
  flexDirection: "column",
1054
1143
  flexShrink: 0,
1144
+ width: "100%",
1055
1145
  maxHeight,
1056
- onMouseEnter: () => onHoverChange?.(true),
1057
- onMouseLeave: () => onHoverChange?.(false),
1058
- children: [
1059
- /* @__PURE__ */ jsx3(Text, { dimColor: true, children: "\u2500\u2500 task progress \u2500\u2500" }),
1060
- maxHeight > 1 ? /* @__PURE__ */ jsx3(
1061
- ScrollBox_default,
1062
- {
1063
- ...scrollRef === void 0 ? {} : { ref: scrollRef },
1064
- flexDirection: "column",
1065
- flexShrink: 1,
1066
- maxHeight: maxHeight - 1,
1067
- children: blocks.map((block) => /* @__PURE__ */ jsx3(TaskStatusLine, { block, interactive }, block.id))
1068
- }
1069
- ) : null
1070
- ]
1146
+ onMouseLeave: () => onHoverChange?.(null),
1147
+ children: split ? /* @__PURE__ */ jsx3(
1148
+ SplitTracks,
1149
+ {
1150
+ taskBlocks,
1151
+ subagentBlocks,
1152
+ interactive,
1153
+ height: maxHeight,
1154
+ columns,
1155
+ mainScrollRef,
1156
+ subagentScrollRef,
1157
+ hoverProps
1158
+ }
1159
+ ) : hasTasks && hasSubagents ? /* @__PURE__ */ jsx3(
1160
+ StackedTracks,
1161
+ {
1162
+ taskBlocks,
1163
+ subagentBlocks,
1164
+ interactive,
1165
+ height: maxHeight,
1166
+ columns,
1167
+ mainScrollRef,
1168
+ subagentScrollRef,
1169
+ hoverProps
1170
+ }
1171
+ ) : /* @__PURE__ */ jsx3(
1172
+ SingleTrack,
1173
+ {
1174
+ role: hasTasks ? "main" : "subagent",
1175
+ blocks: hasTasks ? taskBlocks : subagentBlocks,
1176
+ interactive,
1177
+ height: maxHeight,
1178
+ width: columns,
1179
+ scrollRef: hasTasks ? mainScrollRef : subagentScrollRef,
1180
+ hoverProps
1181
+ }
1182
+ )
1071
1183
  }
1072
1184
  );
1073
1185
  }
1186
+ function SplitTracks({
1187
+ taskBlocks,
1188
+ subagentBlocks,
1189
+ interactive,
1190
+ height,
1191
+ columns,
1192
+ mainScrollRef,
1193
+ subagentScrollRef,
1194
+ hoverProps
1195
+ }) {
1196
+ const contentHeight = Math.max(0, height - 1);
1197
+ const leftWidth = Math.max(1, Math.floor((columns - 1) / 2));
1198
+ const rightWidth = Math.max(1, columns - leftWidth - 1);
1199
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
1200
+ /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "row", width: "100%", children: [
1201
+ /* @__PURE__ */ jsx3(Box_default, { width: leftWidth, ...hoverProps("main"), children: /* @__PURE__ */ jsx3(TrackHeader, { role: "main", width: leftWidth }) }),
1202
+ /* @__PURE__ */ jsx3(Text, { color: "ansi:white", children: "\u252C" }),
1203
+ /* @__PURE__ */ jsx3(Box_default, { width: rightWidth, ...hoverProps("subagent"), children: /* @__PURE__ */ jsx3(TrackHeader, { role: "subagent", width: rightWidth }) })
1204
+ ] }),
1205
+ contentHeight <= 0 ? null : /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "row", width: "100%", height: contentHeight, children: [
1206
+ /* @__PURE__ */ jsx3(Box_default, { width: leftWidth, minWidth: 0, flexDirection: "column", ...hoverProps("main"), children: /* @__PURE__ */ jsx3(
1207
+ TrackScrollBox,
1208
+ {
1209
+ ref: mainScrollRef,
1210
+ blocks: taskBlocks,
1211
+ interactive,
1212
+ height: contentHeight,
1213
+ width: leftWidth
1214
+ }
1215
+ ) }),
1216
+ /* @__PURE__ */ jsx3(TrackDivider, { height: contentHeight }),
1217
+ /* @__PURE__ */ jsx3(Box_default, { width: rightWidth, minWidth: 0, flexDirection: "column", ...hoverProps("subagent"), children: /* @__PURE__ */ jsx3(
1218
+ TrackScrollBox,
1219
+ {
1220
+ ref: subagentScrollRef,
1221
+ blocks: subagentBlocks,
1222
+ interactive,
1223
+ height: contentHeight,
1224
+ width: rightWidth
1225
+ }
1226
+ ) })
1227
+ ] })
1228
+ ] });
1229
+ }
1230
+ function StackedTracks({
1231
+ taskBlocks,
1232
+ subagentBlocks,
1233
+ interactive,
1234
+ height,
1235
+ columns,
1236
+ mainScrollRef,
1237
+ subagentScrollRef,
1238
+ hoverProps
1239
+ }) {
1240
+ if (height <= 1) {
1241
+ return /* @__PURE__ */ jsx3(Box_default, { ...hoverProps("main"), children: /* @__PURE__ */ jsx3(TrackHeader, { role: "main", width: columns }) });
1242
+ }
1243
+ const mainHeight = Math.ceil(height / 2);
1244
+ const subagentHeight = Math.floor(height / 2);
1245
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
1246
+ /* @__PURE__ */ jsx3(
1247
+ SingleTrack,
1248
+ {
1249
+ role: "main",
1250
+ blocks: taskBlocks,
1251
+ interactive,
1252
+ height: mainHeight,
1253
+ width: columns,
1254
+ scrollRef: mainScrollRef,
1255
+ hoverProps
1256
+ }
1257
+ ),
1258
+ /* @__PURE__ */ jsx3(
1259
+ SingleTrack,
1260
+ {
1261
+ role: "subagent",
1262
+ blocks: subagentBlocks,
1263
+ interactive,
1264
+ height: subagentHeight,
1265
+ width: columns,
1266
+ scrollRef: subagentScrollRef,
1267
+ hoverProps
1268
+ }
1269
+ )
1270
+ ] });
1271
+ }
1272
+ function SingleTrack({
1273
+ role,
1274
+ blocks,
1275
+ interactive,
1276
+ height,
1277
+ width,
1278
+ scrollRef,
1279
+ hoverProps
1280
+ }) {
1281
+ const contentHeight = Math.max(0, height - 1);
1282
+ return /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "column", width: "100%", height, ...hoverProps(role), children: [
1283
+ /* @__PURE__ */ jsx3(TrackHeader, { role, width }),
1284
+ contentHeight <= 0 ? null : /* @__PURE__ */ jsx3(
1285
+ TrackScrollBox,
1286
+ {
1287
+ ref: scrollRef,
1288
+ blocks,
1289
+ interactive,
1290
+ height: contentHeight,
1291
+ width
1292
+ }
1293
+ )
1294
+ ] });
1295
+ }
1296
+ function TrackScrollBox({
1297
+ ref,
1298
+ blocks,
1299
+ interactive,
1300
+ height,
1301
+ width
1302
+ }) {
1303
+ return /* @__PURE__ */ jsx3(
1304
+ ScrollBox_default,
1305
+ {
1306
+ ...ref === void 0 ? {} : { ref },
1307
+ flexDirection: "column",
1308
+ flexShrink: 1,
1309
+ width: "100%",
1310
+ height,
1311
+ maxHeight: height,
1312
+ children: blocks.map((block) => /* @__PURE__ */ jsx3(
1313
+ TaskStatusLine,
1314
+ {
1315
+ block,
1316
+ interactive,
1317
+ textWidth: width,
1318
+ maxTextLines: 3
1319
+ },
1320
+ block.id
1321
+ ))
1322
+ }
1323
+ );
1324
+ }
1325
+ function TrackHeader({ role, width }) {
1326
+ const label = role === "main" ? "task plan" : "subagent exploration";
1327
+ const prefix = `\u2500\u2500 ${label} `;
1328
+ const line = prefix.length >= width ? prefix.slice(0, Math.max(0, width)) : `${prefix}${"\u2500".repeat(width - prefix.length)}`;
1329
+ return /* @__PURE__ */ jsx3(Text, { color: "ansi:white", wrap: "truncate-end", children: line });
1330
+ }
1331
+ function TrackDivider({ height }) {
1332
+ return /* @__PURE__ */ jsx3(Box_default, { flexDirection: "column", width: 1, flexShrink: 0, children: Array.from({ length: height }, (_, index) => /* @__PURE__ */ jsx3(Text, { color: "ansi:white", children: "\u2502" }, index)) });
1333
+ }
1074
1334
 
1075
1335
  // src/ui/file-diff-style.ts
1076
1336
  var CONTENT = "#f8f8f2";
@@ -1307,7 +1567,7 @@ function WelcomeCard({
1307
1567
  columns
1308
1568
  }) {
1309
1569
  const wide = Math.max(1, Math.floor(columns)) >= WIDE_WELCOME_COLUMNS;
1310
- const updateHint = updateTo === void 0 ? null : /* @__PURE__ */ jsxs3(Text, { color: "yellowBright", wrap: "truncate-end", children: [
1570
+ const updateHint = updateTo === void 0 ? null : /* @__PURE__ */ jsxs3(Text, { color: "yellowBright", wrap: "wrap", children: [
1311
1571
  "\u25B2 ",
1312
1572
  "Update available: v",
1313
1573
  packageVersion(),
@@ -1315,7 +1575,7 @@ function WelcomeCard({
1315
1575
  "\u2192",
1316
1576
  " v",
1317
1577
  updateTo,
1318
- " \xB7 run: flavor update"
1578
+ "\nRun: flavor update"
1319
1579
  ] });
1320
1580
  return /* @__PURE__ */ jsx4(Box_default, { width: "100%", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: wide ? /* @__PURE__ */ jsxs3(Box_default, { width: "100%", flexDirection: "row", children: [
1321
1581
  /* @__PURE__ */ jsxs3(
@@ -1767,8 +2027,9 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
1767
2027
  const [updateTo, setUpdateTo] = useState2();
1768
2028
  const [transcript, dispatch] = useReducer(transcriptReducer, void 0, createTranscriptState);
1769
2029
  const scrollRef = useRef4(null);
1770
- const taskScrollRef = useRef4(null);
1771
- const taskPanelHovered = useRef4(false);
2030
+ const mainTaskScrollRef = useRef4(null);
2031
+ const subagentTaskScrollRef = useRef4(null);
2032
+ const hoveredTaskTrack = useRef4(null);
1772
2033
  const runtimeRef = useRef4(void 0);
1773
2034
  const pendingPromptRef = useRef4(void 0);
1774
2035
  pendingPromptRef.current ??= new SinglePendingPrompt();
@@ -2065,7 +2326,12 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2065
2326
  use_input_default((character, key, event) => {
2066
2327
  const terminalAction = classifyTerminalInput(key);
2067
2328
  if (terminalAction?.type === "scroll") {
2068
- const scroll = selectWheelScrollTarget(scrollRef.current, taskScrollRef.current, taskPanelHovered.current);
2329
+ const scroll = selectWheelScrollTarget(
2330
+ scrollRef.current,
2331
+ mainTaskScrollRef.current,
2332
+ subagentTaskScrollRef.current,
2333
+ hoveredTaskTrack.current
2334
+ );
2069
2335
  if (scroll !== null) {
2070
2336
  if (terminalAction.rows < 0) scrollUp(scroll, -terminalAction.rows);
2071
2337
  else scrollDown(scroll, terminalAction.rows);
@@ -2356,9 +2622,10 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2356
2622
  ...ideContext === void 0 ? {} : { ideContext },
2357
2623
  completedSlashTokenLength: completedTokenLength,
2358
2624
  scrollRef,
2359
- taskScrollRef,
2360
- onTaskPanelHoverChange: (hovered) => {
2361
- taskPanelHovered.current = hovered;
2625
+ mainTaskScrollRef,
2626
+ subagentTaskScrollRef,
2627
+ onTaskPanelHoverChange: (track) => {
2628
+ hoveredTaskTrack.current = track;
2362
2629
  },
2363
2630
  ...slashCompletion === null ? {} : { completion: slashCompletion },
2364
2631
  ...mentionCompletion === null ? {} : { mentionCompletion, onMentionSelect: selectMention },
@@ -2492,7 +2759,8 @@ function TerminalLayout({
2492
2759
  onMentionSelect,
2493
2760
  completedSlashTokenLength: tokenLength = 0,
2494
2761
  scrollRef,
2495
- taskScrollRef,
2762
+ mainTaskScrollRef,
2763
+ subagentTaskScrollRef,
2496
2764
  onTaskPanelHoverChange,
2497
2765
  onPromptCursorChange,
2498
2766
  ideContext
@@ -2550,7 +2818,9 @@ function TerminalLayout({
2550
2818
  blocks: activeTaskBlocks,
2551
2819
  interactive: activeSession,
2552
2820
  maxHeight: taskPanelRows,
2553
- ...taskScrollRef === void 0 ? {} : { scrollRef: taskScrollRef },
2821
+ columns,
2822
+ ...mainTaskScrollRef === void 0 ? {} : { mainScrollRef: mainTaskScrollRef },
2823
+ ...subagentTaskScrollRef === void 0 ? {} : { subagentScrollRef: subagentTaskScrollRef },
2554
2824
  ...onTaskPanelHoverChange === void 0 ? {} : { onHoverChange: onTaskPanelHoverChange }
2555
2825
  }
2556
2826
  ),
@@ -2771,8 +3041,10 @@ function jumpScroll(scroll, delta) {
2771
3041
  scroll.scrollTo(Math.max(0, target));
2772
3042
  }
2773
3043
  }
2774
- function selectWheelScrollTarget(transcript, tasks, taskPanelHovered) {
2775
- return taskPanelHovered && tasks !== null ? tasks : transcript;
3044
+ function selectWheelScrollTarget(transcript, mainTasks, subagentTasks, hoveredTrack) {
3045
+ if (hoveredTrack === "main" && mainTasks !== null) return mainTasks;
3046
+ if (hoveredTrack === "subagent" && subagentTasks !== null) return subagentTasks;
3047
+ return transcript;
2776
3048
  }
2777
3049
  function taskPanelViewportRows(rows, reservedBottomRows, hasTasks) {
2778
3050
  if (!hasTasks) return 0;