flavor-code 1.2.8 → 1.2.9
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 +35 -0
- package/README.zh-CN.md +36 -6
- package/dist/agent/loop.d.ts +4 -0
- package/dist/agent/types.d.ts +10 -0
- package/dist/{app-NL2O75LQ.js → app-USAFQVSX.js} +379 -12
- package/dist/{chunk-NVLYFU6P.js → chunk-F2HMO5Q2.js} +28 -11
- package/dist/{chunk-6X5PHLZI.js → chunk-G32MCAZA.js} +1 -1
- package/dist/{chunk-N2S7USST.js → chunk-RQTYHUMK.js} +2 -1
- package/dist/{chunk-ED4R7ZCP.js → chunk-WGYNTR4Q.js} +1820 -492
- package/dist/{chunk-MBLAXTUP.js → chunk-XFCJXRJ2.js} +15 -5
- package/dist/{claude-ink-WPWPEL5A.js → claude-ink-ORUA7GWG.js} +2 -2
- package/dist/cli.js +9 -8
- package/dist/config/protected-file.d.ts +6 -0
- package/dist/context/manager.d.ts +2 -0
- package/dist/context/workspace-instructions.d.ts +10 -0
- package/dist/desktop/main.js +12725 -5181
- package/dist/desktop/pixel-worker.js +73 -0
- package/dist/desktop/preload.cjs +80 -2
- package/dist/desktop-renderer/assets/index-D-s27J39.js +151 -0
- package/dist/desktop-renderer/assets/index-DMZBSGrp.css +1 -0
- package/dist/desktop-renderer/index.html +3 -4
- package/dist/harness/local.d.ts +4 -1
- package/dist/jobs/registry.d.ts +48 -0
- package/dist/{load-RN3WBX4C.js → load-6ZMEBHSG.js} +1 -1
- package/dist/permissions/engine.d.ts +7 -0
- package/dist/production.d.ts +13 -1
- package/dist/sdk/index.js +4 -4
- package/dist/terminal/service.d.ts +57 -0
- package/dist/tools/files.d.ts +10 -0
- package/dist/tools/jobs.d.ts +4 -0
- package/dist/tools/runtime.d.ts +2 -0
- package/dist/tools/shell.d.ts +13 -3
- package/dist/tools/terminal.d.ts +3 -0
- package/dist/tools/types.d.ts +76 -4
- package/dist/tools/web.d.ts +53 -0
- package/package.json +13 -2
- package//346/212/200/346/234/257/346/226/271/346/241/210/346/212/245/345/221/212.md +752 -1
- package/dist/desktop-renderer/assets/index-57tXtXhI.js +0 -143
- package/dist/desktop-renderer/assets/index-Cm_ktmXm.css +0 -1
package/README.md
CHANGED
|
@@ -35,8 +35,38 @@ Flavor Code connects to OpenAI, Anthropic, or compatible services and works with
|
|
|
35
35
|
| 🧭 | **Controlled progress on complex tasks** | Task plans, sub-agents, steering, follow-ups, `/loop`, and `/goal` |
|
|
36
36
|
| ⏪ | **Traceable, resumable results** | Full timeline, checkpoints, rewind, traces, diffs, and failure audits |
|
|
37
37
|
| 🧠 | **Local long-term context** | Memory, Skills, plugins, and project guides stored on your machine |
|
|
38
|
+
| 🎨 | **D2C design-to-code** | Import Pixso exports; the agent generates Vue/React implementations with automatic pixel-level visual evaluation (Electron only) |
|
|
38
39
|
| 🛡️ | **Clear permission boundaries** | Independent control over read, write, Shell, network, and destructive actions; Docker supported |
|
|
39
40
|
|
|
41
|
+
## 1.2.9 Runtime Productivity
|
|
42
|
+
|
|
43
|
+
1.2.9 adds layered project instructions, safe writes, background jobs, persistent terminals, and native web tools. Usually you can just describe the goal in natural language and the agent picks the right tool; when you need precise control, name the tool and its parameters explicitly in the prompt.
|
|
44
|
+
|
|
45
|
+
| Feature | How to use |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| **Layered project instructions** | Put `AGENTS.md` / `CLAUDE.md` in the project root or subdirectories; use `AGENTS.local.md` / `CLAUDE.local.md` for local additions in the same directory. Root rules load at startup; subdirectory rules load automatically when the agent touches files there. |
|
|
48
|
+
| **Per-turn change summary** | No configuration needed. After a successful `Write`, `Edit`, or `ApplyPatch`, the turn shows a color-coded `CHANGESET` receipt with workspace-relative paths, `CREATE` / `UPDATE` / `DELETE` operations, per-file line counts, and a total. At most 8 files are shown, with an explicit shown/total footer when more changed. |
|
|
49
|
+
| **File version protection** | No configuration needed. If the IDE, a formatter, or another process modifies a file after the agent read it, the next write fails with `Stale file`; ask the agent to re-read before editing. |
|
|
50
|
+
| **Standard tool presentation protocol** | Tool authors can declare `outputSchema`, `renderForModel`, `presentCall`, and `presentResult`, so the same result can use an appropriate form in the model context, CLI, and desktop. The CLI visually separates file diffs, web evidence, job receipts, foreground `COMMAND` output, and persistent `TERMINAL` output from the final answer. |
|
|
51
|
+
| **Background Shell / Jobs** | Say "start the dev server in the background" and the agent calls `Shell` with `background: true`. Use `JobList` to view jobs, `JobRead` for incremental output, `JobWait` to wait, and `JobKill` to stop. The CLI shows a color-bordered `JOB` receipt separating job metadata, logs, and the final answer; logs show at most the latest 12 lines and lists at most 8 items. Windows prefers UTF-8 and falls back automatically on GBK/GB18030 system diagnostics. |
|
|
52
|
+
| **Foreground command results** | Foreground `Shell` calls render as state-colored `COMMAND` receipts with separate command, stdout, stderr, and exit regions. Long output keeps the first and last 8 lines and explicitly folds the middle; persistent PTY output uses the distinct `TERMINAL` label. |
|
|
53
|
+
| **Desktop background status** | Electron automatically shows the number of running jobs in the session title bar, updated live on start, output, exit, or cancel. |
|
|
54
|
+
| **Persistent PTY** | Say "open a persistent terminal and keep interacting". The agent uses `TerminalOpen` to create a terminal, `TerminalWrite` for input, `TerminalRead` for incremental output, and `TerminalClose` to close it. |
|
|
55
|
+
| **Unified D2C/E2E process lifecycle** | No usage change. Preview and backend services still start/stop from the E2E/D2C workbench, but the underlying layer unifies output limits, process-tree termination, and idempotent cleanup. |
|
|
56
|
+
| **Native WebSearch** | Say "search the web for ...", or explicitly ask for `WebSearch`. It uses keyless DuckDuckGo Lite by default and degrades to Bing on connection failure, HTTP rejection, or no parseable results; up to 20 results per call. The CLI puts the top 5 into a bordered `WEB SEARCH` evidence block with titles and compact sources in search order. |
|
|
57
|
+
| **Native WebFetch** | Say "read this page: `https://...`", or explicitly ask for `WebFetch`. Supports HTTP(S), redirects, HTML-to-text, timeouts, and response size limits, and is compatible with Clash/TUN Fake-IP DNS. Direct access to Fake-IP, intranet, or cloud metadata addresses is still blocked; network operations still follow Flavor permission approval. |
|
|
58
|
+
|
|
59
|
+
Common precise usage:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
Start npm run dev with Shell in background mode, then use JobRead to inspect the startup logs.
|
|
63
|
+
Open a persistent terminal, run a Python REPL in it, execute two snippets, then close the terminal.
|
|
64
|
+
Use WebSearch to find the official TypeScript 7 migration notes, then WebFetch the most relevant official page.
|
|
65
|
+
This directory has its own conventions; follow src/payments/AGENTS.md before modifying code here.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
See [Technical Design Report §38](./技术方案报告.md#38-129-运行时生产力与原生-web-能力) for tool parameters, state machines, security boundaries, and extension interfaces; acceptance criteria are in the [Runtime productivity spec](./docs/specs/2026-08-13-runtime-productivity-waves.md).
|
|
69
|
+
|
|
40
70
|
## Quick Start
|
|
41
71
|
|
|
42
72
|
> [!IMPORTANT]
|
|
@@ -167,6 +197,8 @@ npm run desktop:dist # Windows NSIS installer
|
|
|
167
197
|
|
|
168
198
|
The desktop app provides project and session switching, streaming Markdown, tool and diff views, permission confirmations, task status, and management of Skills, MCP, memory, and models.
|
|
169
199
|
|
|
200
|
+
The **D2C** module in the sidebar supports a complete design-to-code loop: import a Pixso-exported HTML directory, choose a target framework (Vue 3 / React), and submit the generation task to the current session. The agent implements it under `src/d2c-output/<task>/` following the `d2c-pixso` skill (SOP); a Vite dev server then starts automatically for pixel-level comparison, producing a visual-fidelity score and a structured diff report (region offsets, color deviations, font differences). The results workbench offers overlay, curtain, flicker, and heatmap comparison modes, an SVG annotation layer, and a severity-sorted issue list, so each diff can be accepted or rejected individually and trigger module-level fixes. Once visual review passes, you can import a Swagger/OpenAPI document to auto-generate Axios wrappers and an Express mock server, moving into API integration and interactive acceptance.
|
|
201
|
+
|
|
170
202
|
### VS Code / Qoder
|
|
171
203
|
|
|
172
204
|
```bash
|
|
@@ -338,6 +370,9 @@ npm run build
|
|
|
338
370
|
- [Runtime reliability spec](./docs/specs/2026-07-26-runtime-reliability.md)
|
|
339
371
|
- [Control plane, sandbox & VS Code spec](./docs/specs/2026-07-29-control-plane-sandbox-vscode.md)
|
|
340
372
|
- [Multimodal image attachments spec](./docs/specs/2026-07-30-multimodal-image-attachments.md)
|
|
373
|
+
- [D2C design-to-code spec](./docs/specs/2026-08-09-d2c-design-to-code.md)
|
|
374
|
+
- [D2C review & integration spec](./docs/specs/2026-08-10-d2c-review-and-integration.md)
|
|
375
|
+
- [1.2.9 runtime productivity spec](./docs/specs/2026-08-13-runtime-productivity-waves.md)
|
|
341
376
|
- [VS Code next steps](./docs/specs/2026-08-01-flavor-code-vscode-next.md)
|
|
342
377
|
|
|
343
378
|
## Security Notes
|
package/README.zh-CN.md
CHANGED
|
@@ -32,12 +32,42 @@ Flavor Code 接入 OpenAI、Anthropic 或兼容服务,在受控工作区内使
|
|
|
32
32
|
| | 能力 | 你得到什么 |
|
|
33
33
|
| --- | --- | --- |
|
|
34
34
|
| 🖥️ | **一个运行时,三个入口** | CLI、Electron 与 VS Code 共享模型配置、会话和工具能力 |
|
|
35
|
-
| 🧭 | **复杂任务可控推进** | 任务计划、子 Agent、steering、follow-up、`/loop` 和 `/goal` |
|
|
36
|
-
| ⏪ | **结果可追溯、可恢复** | 完整时间线、checkpoint、rewind、trace、Diff 和失败审计 |
|
|
37
|
-
| 🧠 | **本地长期上下文** | 记忆、Skill、插件和项目指南均保存在本机 |
|
|
38
|
-
|
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
| 🧭 | **复杂任务可控推进** | 任务计划、子 Agent、steering、follow-up、`/loop` 和 `/goal` |
|
|
36
|
+
| ⏪ | **结果可追溯、可恢复** | 完整时间线、checkpoint、rewind、trace、Diff 和失败审计 |
|
|
37
|
+
| 🧠 | **本地长期上下文** | 记忆、Skill、插件和项目指南均保存在本机 |
|
|
38
|
+
| 🎨 | **D2C 设计转代码** | 导入 Pixso 导出结果,由 Agent 生成 Vue/React 实现并自动进行像素级视觉评估(仅 Electron) |
|
|
39
|
+
| 🛡️ | **明确的权限边界** | 分别控制读、写、Shell、网络和破坏性操作,也可使用 Docker |
|
|
40
|
+
|
|
41
|
+
## 1.2.9 运行时生产力
|
|
42
|
+
|
|
43
|
+
1.2.9 新增分层项目指令、安全写入、后台任务、持久终端和原生 Web 工具。通常只需用自然语言描述目标,Agent 会选择合适的工具;需要精确控制时,也可以在提示词中明确指定工具和参数。
|
|
44
|
+
|
|
45
|
+
| 功能 | 使用方式 |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| **分层项目指令** | 在项目根目录或子目录放置 `AGENTS.md` / `CLAUDE.md`;同目录需要本地补充时使用 `AGENTS.local.md` / `CLAUDE.local.md`。根规则启动时加载,子目录规则在 Agent 访问该目录文件时自动加载。 |
|
|
48
|
+
| **每轮成果物汇总** | 无需配置。`Write`、`Edit` 或 `ApplyPatch` 成功后,回合结束会显示带语义色的 `CHANGESET` 收据,使用工作区相对路径列出 `CREATE` / `UPDATE` / `DELETE` 操作、各文件行数和总计。最多展示 8 个文件,超出时明确显示已展示数与总数。 |
|
|
49
|
+
| **文件版本保护** | 无需配置。如果 IDE、格式化器或其他进程在 Agent 读取后修改了文件,后续写入会报 `Stale file`;让 Agent 重新读取后再修改即可。 |
|
|
50
|
+
| **标准工具展示协议** | 工具作者可声明 `outputSchema`、`renderForModel`、`presentCall` 和 `presentResult`,让同一结果在模型上下文、CLI 与桌面端分别使用合适的形式。CLI 会把文件 Diff、Web 证据、Job 运行收据、前台 `COMMAND` 和持久 `TERMINAL` 与最终回答明确分开。 |
|
|
51
|
+
| **后台 Shell / Job** | 提示“在后台启动开发服务器”,Agent 会调用 `Shell` 并设置 `background: true`。使用 `JobList` 查看任务、`JobRead` 增量读取输出、`JobWait` 等待结束、`JobKill` 停止任务。CLI 使用带状态色边界的 `JOB` 收据区分任务元数据、日志与最终回答;日志最多显示最近 12 行,列表最多显示 8 项。Windows 优先使用 UTF-8,遇到 GBK/GB18030 系统诊断时自动回退。 |
|
|
52
|
+
| **前台命令结果** | 前台 `Shell` 显示为带状态色的 `COMMAND` 收据,分别展示命令、stdout、stderr 和退出状态。长输出保留开头 8 行与结尾 8 行,并明确折叠中间部分;持久 PTY 使用独立的 `TERMINAL` 标签。 |
|
|
53
|
+
| **桌面后台状态** | Electron 会在会话标题栏自动显示运行中的 Job 数量,并在任务启动、输出、退出或取消时实时更新。 |
|
|
54
|
+
| **持久 PTY** | 提示“打开一个持久终端并继续交互”。Agent 使用 `TerminalOpen` 创建终端、`TerminalWrite` 输入、`TerminalRead` 增量读取输出,并用 `TerminalClose` 关闭。 |
|
|
55
|
+
| **D2C/E2E 统一进程生命周期** | 使用方式不变。预览和后端服务仍从 E2E/D2C 工作台启动或停止,底层统一处理输出限制、进程树终止和幂等清理。 |
|
|
56
|
+
| **原生 WebSearch** | 提示“搜索 Web 上的……”,或明确要求使用 `WebSearch`。默认使用无需密钥的 DuckDuckGo Lite;连接失败、HTTP 拒绝或没有可解析结果时自动降级到 Bing。单次最多返回 20 条;CLI 将前 5 条放入带边界的 `WEB SEARCH` 证据块,按搜索排名显示标题和紧凑来源。 |
|
|
57
|
+
| **原生 WebFetch** | 提示“读取这个网页:`https://...`”,或明确要求使用 `WebFetch`。支持 HTTP(S)、重定向、HTML 转文本、超时和响应大小限制,并兼容 Clash/TUN Fake-IP DNS。直接访问 Fake-IP、内网或云元数据地址仍会被拦截;网络操作继续遵守 Flavor 权限审批。 |
|
|
58
|
+
|
|
59
|
+
常见的精确用法:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
使用 Shell 后台模式启动 npm run dev,然后通过 JobRead 检查启动日志。
|
|
63
|
+
打开持久终端,在其中运行 Python REPL,连续执行两段代码后关闭终端。
|
|
64
|
+
使用 WebSearch 搜索 TypeScript 7 官方迁移说明,再用 WebFetch 读取最相关的官方页面。
|
|
65
|
+
这个目录有独立约定,请先遵守 src/payments/AGENTS.md 再修改代码。
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
原生工具的参数、状态机、安全边界和扩展接口详见[技术方案报告第 38 节](./技术方案报告.md#38-129-运行时生产力与原生-web-能力);验收规格见[运行时生产力规范](./docs/specs/2026-08-13-runtime-productivity-waves.md)。
|
|
69
|
+
|
|
70
|
+
## 快速开始
|
|
41
71
|
|
|
42
72
|
> [!IMPORTANT]
|
|
43
73
|
> CLI 需要 Node.js 20 或更高版本。Windows 桌面端也可以直接从 [Releases](https://github.com/YachuanWzh/flavor-code/releases) 下载。
|
package/dist/agent/loop.d.ts
CHANGED
|
@@ -19,13 +19,17 @@ export interface AgentLoopOptions {
|
|
|
19
19
|
maxExtensions?: number;
|
|
20
20
|
hasActiveProgress?(): boolean;
|
|
21
21
|
agent?: "main" | "subagent";
|
|
22
|
+
ownerId?: string;
|
|
22
23
|
hallucinationGuard?: HallucinationGuard;
|
|
23
24
|
}
|
|
24
25
|
export declare class AgentLoop {
|
|
25
26
|
#private;
|
|
26
27
|
constructor(options: AgentLoopOptions);
|
|
27
28
|
get modelId(): string;
|
|
29
|
+
get iterationLimitMode(): "standard" | "d2c";
|
|
28
30
|
setModel(modelId: string): void;
|
|
29
31
|
setFallbackModel(modelId: string): void;
|
|
32
|
+
/** D2C keeps a hard cap, but may automatically expand it up to ten times. */
|
|
33
|
+
setIterationLimitMode(mode: "standard" | "d2c"): void;
|
|
30
34
|
run(request: AgentRunRequest): AsyncIterable<AgentEvent>;
|
|
31
35
|
}
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -32,6 +32,12 @@ export interface TaskSnapshot {
|
|
|
32
32
|
};
|
|
33
33
|
foregroundTaskId?: string;
|
|
34
34
|
}
|
|
35
|
+
export interface TurnDeliverable {
|
|
36
|
+
path: string;
|
|
37
|
+
operation: "create" | "update" | "delete";
|
|
38
|
+
added: number;
|
|
39
|
+
removed: number;
|
|
40
|
+
}
|
|
35
41
|
export type AgentEvent = {
|
|
36
42
|
type: "model-start";
|
|
37
43
|
id: string;
|
|
@@ -48,6 +54,7 @@ export type AgentEvent = {
|
|
|
48
54
|
input: unknown;
|
|
49
55
|
label?: string;
|
|
50
56
|
hint?: string;
|
|
57
|
+
presentation?: import("../tools/types.js").ToolPresentation;
|
|
51
58
|
} | {
|
|
52
59
|
type: "tool-end";
|
|
53
60
|
id: string;
|
|
@@ -60,6 +67,9 @@ export type AgentEvent = {
|
|
|
60
67
|
snapshot: TaskSnapshot;
|
|
61
68
|
} | {
|
|
62
69
|
type: "tasks-cleared";
|
|
70
|
+
} | {
|
|
71
|
+
type: "deliverables";
|
|
72
|
+
files: readonly TurnDeliverable[];
|
|
63
73
|
} | {
|
|
64
74
|
type: "usage";
|
|
65
75
|
inputTokens: number;
|
|
@@ -15,8 +15,8 @@ import {
|
|
|
15
15
|
packageVersion,
|
|
16
16
|
redactErrorText,
|
|
17
17
|
transcriptReducer
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import "./chunk-
|
|
18
|
+
} from "./chunk-WGYNTR4Q.js";
|
|
19
|
+
import "./chunk-XFCJXRJ2.js";
|
|
20
20
|
import {
|
|
21
21
|
Box_default,
|
|
22
22
|
ClockContext,
|
|
@@ -33,10 +33,10 @@ import {
|
|
|
33
33
|
useStdout,
|
|
34
34
|
use_app_default,
|
|
35
35
|
use_input_default
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-F2HMO5Q2.js";
|
|
37
37
|
import {
|
|
38
38
|
execFileNoThrow
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-RQTYHUMK.js";
|
|
40
40
|
import "./chunk-S32JRDZK.js";
|
|
41
41
|
|
|
42
42
|
// src/ui/app.tsx
|
|
@@ -2452,11 +2452,11 @@ function TerminalLayout({
|
|
|
2452
2452
|
/* @__PURE__ */ jsx5(Box_default, { height: 1 }),
|
|
2453
2453
|
completed.map((turn, index) => /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", children: [
|
|
2454
2454
|
index > 0 ? /* @__PURE__ */ jsx5(TurnSeparator, { width: columns }) : null,
|
|
2455
|
-
/* @__PURE__ */ jsx5(TurnView, { turn, interactive: false })
|
|
2455
|
+
/* @__PURE__ */ jsx5(TurnView, { turn, interactive: false, workspaceName })
|
|
2456
2456
|
] }, turn.id)),
|
|
2457
2457
|
activeWithoutTasks === void 0 ? null : /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", children: [
|
|
2458
2458
|
completed.length > 0 ? /* @__PURE__ */ jsx5(TurnSeparator, { width: columns }) : null,
|
|
2459
|
-
/* @__PURE__ */ jsx5(TurnView, { turn: activeWithoutTasks, interactive: activeSession })
|
|
2459
|
+
/* @__PURE__ */ jsx5(TurnView, { turn: activeWithoutTasks, interactive: activeSession, workspaceName })
|
|
2460
2460
|
] })
|
|
2461
2461
|
] }),
|
|
2462
2462
|
/* @__PURE__ */ jsx5(
|
|
@@ -2708,11 +2708,15 @@ function scrollUp(scroll, amount) {
|
|
|
2708
2708
|
function TurnSeparator({ width }) {
|
|
2709
2709
|
return /* @__PURE__ */ jsx5(Text, { dimColor: true, children: "\u2500".repeat(Math.max(1, width - 1)) });
|
|
2710
2710
|
}
|
|
2711
|
-
function TurnView({
|
|
2711
|
+
function TurnView({
|
|
2712
|
+
turn,
|
|
2713
|
+
interactive,
|
|
2714
|
+
workspaceName
|
|
2715
|
+
}) {
|
|
2712
2716
|
if (turn.kind === "compaction") {
|
|
2713
2717
|
return /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", marginBottom: 1, borderStyle: "round", borderColor: "ansi:yellowBright", paddingX: 1, children: [
|
|
2714
2718
|
/* @__PURE__ */ jsx5(Text, { color: "ansi:yellowBright", bold: true, children: turn.prompt }),
|
|
2715
|
-
turn.blocks.map((block, index) => block.kind === "status" ? /* @__PURE__ */ jsx5(StatusBlockView, { block, interactive }, block.id) : /* @__PURE__ */ jsx5(Box_default, { children: /* @__PURE__ */ jsx5(AssistantText, { text: block.text }) }, `${turn.id}-text-${index}`))
|
|
2719
|
+
turn.blocks.map((block, index) => block.kind === "status" ? /* @__PURE__ */ jsx5(StatusBlockView, { block, interactive, workspaceName }, block.id) : /* @__PURE__ */ jsx5(Box_default, { children: /* @__PURE__ */ jsx5(AssistantText, { text: block.text }) }, `${turn.id}-text-${index}`))
|
|
2716
2720
|
] });
|
|
2717
2721
|
}
|
|
2718
2722
|
return /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", marginBottom: 1, children: [
|
|
@@ -2723,7 +2727,7 @@ function TurnView({ turn, interactive }) {
|
|
|
2723
2727
|
turn.prompt
|
|
2724
2728
|
] })
|
|
2725
2729
|
] }),
|
|
2726
|
-
/* @__PURE__ */ jsx5(Box_default, { flexDirection: "column", paddingLeft: 2, marginTop: 1, children: turn.blocks.map((block, index) => block.kind === "status" ? /* @__PURE__ */ jsx5(StatusBlockView, { block, interactive }, block.id) : /* @__PURE__ */ jsx5(Box_default, { marginBottom: 1, children: /* @__PURE__ */ jsx5(AssistantText, { text: block.text }) }, `${turn.id}-text-${index}`)) })
|
|
2730
|
+
/* @__PURE__ */ jsx5(Box_default, { flexDirection: "column", paddingLeft: 2, marginTop: 1, children: turn.blocks.map((block, index) => block.kind === "status" ? /* @__PURE__ */ jsx5(StatusBlockView, { block, interactive, workspaceName }, block.id) : /* @__PURE__ */ jsx5(Box_default, { marginBottom: 1, children: /* @__PURE__ */ jsx5(AssistantText, { text: block.text }) }, `${turn.id}-text-${index}`)) })
|
|
2727
2731
|
] });
|
|
2728
2732
|
}
|
|
2729
2733
|
var DIFF_CONTENT = fileDiffLineStyle("context").contentColor;
|
|
@@ -2901,20 +2905,383 @@ function PromptLine({
|
|
|
2901
2905
|
}
|
|
2902
2906
|
function StatusBlockView({
|
|
2903
2907
|
block,
|
|
2904
|
-
interactive
|
|
2908
|
+
interactive,
|
|
2909
|
+
workspaceName
|
|
2905
2910
|
}) {
|
|
2906
2911
|
const visibleBlock = cliToolTitle(block);
|
|
2907
2912
|
const outcome = cliToolOutcome(block);
|
|
2908
|
-
const primary = visibleBlock.activity === "model" || visibleBlock.task !== void 0 ? /* @__PURE__ */ jsx5(TaskStatusLine, { block: visibleBlock, interactive }) : visibleBlock.state === "completed" && visibleBlock.presentation !== void 0 ? /* @__PURE__ */ jsx5(
|
|
2913
|
+
const primary = visibleBlock.activity === "model" || visibleBlock.task !== void 0 ? /* @__PURE__ */ jsx5(TaskStatusLine, { block: visibleBlock, interactive }) : visibleBlock.state === "completed" && visibleBlock.presentation !== void 0 ? /* @__PURE__ */ jsx5(ToolPresentationView, { presentation: visibleBlock.presentation, workspaceName }) : /* @__PURE__ */ jsx5(StatusLine, { block: visibleBlock, interactive });
|
|
2909
2914
|
return /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", children: [
|
|
2910
2915
|
primary,
|
|
2911
2916
|
outcome === void 0 ? null : /* @__PURE__ */ jsx5(Box_default, { paddingLeft: 2, children: /* @__PURE__ */ jsxs4(Text, { dimColor: true, children: [
|
|
2912
2917
|
"\u2514 ",
|
|
2913
2918
|
outcome
|
|
2914
2919
|
] }) }),
|
|
2915
|
-
block.details === void 0 ? null : /* @__PURE__ */ jsx5(Box_default, { paddingLeft: 2, children: /* @__PURE__ */ jsx5(AssistantText, { text: block.details }) })
|
|
2920
|
+
block.details === void 0 || block.presentation?.kind === "changeset" ? null : /* @__PURE__ */ jsx5(Box_default, { paddingLeft: 2, children: /* @__PURE__ */ jsx5(AssistantText, { text: block.details }) })
|
|
2921
|
+
] });
|
|
2922
|
+
}
|
|
2923
|
+
function ToolPresentationView({
|
|
2924
|
+
presentation,
|
|
2925
|
+
workspaceName
|
|
2926
|
+
}) {
|
|
2927
|
+
if (presentation.kind === "changeset") return /* @__PURE__ */ jsx5(ChangeSetPresentationView, { presentation, workspaceName });
|
|
2928
|
+
if (presentation.kind === "file-change") return /* @__PURE__ */ jsx5(FileDiffView, { presentation });
|
|
2929
|
+
if (presentation.kind === "terminal") return /* @__PURE__ */ jsx5(CommandPresentationView, { presentation });
|
|
2930
|
+
if (presentation.kind === "web") return /* @__PURE__ */ jsx5(WebPresentationView, { presentation });
|
|
2931
|
+
if (presentation.kind === "job") return /* @__PURE__ */ jsx5(JobPresentationView, { presentation });
|
|
2932
|
+
return /* @__PURE__ */ jsx5(Box_default, { paddingLeft: 2, children: /* @__PURE__ */ jsxs4(Text, { children: [
|
|
2933
|
+
presentation.title,
|
|
2934
|
+
presentation.summary ? ` \xB7 ${presentation.summary}` : ""
|
|
2935
|
+
] }) });
|
|
2936
|
+
}
|
|
2937
|
+
var CLI_CHANGESET_FILE_LIMIT = 8;
|
|
2938
|
+
var CHANGESET_TONE = "#b99bf8";
|
|
2939
|
+
function ChangeSetPresentationView({
|
|
2940
|
+
presentation,
|
|
2941
|
+
workspaceName
|
|
2942
|
+
}) {
|
|
2943
|
+
const visibleFiles = presentation.files.slice(0, CLI_CHANGESET_FILE_LIMIT);
|
|
2944
|
+
const added = presentation.files.reduce((total, file) => total + file.added, 0);
|
|
2945
|
+
const removed = presentation.files.reduce((total, file) => total + file.removed, 0);
|
|
2946
|
+
const fileLabel = presentation.files.length === 1 ? "FILE" : "FILES";
|
|
2947
|
+
const showing = presentation.files.length > visibleFiles.length ? ` \xB7 Showing ${visibleFiles.length} of ${presentation.files.length}` : "";
|
|
2948
|
+
return /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", paddingLeft: 2, marginBottom: 1, children: [
|
|
2949
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
2950
|
+
/* @__PURE__ */ jsx5(Text, { color: CHANGESET_TONE, children: "\u250C\u2500 " }),
|
|
2951
|
+
/* @__PURE__ */ jsxs4(Text, { color: CHANGESET_TONE, bold: true, children: [
|
|
2952
|
+
"CHANGESET \xB7 ",
|
|
2953
|
+
presentation.files.length,
|
|
2954
|
+
" ",
|
|
2955
|
+
fileLabel
|
|
2956
|
+
] })
|
|
2957
|
+
] }),
|
|
2958
|
+
visibleFiles.map((file) => {
|
|
2959
|
+
const operation = file.operation.toUpperCase();
|
|
2960
|
+
const stats = `+${file.added} -${file.removed}`;
|
|
2961
|
+
return /* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
2962
|
+
/* @__PURE__ */ jsx5(Text, { color: CHANGESET_TONE, children: "\u2502 " }),
|
|
2963
|
+
/* @__PURE__ */ jsx5(Text, { color: changeSetOperationColor(file.operation), bold: true, children: operation.padEnd(8) }),
|
|
2964
|
+
/* @__PURE__ */ jsxs4(Text, { children: [
|
|
2965
|
+
/* @__PURE__ */ jsxs4(Text, { color: "ansi:green", children: [
|
|
2966
|
+
"+",
|
|
2967
|
+
file.added
|
|
2968
|
+
] }),
|
|
2969
|
+
" ",
|
|
2970
|
+
/* @__PURE__ */ jsxs4(Text, { color: "#e06c50", children: [
|
|
2971
|
+
"-",
|
|
2972
|
+
file.removed
|
|
2973
|
+
] }),
|
|
2974
|
+
" ".repeat(Math.max(1, 9 - stats.length))
|
|
2975
|
+
] }),
|
|
2976
|
+
/* @__PURE__ */ jsx5(Text, { color: "ansi:whiteBright", wrap: "truncate-end", children: workspaceRelativePath(file.path, workspaceName) })
|
|
2977
|
+
] }, `${file.operation}:${file.path}`);
|
|
2978
|
+
}),
|
|
2979
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
2980
|
+
/* @__PURE__ */ jsx5(Text, { color: CHANGESET_TONE, children: "\u2514\u2500 " }),
|
|
2981
|
+
/* @__PURE__ */ jsxs4(Text, { children: [
|
|
2982
|
+
/* @__PURE__ */ jsxs4(Text, { color: "ansi:green", children: [
|
|
2983
|
+
"+",
|
|
2984
|
+
added
|
|
2985
|
+
] }),
|
|
2986
|
+
" ",
|
|
2987
|
+
/* @__PURE__ */ jsxs4(Text, { color: "#e06c50", children: [
|
|
2988
|
+
"-",
|
|
2989
|
+
removed
|
|
2990
|
+
] }),
|
|
2991
|
+
/* @__PURE__ */ jsx5(Text, { dimColor: true, children: showing })
|
|
2992
|
+
] })
|
|
2993
|
+
] })
|
|
2994
|
+
] });
|
|
2995
|
+
}
|
|
2996
|
+
function changeSetOperationColor(operation) {
|
|
2997
|
+
if (operation === "create") return "ansi:green";
|
|
2998
|
+
if (operation === "delete") return "#e06c50";
|
|
2999
|
+
return "ansi:cyanBright";
|
|
3000
|
+
}
|
|
3001
|
+
function workspaceRelativePath(value, workspaceName) {
|
|
3002
|
+
const normalized = value.replace(/\\/gu, "/");
|
|
3003
|
+
const marker = `/${workspaceName}/`;
|
|
3004
|
+
const markerIndex = normalized.toLocaleLowerCase().lastIndexOf(marker.toLocaleLowerCase());
|
|
3005
|
+
if (markerIndex >= 0) return normalized.slice(markerIndex + marker.length);
|
|
3006
|
+
const rootPrefix = `${workspaceName}/`;
|
|
3007
|
+
if (normalized.toLocaleLowerCase().startsWith(rootPrefix.toLocaleLowerCase())) return normalized.slice(rootPrefix.length);
|
|
3008
|
+
return normalized;
|
|
3009
|
+
}
|
|
3010
|
+
var CLI_COMMAND_OUTPUT_LINE_LIMIT = 16;
|
|
3011
|
+
function CommandPresentationView({
|
|
3012
|
+
presentation
|
|
3013
|
+
}) {
|
|
3014
|
+
const state = presentation.state ?? commandState(presentation.exitCode);
|
|
3015
|
+
const tone = jobStateColor(state);
|
|
3016
|
+
const label = presentation.variant === "terminal" ? "TERMINAL" : "COMMAND";
|
|
3017
|
+
const hasStdout = jobOutputLines(presentation.stdout ?? "").length > 0;
|
|
3018
|
+
const hasStderr = jobOutputLines(presentation.stderr ?? "").length > 0;
|
|
3019
|
+
const perStreamLimit = hasStdout && hasStderr ? Math.floor(CLI_COMMAND_OUTPUT_LINE_LIMIT / 2) : CLI_COMMAND_OUTPUT_LINE_LIMIT;
|
|
3020
|
+
const stdout = boundedCommandLines(presentation.stdout ?? "", perStreamLimit);
|
|
3021
|
+
const stderr = boundedCommandLines(presentation.stderr ?? "", perStreamLimit);
|
|
3022
|
+
return /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", paddingLeft: 2, marginBottom: 1, children: [
|
|
3023
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3024
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u250C\u2500 " }),
|
|
3025
|
+
/* @__PURE__ */ jsxs4(Text, { color: tone, bold: true, children: [
|
|
3026
|
+
label,
|
|
3027
|
+
" \xB7 ",
|
|
3028
|
+
state.toUpperCase()
|
|
3029
|
+
] })
|
|
3030
|
+
] }),
|
|
3031
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3032
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u2502 " }),
|
|
3033
|
+
/* @__PURE__ */ jsx5(Text, { color: "ansi:whiteBright", bold: true, wrap: "truncate-end", children: presentation.command ?? presentation.title })
|
|
3034
|
+
] }),
|
|
3035
|
+
stdout.total === 0 ? null : /* @__PURE__ */ jsx5(CommandOutputSection, { label: "OUTPUT", value: stdout, tone, error: false }),
|
|
3036
|
+
stderr.total === 0 ? null : /* @__PURE__ */ jsx5(CommandOutputSection, { label: "ERROR", value: stderr, tone, error: true }),
|
|
3037
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3038
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u2514\u2500 " }),
|
|
3039
|
+
/* @__PURE__ */ jsx5(Text, { dimColor: true, children: commandFooter(presentation, state) })
|
|
3040
|
+
] })
|
|
3041
|
+
] });
|
|
3042
|
+
}
|
|
3043
|
+
function CommandOutputSection({
|
|
3044
|
+
label,
|
|
3045
|
+
value,
|
|
3046
|
+
tone,
|
|
3047
|
+
error
|
|
3048
|
+
}) {
|
|
3049
|
+
return /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
3050
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3051
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u251C\u2500 " }),
|
|
3052
|
+
/* @__PURE__ */ jsx5(Text, { color: error ? "#e06c50" : tone, bold: true, children: label }),
|
|
3053
|
+
/* @__PURE__ */ jsx5(Text, { dimColor: true, children: ` \xB7 ${value.total} ${value.total === 1 ? "LINE" : "LINES"}` })
|
|
3054
|
+
] }),
|
|
3055
|
+
value.head.map((line, index) => /* @__PURE__ */ jsx5(CommandOutputLine, { line, tone, error }, `head:${index}`)),
|
|
3056
|
+
value.hidden === 0 ? null : /* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3057
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u2502 " }),
|
|
3058
|
+
/* @__PURE__ */ jsxs4(Text, { dimColor: true, children: [
|
|
3059
|
+
"\u2026 ",
|
|
3060
|
+
value.hidden,
|
|
3061
|
+
" ",
|
|
3062
|
+
value.hidden === 1 ? "line" : "lines",
|
|
3063
|
+
" hidden"
|
|
3064
|
+
] })
|
|
3065
|
+
] }),
|
|
3066
|
+
value.tail.map((line, index) => /* @__PURE__ */ jsx5(CommandOutputLine, { line, tone, error }, `tail:${index}`))
|
|
3067
|
+
] });
|
|
3068
|
+
}
|
|
3069
|
+
function CommandOutputLine({ line, tone, error }) {
|
|
3070
|
+
return /* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3071
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u2502 " }),
|
|
3072
|
+
/* @__PURE__ */ jsx5(Text, { color: error ? "#e06c50" : "#b8bcc2", wrap: "truncate-end", children: line === "" ? " " : line })
|
|
3073
|
+
] });
|
|
3074
|
+
}
|
|
3075
|
+
function boundedCommandLines(output, limit) {
|
|
3076
|
+
const lines = jobOutputLines(output);
|
|
3077
|
+
if (lines.length <= limit) return { total: lines.length, head: lines, tail: [], hidden: 0 };
|
|
3078
|
+
const headCount = Math.ceil(limit / 2);
|
|
3079
|
+
const tailCount = Math.floor(limit / 2);
|
|
3080
|
+
return {
|
|
3081
|
+
total: lines.length,
|
|
3082
|
+
head: lines.slice(0, headCount),
|
|
3083
|
+
tail: lines.slice(-tailCount),
|
|
3084
|
+
hidden: lines.length - headCount - tailCount
|
|
3085
|
+
};
|
|
3086
|
+
}
|
|
3087
|
+
function commandState(exitCode) {
|
|
3088
|
+
if (exitCode === void 0) return "running";
|
|
3089
|
+
return exitCode === 0 ? "completed" : "failed";
|
|
3090
|
+
}
|
|
3091
|
+
function commandFooter(presentation, state) {
|
|
3092
|
+
const parts = [presentation.exitCode === void 0 ? state : presentation.exitCode === null ? "no exit code" : `exit ${presentation.exitCode}`];
|
|
3093
|
+
if (presentation.truncated === true) parts.push("output truncated");
|
|
3094
|
+
return parts.join(" \xB7 ");
|
|
3095
|
+
}
|
|
3096
|
+
var CLI_WEB_RESULT_LIMIT = 5;
|
|
3097
|
+
function WebPresentationView({
|
|
3098
|
+
presentation
|
|
3099
|
+
}) {
|
|
3100
|
+
const items = presentation.items ?? [];
|
|
3101
|
+
if (presentation.items === void 0) return /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", paddingLeft: 2, marginBottom: 1, children: [
|
|
3102
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3103
|
+
/* @__PURE__ */ jsx5(Text, { color: "#5f87af", children: "\u250C\u2500 " }),
|
|
3104
|
+
/* @__PURE__ */ jsx5(Text, { color: "ansi:cyanBright", bold: true, children: "WEB FETCH" }),
|
|
3105
|
+
presentation.summary === void 0 ? null : /* @__PURE__ */ jsx5(Text, { dimColor: true, children: ` \xB7 ${presentation.summary}` })
|
|
3106
|
+
] }),
|
|
3107
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3108
|
+
/* @__PURE__ */ jsx5(Text, { color: "#5f87af", children: "\u2502 " }),
|
|
3109
|
+
/* @__PURE__ */ jsx5(Text, { color: "ansi:whiteBright", wrap: "truncate-end", children: presentation.url ?? presentation.title })
|
|
3110
|
+
] }),
|
|
3111
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3112
|
+
/* @__PURE__ */ jsx5(Text, { color: "#5f87af", children: "\u2514\u2500 " }),
|
|
3113
|
+
/* @__PURE__ */ jsx5(Text, { dimColor: true, children: "Page content added to context" })
|
|
3114
|
+
] })
|
|
3115
|
+
] });
|
|
3116
|
+
const visibleItems = items.slice(0, CLI_WEB_RESULT_LIMIT);
|
|
3117
|
+
const query = presentation.title.replace(/^Search:\s*/iu, "").trim();
|
|
3118
|
+
return /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", paddingLeft: 2, marginBottom: 1, children: [
|
|
3119
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3120
|
+
/* @__PURE__ */ jsx5(Text, { color: "#5f87af", children: "\u250C\u2500 " }),
|
|
3121
|
+
/* @__PURE__ */ jsx5(Text, { color: "ansi:cyanBright", bold: true, children: "WEB SEARCH" }),
|
|
3122
|
+
/* @__PURE__ */ jsx5(Text, { dimColor: true, children: ` \xB7 ${items.length} ${items.length === 1 ? "RESULT" : "RESULTS"}` })
|
|
3123
|
+
] }),
|
|
3124
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3125
|
+
/* @__PURE__ */ jsx5(Text, { color: "#5f87af", children: "\u2502 " }),
|
|
3126
|
+
/* @__PURE__ */ jsx5(Text, { color: "ansi:whiteBright", bold: true, wrap: "truncate-end", children: query })
|
|
3127
|
+
] }),
|
|
3128
|
+
/* @__PURE__ */ jsx5(Text, { color: "#5f87af", children: "\u2502" }),
|
|
3129
|
+
visibleItems.map((item, index) => /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", children: [
|
|
3130
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3131
|
+
/* @__PURE__ */ jsx5(Text, { color: "#5f87af", children: "\u2502 " }),
|
|
3132
|
+
/* @__PURE__ */ jsx5(Text, { color: "ansi:cyanBright", bold: true, children: String(index + 1).padStart(2, "0") }),
|
|
3133
|
+
/* @__PURE__ */ jsxs4(Text, { color: "ansi:whiteBright", wrap: "truncate-end", children: [
|
|
3134
|
+
" ",
|
|
3135
|
+
item.title
|
|
3136
|
+
] })
|
|
3137
|
+
] }),
|
|
3138
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3139
|
+
/* @__PURE__ */ jsx5(Text, { color: "#5f87af", children: "\u2502 " }),
|
|
3140
|
+
/* @__PURE__ */ jsx5(Text, { dimColor: true, wrap: "truncate-end", children: compactWebSource(item.url) })
|
|
3141
|
+
] })
|
|
3142
|
+
] }, item.url)),
|
|
3143
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3144
|
+
/* @__PURE__ */ jsx5(Text, { color: "#5f87af", children: "\u2514\u2500 " }),
|
|
3145
|
+
/* @__PURE__ */ jsx5(Text, { dimColor: true, children: items.length > visibleItems.length ? `Showing ${visibleItems.length} of ${items.length}` : `${items.length} ${items.length === 1 ? "source" : "sources"}` })
|
|
3146
|
+
] })
|
|
3147
|
+
] });
|
|
3148
|
+
}
|
|
3149
|
+
function compactWebSource(value) {
|
|
3150
|
+
try {
|
|
3151
|
+
const url = new URL(value);
|
|
3152
|
+
const hostname = url.hostname.replace(/^www\./iu, "");
|
|
3153
|
+
const path = url.pathname === "/" ? "" : url.pathname.replace(/\/$/u, "");
|
|
3154
|
+
return `${hostname}${path}`;
|
|
3155
|
+
} catch {
|
|
3156
|
+
return value;
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
var CLI_JOB_LOG_LINE_LIMIT = 12;
|
|
3160
|
+
var CLI_JOB_LIST_LIMIT = 8;
|
|
3161
|
+
function JobPresentationView({
|
|
3162
|
+
presentation
|
|
3163
|
+
}) {
|
|
3164
|
+
if (presentation.action === "list") return /* @__PURE__ */ jsx5(JobListPresentationView, { presentation });
|
|
3165
|
+
const state = presentation.state ?? "running";
|
|
3166
|
+
const tone = jobStateColor(state);
|
|
3167
|
+
const lines = jobOutputLines(presentation.output ?? "");
|
|
3168
|
+
const visibleLines = lines.slice(-CLI_JOB_LOG_LINE_LIMIT);
|
|
3169
|
+
const hiddenLines = lines.length - visibleLines.length;
|
|
3170
|
+
const showLog = presentation.action === "read" || presentation.action === "kill" || lines.length > 0;
|
|
3171
|
+
return /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", paddingLeft: 2, marginBottom: 1, children: [
|
|
3172
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3173
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u250C\u2500 " }),
|
|
3174
|
+
/* @__PURE__ */ jsxs4(Text, { color: tone, bold: true, children: [
|
|
3175
|
+
"JOB \xB7 ",
|
|
3176
|
+
state.toUpperCase()
|
|
3177
|
+
] })
|
|
3178
|
+
] }),
|
|
3179
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3180
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u2502 " }),
|
|
3181
|
+
/* @__PURE__ */ jsx5(Text, { color: "ansi:whiteBright", bold: true, children: presentation.id ?? "unknown job" }),
|
|
3182
|
+
presentation.jobKind === void 0 ? null : /* @__PURE__ */ jsx5(Text, { dimColor: true, children: ` \xB7 ${presentation.jobKind}` })
|
|
3183
|
+
] }),
|
|
3184
|
+
presentation.label === void 0 ? null : /* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3185
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u2502 " }),
|
|
3186
|
+
/* @__PURE__ */ jsx5(Text, { color: "ansi:whiteBright", wrap: "truncate-end", children: presentation.label })
|
|
3187
|
+
] }),
|
|
3188
|
+
presentation.error === void 0 ? null : /* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3189
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u2502 " }),
|
|
3190
|
+
/* @__PURE__ */ jsx5(Text, { color: "#e06c50", wrap: "truncate-end", children: presentation.error })
|
|
3191
|
+
] }),
|
|
3192
|
+
showLog ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
3193
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3194
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u251C\u2500 " }),
|
|
3195
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, bold: true, children: "LOG" }),
|
|
3196
|
+
/* @__PURE__ */ jsx5(Text, { dimColor: true, children: lines.length === 0 ? " \xB7 NO NEW OUTPUT" : ` \xB7 ${lines.length} ${lines.length === 1 ? "LINE" : "LINES"}` })
|
|
3197
|
+
] }),
|
|
3198
|
+
hiddenLines > 0 ? /* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3199
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u2502 " }),
|
|
3200
|
+
/* @__PURE__ */ jsxs4(Text, { dimColor: true, children: [
|
|
3201
|
+
"\u2026 ",
|
|
3202
|
+
hiddenLines,
|
|
3203
|
+
" earlier ",
|
|
3204
|
+
hiddenLines === 1 ? "line" : "lines",
|
|
3205
|
+
" hidden"
|
|
3206
|
+
] })
|
|
3207
|
+
] }) : null,
|
|
3208
|
+
visibleLines.map((line, index) => /* @__PURE__ */ jsx5(JobLogLine, { line, tone }, `${index}:${line}`))
|
|
3209
|
+
] }) : null,
|
|
3210
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3211
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u2514\u2500 " }),
|
|
3212
|
+
/* @__PURE__ */ jsx5(Text, { dimColor: true, children: jobFooter(presentation) })
|
|
3213
|
+
] })
|
|
2916
3214
|
] });
|
|
2917
3215
|
}
|
|
3216
|
+
function JobListPresentationView({
|
|
3217
|
+
presentation
|
|
3218
|
+
}) {
|
|
3219
|
+
const jobs = presentation.jobs ?? [];
|
|
3220
|
+
const visibleJobs = jobs.slice(0, CLI_JOB_LIST_LIMIT);
|
|
3221
|
+
return /* @__PURE__ */ jsxs4(Box_default, { flexDirection: "column", paddingLeft: 2, marginBottom: 1, children: [
|
|
3222
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3223
|
+
/* @__PURE__ */ jsx5(Text, { color: "#d7a657", children: "\u250C\u2500 " }),
|
|
3224
|
+
/* @__PURE__ */ jsxs4(Text, { color: "#d7a657", bold: true, children: [
|
|
3225
|
+
"JOBS \xB7 ",
|
|
3226
|
+
jobs.length
|
|
3227
|
+
] })
|
|
3228
|
+
] }),
|
|
3229
|
+
jobs.length === 0 ? /* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3230
|
+
/* @__PURE__ */ jsx5(Text, { color: "#d7a657", children: "\u2502 " }),
|
|
3231
|
+
/* @__PURE__ */ jsx5(Text, { dimColor: true, children: "No background jobs" })
|
|
3232
|
+
] }) : visibleJobs.map((job) => /* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3233
|
+
/* @__PURE__ */ jsx5(Text, { color: "#d7a657", children: "\u2502 " }),
|
|
3234
|
+
/* @__PURE__ */ jsx5(Text, { color: jobStateColor(job.state), bold: true, children: job.state.toUpperCase().padEnd(9) }),
|
|
3235
|
+
/* @__PURE__ */ jsxs4(Text, { color: "ansi:whiteBright", children: [
|
|
3236
|
+
" ",
|
|
3237
|
+
job.id
|
|
3238
|
+
] }),
|
|
3239
|
+
/* @__PURE__ */ jsxs4(Text, { dimColor: true, wrap: "truncate-end", children: [
|
|
3240
|
+
" \xB7 ",
|
|
3241
|
+
job.label
|
|
3242
|
+
] })
|
|
3243
|
+
] }, job.id)),
|
|
3244
|
+
/* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3245
|
+
/* @__PURE__ */ jsx5(Text, { color: "#d7a657", children: "\u2514\u2500 " }),
|
|
3246
|
+
/* @__PURE__ */ jsx5(Text, { dimColor: true, children: jobs.length > visibleJobs.length ? `Showing ${visibleJobs.length} of ${jobs.length}` : `${jobs.length} ${jobs.length === 1 ? "job" : "jobs"}` })
|
|
3247
|
+
] })
|
|
3248
|
+
] });
|
|
3249
|
+
}
|
|
3250
|
+
function JobLogLine({ line, tone }) {
|
|
3251
|
+
const error = /^(?:\[stderr\]|ERR(?:OR)?(?:!|:|\s)|npm ERR!)/iu.test(line.trimStart());
|
|
3252
|
+
const stage = /^={3}.*={3}$/u.test(line.trim());
|
|
3253
|
+
return /* @__PURE__ */ jsxs4(Box_default, { children: [
|
|
3254
|
+
/* @__PURE__ */ jsx5(Text, { color: tone, children: "\u2502 " }),
|
|
3255
|
+
/* @__PURE__ */ jsx5(
|
|
3256
|
+
Text,
|
|
3257
|
+
{
|
|
3258
|
+
...error ? { color: "#e06c50" } : stage ? { color: "ansi:cyanBright", bold: true } : { dimColor: true },
|
|
3259
|
+
wrap: "truncate-end",
|
|
3260
|
+
children: line === "" ? " " : line
|
|
3261
|
+
}
|
|
3262
|
+
)
|
|
3263
|
+
] });
|
|
3264
|
+
}
|
|
3265
|
+
function jobOutputLines(output) {
|
|
3266
|
+
if (output === "") return [];
|
|
3267
|
+
const lines = output.replace(/\r\n?/gu, "\n").split("\n");
|
|
3268
|
+
if (lines.at(-1) === "") lines.pop();
|
|
3269
|
+
return lines;
|
|
3270
|
+
}
|
|
3271
|
+
function jobStateColor(state) {
|
|
3272
|
+
if (state === "completed") return "ansi:green";
|
|
3273
|
+
if (state === "failed") return "#e06c50";
|
|
3274
|
+
if (state === "cancelled") return "#858585";
|
|
3275
|
+
return "#d7a657";
|
|
3276
|
+
}
|
|
3277
|
+
function jobFooter(presentation) {
|
|
3278
|
+
const parts = [];
|
|
3279
|
+
if (presentation.exitCode !== void 0) parts.push(presentation.exitCode === null ? "no exit code" : `exit ${presentation.exitCode}`);
|
|
3280
|
+
else parts.push(presentation.state ?? "running");
|
|
3281
|
+
if (presentation.cursor !== void 0) parts.push(`cursor ${presentation.cursor}`);
|
|
3282
|
+
if (presentation.truncated === true) parts.push("output truncated");
|
|
3283
|
+
return parts.join(" \xB7 ");
|
|
3284
|
+
}
|
|
2918
3285
|
function cliToolTitle(block) {
|
|
2919
3286
|
if (block.tool === void 0 || block.presentation !== void 0) return block;
|
|
2920
3287
|
const input = record(block.tool.input);
|