flavor-code 1.4.0-beta.6 → 1.4.0-beta.7
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 +2 -0
- package/README.zh-CN.md +2 -0
- package/dist/{app-6JRSYZYV.js → app-H2XGMAOY.js} +38 -5
- package/dist/{chunk-NLYZ7DMC.js → chunk-ITKOMJD6.js} +78 -16
- package/dist/{chunk-6MXAOTIZ.js → chunk-PT72RZVC.js} +1 -1
- package/dist/{chunk-2BF7CVWZ.js → chunk-RAYH6K2H.js} +2 -2
- package/dist/cli-main.js +4 -4
- package/dist/desktop/main.js +78 -16
- package/dist/desktop-renderer/assets/index-DoW9kFm4.js +154 -0
- package/dist/desktop-renderer/assets/{interactive-terminal-D2J4feTJ.js → interactive-terminal-OJuLa-R6.js} +1 -1
- package/dist/desktop-renderer/index.html +1 -1
- package/dist/sdk/index.js +2 -2
- package/dist/tools/lsp.d.ts +2 -0
- package/package.json +1 -1
- package/dist/desktop-renderer/assets/index-nR67Z0XT.js +0 -154
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-
|
|
5
|
+
} from "./chunk-RAYH6K2H.js";
|
|
6
6
|
import {
|
|
7
7
|
COMMAND_DESCRIPTIONS,
|
|
8
8
|
MVP_COMMANDS,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
thinkingWindow,
|
|
20
20
|
transcriptReducer,
|
|
21
21
|
withTimeout
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-ITKOMJD6.js";
|
|
23
23
|
import "./chunk-N5MXHJKD.js";
|
|
24
24
|
import "./chunk-KQMKY7C5.js";
|
|
25
25
|
import {
|
|
@@ -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(
|
|
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:
|
|
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
|
}
|
|
@@ -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:
|
|
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 : {
|
|
@@ -18827,10 +18838,12 @@ var LspConnection = class {
|
|
|
18827
18838
|
this.#disposed = true;
|
|
18828
18839
|
this.#rejectAll(new Error("LSP connection disposed"));
|
|
18829
18840
|
this.#shutdownPromise = (async () => {
|
|
18841
|
+
const closed = waitForProcessClose(this.#process);
|
|
18830
18842
|
await terminateProcessTree(this.#process.pid);
|
|
18831
18843
|
this.#process.stdin.destroy();
|
|
18832
18844
|
this.#process.stdout.destroy();
|
|
18833
18845
|
this.#process.stderr.destroy();
|
|
18846
|
+
await closed;
|
|
18834
18847
|
})();
|
|
18835
18848
|
return this.#shutdownPromise;
|
|
18836
18849
|
}
|
|
@@ -18949,6 +18962,18 @@ var LspConnection = class {
|
|
|
18949
18962
|
this.#pending.clear();
|
|
18950
18963
|
}
|
|
18951
18964
|
};
|
|
18965
|
+
function waitForProcessClose(child) {
|
|
18966
|
+
if (child.exitCode !== null || child.signalCode !== null) return Promise.resolve();
|
|
18967
|
+
return new Promise((resolveClose) => {
|
|
18968
|
+
const finish = () => {
|
|
18969
|
+
clearTimeout(timer);
|
|
18970
|
+
resolveClose();
|
|
18971
|
+
};
|
|
18972
|
+
const timer = setTimeout(finish, 2e3);
|
|
18973
|
+
timer.unref();
|
|
18974
|
+
child.once("close", finish);
|
|
18975
|
+
});
|
|
18976
|
+
}
|
|
18952
18977
|
var LspBuffer = class {
|
|
18953
18978
|
#data = Buffer.alloc(0);
|
|
18954
18979
|
feed(chunk, onMessage) {
|
|
@@ -18979,7 +19004,7 @@ var TYPESCRIPT_CLI = resolve23(
|
|
|
18979
19004
|
var KNOWN_SERVERS = [
|
|
18980
19005
|
{
|
|
18981
19006
|
language: "typescript",
|
|
18982
|
-
extensions: [".ts", ".tsx", ".mts", ".cts"],
|
|
19007
|
+
extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"],
|
|
18983
19008
|
command: process.execPath,
|
|
18984
19009
|
args: [TYPESCRIPT_CLI, "--lsp", "--stdio"],
|
|
18985
19010
|
rootFiles: ["tsconfig.json", "jsconfig.json"]
|
|
@@ -19064,35 +19089,39 @@ var RealLspManager = class {
|
|
|
19064
19089
|
if (this.#disposed) throw new Error("LSP manager is disposed");
|
|
19065
19090
|
const language = this.#languageForUri(uri);
|
|
19066
19091
|
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
19092
|
const config = this.#serverConfigs.find((c) => c.language === language);
|
|
19072
19093
|
if (config === void 0) throw new Error(`No language server configured for ${language}`);
|
|
19073
|
-
const
|
|
19074
|
-
|
|
19075
|
-
|
|
19076
|
-
|
|
19094
|
+
const filePath = uriToPath(uri);
|
|
19095
|
+
const projectRoot = findLanguageServerRoot(filePath, this.#workspace, config.rootFiles);
|
|
19096
|
+
if (projectRoot === void 0) {
|
|
19097
|
+
throw new Error(`Cannot start ${language} language server: no ${config.rootFiles.join(" or ")} found from ${dirname15(filePath)} up to workspace ${this.#workspace}`);
|
|
19098
|
+
}
|
|
19099
|
+
const connectionKey = `${language}:${projectRoot}`;
|
|
19100
|
+
const existing = this.#connections.get(connectionKey);
|
|
19101
|
+
if (existing !== void 0) return existing;
|
|
19102
|
+
const pending = this.#pendingStarts.get(connectionKey);
|
|
19103
|
+
if (pending !== void 0) return pending;
|
|
19104
|
+
const startPromise = this.#startServer(config, projectRoot);
|
|
19105
|
+
this.#pendingStarts.set(connectionKey, startPromise);
|
|
19077
19106
|
try {
|
|
19078
19107
|
const connection = await startPromise;
|
|
19079
19108
|
if (this.#disposed) {
|
|
19080
19109
|
await connection.shutdown();
|
|
19081
19110
|
throw new Error("LSP manager is disposed");
|
|
19082
19111
|
}
|
|
19083
|
-
this.#connections.set(
|
|
19112
|
+
this.#connections.set(connectionKey, connection);
|
|
19084
19113
|
return connection;
|
|
19085
19114
|
} finally {
|
|
19086
|
-
this.#pendingStarts.delete(
|
|
19115
|
+
this.#pendingStarts.delete(connectionKey);
|
|
19087
19116
|
}
|
|
19088
19117
|
}
|
|
19089
|
-
async #startServer(config) {
|
|
19118
|
+
async #startServer(config, projectRoot) {
|
|
19090
19119
|
try {
|
|
19091
19120
|
await access2(config.command, constants10.X_OK);
|
|
19092
19121
|
} catch {
|
|
19093
19122
|
}
|
|
19094
|
-
const connection = new LspConnection(config.command, config.args,
|
|
19095
|
-
const rootUri = pathToFileURL2(
|
|
19123
|
+
const connection = new LspConnection(config.command, config.args, projectRoot);
|
|
19124
|
+
const rootUri = pathToFileURL2(projectRoot).href;
|
|
19096
19125
|
try {
|
|
19097
19126
|
await connection.initialize(rootUri);
|
|
19098
19127
|
this.#onStatus?.(`${config.language} Language Server ready (${config.command})`);
|
|
@@ -19128,7 +19157,21 @@ function createLspTools(workspace, options = {}) {
|
|
|
19128
19157
|
const toUri = (filePath) => pathToFileURL2(filePath).href;
|
|
19129
19158
|
const langTag = (file) => {
|
|
19130
19159
|
const ext = file.slice(file.lastIndexOf(".")).toLowerCase();
|
|
19131
|
-
const map = {
|
|
19160
|
+
const map = {
|
|
19161
|
+
".ts": "ts",
|
|
19162
|
+
".tsx": "tsx",
|
|
19163
|
+
".mts": "ts",
|
|
19164
|
+
".cts": "ts",
|
|
19165
|
+
".js": "js",
|
|
19166
|
+
".jsx": "jsx",
|
|
19167
|
+
".mjs": "js",
|
|
19168
|
+
".cjs": "js",
|
|
19169
|
+
".py": "py",
|
|
19170
|
+
".pyi": "py",
|
|
19171
|
+
".pyx": "py",
|
|
19172
|
+
".rs": "rs",
|
|
19173
|
+
".go": "go"
|
|
19174
|
+
};
|
|
19132
19175
|
const tag = map[ext];
|
|
19133
19176
|
return tag === void 0 ? "" : " [" + tag + "]";
|
|
19134
19177
|
};
|
|
@@ -19196,6 +19239,12 @@ function languageIdForPath(filePath) {
|
|
|
19196
19239
|
return "typescript";
|
|
19197
19240
|
case ".cts":
|
|
19198
19241
|
return "typescript";
|
|
19242
|
+
case ".jsx":
|
|
19243
|
+
return "javascriptreact";
|
|
19244
|
+
case ".js":
|
|
19245
|
+
case ".mjs":
|
|
19246
|
+
case ".cjs":
|
|
19247
|
+
return "javascript";
|
|
19199
19248
|
case ".py":
|
|
19200
19249
|
case ".pyi":
|
|
19201
19250
|
case ".pyx":
|
|
@@ -19208,6 +19257,19 @@ function languageIdForPath(filePath) {
|
|
|
19208
19257
|
return "typescript";
|
|
19209
19258
|
}
|
|
19210
19259
|
}
|
|
19260
|
+
function findLanguageServerRoot(filePath, workspace, rootFiles) {
|
|
19261
|
+
const root = resolve23(workspace);
|
|
19262
|
+
const target = resolve23(filePath);
|
|
19263
|
+
if (!isWithin7(root, target)) return void 0;
|
|
19264
|
+
let current = dirname15(target);
|
|
19265
|
+
while (true) {
|
|
19266
|
+
if (rootFiles.some((file) => existsSync5(resolve23(current, file)))) return current;
|
|
19267
|
+
if (current === root) return void 0;
|
|
19268
|
+
const parent = dirname15(current);
|
|
19269
|
+
if (parent === current || !isWithin7(root, parent)) return void 0;
|
|
19270
|
+
current = parent;
|
|
19271
|
+
}
|
|
19272
|
+
}
|
|
19211
19273
|
function isWithin7(root, candidate) {
|
|
19212
19274
|
const delta = relative17(root, candidate);
|
|
19213
19275
|
return delta === "" || !delta.startsWith(`..${sep17}`) && delta !== ".." && !isAbsolute12(delta);
|
|
@@ -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:
|
|
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:
|
|
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-
|
|
6
|
+
} from "./chunk-PT72RZVC.js";
|
|
7
7
|
import {
|
|
8
8
|
staticTaskLines
|
|
9
|
-
} from "./chunk-
|
|
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-
|
|
32
|
+
} from "./chunk-ITKOMJD6.js";
|
|
33
33
|
import {
|
|
34
34
|
MEMORY_RESTART_EXIT_CODE
|
|
35
35
|
} from "./chunk-N5MXHJKD.js";
|
|
@@ -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-
|
|
924
|
+
import("./app-H2XGMAOY.js")
|
|
925
925
|
]);
|
|
926
926
|
const instance = await render(createElement(
|
|
927
927
|
AlternateScreen,
|
package/dist/desktop/main.js
CHANGED
|
@@ -16371,7 +16371,7 @@ function transcriptReducer(state, action) {
|
|
|
16371
16371
|
return finishActive(withUsage);
|
|
16372
16372
|
}
|
|
16373
16373
|
if (event.type === "text") {
|
|
16374
|
-
return { ...state, active:
|
|
16374
|
+
return { ...state, active: addStreamingText(state.active, event.text) };
|
|
16375
16375
|
}
|
|
16376
16376
|
if (event.type === "thinking") {
|
|
16377
16377
|
return { ...state, active: attachThinking(state.active, event.text) };
|
|
@@ -16829,6 +16829,17 @@ function addText(turn, text, onNewLine = false) {
|
|
|
16829
16829
|
}
|
|
16830
16830
|
return withBlocks({ ...turn, assistantText }, blocks);
|
|
16831
16831
|
}
|
|
16832
|
+
function addStreamingText(turn, text) {
|
|
16833
|
+
const activity = turn.blocks.find((block) => block.kind === "status" && block.activity === "model" && block.state === "running");
|
|
16834
|
+
if (activity === void 0) return addText(turn, text);
|
|
16835
|
+
const withoutActivity = withBlocks(turn, turn.blocks.filter((block) => block !== activity));
|
|
16836
|
+
const withText = addText(withoutActivity, text);
|
|
16837
|
+
const { thinkingText: _thinkingText, ...writingActivity } = activity;
|
|
16838
|
+
return withBlocks(withText, [...withText.blocks, {
|
|
16839
|
+
...writingActivity,
|
|
16840
|
+
text: "Writing response"
|
|
16841
|
+
}]);
|
|
16842
|
+
}
|
|
16832
16843
|
function boundedTranscriptBlock(block) {
|
|
16833
16844
|
const presentation = block.presentation === void 0 ? void 0 : boundedTranscriptPresentation(block.presentation);
|
|
16834
16845
|
const tool = block.tool === void 0 ? void 0 : {
|
|
@@ -20311,10 +20322,12 @@ var LspConnection = class {
|
|
|
20311
20322
|
this.#disposed = true;
|
|
20312
20323
|
this.#rejectAll(new Error("LSP connection disposed"));
|
|
20313
20324
|
this.#shutdownPromise = (async () => {
|
|
20325
|
+
const closed = waitForProcessClose(this.#process);
|
|
20314
20326
|
await terminateProcessTree3(this.#process.pid);
|
|
20315
20327
|
this.#process.stdin.destroy();
|
|
20316
20328
|
this.#process.stdout.destroy();
|
|
20317
20329
|
this.#process.stderr.destroy();
|
|
20330
|
+
await closed;
|
|
20318
20331
|
})();
|
|
20319
20332
|
return this.#shutdownPromise;
|
|
20320
20333
|
}
|
|
@@ -20433,6 +20446,18 @@ var LspConnection = class {
|
|
|
20433
20446
|
this.#pending.clear();
|
|
20434
20447
|
}
|
|
20435
20448
|
};
|
|
20449
|
+
function waitForProcessClose(child) {
|
|
20450
|
+
if (child.exitCode !== null || child.signalCode !== null) return Promise.resolve();
|
|
20451
|
+
return new Promise((resolveClose) => {
|
|
20452
|
+
const finish = () => {
|
|
20453
|
+
clearTimeout(timer);
|
|
20454
|
+
resolveClose();
|
|
20455
|
+
};
|
|
20456
|
+
const timer = setTimeout(finish, 2e3);
|
|
20457
|
+
timer.unref();
|
|
20458
|
+
child.once("close", finish);
|
|
20459
|
+
});
|
|
20460
|
+
}
|
|
20436
20461
|
var LspBuffer = class {
|
|
20437
20462
|
#data = Buffer.alloc(0);
|
|
20438
20463
|
feed(chunk, onMessage) {
|
|
@@ -20463,7 +20488,7 @@ var TYPESCRIPT_CLI = resolve26(
|
|
|
20463
20488
|
var KNOWN_SERVERS = [
|
|
20464
20489
|
{
|
|
20465
20490
|
language: "typescript",
|
|
20466
|
-
extensions: [".ts", ".tsx", ".mts", ".cts"],
|
|
20491
|
+
extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"],
|
|
20467
20492
|
command: process.execPath,
|
|
20468
20493
|
args: [TYPESCRIPT_CLI, "--lsp", "--stdio"],
|
|
20469
20494
|
rootFiles: ["tsconfig.json", "jsconfig.json"]
|
|
@@ -20548,35 +20573,39 @@ var RealLspManager = class {
|
|
|
20548
20573
|
if (this.#disposed) throw new Error("LSP manager is disposed");
|
|
20549
20574
|
const language = this.#languageForUri(uri);
|
|
20550
20575
|
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
20576
|
const config = this.#serverConfigs.find((c) => c.language === language);
|
|
20556
20577
|
if (config === void 0) throw new Error(`No language server configured for ${language}`);
|
|
20557
|
-
const
|
|
20558
|
-
|
|
20559
|
-
|
|
20560
|
-
|
|
20578
|
+
const filePath = uriToPath(uri);
|
|
20579
|
+
const projectRoot = findLanguageServerRoot(filePath, this.#workspace, config.rootFiles);
|
|
20580
|
+
if (projectRoot === void 0) {
|
|
20581
|
+
throw new Error(`Cannot start ${language} language server: no ${config.rootFiles.join(" or ")} found from ${dirname18(filePath)} up to workspace ${this.#workspace}`);
|
|
20582
|
+
}
|
|
20583
|
+
const connectionKey = `${language}:${projectRoot}`;
|
|
20584
|
+
const existing = this.#connections.get(connectionKey);
|
|
20585
|
+
if (existing !== void 0) return existing;
|
|
20586
|
+
const pending2 = this.#pendingStarts.get(connectionKey);
|
|
20587
|
+
if (pending2 !== void 0) return pending2;
|
|
20588
|
+
const startPromise = this.#startServer(config, projectRoot);
|
|
20589
|
+
this.#pendingStarts.set(connectionKey, startPromise);
|
|
20561
20590
|
try {
|
|
20562
20591
|
const connection = await startPromise;
|
|
20563
20592
|
if (this.#disposed) {
|
|
20564
20593
|
await connection.shutdown();
|
|
20565
20594
|
throw new Error("LSP manager is disposed");
|
|
20566
20595
|
}
|
|
20567
|
-
this.#connections.set(
|
|
20596
|
+
this.#connections.set(connectionKey, connection);
|
|
20568
20597
|
return connection;
|
|
20569
20598
|
} finally {
|
|
20570
|
-
this.#pendingStarts.delete(
|
|
20599
|
+
this.#pendingStarts.delete(connectionKey);
|
|
20571
20600
|
}
|
|
20572
20601
|
}
|
|
20573
|
-
async #startServer(config) {
|
|
20602
|
+
async #startServer(config, projectRoot) {
|
|
20574
20603
|
try {
|
|
20575
20604
|
await access2(config.command, constants10.X_OK);
|
|
20576
20605
|
} catch {
|
|
20577
20606
|
}
|
|
20578
|
-
const connection = new LspConnection(config.command, config.args,
|
|
20579
|
-
const rootUri = pathToFileURL3(
|
|
20607
|
+
const connection = new LspConnection(config.command, config.args, projectRoot);
|
|
20608
|
+
const rootUri = pathToFileURL3(projectRoot).href;
|
|
20580
20609
|
try {
|
|
20581
20610
|
await connection.initialize(rootUri);
|
|
20582
20611
|
this.#onStatus?.(`${config.language} Language Server ready (${config.command})`);
|
|
@@ -20612,7 +20641,21 @@ function createLspTools(workspace, options = {}) {
|
|
|
20612
20641
|
const toUri = (filePath) => pathToFileURL3(filePath).href;
|
|
20613
20642
|
const langTag = (file) => {
|
|
20614
20643
|
const ext = file.slice(file.lastIndexOf(".")).toLowerCase();
|
|
20615
|
-
const map = {
|
|
20644
|
+
const map = {
|
|
20645
|
+
".ts": "ts",
|
|
20646
|
+
".tsx": "tsx",
|
|
20647
|
+
".mts": "ts",
|
|
20648
|
+
".cts": "ts",
|
|
20649
|
+
".js": "js",
|
|
20650
|
+
".jsx": "jsx",
|
|
20651
|
+
".mjs": "js",
|
|
20652
|
+
".cjs": "js",
|
|
20653
|
+
".py": "py",
|
|
20654
|
+
".pyi": "py",
|
|
20655
|
+
".pyx": "py",
|
|
20656
|
+
".rs": "rs",
|
|
20657
|
+
".go": "go"
|
|
20658
|
+
};
|
|
20616
20659
|
const tag = map[ext];
|
|
20617
20660
|
return tag === void 0 ? "" : " [" + tag + "]";
|
|
20618
20661
|
};
|
|
@@ -20680,6 +20723,12 @@ function languageIdForPath(filePath) {
|
|
|
20680
20723
|
return "typescript";
|
|
20681
20724
|
case ".cts":
|
|
20682
20725
|
return "typescript";
|
|
20726
|
+
case ".jsx":
|
|
20727
|
+
return "javascriptreact";
|
|
20728
|
+
case ".js":
|
|
20729
|
+
case ".mjs":
|
|
20730
|
+
case ".cjs":
|
|
20731
|
+
return "javascript";
|
|
20683
20732
|
case ".py":
|
|
20684
20733
|
case ".pyi":
|
|
20685
20734
|
case ".pyx":
|
|
@@ -20692,6 +20741,19 @@ function languageIdForPath(filePath) {
|
|
|
20692
20741
|
return "typescript";
|
|
20693
20742
|
}
|
|
20694
20743
|
}
|
|
20744
|
+
function findLanguageServerRoot(filePath, workspace, rootFiles) {
|
|
20745
|
+
const root = resolve26(workspace);
|
|
20746
|
+
const target = resolve26(filePath);
|
|
20747
|
+
if (!isWithin7(root, target)) return void 0;
|
|
20748
|
+
let current = dirname18(target);
|
|
20749
|
+
while (true) {
|
|
20750
|
+
if (rootFiles.some((file) => existsSync5(resolve26(current, file)))) return current;
|
|
20751
|
+
if (current === root) return void 0;
|
|
20752
|
+
const parent = dirname18(current);
|
|
20753
|
+
if (parent === current || !isWithin7(root, parent)) return void 0;
|
|
20754
|
+
current = parent;
|
|
20755
|
+
}
|
|
20756
|
+
}
|
|
20695
20757
|
function isWithin7(root, candidate) {
|
|
20696
20758
|
const delta = relative18(root, candidate);
|
|
20697
20759
|
return delta === "" || !delta.startsWith(`..${sep18}`) && delta !== ".." && !isAbsolute14(delta);
|