flavor-code 1.4.0-beta.6 → 1.4.0-beta.8

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/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,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-NLYZ7DMC.js";
22
+ } from "./chunk-LLC7WBXP.js";
23
23
  import "./chunk-N5MXHJKD.js";
24
- import "./chunk-KQMKY7C5.js";
24
+ import "./chunk-EXOSMO57.js";
25
25
  import {
26
26
  Box_default,
27
27
  ClockContext,
@@ -1007,7 +1007,7 @@ function TaskStatusLine({ block, interactive }) {
1007
1007
  thinkingScroll.current = { start: state.start, lastTime: time };
1008
1008
  return state.text;
1009
1009
  })() : void 0;
1010
- return /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "column", children: [
1010
+ return /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "column", width: "100%", children: [
1011
1011
  /* @__PURE__ */ jsxs2(Box_default, { ref, flexDirection: "row", children: [
1012
1012
  /* @__PURE__ */ jsxs2(Text, { ...presentation.color === void 0 ? {} : { color: presentation.color }, children: [
1013
1013
  presentation.glyph,
@@ -1039,38 +1039,70 @@ function ThinkingLineView({ text }) {
1039
1039
  /* @__PURE__ */ jsx3(Text, { color: THINKING_TEXT, wrap: "truncate-end", children: text })
1040
1040
  ] });
1041
1041
  }
1042
+ var SPLIT_TRACK_MIN_COLUMNS = 72;
1042
1043
  function TaskProgressPanel({
1043
1044
  blocks,
1044
1045
  interactive,
1045
1046
  maxHeight = 8,
1047
+ columns = 80,
1046
1048
  scrollRef,
1047
1049
  onHoverChange
1048
1050
  }) {
1049
1051
  if (blocks.length === 0 || maxHeight <= 0) return null;
1052
+ const taskBlocks = blocks.filter((block) => block.task?.role === "main");
1053
+ const subagentBlocks = blocks.filter((block) => block.task?.role === "subagent");
1054
+ const hasTasks = taskBlocks.length > 0;
1055
+ const hasSubagents = subagentBlocks.length > 0;
1056
+ const split = hasTasks && hasSubagents && columns >= SPLIT_TRACK_MIN_COLUMNS;
1050
1057
  return /* @__PURE__ */ jsxs2(
1051
1058
  Box_default,
1052
1059
  {
1053
1060
  flexDirection: "column",
1054
1061
  flexShrink: 0,
1062
+ width: "100%",
1055
1063
  maxHeight,
1056
1064
  onMouseEnter: () => onHoverChange?.(true),
1057
1065
  onMouseLeave: () => onHoverChange?.(false),
1058
1066
  children: [
1059
- /* @__PURE__ */ jsx3(Text, { dimColor: true, children: "\u2500\u2500 task progress \u2500\u2500" }),
1067
+ split ? /* @__PURE__ */ jsx3(SplitTrackHeaders, {}) : /* @__PURE__ */ jsx3(TrackHeader, { role: hasTasks ? "main" : "subagent" }),
1060
1068
  maxHeight > 1 ? /* @__PURE__ */ jsx3(
1061
1069
  ScrollBox_default,
1062
1070
  {
1063
1071
  ...scrollRef === void 0 ? {} : { ref: scrollRef },
1064
1072
  flexDirection: "column",
1065
1073
  flexShrink: 1,
1074
+ width: "100%",
1066
1075
  maxHeight: maxHeight - 1,
1067
- children: blocks.map((block) => /* @__PURE__ */ jsx3(TaskStatusLine, { block, interactive }, block.id))
1076
+ children: split ? pairedTrackRows(taskBlocks, subagentBlocks).map(([task, subagent], index) => /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "row", width: "100%", columnGap: 2, children: [
1077
+ /* @__PURE__ */ jsx3(Box_default, { flexBasis: 0, flexGrow: 1, minWidth: 0, flexDirection: "column", children: task === void 0 ? null : /* @__PURE__ */ jsx3(TaskStatusLine, { block: task, interactive }) }),
1078
+ /* @__PURE__ */ jsx3(Box_default, { flexBasis: 0, flexGrow: 1, minWidth: 0, flexDirection: "column", children: subagent === void 0 ? null : /* @__PURE__ */ jsx3(TaskStatusLine, { block: subagent, interactive }) })
1079
+ ] }, `${task?.id ?? "task"}:${subagent?.id ?? "subagent"}:${index}`)) : hasTasks && hasSubagents ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1080
+ taskBlocks.map((block) => /* @__PURE__ */ jsx3(TaskStatusLine, { block, interactive }, block.id)),
1081
+ /* @__PURE__ */ jsx3(TrackHeader, { role: "subagent" }),
1082
+ subagentBlocks.map((block) => /* @__PURE__ */ jsx3(TaskStatusLine, { block, interactive }, block.id))
1083
+ ] }) : (hasTasks ? taskBlocks : subagentBlocks).map((block) => /* @__PURE__ */ jsx3(TaskStatusLine, { block, interactive }, block.id))
1068
1084
  }
1069
1085
  ) : null
1070
1086
  ]
1071
1087
  }
1072
1088
  );
1073
1089
  }
