flavor-code 1.3.13 → 1.3.16
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/agent/loop.d.ts +10 -1
- package/dist/agent/types.d.ts +1 -1
- package/dist/{app-2SBDQ6NS.js → app-6SEGTMMC.js} +136 -31
- package/dist/chunk-CIVPKHF4.js +53 -0
- package/dist/{chunk-JFKRX2KG.js → chunk-HJOCNKPN.js} +1 -1
- package/dist/{chunk-EYCTP5JB.js → chunk-LMFN2QEA.js} +1 -1
- package/dist/{chunk-W2D2MLY2.js → chunk-S525EOFQ.js} +182 -34
- package/dist/cli-main.js +1037 -0
- package/dist/cli.js +84 -1000
- package/dist/context/manager.d.ts +7 -0
- package/dist/desktop/main.js +360 -194
- package/dist/desktop-renderer/assets/{index-BiDVkW9t.js → index-C3JpD2_B.js} +6 -6
- package/dist/desktop-renderer/assets/index-ZZsUx916.css +1 -0
- package/dist/desktop-renderer/assets/{interactive-terminal-CKHHiGNG.js → interactive-terminal-f1PNniPO.js} +1 -1
- package/dist/desktop-renderer/index.html +2 -2
- package/dist/{load-LTTKVPJZ.js → load-DELQW42K.js} +1 -1
- package/dist/sdk/index.js +4 -3
- package/dist/utils/memory-restart.d.ts +33 -0
- package/package.json +3 -1
- package/dist/desktop-renderer/assets/index-DHTr_Acb.css +0 -1
package/README.md
CHANGED
|
@@ -254,7 +254,7 @@ flavor mcp disable docs
|
|
|
254
254
|
|
|
255
255
|
A Skill is a `SKILL.md` with YAML frontmatter, placed in `.flavor/skills/<name>/` or `~/.flavor-code/skills/<name>/`. Flavor loads skills progressively based on the task, and you can invoke one explicitly with `/<skill-name>`. Skill bodies support `$ARGUMENTS`, `$ARGUMENTS[N]`, and `$N` substitutions. A running composite Skill can load a dependency through the read-only `Skill` tool; plugin-qualified names such as `superharness:test-driven-development` resolve to discovered skills.
|
|
256
256
|
|
|
257
|
-
Plugins live in `.flavor/plugins/` and can register commands, tools, hooks, Skill roots, and model adapters. `additionalContext` returned by `SessionStart` and `UserPromptSubmit` hooks is added to the current task context, enabling reliable project-level engineering policy injection. Plugin loads record a content fingerprint plus declared capabilities. Worker/vm isolation is available through the embedding API's `pluginSandbox: true` option; the compatibility default remains in-process because bundled and existing plugins use Node.js APIs that the isolated runtime does not yet mediate.
|
|
257
|
+
Plugins live in `.flavor/plugins/` and can register commands, tools, hooks, Skill roots, and model adapters. Official plugins can be installed with the plugin manager: `npx --yes @flavor-code/plugin-manager`. `additionalContext` returned by `SessionStart` and `UserPromptSubmit` hooks is added to the current task context, enabling reliable project-level engineering policy injection. Plugin loads record a content fingerprint plus declared capabilities. Worker/vm isolation is available through the embedding API's `pluginSandbox: true` option; the compatibility default remains in-process because bundled and existing plugins use Node.js APIs that the isolated runtime does not yet mediate.
|
|
258
258
|
|
|
259
259
|
When the `flavor-island` plugin is loaded, Flavor also starts a Flavor Island local control channel: a loopback-only IPC service (Windows named pipe, or Unix socket on macOS/Linux) secured by a random token. A host app (such as the Flavor Island desktop) can use it to abort, steer, or send follow-ups to a running session, and desktop hosts can also bring their window into focus. The channel's endpoint, token, and capability list are exposed to the host plugin via hook event context (`islandControlEndpoint`/`islandControlToken`/`islandControlCapabilities`); model-call duration and token usage, plus the final task summary and deliverables, are reported through hook events so the host can show live status and a result overview.
|
|
260
260
|
|
package/README.zh-CN.md
CHANGED
|
@@ -254,7 +254,7 @@ flavor mcp disable docs
|
|
|
254
254
|
|
|
255
255
|
Skill 是带有 YAML 头信息的 `SKILL.md`,放在 `.flavor/skills/<name>/` 或 `~/.flavor-code/skills/<name>/`。Flavor 会按任务渐进加载,也支持通过 `/<skill-name>` 显式调用。Skill 正文支持 `$ARGUMENTS`、`$ARGUMENTS[N]` 和 `$N` 参数占位符;运行中的组合 Skill 可以使用只读 `Skill` 工具继续加载依赖 Skill,插件限定名称(如 `superharness:test-driven-development`)会安全解析到已发现的 Skill。
|
|
256
256
|
|
|
257
|
-
插件放在 `.flavor/plugins/`,可以注册命令、工具、Hook、Skill
|
|
257
|
+
插件放在 `.flavor/plugins/`,可以注册命令、工具、Hook、Skill 根目录和模型适配器。官方插件可通过插件管理器安装:`npx --yes @flavor-code/plugin-manager`。`SessionStart` 与 `UserPromptSubmit` Hook 返回的 `additionalContext` 会进入当前任务上下文,可用于注入项目级工程规则。插件加载会记录内容指纹与声明的能力。可通过嵌入 API 的 `pluginSandbox: true` 启用 Worker/vm 隔离;由于内置插件和已有插件依赖沙箱尚未代理的 Node.js API,当前兼容默认值仍为进程内运行。
|
|
258
258
|
|
|
259
259
|
加载 `flavor-island` 插件时,Flavor 会额外启动一个 Flavor Island 本地控制通道:这是一个只监听本机回环的 IPC 服务(Windows 使用 named pipe,macOS/Linux 使用 Unix socket),通过随机 token 认证。宿主应用(如 Flavor Island 桌面端)可以借此对运行中的会话执行中止、steering、follow-up 等操作,桌面端还支持把窗口带到前台(focus)。通道的地址、token 与能力列表会通过 Hook 事件上下文(`islandControlEndpoint`/`islandControlToken`/`islandControlCapabilities`)提供给宿主插件,模型调用的耗时与 token 用量、任务结束时的摘要和交付文件也会随 Hook 事件上报,方便宿主展示运行状态与结果概览。
|
|
260
260
|
|
package/dist/agent/loop.d.ts
CHANGED
|
@@ -4,7 +4,16 @@ import type { HookBus } from "../hooks/bus.js";
|
|
|
4
4
|
import type { ModelRegistry } from "../models/registry.js";
|
|
5
5
|
import { type ModelMessage, type ModelTool } from "../models/types.js";
|
|
6
6
|
import type { ToolRuntime } from "../tools/runtime.js";
|
|
7
|
-
import type { AgentEvent, AgentRunRequest } from "./types.js";
|
|
7
|
+
import type { AgentError, AgentEvent, AgentRunRequest } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Stop a turn before the V8 heap reaches its hard limit. A retained-memory
|
|
10
|
+
* leak otherwise ends in a native OOM crash with no recovery; tripping this
|
|
11
|
+
* watermark saves the session and lets the launcher relaunch on a fresh heap.
|
|
12
|
+
* 0.8 keeps headroom for compaction payloads and the GC death spiral that
|
|
13
|
+
* starts near ~0.95.
|
|
14
|
+
*/
|
|
15
|
+
export declare const MEMORY_PRESSURE_HEAP_RATIO = 0.8;
|
|
16
|
+
export declare function memoryPressureError(heapUsed: number, heapLimit: number): AgentError | undefined;
|
|
8
17
|
export interface AgentLoopOptions {
|
|
9
18
|
registry: ModelRegistry;
|
|
10
19
|
modelId: string;
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface AgentRunRequest {
|
|
|
15
15
|
/** Messages supplied while a tool batch is running, injected before the next model call. */
|
|
16
16
|
getSteeringMessages?(): readonly string[];
|
|
17
17
|
}
|
|
18
|
-
export type AgentErrorCode = ProviderErrorCode | "iteration_limit" | "incomplete_stream" | "empty_response";
|
|
18
|
+
export type AgentErrorCode = ProviderErrorCode | "iteration_limit" | "incomplete_stream" | "empty_response" | "memory_pressure";
|
|
19
19
|
export interface AgentError {
|
|
20
20
|
code: AgentErrorCode;
|
|
21
21
|
message: string;
|
|
@@ -18,8 +18,9 @@ import {
|
|
|
18
18
|
thinkingWindow,
|
|
19
19
|
transcriptReducer,
|
|
20
20
|
withTimeout
|
|
21
|
-
} from "./chunk-
|
|
22
|
-
import "./chunk-
|
|
21
|
+
} from "./chunk-S525EOFQ.js";
|
|
22
|
+
import "./chunk-CIVPKHF4.js";
|
|
23
|
+
import "./chunk-HJOCNKPN.js";
|
|
23
24
|
import {
|
|
24
25
|
Box_default,
|
|
25
26
|
ClockContext,
|
|
@@ -1749,6 +1750,27 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
1749
1750
|
const clipboardBusy = useRef4(false);
|
|
1750
1751
|
const textBuf = useRef4({ pending: "", timer: null });
|
|
1751
1752
|
const thinkingBuf = useRef4({ pending: "", timer: null });
|
|
1753
|
+
const promptDraftRef = useRef4({
|
|
1754
|
+
text: input,
|
|
1755
|
+
cursor: promptCursor,
|
|
1756
|
+
pastedBlocks,
|
|
1757
|
+
imageAttachments
|
|
1758
|
+
});
|
|
1759
|
+
promptDraftRef.current = { text: input, cursor: promptCursor, pastedBlocks, imageAttachments };
|
|
1760
|
+
const commitPromptDraft = (next) => {
|
|
1761
|
+
const current = promptDraftRef.current;
|
|
1762
|
+
const resolved = {
|
|
1763
|
+
text: next.text,
|
|
1764
|
+
cursor: next.cursor,
|
|
1765
|
+
pastedBlocks: next.pastedBlocks ?? current.pastedBlocks,
|
|
1766
|
+
imageAttachments: next.imageAttachments ?? current.imageAttachments
|
|
1767
|
+
};
|
|
1768
|
+
promptDraftRef.current = resolved;
|
|
1769
|
+
setInput(resolved.text);
|
|
1770
|
+
setPromptCursor(resolved.cursor);
|
|
1771
|
+
if (next.pastedBlocks !== void 0) setPastedBlocks(next.pastedBlocks);
|
|
1772
|
+
if (next.imageAttachments !== void 0) setImageAttachments(next.imageAttachments);
|
|
1773
|
+
};
|
|
1752
1774
|
useTerminalTitle("Flavor Code");
|
|
1753
1775
|
const flushText = () => {
|
|
1754
1776
|
flushThinking();
|
|
@@ -1961,9 +1983,9 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
1961
1983
|
const completedTokenLength = completedSlashTokenLength(input, slashCandidates, slashCompletion !== null);
|
|
1962
1984
|
const selection = useSelection();
|
|
1963
1985
|
const selectMention = (path) => {
|
|
1964
|
-
const
|
|
1965
|
-
|
|
1966
|
-
|
|
1986
|
+
const draft = promptDraftRef.current;
|
|
1987
|
+
const next = completeMentionSelection(draft.text, draft.cursor, path);
|
|
1988
|
+
commitPromptDraft(next);
|
|
1967
1989
|
setMentionSelection(0);
|
|
1968
1990
|
setDismissedMentionInput(next.text);
|
|
1969
1991
|
};
|
|
@@ -2171,6 +2193,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
2171
2193
|
setInput("");
|
|
2172
2194
|
setPastedBlocks([]);
|
|
2173
2195
|
setImageAttachments([]);
|
|
2196
|
+
promptDraftRef.current = { text: "", cursor: 0, pastedBlocks: [], imageAttachments: [] };
|
|
2174
2197
|
setClipboardNotice(void 0);
|
|
2175
2198
|
setPromptCursor(0);
|
|
2176
2199
|
setSlashSelection(0);
|
|
@@ -2205,37 +2228,41 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
2205
2228
|
return;
|
|
2206
2229
|
}
|
|
2207
2230
|
if (key.backspace) {
|
|
2208
|
-
const
|
|
2231
|
+
const draft = promptDraftRef.current;
|
|
2232
|
+
const imageEdit = removeLastCliImageOnBackspace(draft.text, draft.cursor, draft.imageAttachments);
|
|
2209
2233
|
if (imageEdit.handled) {
|
|
2210
2234
|
setImageAttachments(imageEdit.images);
|
|
2235
|
+
promptDraftRef.current = { ...draft, imageAttachments: imageEdit.images };
|
|
2211
2236
|
setClipboardNotice(imageEdit.images.length === 0 ? "Removed image attachment." : `Removed image attachment; ${imageEdit.images.length} remaining.`);
|
|
2212
2237
|
return;
|
|
2213
2238
|
}
|
|
2214
2239
|
const next = editPromptWithPastedBlocks(
|
|
2215
|
-
{ text:
|
|
2240
|
+
{ text: draft.text, cursor: draft.cursor },
|
|
2216
2241
|
{ type: "backspace" },
|
|
2217
|
-
pastedBlocks
|
|
2242
|
+
draft.pastedBlocks
|
|
2218
2243
|
);
|
|
2219
|
-
|
|
2220
|
-
setPromptCursor(next.cursor);
|
|
2221
|
-
setPastedBlocks(next.pastedBlocks);
|
|
2244
|
+
commitPromptDraft(next);
|
|
2222
2245
|
setSlashSelection(0);
|
|
2223
2246
|
setDismissedSlashInput(void 0);
|
|
2224
2247
|
setMentionSelection(0);
|
|
2225
2248
|
setDismissedMentionInput(void 0);
|
|
2226
2249
|
} else if (key.delete) {
|
|
2227
|
-
|
|
2250
|
+
const draft = promptDraftRef.current;
|
|
2251
|
+
commitPromptDraft({ ...editPrompt({ text: draft.text, cursor: draft.cursor }, { type: "delete" }), pastedBlocks: draft.pastedBlocks });
|
|
2228
2252
|
setSlashSelection(0);
|
|
2229
2253
|
setDismissedSlashInput(void 0);
|
|
2230
2254
|
setMentionSelection(0);
|
|
2231
2255
|
setDismissedMentionInput(void 0);
|
|
2232
|
-
} else if (key.leftArrow)
|
|
2233
|
-
|
|
2234
|
-
|
|
2256
|
+
} else if (key.leftArrow) {
|
|
2257
|
+
const draft = promptDraftRef.current;
|
|
2258
|
+
commitPromptDraft({ ...editPrompt({ text: draft.text, cursor: draft.cursor }, { type: "left" }), pastedBlocks: draft.pastedBlocks });
|
|
2259
|
+
} else if (key.rightArrow) {
|
|
2260
|
+
const draft = promptDraftRef.current;
|
|
2261
|
+
commitPromptDraft({ ...editPrompt({ text: draft.text, cursor: draft.cursor }, { type: "right" }), pastedBlocks: draft.pastedBlocks });
|
|
2262
|
+
} else if (terminalAction?.type === "history" && terminalAction.direction === "up" && history.length) {
|
|
2235
2263
|
const next = navigateHistory({ history, cursor: historyCursor }, "up");
|
|
2236
2264
|
setHistoryCursor(next.cursor);
|
|
2237
|
-
|
|
2238
|
-
setPromptCursor(next.promptCursor);
|
|
2265
|
+
commitPromptDraft({ text: next.input, cursor: next.promptCursor, pastedBlocks: [] });
|
|
2239
2266
|
setSlashSelection(0);
|
|
2240
2267
|
setDismissedSlashInput(void 0);
|
|
2241
2268
|
setMentionSelection(0);
|
|
@@ -2243,17 +2270,18 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
2243
2270
|
} else if (terminalAction?.type === "history" && terminalAction.direction === "down" && history.length) {
|
|
2244
2271
|
const next = navigateHistory({ history, cursor: historyCursor }, "down");
|
|
2245
2272
|
setHistoryCursor(next.cursor);
|
|
2246
|
-
|
|
2247
|
-
setPromptCursor(next.promptCursor);
|
|
2273
|
+
commitPromptDraft({ text: next.input, cursor: next.promptCursor, pastedBlocks: [] });
|
|
2248
2274
|
setSlashSelection(0);
|
|
2249
2275
|
setDismissedSlashInput(void 0);
|
|
2250
2276
|
setMentionSelection(0);
|
|
2251
2277
|
setDismissedMentionInput(void 0);
|
|
2252
2278
|
} else if (!key.ctrl && !key.meta && character) {
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2279
|
+
const draft = promptDraftRef.current;
|
|
2280
|
+
const nextPastedBlocks = /[\r\n]/u.test(character) ? [...draft.pastedBlocks, { id: draft.pastedBlocks.length + 1, text: character }] : draft.pastedBlocks;
|
|
2281
|
+
commitPromptDraft({
|
|
2282
|
+
...editPrompt({ text: draft.text, cursor: draft.cursor }, { type: "insert", value: character }),
|
|
2283
|
+
pastedBlocks: nextPastedBlocks
|
|
2284
|
+
});
|
|
2257
2285
|
setSlashSelection(0);
|
|
2258
2286
|
setDismissedSlashInput(void 0);
|
|
2259
2287
|
setMentionSelection(0);
|
|
@@ -2330,6 +2358,73 @@ function StartingLayout({
|
|
|
2330
2358
|
}
|
|
2331
2359
|
);
|
|
2332
2360
|
}
|
|
2361
|
+
var CLI_VISIBLE_TURN_LIMIT = 40;
|
|
2362
|
+
var CLI_VISIBLE_BLOCK_LIMIT = 320;
|
|
2363
|
+
var CLI_VISIBLE_BLOCKS_PER_TURN = 80;
|
|
2364
|
+
var CLI_VISIBLE_TEXT_CHARS = 32e3;
|
|
2365
|
+
function boundedCliDisplayText(text, limit = CLI_VISIBLE_TEXT_CHARS) {
|
|
2366
|
+
if (text.length <= limit) return text;
|
|
2367
|
+
const half = Math.floor((limit - 80) / 2);
|
|
2368
|
+
return `${text.slice(0, half)}
|
|
2369
|
+
|
|
2370
|
+
\u2026 ${text.length - half * 2} characters hidden to keep the terminal responsive \u2026
|
|
2371
|
+
|
|
2372
|
+
${text.slice(-half)}`;
|
|
2373
|
+
}
|
|
2374
|
+
function boundedCliPresentation(presentation) {
|
|
2375
|
+
if (presentation.kind === "terminal") return {
|
|
2376
|
+
...presentation,
|
|
2377
|
+
...presentation.stdout === void 0 ? {} : { stdout: boundedCliDisplayText(presentation.stdout) },
|
|
2378
|
+
...presentation.stderr === void 0 ? {} : { stderr: boundedCliDisplayText(presentation.stderr) }
|
|
2379
|
+
};
|
|
2380
|
+
if (presentation.kind === "job" && presentation.output !== void 0) return {
|
|
2381
|
+
...presentation,
|
|
2382
|
+
output: boundedCliDisplayText(presentation.output)
|
|
2383
|
+
};
|
|
2384
|
+
return presentation;
|
|
2385
|
+
}
|
|
2386
|
+
function boundedCliTurn(turn, maxBlocks = CLI_VISIBLE_BLOCKS_PER_TURN) {
|
|
2387
|
+
const blockLimit = Math.max(1, Math.floor(maxBlocks));
|
|
2388
|
+
const hiddenBlocks = Math.max(0, turn.blocks.length - blockLimit);
|
|
2389
|
+
const visible = turn.blocks.slice(-blockLimit).map((block) => block.kind === "text" ? { ...block, text: boundedCliDisplayText(block.text) } : {
|
|
2390
|
+
...block,
|
|
2391
|
+
...block.details === void 0 ? {} : { details: boundedCliDisplayText(block.details) },
|
|
2392
|
+
...block.presentation === void 0 ? {} : { presentation: boundedCliPresentation(block.presentation) }
|
|
2393
|
+
});
|
|
2394
|
+
const blocks = hiddenBlocks === 0 ? visible : [{
|
|
2395
|
+
kind: "status",
|
|
2396
|
+
id: `display-window:${turn.id}`,
|
|
2397
|
+
state: "info",
|
|
2398
|
+
text: `\xB7 ${hiddenBlocks} earlier output items hidden to keep the terminal responsive`
|
|
2399
|
+
}, ...visible];
|
|
2400
|
+
return {
|
|
2401
|
+
hiddenBlocks,
|
|
2402
|
+
turn: {
|
|
2403
|
+
...turn,
|
|
2404
|
+
prompt: boundedCliDisplayText(turn.prompt, 16e3),
|
|
2405
|
+
blocks,
|
|
2406
|
+
statusLines: blocks.filter((block) => block.kind === "status").map((block) => block.text)
|
|
2407
|
+
}
|
|
2408
|
+
};
|
|
2409
|
+
}
|
|
2410
|
+
function cliTranscriptWindow(completed, maxTurns = CLI_VISIBLE_TURN_LIMIT, maxBlocks = CLI_VISIBLE_BLOCK_LIMIT) {
|
|
2411
|
+
const turns = [];
|
|
2412
|
+
let remainingBlocks = Math.max(1, Math.floor(maxBlocks));
|
|
2413
|
+
let hiddenBlocks = 0;
|
|
2414
|
+
for (let index = completed.length - 1; index >= 0 && turns.length < Math.max(1, Math.floor(maxTurns)); index -= 1) {
|
|
2415
|
+
const source = completed[index];
|
|
2416
|
+
if (remainingBlocks <= 0) break;
|
|
2417
|
+
const allowance = Math.min(CLI_VISIBLE_BLOCKS_PER_TURN, remainingBlocks);
|
|
2418
|
+
const bounded = boundedCliTurn(source, allowance);
|
|
2419
|
+
turns.push(bounded.turn);
|
|
2420
|
+
hiddenBlocks += bounded.hiddenBlocks;
|
|
2421
|
+
remainingBlocks -= Math.min(source.blocks.length, allowance);
|
|
2422
|
+
}
|
|
2423
|
+
turns.reverse();
|
|
2424
|
+
const hiddenTurns = completed.length - turns.length;
|
|
2425
|
+
for (let index = 0; index < hiddenTurns; index += 1) hiddenBlocks += completed[index]?.blocks.length ?? 0;
|
|
2426
|
+
return { turns, hiddenTurns, hiddenBlocks };
|
|
2427
|
+
}
|
|
2333
2428
|
function TerminalLayout({
|
|
2334
2429
|
model,
|
|
2335
2430
|
serviceName,
|
|
@@ -2369,12 +2464,14 @@ function TerminalLayout({
|
|
|
2369
2464
|
const activeTaskBlocks = active?.blocks.filter(
|
|
2370
2465
|
(block) => block.kind === "status" && block.task !== void 0
|
|
2371
2466
|
) ?? [];
|
|
2372
|
-
const
|
|
2467
|
+
const rawActiveWithoutTasks = active === void 0 ? void 0 : {
|
|
2373
2468
|
...active,
|
|
2374
2469
|
blocks: active.blocks.filter(
|
|
2375
2470
|
(block) => !(block.kind === "status" && block.task !== void 0)
|
|
2376
2471
|
)
|
|
2377
2472
|
};
|
|
2473
|
+
const activeWithoutTasks = rawActiveWithoutTasks === void 0 ? void 0 : boundedCliTurn(rawActiveWithoutTasks).turn;
|
|
2474
|
+
const completedWindow = cliTranscriptWindow(completed);
|
|
2378
2475
|
const questionRows = questions === void 0 ? 0 : 4 + (questions[questionIndex]?.options.length ?? 0) + questions.length * 2;
|
|
2379
2476
|
const memoryReviewRows = memoryReviews.length === 0 ? 0 : 5;
|
|
2380
2477
|
const fixedBottomRows = (approval === void 0 ? 0 : 3) + questionRows + memoryReviewRows + menuRows + (pendingPrompt === void 0 ? 0 : 1) + imageAttachments.length + (clipboardNotice === void 0 ? 0 : 1) + 2;
|
|
@@ -2391,12 +2488,19 @@ function TerminalLayout({
|
|
|
2391
2488
|
workspaceName
|
|
2392
2489
|
] }),
|
|
2393
2490
|
/* @__PURE__ */ jsx5(Box_default, { height: 1 }),
|
|
2394
|
-
|
|
2491
|
+
completedWindow.hiddenTurns > 0 || completedWindow.hiddenBlocks > 0 ? /* @__PURE__ */ jsxs4(Text, { dimColor: true, children: [
|
|
2492
|
+
"\u2026 ",
|
|
2493
|
+
completedWindow.hiddenTurns,
|
|
2494
|
+
" earlier turns and ",
|
|
2495
|
+
completedWindow.hiddenBlocks,
|
|
2496
|
+
" output items are outside the live render window"
|
|
2497
|
+
] }) : null,
|
|
2498
|
+
completedWindow.turns.map((turn, index) => /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", children: [
|
|
2395
2499
|
index > 0 ? /* @__PURE__ */ jsx5(TurnSeparator, { width: columns }) : null,
|
|
2396
2500
|
/* @__PURE__ */ jsx5(TurnView, { turn, interactive: false, workspaceName })
|
|
2397
2501
|
] }, turn.id)),
|
|
2398
2502
|
activeWithoutTasks === void 0 ? null : /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", children: [
|
|
2399
|
-
|
|
2503
|
+
completedWindow.turns.length > 0 ? /* @__PURE__ */ jsx5(TurnSeparator, { width: columns }) : null,
|
|
2400
2504
|
/* @__PURE__ */ jsx5(TurnView, { turn: activeWithoutTasks, interactive: activeSession, workspaceName })
|
|
2401
2505
|
] })
|
|
2402
2506
|
] }),
|
|
@@ -3443,11 +3547,6 @@ function navigateHistory(state, direction) {
|
|
|
3443
3547
|
const input = state.history[cursor] ?? "";
|
|
3444
3548
|
return { cursor, input, promptCursor: [...input].length };
|
|
3445
3549
|
}
|
|
3446
|
-
function updatePrompt(edit, text, cursor, setText, setCursor) {
|
|
3447
|
-
const next = editPrompt({ text, cursor }, edit);
|
|
3448
|
-
setText(next.text);
|
|
3449
|
-
setCursor(next.cursor);
|
|
3450
|
-
}
|
|
3451
3550
|
async function submitSafely(session, prompt, report) {
|
|
3452
3551
|
try {
|
|
3453
3552
|
await session.submit(prompt);
|
|
@@ -3499,6 +3598,10 @@ function safeReport(report, value) {
|
|
|
3499
3598
|
}
|
|
3500
3599
|
export {
|
|
3501
3600
|
App,
|
|
3601
|
+
CLI_VISIBLE_BLOCKS_PER_TURN,
|
|
3602
|
+
CLI_VISIBLE_BLOCK_LIMIT,
|
|
3603
|
+
CLI_VISIBLE_TEXT_CHARS,
|
|
3604
|
+
CLI_VISIBLE_TURN_LIMIT,
|
|
3502
3605
|
FooterStatus,
|
|
3503
3606
|
HISTORY_CAP,
|
|
3504
3607
|
MentionMenu,
|
|
@@ -3507,7 +3610,9 @@ export {
|
|
|
3507
3610
|
SinglePendingPrompt,
|
|
3508
3611
|
TerminalLayout,
|
|
3509
3612
|
appRuntimeOptions,
|
|
3613
|
+
boundedCliTurn,
|
|
3510
3614
|
classifyTerminalInput,
|
|
3615
|
+
cliTranscriptWindow,
|
|
3511
3616
|
closeAndDisposeRuntime,
|
|
3512
3617
|
completionKeyAction,
|
|
3513
3618
|
editPrompt,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// src/utils/memory-restart.ts
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
var MEMORY_RESTART_EXIT_CODE = 75;
|
|
7
|
+
var MEMORY_RESTART_MARKER_FILE = "memory-restart.json";
|
|
8
|
+
var MEMORY_RESTART_MAX_ATTEMPTS = 3;
|
|
9
|
+
var MEMORY_RESTART_WINDOW_MS = 30 * 60 * 1e3;
|
|
10
|
+
var SESSION_ID_PATTERN = /^session-[A-Za-z0-9_-]+$/u;
|
|
11
|
+
function memoryRestartMarkerPath(workspace) {
|
|
12
|
+
return join(workspace, ".flavor", "tmp", MEMORY_RESTART_MARKER_FILE);
|
|
13
|
+
}
|
|
14
|
+
function nextMemoryRestartMarker(previous, sessionId, now) {
|
|
15
|
+
const reusable = previous !== void 0 && previous.sessionId === sessionId && now.getTime() - Date.parse(previous.requestedAt) < MEMORY_RESTART_WINDOW_MS && Number.isInteger(previous.attempts) && previous.attempts > 0;
|
|
16
|
+
return { sessionId, requestedAt: now.toISOString(), attempts: reusable ? previous.attempts + 1 : 1 };
|
|
17
|
+
}
|
|
18
|
+
function shouldRelaunchForMemoryRestart(marker) {
|
|
19
|
+
return marker !== void 0 && SESSION_ID_PATTERN.test(marker.sessionId) && Number.isInteger(marker.attempts) && marker.attempts >= 1 && marker.attempts <= MEMORY_RESTART_MAX_ATTEMPTS;
|
|
20
|
+
}
|
|
21
|
+
function memoryRestartArgs(argv, marker) {
|
|
22
|
+
if (!shouldRelaunchForMemoryRestart(marker)) return void 0;
|
|
23
|
+
const stripped = [];
|
|
24
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
25
|
+
const argument = argv[index];
|
|
26
|
+
if (argument === "--resume") {
|
|
27
|
+
if (index + 1 < argv.length && !argv[index + 1].startsWith("-")) index += 1;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (argument.startsWith("--resume=")) continue;
|
|
31
|
+
stripped.push(argument);
|
|
32
|
+
}
|
|
33
|
+
return [...stripped, "--resume", marker.sessionId];
|
|
34
|
+
}
|
|
35
|
+
function parseMemoryRestartMarker(json) {
|
|
36
|
+
try {
|
|
37
|
+
const value = JSON.parse(json);
|
|
38
|
+
if (typeof value.sessionId !== "string" || typeof value.requestedAt !== "string" || typeof value.attempts !== "number") {
|
|
39
|
+
return void 0;
|
|
40
|
+
}
|
|
41
|
+
return { sessionId: value.sessionId, requestedAt: value.requestedAt, attempts: value.attempts };
|
|
42
|
+
} catch {
|
|
43
|
+
return void 0;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
MEMORY_RESTART_EXIT_CODE,
|
|
49
|
+
memoryRestartMarkerPath,
|
|
50
|
+
nextMemoryRestartMarker,
|
|
51
|
+
memoryRestartArgs,
|
|
52
|
+
parseMemoryRestartMarker
|
|
53
|
+
};
|
|
@@ -129,7 +129,7 @@ var FlavorConfigSchema = z.object({
|
|
|
129
129
|
context: z.object({
|
|
130
130
|
windowTokens: z.number().int().positive().default(2e5),
|
|
131
131
|
reservedOutputTokens: z.number().int().nonnegative().default(2e4),
|
|
132
|
-
autoCompactBufferTokens: z.number().int().nonnegative().default(
|
|
132
|
+
autoCompactBufferTokens: z.number().int().nonnegative().default(27e3),
|
|
133
133
|
warningBufferTokens: z.number().int().nonnegative().default(2e4),
|
|
134
134
|
blockingBufferTokens: z.number().int().nonnegative().default(3e3),
|
|
135
135
|
microcompactKeepRecentToolResults: z.number().int().nonnegative().default(5),
|