1090
+ function TrackHeader({ role }) {
1091
+ return /* @__PURE__ */ jsxs2(Text, { dimColor: true, children: [
1092
+ "\u2500\u2500 ",
1093
+ role === "main" ? "task plan" : "subagent exploration",
1094
+ " \u2500\u2500"
1095
+ ] });
1096
+ }
1097
+ function SplitTrackHeaders() {
1098
+ return /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "row", width: "100%", columnGap: 2, children: [
1099
+ /* @__PURE__ */ jsx3(Box_default, { flexBasis: 0, flexGrow: 1, minWidth: 0, children: /* @__PURE__ */ jsx3(TrackHeader, { role: "main" }) }),
1100
+ /* @__PURE__ */ jsx3(Box_default, { flexBasis: 0, flexGrow: 1, minWidth: 0, children: /* @__PURE__ */ jsx3(TrackHeader, { role: "subagent" }) })
1101
+ ] });
1102
+ }
1103
+ function pairedTrackRows(tasks, subagents) {
1104
+ return Array.from({ length: Math.max(tasks.length, subagents.length) }, (_, index) => [tasks[index], subagents[index]]);
1105
+ }
1074
1106
 
1075
1107
  // src/ui/file-diff-style.ts
1076
1108
  var CONTENT = "#f8f8f2";
@@ -2550,6 +2582,7 @@ function TerminalLayout({
2550
2582
  blocks: activeTaskBlocks,
2551
2583
  interactive: activeSession,
2552
2584
  maxHeight: taskPanelRows,
2585
+ columns,
2553
2586
  ...taskScrollRef === void 0 ? {} : { scrollRef: taskScrollRef },
2554
2587
  ...onTaskPanelHoverChange === void 0 ? {} : { onHoverChange: onTaskPanelHoverChange }
2555
2588
  }
@@ -4,7 +4,7 @@ import {
4
4
  message,
5
5
  redactErrorText,
6
6
  redactSecrets
7
- } from "./chunk-NLYZ7DMC.js";
7
+ } from "./chunk-LLC7WBXP.js";
8
8
 
9
9
  // src/rpc/server.ts
10
10
  import { createInterface } from "readline";
@@ -37,9 +37,10 @@ var ProviderConfigSchema = z.object({
37
37
  // Defaults to DEFAULT_THINKING_BUDGET; set to 0 to disable the request
38
38
  // parameter. Provider thinking deltas are forwarded whenever they arrive.
39
39
  thinkingBudget: z.number().int().min(0).optional(),
40
- // Reasoning effort requested from the OpenAI Responses protocol. Omitted by
41
- // default so strict compatible gateways never see an unknown parameter.
42
- thinkingEffort: z.enum(["low", "medium", "high"]).optional(),
40
+ // Reasoning effort requested from the OpenAI Responses protocol (sent as
41
+ // reasoning.effort). Omitted by default so strict compatible gateways never
42
+ // see an unknown parameter and the endpoint uses its server-side default.
43
+ thinkingEffort: z.enum(["minimal", "low", "medium", "high", "xhigh"]).optional(),
43
44
  // Send the Claude Code client fingerprint (User-Agent/x-app) with Anthropic requests,
44
45
  // for gateways that restrict the Anthropic protocol to Claude clients.
45
46
  claudeClient: z.boolean().optional(),
@@ -23,7 +23,7 @@ import {
23
23
  redactConfig,
24
24
  setProjectMcpServerDisabled,
25
25
  updateProtectedFile
26
- } from "./chunk-KQMKY7C5.js";
26
+ } from "./chunk-EXOSMO57.js";
27
27
  import {
28
28
  AuditLogger,
29
29
  appendUsageLog,
@@ -1399,7 +1399,7 @@ function transcriptReducer(state, action) {
1399
1399
  return finishActive(withUsage);
1400
1400
  }
1401
1401
  if (event.type === "text") {
1402
- return { ...state, active: addText(withoutModelActivity(state.active), event.text) };
1402
+ return { ...state, active: addStreamingText(state.active, event.text) };
1403
1403
  }
1404
1404
  if (event.type === "thinking") {
1405
1405
  return { ...state, active: attachThinking(state.active, event.text) };
@@ -1857,6 +1857,17 @@ function addText(turn, text, onNewLine = false) {
1857
1857
  }
1858
1858
  return withBlocks({ ...turn, assistantText }, blocks);
1859
1859
  }
1860
+ function addStreamingText(turn, text) {
1861
+ const activity = turn.blocks.find((block) => block.kind === "status" && block.activity === "model" && block.state === "running");
1862
+ if (activity === void 0) return addText(turn, text);
1863
+ const withoutActivity = withBlocks(turn, turn.blocks.filter((block) => block !== activity));
1864
+ const withText = addText(withoutActivity, text);
1865
+ const { thinkingText: _thinkingText, ...writingActivity } = activity;
1866
+ return withBlocks(withText, [...withText.blocks, {
1867
+ ...writingActivity,
1868
+ text: "Writing response"
1869
+ }]);
1870
+ }
1860
1871
  function boundedTranscriptBlock(block) {
1861
1872
  const presentation = block.presentation === void 0 ? void 0 : boundedTranscriptPresentation(block.presentation);
1862
1873
  const tool = block.tool === void 0 ? void 0 : {
@@ -8780,6 +8791,8 @@ function modelToolFromZod(name, description, schema) {
8780
8791
  }
8781
8792
  function ensureStrictSchema(schema) {
8782
8793
  const output = { ...schema };
8794
+ delete output.propertyNames;
8795
+ delete output.patternProperties;
8783
8796
  for (const keyword of ["anyOf", "oneOf", "allOf", "prefixItems"]) {
8784
8797
  const branches = schema[keyword];
8785
8798
  if (Array.isArray(branches)) {
@@ -18827,10 +18840,12 @@ var LspConnection = class {
18827
18840
  this.#disposed = true;
18828
18841
  this.#rejectAll(new Error("LSP connection disposed"));
18829
18842
  this.#shutdownPromise = (async () => {
18843
+ const closed = waitForProcessClose(this.#process);
18830
18844
  await terminateProcessTree(this.#process.pid);
18831
18845
  this.#process.stdin.destroy();
18832
18846
  this.#process.stdout.destroy();
18833
18847
  this.#process.stderr.destroy();
18848
+ await closed;
18834
18849
  })();
18835
18850
  return this.#shutdownPromise;
18836
18851
  }
@@ -18949,6 +18964,18 @@ var LspConnection = class {
18949
18964
  this.#pending.clear();
18950
18965
  }
18951
18966
  };
18967
+ function waitForProcessClose(child) {
18968
+ if (child.exitCode !== null || child.signalCode !== null) return Promise.resolve();
18969
+ return new Promise((resolveClose) => {
18970
+ const finish = () => {
18971
+ clearTimeout(timer);
18972
+ resolveClose();
18973
+ };
18974
+ const timer = setTimeout(finish, 2e3);
18975
+ timer.unref();
18976
+ child.once("close", finish);
18977
+ });
18978
+ }
18952
18979
  var LspBuffer = class {
18953
18980
  #data = Buffer.alloc(0);
18954
18981
  feed(chunk, onMessage) {
@@ -18979,7 +19006,7 @@ var TYPESCRIPT_CLI = resolve23(
18979
19006
  var KNOWN_SERVERS = [
18980
19007
  {
18981
19008
  language: "typescript",
18982
- extensions: [".ts", ".tsx", ".mts", ".cts"],
19009
+ extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"],
18983
19010
  command: process.execPath,
18984
19011
  args: [TYPESCRIPT_CLI, "--lsp", "--stdio"],
18985
19012
  rootFiles: ["tsconfig.json", "jsconfig.json"]
@@ -19064,35 +19091,39 @@ var RealLspManager = class {
19064
19091
  if (this.#disposed) throw new Error("LSP manager is disposed");
19065
19092
  const language = this.#languageForUri(uri);
19066
19093
  if (language === void 0) throw new Error(`No language server configured for ${uri}; use Read/Grep or the project compiler`);
19067
- const existing = this.#connections.get(language);
19068
- if (existing !== void 0) return existing;
19069
- const pending = this.#pendingStarts.get(language);
19070
- if (pending !== void 0) return pending;
19071
19094
  const config = this.#serverConfigs.find((c) => c.language === language);
19072
19095
  if (config === void 0) throw new Error(`No language server configured for ${language}`);
19073
- const hasRoot = config.rootFiles.some((file) => existsSync5(resolve23(this.#workspace, file)));
19074
- if (!hasRoot) throw new Error(`Cannot start ${language} language server: workspace needs ${config.rootFiles.join(" or ")}`);
19075
- const startPromise = this.#startServer(config);
19076
- this.#pendingStarts.set(language, startPromise);
19096
+ const filePath = uriToPath(uri);
19097
+ const projectRoot = findLanguageServerRoot(filePath, this.#workspace, config.rootFiles);
19098
+ if (projectRoot === void 0) {
19099
+ throw new Error(`Cannot start ${language} language server: no ${config.rootFiles.join(" or ")} found from ${dirname15(filePath)} up to workspace ${this.#workspace}`);
19100
+ }
19101
+ const connectionKey = `${language}:${projectRoot}`;
19102
+ const existing = this.#connections.get(connectionKey);
19103
+ if (existing !== void 0) return existing;
19104
+ const pending = this.#pendingStarts.get(connectionKey);
19105
+ if (pending !== void 0) return pending;
19106
+ const startPromise = this.#startServer(config, projectRoot);
19107
+ this.#pendingStarts.set(connectionKey, startPromise);
19077
19108
  try {
19078
19109
  const connection = await startPromise;
19079
19110
  if (this.#disposed) {
19080
19111
  await connection.shutdown();
19081
19112
  throw new Error("LSP manager is disposed");
19082
19113
  }
19083
- this.#connections.set(language, connection);
19114
+ this.#connections.set(connectionKey, connection);
19084
19115
  return connection;
19085
19116
  } finally {
19086
- this.#pendingStarts.delete(language);
19117
+ this.#pendingStarts.delete(connectionKey);
19087
19118
  }
19088
19119
  }
19089
- async #startServer(config) {
19120
+ async #startServer(config, projectRoot) {
19090
19121
  try {
19091
19122
  await access2(config.command, constants10.X_OK);
19092
19123
  } catch {
19093
19124
  }
19094
- const connection = new LspConnection(config.command, config.args, this.#workspace);
19095
- const rootUri = pathToFileURL2(this.#workspace).href;
19125
+ const connection = new LspConnection(config.command, config.args, projectRoot);
19126
+ const rootUri = pathToFileURL2(projectRoot).href;
19096
19127
  try {
19097
19128
  await connection.initialize(rootUri);
19098
19129
  this.#onStatus?.(`${config.language} Language Server ready (${config.command})`);
@@ -19128,7 +19159,21 @@ function createLspTools(workspace, options = {}) {
19128
19159
  const toUri = (filePath) => pathToFileURL2(filePath).href;
19129
19160
  const langTag = (file) => {
19130
19161
  const ext = file.slice(file.lastIndexOf(".")).toLowerCase();
19131
- const map = { ".ts": "ts", ".tsx": "tsx", ".mts": "ts", ".cts": "ts", ".py": "py", ".pyi": "py", ".pyx": "py", ".rs": "rs", ".go": "go" };
19162
+ const map = {
19163
+ ".ts": "ts",
19164
+ ".tsx": "tsx",
19165
+ ".mts": "ts",
19166
+ ".cts": "ts",
19167
+ ".js": "js",
19168
+ ".jsx": "jsx",
19169
+ ".mjs": "js",
19170
+ ".cjs": "js",
19171
+ ".py": "py",
19172
+ ".pyi": "py",
19173
+ ".pyx": "py",
19174
+ ".rs": "rs",
19175
+ ".go": "go"
19176
+ };
19132
19177
  const tag = map[ext];
19133
19178
  return tag === void 0 ? "" : " [" + tag + "]";
19134
19179
  };
@@ -19196,6 +19241,12 @@ function languageIdForPath(filePath) {
19196
19241
  return "typescript";
19197
19242
  case ".cts":
19198
19243
  return "typescript";
19244
+ case ".jsx":
19245
+ return "javascriptreact";
19246
+ case ".js":
19247
+ case ".mjs":
19248
+ case ".cjs":
19249
+ return "javascript";
19199
19250
  case ".py":
19200
19251
  case ".pyi":
19201
19252
  case ".pyx":
@@ -19208,6 +19259,19 @@ function languageIdForPath(filePath) {
19208
19259
  return "typescript";
19209
19260
  }
19210
19261
  }
19262
+ function findLanguageServerRoot(filePath, workspace, rootFiles) {
19263
+ const root = resolve23(workspace);
19264
+ const target = resolve23(filePath);
19265
+ if (!isWithin7(root, target)) return void 0;
19266
+ let current = dirname15(target);
19267
+ while (true) {
19268
+ if (rootFiles.some((file) => existsSync5(resolve23(current, file)))) return current;
19269
+ if (current === root) return void 0;
19270
+ const parent = dirname15(current);
19271
+ if (parent === current || !isWithin7(root, parent)) return void 0;
19272
+ current = parent;
19273
+ }
19274
+ }
19211
19275
  function isWithin7(root, candidate) {
19212
19276
  const delta = relative17(root, candidate);
19213
19277
  return delta === "" || !delta.startsWith(`..${sep17}`) && delta !== ".." && !isAbsolute12(delta);
@@ -25426,7 +25490,12 @@ async function registerConfiguredAdapters(providers, registry, environment, diag
25426
25490
  if (result.llmConfig !== void 0) {
25427
25491
  apiProtocol = result.llmConfig.apiType;
25428
25492
  runtimeName = result.llmConfig.providerId;
25429
- runtimeProvider = providerFromOAuthConfig(result.llmConfig);
25493
+ runtimeProvider = {
25494
+ ...providerFromOAuthConfig(result.llmConfig),
25495
+ ...provider.thinkingEffort === void 0 ? {} : { thinkingEffort: provider.thinkingEffort },
25496
+ ...provider.thinkingBudget === void 0 ? {} : { thinkingBudget: provider.thinkingBudget },
25497
+ ...provider.claudeClient === void 0 ? {} : { claudeClient: provider.claudeClient }
25498
+ };
25430
25499
  effectiveLlm ??= effectiveRuntime(result, credentialId);
25431
25500
  }
25432
25501
  }
@@ -28,13 +28,13 @@ function statusPresentation(block, elapsedMs, interactive) {
28
28
  if (block.state === "running" && block.activity === "model") {
29
29
  return interactive ? {
30
30
  glyph: activityFrame(elapsedMs),
31
- text: "Flavoring",
31
+ text: block.text,
32
32
  color: "#81c8f2",
33
33
  metaLabel: formatElapsed(elapsedMs),
34
34
  metaColor: "ansi:blackBright"
35
35
  } : {
36
36
  glyph: "\xB7",
37
- text: "Flavoring",
37
+ text: block.text,
38
38
  color: "#81c8f2"
39
39
  };
40
40
  }
package/dist/cli-main.js CHANGED
@@ -3,10 +3,10 @@ import { createRequire } from "node:module"; const require = createRequire(impor
3
3
  import {
4
4
  FlavorRpcServer,
5
5
  TraceRecorder
6
- } from "./chunk-6MXAOTIZ.js";
6
+ } from "./chunk-EUKT7HEU.js";
7
7
  import {
8
8
  staticTaskLines
9
- } from "./chunk-2BF7CVWZ.js";
9
+ } from "./chunk-RAYH6K2H.js";
10
10
  import {
11
11
  DEFAULT_MAX_OUTPUT_BYTES,
12
12
  MAX_ALIAS_LENGTH,
@@ -29,7 +29,7 @@ import {
29
29
  redactErrorText,
30
30
  runDoctor,
31
31
  runPalBroker
32
- } from "./chunk-NLYZ7DMC.js";
32
+ } from "./chunk-LLC7WBXP.js";
33
33
  import {
34
34
  MEMORY_RESTART_EXIT_CODE
35
35
  } from "./chunk-N5MXHJKD.js";
@@ -41,7 +41,7 @@ import {
41
41
  readRecoverableFile,
42
42
  setProjectSkillDisabled,
43
43
  updateProtectedFile
44
- } from "./chunk-KQMKY7C5.js";
44
+ } from "./chunk-EXOSMO57.js";
45
45
  import {
46
46
  gt,
47
47
  isValidVersion
@@ -749,7 +749,7 @@ async function runEvaluationFile(path, outputPath) {
749
749
  })),
750
750
  ...parsed.maxTokens === void 0 ? {} : { maxTokens: parsed.maxTokens }
751
751
  };
752
- const configured = await import("./load-F4AYLCF6.js").then(({ loadConfig: loadConfig2 }) => loadConfig2({ cwd: workspace, home: process.env.USERPROFILE ?? process.env.HOME ?? workspace }));
752
+ const configured = await import("./load-EW56Q2MM.js").then(({ loadConfig: loadConfig2 }) => loadConfig2({ cwd: workspace, home: process.env.USERPROFILE ?? process.env.HOME ?? workspace }));
753
753
  const environment = createExecutionEnvironment(workspace, configured.config.execution) ?? new LocalExecutionEnvironment();
754
754
  let report;
755
755
  try {
@@ -921,7 +921,7 @@ async function runInteractiveCli(props) {
921
921
  const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
922
922
  import("./claude-ink-6EZHF64C.js"),
923
923
  import("react"),
924
- import("./app-6JRSYZYV.js")
924
+ import("./app-KSUBHHLR.js")
925
925
  ]);
926
926
  const instance = await render(createElement(
927
927
  AlternateScreen,
@@ -24,6 +24,8 @@ export declare const ProviderConfigSchema: z.ZodObject<{
24
24
  high: "high";
25
25
  low: "low";
26
26
  medium: "medium";
27
+ minimal: "minimal";
28
+ xhigh: "xhigh";
27
29
  }>>;
28
30
  claudeClient: z.ZodOptional<z.ZodBoolean>;
29
31
  apiType: z.ZodOptional<z.ZodEnum<{
@@ -79,6 +81,8 @@ export declare const FlavorConfigSchema: z.ZodObject<{
79
81
  high: "high";
80
82
  low: "low";
81
83
  medium: "medium";
84
+ minimal: "minimal";
85
+ xhigh: "xhigh";
82
86
  }>>;
83
87
  claudeClient: z.ZodOptional<z.ZodBoolean>;
84
88
  apiType: z.ZodOptional<z.ZodEnum<{
@@ -213,9 +213,10 @@ var ProviderConfigSchema = z2.object({
213
213
  // Defaults to DEFAULT_THINKING_BUDGET; set to 0 to disable the request
214
214
  // parameter. Provider thinking deltas are forwarded whenever they arrive.
215
215
  thinkingBudget: z2.number().int().min(0).optional(),
216
- // Reasoning effort requested from the OpenAI Responses protocol. Omitted by
217
- // default so strict compatible gateways never see an unknown parameter.
218
- thinkingEffort: z2.enum(["low", "medium", "high"]).optional(),
216
+ // Reasoning effort requested from the OpenAI Responses protocol (sent as
217
+ // reasoning.effort). Omitted by default so strict compatible gateways never
218
+ // see an unknown parameter and the endpoint uses its server-side default.
219
+ thinkingEffort: z2.enum(["minimal", "low", "medium", "high", "xhigh"]).optional(),
219
220
  // Send the Claude Code client fingerprint (User-Agent/x-app) with Anthropic requests,
220
221
  // for gateways that restrict the Anthropic protocol to Claude clients.
221
222
  claudeClient: z2.boolean().optional(),
@@ -6543,6 +6544,8 @@ function modelToolFromZod(name, description, schema) {
6543
6544
  }
6544
6545
  function ensureStrictSchema(schema) {
6545
6546
  const output = { ...schema };
6547
+ delete output.propertyNames;
6548
+ delete output.patternProperties;
6546
6549
  for (const keyword of ["anyOf", "oneOf", "allOf", "prefixItems"]) {
6547
6550
  const branches = schema[keyword];
6548
6551
  if (Array.isArray(branches)) {
@@ -16371,7 +16374,7 @@ function transcriptReducer(state, action) {
16371
16374
  return finishActive(withUsage);
16372
16375
  }
16373
16376
  if (event.type === "text") {
16374
- return { ...state, active: addText(withoutModelActivity(state.active), event.text) };
16377
+ return { ...state, active: addStreamingText(state.active, event.text) };
16375
16378
  }
16376
16379
  if (event.type === "thinking") {
16377
16380
  return { ...state, active: attachThinking(state.active, event.text) };
@@ -16829,6 +16832,17 @@ function addText(turn, text, onNewLine = false) {
16829
16832
  }
16830
16833
  return withBlocks({ ...turn, assistantText }, blocks);
16831
16834
  }
16835
+ function addStreamingText(turn, text) {
16836
+ const activity = turn.blocks.find((block) => block.kind === "status" && block.activity === "model" && block.state === "running");
16837
+ if (activity === void 0) return addText(turn, text);
16838
+ const withoutActivity = withBlocks(turn, turn.blocks.filter((block) => block !== activity));
16839
+ const withText = addText(withoutActivity, text);
16840
+ const { thinkingText: _thinkingText, ...writingActivity } = activity;
16841
+ return withBlocks(withText, [...withText.blocks, {
16842
+ ...writingActivity,
16843
+ text: "Writing response"
16844
+ }]);
16845
+ }
16832
16846
  function boundedTranscriptBlock(block) {
16833
16847
  const presentation = block.presentation === void 0 ? void 0 : boundedTranscriptPresentation(block.presentation);
16834
16848
  const tool = block.tool === void 0 ? void 0 : {
@@ -20311,10 +20325,12 @@ var LspConnection = class {
20311
20325
  this.#disposed = true;
20312
20326
  this.#rejectAll(new Error("LSP connection disposed"));
20313
20327
  this.#shutdownPromise = (async () => {
20328
+ const closed = waitForProcessClose(this.#process);
20314
20329
  await terminateProcessTree3(this.#process.pid);
20315
20330
  this.#process.stdin.destroy();
20316
20331
  this.#process.stdout.destroy();
20317
20332
  this.#process.stderr.destroy();
20333
+ await closed;
20318
20334
  })();
20319
20335
  return this.#shutdownPromise;
20320
20336
  }
@@ -20433,6 +20449,18 @@ var LspConnection = class {
20433
20449
  this.#pending.clear();
20434
20450
  }
20435
20451
  };
20452
+ function waitForProcessClose(child) {
20453
+ if (child.exitCode !== null || child.signalCode !== null) return Promise.resolve();
20454
+ return new Promise((resolveClose) => {
20455
+ const finish = () => {
20456
+ clearTimeout(timer);
20457
+ resolveClose();
20458
+ };
20459
+ const timer = setTimeout(finish, 2e3);
20460
+ timer.unref();
20461
+ child.once("close", finish);
20462
+ });
20463
+ }
20436
20464
  var LspBuffer = class {
20437
20465
  #data = Buffer.alloc(0);
20438
20466
  feed(chunk, onMessage) {
@@ -20463,7 +20491,7 @@ var TYPESCRIPT_CLI = resolve26(
20463
20491
  var KNOWN_SERVERS = [
20464
20492
  {
20465
20493
  language: "typescript",
20466
- extensions: [".ts", ".tsx", ".mts", ".cts"],
20494
+ extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"],
20467
20495
  command: process.execPath,
20468
20496
  args: [TYPESCRIPT_CLI, "--lsp", "--stdio"],
20469
20497
  rootFiles: ["tsconfig.json", "jsconfig.json"]
@@ -20548,35 +20576,39 @@ var RealLspManager = class {
20548
20576
  if (this.#disposed) throw new Error("LSP manager is disposed");
20549
20577
  const language = this.#languageForUri(uri);
20550
20578
  if (language === void 0) throw new Error(`No language server configured for ${uri}; use Read/Grep or the project compiler`);
20551
- const existing = this.#connections.get(language);
20552
- if (existing !== void 0) return existing;
20553
- const pending2 = this.#pendingStarts.get(language);
20554
- if (pending2 !== void 0) return pending2;
20555
20579
  const config = this.#serverConfigs.find((c) => c.language === language);
20556
20580
  if (config === void 0) throw new Error(`No language server configured for ${language}`);
20557
- const hasRoot = config.rootFiles.some((file) => existsSync5(resolve26(this.#workspace, file)));
20558
- if (!hasRoot) throw new Error(`Cannot start ${language} language server: workspace needs ${config.rootFiles.join(" or ")}`);
20559
- const startPromise = this.#startServer(config);
20560
- this.#pendingStarts.set(language, startPromise);
20581
+ const filePath = uriToPath(uri);
20582
+ const projectRoot = findLanguageServerRoot(filePath, this.#workspace, config.rootFiles);
20583
+ if (projectRoot === void 0) {
20584
+ throw new Error(`Cannot start ${language} language server: no ${config.rootFiles.join(" or ")} found from ${dirname18(filePath)} up to workspace ${this.#workspace}`);
20585
+ }
20586
+ const connectionKey = `${language}:${projectRoot}`;
20587
+ const existing = this.#connections.get(connectionKey);
20588
+ if (existing !== void 0) return existing;
20589
+ const pending2 = this.#pendingStarts.get(connectionKey);
20590
+ if (pending2 !== void 0) return pending2;
20591
+ const startPromise = this.#startServer(config, projectRoot);
20592
+ this.#pendingStarts.set(connectionKey, startPromise);
20561
20593
  try {
20562
20594
  const connection = await startPromise;
20563
20595
  if (this.#disposed) {
20564
20596
  await connection.shutdown();
20565
20597
  throw new Error("LSP manager is disposed");
20566
20598
  }
20567
- this.#connections.set(language, connection);
20599
+ this.#connections.set(connectionKey, connection);
20568
20600
  return connection;
20569
20601
  } finally {
20570
- this.#pendingStarts.delete(language);
20602
+ this.#pendingStarts.delete(connectionKey);
20571
20603
  }
20572
20604
  }
20573
- async #startServer(config) {
20605
+ async #startServer(config, projectRoot) {
20574
20606
  try {
20575
20607
  await access2(config.command, constants10.X_OK);
20576
20608
  } catch {
20577
20609
  }
20578
- const connection = new LspConnection(config.command, config.args, this.#workspace);
20579
- const rootUri = pathToFileURL3(this.#workspace).href;
20610
+ const connection = new LspConnection(config.command, config.args, projectRoot);
20611
+ const rootUri = pathToFileURL3(projectRoot).href;
20580
20612
  try {
20581
20613
  await connection.initialize(rootUri);
20582
20614
  this.#onStatus?.(`${config.language} Language Server ready (${config.command})`);
@@ -20612,7 +20644,21 @@ function createLspTools(workspace, options = {}) {
20612
20644
  const toUri = (filePath) => pathToFileURL3(filePath).href;
20613
20645
  const langTag = (file) => {
20614
20646
  const ext = file.slice(file.lastIndexOf(".")).toLowerCase();
20615
- const map = { ".ts": "ts", ".tsx": "tsx", ".mts": "ts", ".cts": "ts", ".py": "py", ".pyi": "py", ".pyx": "py", ".rs": "rs", ".go": "go" };
20647
+ const map = {
20648
+ ".ts": "ts",
20649
+ ".tsx": "tsx",
20650
+ ".mts": "ts",
20651
+ ".cts": "ts",
20652
+ ".js": "js",
20653
+ ".jsx": "jsx",
20654
+ ".mjs": "js",
20655
+ ".cjs": "js",
20656
+ ".py": "py",
20657
+ ".pyi": "py",
20658
+ ".pyx": "py",
20659
+ ".rs": "rs",
20660
+ ".go": "go"
20661
+ };
20616
20662
  const tag = map[ext];
20617
20663
  return tag === void 0 ? "" : " [" + tag + "]";
20618
20664
  };
@@ -20680,6 +20726,12 @@ function languageIdForPath(filePath) {
20680
20726
  return "typescript";
20681
20727
  case ".cts":
20682
20728
  return "typescript";
20729
+ case ".jsx":
20730
+ return "javascriptreact";
20731
+ case ".js":
20732
+ case ".mjs":
20733
+ case ".cjs":
20734
+ return "javascript";
20683
20735
  case ".py":
20684
20736
  case ".pyi":
20685
20737
  case ".pyx":
@@ -20692,6 +20744,19 @@ function languageIdForPath(filePath) {
20692
20744
  return "typescript";
20693
20745
  }
20694
20746
  }
20747
+ function findLanguageServerRoot(filePath, workspace, rootFiles) {
20748
+ const root = resolve26(workspace);
20749
+ const target = resolve26(filePath);
20750
+ if (!isWithin7(root, target)) return void 0;
20751
+ let current = dirname18(target);
20752
+ while (true) {
20753
+ if (rootFiles.some((file) => existsSync5(resolve26(current, file)))) return current;
20754
+ if (current === root) return void 0;
20755
+ const parent = dirname18(current);
20756
+ if (parent === current || !isWithin7(root, parent)) return void 0;
20757
+ current = parent;
20758
+ }
20759
+ }
20695
20760
  function isWithin7(root, candidate) {
20696
20761
  const delta = relative18(root, candidate);
20697
20762
  return delta === "" || !delta.startsWith(`..${sep18}`) && delta !== ".." && !isAbsolute14(delta);
@@ -29064,7 +29129,12 @@ async function registerConfiguredAdapters(providers, registry, environment, diag
29064
29129
  if (result.llmConfig !== void 0) {
29065
29130
  apiProtocol = result.llmConfig.apiType;
29066
29131
  runtimeName = result.llmConfig.providerId;
29067
- runtimeProvider = providerFromOAuthConfig(result.llmConfig);
29132
+ runtimeProvider = {
29133
+ ...providerFromOAuthConfig(result.llmConfig),
29134
+ ...provider.thinkingEffort === void 0 ? {} : { thinkingEffort: provider.thinkingEffort },
29135
+ ...provider.thinkingBudget === void 0 ? {} : { thinkingBudget: provider.thinkingBudget },
29136
+ ...provider.claudeClient === void 0 ? {} : { claudeClient: provider.claudeClient }
29137
+ };
29068
29138
  effectiveLlm ??= effectiveRuntime(result, credentialId);
29069
29139
  }
29070
29140
  }