@couralabs/claudin 0.1.5 → 0.1.6
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/claudin.js +577 -167
- package/package.json +1 -1
package/claudin.js
CHANGED
|
@@ -5928,6 +5928,12 @@ var backgroundColorSchema = object({
|
|
|
5928
5928
|
a: channelSchema
|
|
5929
5929
|
});
|
|
5930
5930
|
var TRANSPARENT_BACKGROUND = { r: 0, g: 0, b: 0, a: 0 };
|
|
5931
|
+
// packages/events/src/models/customTools.ts
|
|
5932
|
+
var CUSTOM_SERVER_NAME = "claudin";
|
|
5933
|
+
var BATCH_EDIT_BASE_NAME = "BatchEdit";
|
|
5934
|
+
var BATCH_EDIT_TOOL_NAME = `mcp__${CUSTOM_SERVER_NAME}__${BATCH_EDIT_BASE_NAME}`;
|
|
5935
|
+
var CUSTOM_PREFIX = `mcp__${CUSTOM_SERVER_NAME}__`;
|
|
5936
|
+
var stripCustomPrefix = (toolName) => toolName.startsWith(CUSTOM_PREFIX) ? toolName.slice(CUSTOM_PREFIX.length) : toolName;
|
|
5931
5937
|
// packages/events/src/models/fileDiff.ts
|
|
5932
5938
|
var fileDiffSchema = object({
|
|
5933
5939
|
path: string2(),
|
|
@@ -6064,6 +6070,7 @@ function appendEntry(state, entry) {
|
|
|
6064
6070
|
};
|
|
6065
6071
|
}
|
|
6066
6072
|
var appendNotice = (state, text) => appendEntry(state, { kind: "notice", text });
|
|
6073
|
+
var appendMarkdownNotice = (state, text) => appendEntry(state, { kind: "notice", text, markdown: true });
|
|
6067
6074
|
|
|
6068
6075
|
// packages/events/src/reducers/reduceHistory.ts
|
|
6069
6076
|
var NO_MATCH_NOTICE = "No earlier prompt matches";
|
|
@@ -6111,6 +6118,7 @@ var agentSessionId = string2();
|
|
|
6111
6118
|
var content = sdkValue();
|
|
6112
6119
|
var agentOptions = sdkValue().optional();
|
|
6113
6120
|
var effortLevelSchema = _enum(["low", "medium", "high", "xhigh", "max"]);
|
|
6121
|
+
var DEFAULT_EFFORT = "high";
|
|
6114
6122
|
var permissionModeSchema = _enum(["auto", "acceptEdits", "bypassPermissions", "dontAsk"]);
|
|
6115
6123
|
var DEFAULT_PERMISSION_MODE = "bypassPermissions";
|
|
6116
6124
|
var PERMISSION_MODE_LABELS = {
|
|
@@ -6145,8 +6153,6 @@ var agentRequestSchemas = [
|
|
|
6145
6153
|
options: agentOptions
|
|
6146
6154
|
}),
|
|
6147
6155
|
object({ type: literal("agent.prompt.requested"), agentSessionId, content }),
|
|
6148
|
-
object({ type: literal("agent.prompt.queue.requested"), agentSessionId, content }),
|
|
6149
|
-
object({ type: literal("agent.prompt.steer.requested"), agentSessionId, content }),
|
|
6150
6156
|
object({ type: literal("agent.prompt.cancel.requested"), agentSessionId }),
|
|
6151
6157
|
object({ type: literal("agent.task.stop.requested"), agentSessionId, taskId: string2() }),
|
|
6152
6158
|
object({
|
|
@@ -6218,6 +6224,7 @@ var createSessionState = (sessionId) => ({
|
|
|
6218
6224
|
models: [],
|
|
6219
6225
|
sessionList: [],
|
|
6220
6226
|
queuedTurns: 0,
|
|
6227
|
+
queuedPrompts: [],
|
|
6221
6228
|
tasks: [],
|
|
6222
6229
|
transcript: [],
|
|
6223
6230
|
entryCounter: 0,
|
|
@@ -6317,10 +6324,11 @@ function describeSystemMessage(message) {
|
|
|
6317
6324
|
var OPEN_STATUSES = new Set(["running", "awaiting_approval", "awaiting_answer"]);
|
|
6318
6325
|
var isToolsEntry = (entry) => entry.kind === "tools";
|
|
6319
6326
|
var listToolCalls = (state) => state.transcript.filter(isToolsEntry).flatMap((entry) => entry.calls);
|
|
6320
|
-
var EDIT_TOOLS = new Set(["Write", "Edit", "MultiEdit", "
|
|
6321
|
-
var
|
|
6327
|
+
var EDIT_TOOLS = new Set(["Write", "Edit", "MultiEdit", "mcp__claudin__BatchEdit"]);
|
|
6328
|
+
var listBatchEditPaths = (input) => Array.isArray(input.edits) ? input.edits.map((edit) => edit?.file_path) : [];
|
|
6329
|
+
var readEditedPaths = (call) => call.name === BATCH_EDIT_TOOL_NAME ? listBatchEditPaths(call.input) : EDIT_TOOLS.has(call.name) ? [call.input.file_path ?? call.input.notebook_path] : [];
|
|
6322
6330
|
var listEditedFiles = (state) => [
|
|
6323
|
-
...new Set(listToolCalls(state).filter((call) =>
|
|
6331
|
+
...new Set(listToolCalls(state).filter((call) => call.status === "completed").flatMap(readEditedPaths).filter((path) => typeof path === "string"))
|
|
6324
6332
|
];
|
|
6325
6333
|
function countTurnTools(state) {
|
|
6326
6334
|
const lastUser = state.transcript.findLastIndex((entry) => entry.kind === "user");
|
|
@@ -6519,6 +6527,43 @@ function reduceStreamEvent(state, event) {
|
|
|
6519
6527
|
}
|
|
6520
6528
|
}
|
|
6521
6529
|
|
|
6530
|
+
// packages/events/src/reducers/reduceTaskModel.ts
|
|
6531
|
+
var readMessageModel = (message) => {
|
|
6532
|
+
if (message.type === "assistant")
|
|
6533
|
+
return message.message.model;
|
|
6534
|
+
if (message.type !== "stream_event")
|
|
6535
|
+
return;
|
|
6536
|
+
const event = message.event;
|
|
6537
|
+
return event.type === "message_start" ? event.message?.model : undefined;
|
|
6538
|
+
};
|
|
6539
|
+
var readRequestedModel = (state, toolUseId) => {
|
|
6540
|
+
const model = listToolCalls(state).find((call) => call.id === toolUseId)?.input.model;
|
|
6541
|
+
return typeof model === "string" ? model : undefined;
|
|
6542
|
+
};
|
|
6543
|
+
function reduceTaskModel(state, message) {
|
|
6544
|
+
if (message.type !== "assistant" && message.type !== "stream_event")
|
|
6545
|
+
return state;
|
|
6546
|
+
const model = readMessageModel(message);
|
|
6547
|
+
const parentId = message.parent_tool_use_id;
|
|
6548
|
+
const stale = (task) => task.toolUseId === parentId && task.model !== model;
|
|
6549
|
+
if (!model || !parentId || !state.tasks.some(stale))
|
|
6550
|
+
return state;
|
|
6551
|
+
const tasks = state.tasks.map((task) => stale(task) ? { ...task, model } : task);
|
|
6552
|
+
return { ...state, tasks };
|
|
6553
|
+
}
|
|
6554
|
+
|
|
6555
|
+
// packages/events/src/reducers/reduceTaskToolUse.ts
|
|
6556
|
+
function reduceTaskToolUse(state, message) {
|
|
6557
|
+
if (message.type !== "assistant" || !message.parent_tool_use_id)
|
|
6558
|
+
return state;
|
|
6559
|
+
const call = message.message.content.findLast((block) => block.type === "tool_use");
|
|
6560
|
+
if (call?.type !== "tool_use")
|
|
6561
|
+
return state;
|
|
6562
|
+
const lastToolCall = { name: call.name, input: call.input ?? {} };
|
|
6563
|
+
const tasks = state.tasks.map((task) => task.toolUseId === message.parent_tool_use_id ? { ...task, lastToolCall } : task);
|
|
6564
|
+
return { ...state, tasks };
|
|
6565
|
+
}
|
|
6566
|
+
|
|
6522
6567
|
// packages/events/src/reducers/reduceTaskProgress.ts
|
|
6523
6568
|
function reduceTaskProgress(state, message) {
|
|
6524
6569
|
const { tool_use_id: toolUseId, summary } = message;
|
|
@@ -6539,6 +6584,8 @@ var startTask = (state, message) => {
|
|
|
6539
6584
|
kind: message.subagent_type ?? message.task_type ?? "task",
|
|
6540
6585
|
description: message.description,
|
|
6541
6586
|
startedAt: state.now,
|
|
6587
|
+
toolUseId: message.tool_use_id,
|
|
6588
|
+
model: readRequestedModel(state, message.tool_use_id),
|
|
6542
6589
|
tokens: 0,
|
|
6543
6590
|
paused: false
|
|
6544
6591
|
};
|
|
@@ -6609,9 +6656,12 @@ function reduceAgentMessage(state, message) {
|
|
|
6609
6656
|
};
|
|
6610
6657
|
case "stream_event":
|
|
6611
6658
|
if (message.parent_tool_use_id)
|
|
6612
|
-
return state;
|
|
6659
|
+
return reduceTaskModel(state, message);
|
|
6613
6660
|
return reduceStreamEvent(state, message.event);
|
|
6614
6661
|
case "assistant":
|
|
6662
|
+
if (message.parent_tool_use_id) {
|
|
6663
|
+
return reduceTaskToolUse(reduceTaskModel(state, message), message);
|
|
6664
|
+
}
|
|
6615
6665
|
return reduceAssistant(state, message);
|
|
6616
6666
|
case "user":
|
|
6617
6667
|
return isPromptEcho(message) ? reduceCheckpoint(state, message) : reduceToolResults(state, message);
|
|
@@ -6628,7 +6678,8 @@ function reduceTaskMessage(state, message) {
|
|
|
6628
6678
|
return reduceTaskProgress(state, message);
|
|
6629
6679
|
}
|
|
6630
6680
|
if (message.type === "system" && message.subtype === "task_notification") {
|
|
6631
|
-
|
|
6681
|
+
const text = describeSystemMessage(message);
|
|
6682
|
+
return text ? appendMarkdownNotice(state, text) : state;
|
|
6632
6683
|
}
|
|
6633
6684
|
return state;
|
|
6634
6685
|
}
|
|
@@ -6812,6 +6863,23 @@ function changeQuestionCustom(state, text) {
|
|
|
6812
6863
|
return question ? withDraft(state, { ...question, custom: text }) : state;
|
|
6813
6864
|
}
|
|
6814
6865
|
|
|
6866
|
+
// packages/events/src/reducers/reduceTheme.ts
|
|
6867
|
+
var applyLoadedTheme = (state, theme = state.theme) => ({
|
|
6868
|
+
...state,
|
|
6869
|
+
theme
|
|
6870
|
+
});
|
|
6871
|
+
var applySavedTheme = (state, theme) => appendNotice({ ...state, theme }, `Theme set to ${theme}`);
|
|
6872
|
+
|
|
6873
|
+
// packages/events/src/reducers/reducePromptQueue.ts
|
|
6874
|
+
var queuePrompt = (state, content) => ({
|
|
6875
|
+
...state,
|
|
6876
|
+
queuedPrompts: [...state.queuedPrompts, content]
|
|
6877
|
+
});
|
|
6878
|
+
var dequeuePrompt = (state) => ({
|
|
6879
|
+
...state,
|
|
6880
|
+
queuedPrompts: state.queuedPrompts.slice(1)
|
|
6881
|
+
});
|
|
6882
|
+
|
|
6815
6883
|
// packages/events/src/reducers/reduceToast.ts
|
|
6816
6884
|
var withToast = (state, toast) => ({
|
|
6817
6885
|
...state,
|
|
@@ -6839,6 +6907,8 @@ var pickerSize = (state, kind) => {
|
|
|
6839
6907
|
return state.models.length;
|
|
6840
6908
|
if (kind === "theme")
|
|
6841
6909
|
return THEME_NAMES.length;
|
|
6910
|
+
if (kind === "effort")
|
|
6911
|
+
return effortLevelSchema.options.length;
|
|
6842
6912
|
if (kind === "rewind")
|
|
6843
6913
|
return listCheckpoints(state).length;
|
|
6844
6914
|
return state.sessionList.length;
|
|
@@ -6857,6 +6927,11 @@ var openThemePicker = (state) => {
|
|
|
6857
6927
|
const selected = Math.max(THEME_NAMES.indexOf(state.theme), 0);
|
|
6858
6928
|
return { ...state, ui: { ...state.ui, picker: { kind: "theme", selected } } };
|
|
6859
6929
|
};
|
|
6930
|
+
var openEffortPicker = (state) => {
|
|
6931
|
+
const current = state.effort || DEFAULT_EFFORT;
|
|
6932
|
+
const selected = Math.max(effortLevelSchema.options.findIndex((level) => level === current), 0);
|
|
6933
|
+
return { ...state, ui: { ...state.ui, picker: { kind: "effort", selected } } };
|
|
6934
|
+
};
|
|
6860
6935
|
function openRewindPicker(state) {
|
|
6861
6936
|
const size = listCheckpoints(state).length;
|
|
6862
6937
|
if (size === 0)
|
|
@@ -6881,8 +6956,12 @@ function reduceUi(state, event) {
|
|
|
6881
6956
|
return { ...state, ui: { ...state.ui, picker: null } };
|
|
6882
6957
|
case "ui.theme.picker.opened":
|
|
6883
6958
|
return openThemePicker(state);
|
|
6884
|
-
case "ui.
|
|
6885
|
-
return
|
|
6959
|
+
case "ui.effort.picker.opened":
|
|
6960
|
+
return openEffortPicker(state);
|
|
6961
|
+
case "ui.prompt.queued":
|
|
6962
|
+
return queuePrompt(state, event.content);
|
|
6963
|
+
case "ui.prompt.dequeued":
|
|
6964
|
+
return dequeuePrompt(state);
|
|
6886
6965
|
case "ui.rewind.picker.opened":
|
|
6887
6966
|
return openRewindPicker(state);
|
|
6888
6967
|
case "ui.history.moved":
|
|
@@ -6961,9 +7040,6 @@ var reduceTimedEvent = (state, event, at) => reduceSessionState({ ...state, now:
|
|
|
6961
7040
|
function reduceSessionState(state, event) {
|
|
6962
7041
|
switch (event.type) {
|
|
6963
7042
|
case "agent.prompt.requested":
|
|
6964
|
-
return reducePrompt(state, event.content, false);
|
|
6965
|
-
case "agent.prompt.queue.requested":
|
|
6966
|
-
case "agent.prompt.steer.requested":
|
|
6967
7043
|
return reducePrompt(state, event.content, state.status !== "idle");
|
|
6968
7044
|
case "agent.message.received":
|
|
6969
7045
|
return reduceAgentMessage(state, event.message);
|
|
@@ -7040,9 +7116,11 @@ function reduceSessionState(state, event) {
|
|
|
7040
7116
|
case "workspace.info.received":
|
|
7041
7117
|
return { ...state, cwd: event.cwd, gitBranch: event.gitBranch, gitStats: event.gitStats };
|
|
7042
7118
|
case "options.loaded":
|
|
7043
|
-
return applyLoadedBackground(state, event.background);
|
|
7119
|
+
return applyLoadedTheme(applyLoadedBackground(state, event.background), event.theme);
|
|
7044
7120
|
case "options.background.saved":
|
|
7045
7121
|
return applySavedBackground(state, event.color);
|
|
7122
|
+
case "options.theme.saved":
|
|
7123
|
+
return applySavedTheme(state, event.theme);
|
|
7046
7124
|
case "workspace.files.received":
|
|
7047
7125
|
return updateFileMatches(state, event.query, event.matches);
|
|
7048
7126
|
default:
|
|
@@ -7055,13 +7133,22 @@ var optionsRequestSchemas = [
|
|
|
7055
7133
|
object({
|
|
7056
7134
|
type: literal("options.background.save.requested"),
|
|
7057
7135
|
color: backgroundColorSchema
|
|
7058
|
-
})
|
|
7136
|
+
}),
|
|
7137
|
+
object({ type: literal("options.theme.save.requested"), theme: themeNameSchema })
|
|
7059
7138
|
];
|
|
7060
7139
|
var optionsResponseSchemas = [
|
|
7061
|
-
object({
|
|
7062
|
-
|
|
7140
|
+
object({
|
|
7141
|
+
type: literal("options.loaded"),
|
|
7142
|
+
background: backgroundColorSchema.optional(),
|
|
7143
|
+
theme: themeNameSchema.optional()
|
|
7144
|
+
}),
|
|
7145
|
+
object({ type: literal("options.background.saved"), color: backgroundColorSchema }),
|
|
7146
|
+
object({ type: literal("options.theme.saved"), theme: themeNameSchema })
|
|
7063
7147
|
];
|
|
7064
|
-
var optionsFileSchema = looseObject({
|
|
7148
|
+
var optionsFileSchema = looseObject({
|
|
7149
|
+
background: backgroundColorSchema.optional(),
|
|
7150
|
+
theme: themeNameSchema.optional()
|
|
7151
|
+
});
|
|
7065
7152
|
// packages/events/src/requests/sessionRequestEvents.ts
|
|
7066
7153
|
var sessionRequestSchemas = [
|
|
7067
7154
|
object({ type: literal("session.create.requested") }),
|
|
@@ -7122,7 +7209,6 @@ var agentResponseSchemas = [
|
|
|
7122
7209
|
}),
|
|
7123
7210
|
object({ type: literal("agent.session.created"), agentSessionId: agentSessionId2 }),
|
|
7124
7211
|
object({ type: literal("agent.message.received"), message: unknown() }),
|
|
7125
|
-
object({ type: literal("agent.prompt.accepted"), agentSessionId: agentSessionId2 }),
|
|
7126
7212
|
object({ type: literal("agent.prompt.cancelled"), agentSessionId: agentSessionId2 }),
|
|
7127
7213
|
object({
|
|
7128
7214
|
type: literal("agent.tool.approval.required"),
|
|
@@ -7532,11 +7618,10 @@ var sdkRuntime = {
|
|
|
7532
7618
|
};
|
|
7533
7619
|
// packages/agent/src/runtime/buildUserMessage.ts
|
|
7534
7620
|
var isSlashCommand = (content) => readPromptText(content).trimStart().startsWith("/");
|
|
7535
|
-
var buildUserMessage = (content
|
|
7621
|
+
var buildUserMessage = (content) => ({
|
|
7536
7622
|
type: "user",
|
|
7537
7623
|
message: { role: "user", content },
|
|
7538
7624
|
parent_tool_use_id: null,
|
|
7539
|
-
priority,
|
|
7540
7625
|
client_composed: isSlashCommand(content) ? undefined : true
|
|
7541
7626
|
});
|
|
7542
7627
|
// node_modules/.bun/p-defer@4.0.1/node_modules/p-defer/index.js
|
|
@@ -8761,6 +8846,110 @@ class PermissionGate {
|
|
|
8761
8846
|
}
|
|
8762
8847
|
}
|
|
8763
8848
|
|
|
8849
|
+
// packages/agent/src/tools/customToolsServer.ts
|
|
8850
|
+
import { createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
|
|
8851
|
+
|
|
8852
|
+
// packages/agent/src/tools/batchEdit/batchEditTool.ts
|
|
8853
|
+
import { tool } from "@anthropic-ai/claude-agent-sdk";
|
|
8854
|
+
|
|
8855
|
+
// packages/agent/src/tools/batchEdit/batchEditSchema.ts
|
|
8856
|
+
var textEditSchema = object({
|
|
8857
|
+
file_path: string2().describe("Absolute path of the file to modify"),
|
|
8858
|
+
old_string: string2().describe("Exact text to replace; empty only to create a new file with new_string"),
|
|
8859
|
+
new_string: string2().describe("Replacement text; must differ from old_string"),
|
|
8860
|
+
replace_all: boolean2().optional().describe("Replace every occurrence of old_string")
|
|
8861
|
+
});
|
|
8862
|
+
var batchEditShape = {
|
|
8863
|
+
edits: array(textEditSchema).min(1).describe("Edits applied in order; edits to one file see the result of earlier ones")
|
|
8864
|
+
};
|
|
8865
|
+
|
|
8866
|
+
// packages/agent/src/tools/batchEdit/stageEdits.ts
|
|
8867
|
+
import { isAbsolute, resolve } from "path";
|
|
8868
|
+
|
|
8869
|
+
// packages/agent/src/tools/batchEdit/applyTextEdit.ts
|
|
8870
|
+
var failEdit = (reason) => ({ ok: false, reason });
|
|
8871
|
+
function applyTextEdit(content, edit) {
|
|
8872
|
+
const { old_string: oldText, new_string: newText, replace_all: replaceAll } = edit;
|
|
8873
|
+
if (oldText === newText)
|
|
8874
|
+
return failEdit("old_string and new_string are identical");
|
|
8875
|
+
if (oldText === "") {
|
|
8876
|
+
return content === "" ? { ok: true, content: newText, replacements: 1 } : failEdit("old_string is empty but the file already has content");
|
|
8877
|
+
}
|
|
8878
|
+
const parts = content.split(oldText);
|
|
8879
|
+
const matches = parts.length - 1;
|
|
8880
|
+
if (matches === 0)
|
|
8881
|
+
return failEdit("old_string was not found in the file");
|
|
8882
|
+
if (matches > 1 && !replaceAll) {
|
|
8883
|
+
return failEdit(`old_string matches ${matches} times; add context or set replace_all`);
|
|
8884
|
+
}
|
|
8885
|
+
return { ok: true, content: parts.join(newText), replacements: matches };
|
|
8886
|
+
}
|
|
8887
|
+
|
|
8888
|
+
// packages/agent/src/tools/batchEdit/stageEdits.ts
|
|
8889
|
+
var failStage = (index, edit, reason) => ({
|
|
8890
|
+
ok: false,
|
|
8891
|
+
message: `Edit ${index + 1} (${edit.file_path}): ${reason}`
|
|
8892
|
+
});
|
|
8893
|
+
async function stageEdits(edits, readFile) {
|
|
8894
|
+
const files = new Map;
|
|
8895
|
+
for (const [index, edit] of edits.entries()) {
|
|
8896
|
+
if (!isAbsolute(edit.file_path))
|
|
8897
|
+
return failStage(index, edit, "file_path must be absolute");
|
|
8898
|
+
const path = resolve(edit.file_path);
|
|
8899
|
+
const current = files.get(path)?.content ?? await readFile(path);
|
|
8900
|
+
if (current === undefined && edit.old_string !== "") {
|
|
8901
|
+
return failStage(index, edit, "the file does not exist");
|
|
8902
|
+
}
|
|
8903
|
+
const outcome = applyTextEdit(current ?? "", edit);
|
|
8904
|
+
if (!outcome.ok)
|
|
8905
|
+
return failStage(index, edit, outcome.reason);
|
|
8906
|
+
const replacements = (files.get(path)?.replacements ?? 0) + outcome.replacements;
|
|
8907
|
+
files.set(path, { content: outcome.content, replacements });
|
|
8908
|
+
}
|
|
8909
|
+
return { ok: true, files };
|
|
8910
|
+
}
|
|
8911
|
+
|
|
8912
|
+
// packages/agent/src/tools/batchEdit/runBatchEdit.ts
|
|
8913
|
+
var readFileText = async (path) => {
|
|
8914
|
+
const file = Bun.file(path);
|
|
8915
|
+
return await file.exists() ? file.text() : undefined;
|
|
8916
|
+
};
|
|
8917
|
+
var describeFiles = (files) => [...files].map(([path, { replacements }]) => `- ${path}: ${replacements} replacement(s)`).join(`
|
|
8918
|
+
`);
|
|
8919
|
+
async function runBatchEdit(edits, readFile = readFileText) {
|
|
8920
|
+
const staged = await stageEdits(edits, readFile);
|
|
8921
|
+
if (!staged.ok) {
|
|
8922
|
+
return { isError: true, text: `${staged.message}
|
|
8923
|
+
No files were changed.` };
|
|
8924
|
+
}
|
|
8925
|
+
try {
|
|
8926
|
+
await Promise.all([...staged.files].map(([path, { content }]) => Bun.write(path, content)));
|
|
8927
|
+
} catch (error) {
|
|
8928
|
+
return { isError: true, text: `Writing failed, files may be partly changed: ${error}` };
|
|
8929
|
+
}
|
|
8930
|
+
return {
|
|
8931
|
+
isError: false,
|
|
8932
|
+
text: `Applied ${edits.length} edit(s) to ${staged.files.size} file(s):
|
|
8933
|
+
${describeFiles(staged.files)}`
|
|
8934
|
+
};
|
|
8935
|
+
}
|
|
8936
|
+
|
|
8937
|
+
// packages/agent/src/tools/batchEdit/batchEditTool.ts
|
|
8938
|
+
var DESCRIPTION = `Apply many exact-string edits across one or more files in a single call. Each edit works like Edit (file_path, old_string, new_string, replace_all). Edits run in order, and edits to the same file build on each other. The batch is all-or-nothing: if any edit fails validation, no file is changed.`;
|
|
8939
|
+
var batchEditTool = tool(BATCH_EDIT_BASE_NAME, DESCRIPTION, batchEditShape, async ({ edits }) => {
|
|
8940
|
+
const { isError, text } = await runBatchEdit(edits);
|
|
8941
|
+
return { isError, content: [{ type: "text", text }] };
|
|
8942
|
+
});
|
|
8943
|
+
|
|
8944
|
+
// packages/agent/src/tools/customToolsServer.ts
|
|
8945
|
+
var CUSTOM_MCP_SERVERS = {
|
|
8946
|
+
[CUSTOM_SERVER_NAME]: createSdkMcpServer({
|
|
8947
|
+
name: CUSTOM_SERVER_NAME,
|
|
8948
|
+
tools: [batchEditTool],
|
|
8949
|
+
alwaysLoad: true
|
|
8950
|
+
})
|
|
8951
|
+
};
|
|
8952
|
+
|
|
8764
8953
|
// packages/agent/src/profile/adhdSystemPrompt.ts
|
|
8765
8954
|
var ADHD_SYSTEM_PROMPT = `For the rest of this session, shape every response for a reader with ADHD. The output is not just brief; it is shaped so an ADHD brain can act on it.
|
|
8766
8955
|
|
|
@@ -8875,8 +9064,7 @@ var AGENT_TOOLS = [
|
|
|
8875
9064
|
"TodoWrite",
|
|
8876
9065
|
"AskUserQuestion",
|
|
8877
9066
|
"Write",
|
|
8878
|
-
"Edit"
|
|
8879
|
-
"NotebookEdit"
|
|
9067
|
+
"Edit"
|
|
8880
9068
|
];
|
|
8881
9069
|
var AGENT_DISALLOWED_TOOLS = [
|
|
8882
9070
|
"Agent(Explore)",
|
|
@@ -8903,11 +9091,12 @@ var TOOL_USAGE = {
|
|
|
8903
9091
|
AskUserQuestion: "ask the user",
|
|
8904
9092
|
Write: "create new files with content",
|
|
8905
9093
|
Edit: "update files",
|
|
8906
|
-
|
|
9094
|
+
mcp__claudin__BatchEdit: "update files mutiples files or multiple replaces in same file"
|
|
8907
9095
|
};
|
|
8908
9096
|
var TOOL_GUIDANCE = `Always use the dedicated tool, never a workaround:
|
|
8909
9097
|
${AGENT_TOOLS.map((tool) => `- Use *${tool}* to ${TOOL_USAGE[tool]}`).join(`
|
|
8910
|
-
`)}
|
|
9098
|
+
`)}
|
|
9099
|
+
- Use *${BATCH_EDIT_TOOL_NAME}* instead of repeated *Edit* calls to make several edits, across one or many files, in one call`;
|
|
8911
9100
|
|
|
8912
9101
|
// packages/agent/src/profile/agentSystemPrompt.ts
|
|
8913
9102
|
var AGENT_SYSTEM_PROMPT = [ADHD_SYSTEM_PROMPT, TOOL_GUIDANCE, SUBAGENT_GUIDANCE].join(`
|
|
@@ -8917,6 +9106,8 @@ var AGENT_SYSTEM_PROMPT = [ADHD_SYSTEM_PROMPT, TOOL_GUIDANCE, SUBAGENT_GUIDANCE]
|
|
|
8917
9106
|
// packages/agent/src/profile/agentProfile.ts
|
|
8918
9107
|
var AGENT_PROFILE_OPTIONS = {
|
|
8919
9108
|
tools: AGENT_TOOLS,
|
|
9109
|
+
mcpServers: CUSTOM_MCP_SERVERS,
|
|
9110
|
+
toolAliases: { [BATCH_EDIT_BASE_NAME]: BATCH_EDIT_TOOL_NAME },
|
|
8920
9111
|
disallowedTools: AGENT_DISALLOWED_TOOLS,
|
|
8921
9112
|
systemPrompt: AGENT_SYSTEM_PROMPT,
|
|
8922
9113
|
agents: AGENT_SUBAGENTS,
|
|
@@ -8951,11 +9142,25 @@ var AGENT_PROFILE_OPTIONS = {
|
|
|
8951
9142
|
includeHookEvents: true
|
|
8952
9143
|
};
|
|
8953
9144
|
|
|
8954
|
-
// packages/agent/src/session/
|
|
8955
|
-
|
|
8956
|
-
|
|
9145
|
+
// packages/agent/src/session/readLiveTaskIds.ts
|
|
9146
|
+
var FINISHED_STATUSES2 = ["completed", "failed", "killed"];
|
|
9147
|
+
var withTask = (current, id) => new Set([...current, id]);
|
|
9148
|
+
var withoutTask = (current, id) => new Set([...current].filter((taskId) => taskId !== id));
|
|
9149
|
+
function readLiveTaskIds(message, current) {
|
|
9150
|
+
if (message.type !== "system")
|
|
8957
9151
|
return current;
|
|
8958
|
-
|
|
9152
|
+
switch (message.subtype) {
|
|
9153
|
+
case "background_tasks_changed":
|
|
9154
|
+
return new Set(message.tasks.filter((task) => !task.ambient).map((task) => task.task_id));
|
|
9155
|
+
case "task_started":
|
|
9156
|
+
return message.ambient ? current : withTask(current, message.task_id);
|
|
9157
|
+
case "task_updated":
|
|
9158
|
+
return FINISHED_STATUSES2.includes(message.patch.status ?? "") ? withoutTask(current, message.task_id) : current;
|
|
9159
|
+
case "task_notification":
|
|
9160
|
+
return withoutTask(current, message.task_id);
|
|
9161
|
+
default:
|
|
9162
|
+
return current;
|
|
9163
|
+
}
|
|
8959
9164
|
}
|
|
8960
9165
|
|
|
8961
9166
|
// packages/agent/src/session/agentSession.ts
|
|
@@ -8972,7 +9177,7 @@ class AgentSession {
|
|
|
8972
9177
|
elicitations;
|
|
8973
9178
|
query;
|
|
8974
9179
|
pendingTurns = 0;
|
|
8975
|
-
|
|
9180
|
+
liveTaskIds = new Set;
|
|
8976
9181
|
pumping = false;
|
|
8977
9182
|
constructor(agentSessionId, baseOptions, runtime) {
|
|
8978
9183
|
this.baseOptions = baseOptions;
|
|
@@ -8988,13 +9193,13 @@ class AgentSession {
|
|
|
8988
9193
|
}
|
|
8989
9194
|
});
|
|
8990
9195
|
}
|
|
8991
|
-
prompt(content
|
|
8992
|
-
this.send(content
|
|
9196
|
+
prompt(content) {
|
|
9197
|
+
this.send(content);
|
|
8993
9198
|
return this.streamTurn();
|
|
8994
9199
|
}
|
|
8995
|
-
send(content
|
|
9200
|
+
send(content) {
|
|
8996
9201
|
this.pendingTurns += 1;
|
|
8997
|
-
this.input.push(buildUserMessage(content
|
|
9202
|
+
this.input.push(buildUserMessage(content));
|
|
8998
9203
|
}
|
|
8999
9204
|
async* streamTurn() {
|
|
9000
9205
|
if (this.pumping)
|
|
@@ -9094,11 +9299,11 @@ class AgentSession {
|
|
|
9094
9299
|
if (done)
|
|
9095
9300
|
break;
|
|
9096
9301
|
sink.push({ type: "agent.message.received", message: value });
|
|
9097
|
-
this.
|
|
9302
|
+
this.liveTaskIds = readLiveTaskIds(value, this.liveTaskIds);
|
|
9098
9303
|
if (value.type !== "result")
|
|
9099
9304
|
continue;
|
|
9100
9305
|
this.pendingTurns = Math.max(this.pendingTurns - 1, 0);
|
|
9101
|
-
if (this.pendingTurns === 0 && this.
|
|
9306
|
+
if (this.pendingTurns === 0 && this.liveTaskIds.size === 0)
|
|
9102
9307
|
break;
|
|
9103
9308
|
}
|
|
9104
9309
|
sink.end();
|
|
@@ -9165,19 +9370,21 @@ async function readOptions2(path) {
|
|
|
9165
9370
|
const parsed = optionsFileSchema.safeParse(stored);
|
|
9166
9371
|
return parsed.success ? parsed.data : {};
|
|
9167
9372
|
}
|
|
9168
|
-
async
|
|
9169
|
-
await Bun.write(path, JSON.stringify({ ...await readOptions2(path),
|
|
9170
|
-
}
|
|
9373
|
+
var saveOption = async (path, option) => {
|
|
9374
|
+
await Bun.write(path, JSON.stringify({ ...await readOptions2(path), ...option }, null, 2));
|
|
9375
|
+
};
|
|
9376
|
+
var saveBackground = (path, background) => saveOption(path, { background });
|
|
9377
|
+
var saveTheme = (path, theme) => saveOption(path, { theme });
|
|
9171
9378
|
|
|
9172
9379
|
// packages/daemon/src/workspace/resolvePath.ts
|
|
9173
9380
|
import { stat } from "fs/promises";
|
|
9174
9381
|
import { homedir as homedir2 } from "os";
|
|
9175
|
-
import { join as join3, resolve } from "path";
|
|
9382
|
+
import { join as join3, resolve as resolve2 } from "path";
|
|
9176
9383
|
var isDirectory = async (path) => (await stat(path).catch(() => {
|
|
9177
9384
|
return;
|
|
9178
9385
|
}))?.isDirectory() ?? false;
|
|
9179
9386
|
var expandHome = (path) => path === "~" || path.startsWith("~/") ? join3(homedir2(), path.slice(1)) : path;
|
|
9180
|
-
var resolveUserPath = (base, path) =>
|
|
9387
|
+
var resolveUserPath = (base, path) => resolve2(base, expandHome(path.trim()));
|
|
9181
9388
|
|
|
9182
9389
|
// packages/daemon/src/server/daemonContext.ts
|
|
9183
9390
|
var SESSIONS_DIRECTORY = join4(homedir3(), ".claudin", "sessions");
|
|
@@ -9245,11 +9452,7 @@ async function createDaemonContext(store = new FileSessionStore(SESSIONS_DIRECTO
|
|
|
9245
9452
|
// packages/daemon/src/client/replayClient.ts
|
|
9246
9453
|
var MAX_GAP_MS = 1500;
|
|
9247
9454
|
var READ_ONLY_REASON = "Replay is read-only";
|
|
9248
|
-
var PROMPT_TYPES = new Set([
|
|
9249
|
-
"agent.prompt.requested",
|
|
9250
|
-
"agent.prompt.queue.requested",
|
|
9251
|
-
"agent.prompt.steer.requested"
|
|
9252
|
-
]);
|
|
9455
|
+
var PROMPT_TYPES = new Set(["agent.prompt.requested"]);
|
|
9253
9456
|
|
|
9254
9457
|
class ReplayClient {
|
|
9255
9458
|
stored;
|
|
@@ -9362,16 +9565,6 @@ var agentHandlers = {
|
|
|
9362
9565
|
async* "agent.prompt.requested"({ agents }, request) {
|
|
9363
9566
|
yield* agents.requireSession(request.agentSessionId).prompt(request.content);
|
|
9364
9567
|
},
|
|
9365
|
-
async* "agent.prompt.queue.requested"({ agents }, request) {
|
|
9366
|
-
const turn = agents.requireSession(request.agentSessionId).prompt(request.content, "later");
|
|
9367
|
-
yield { type: "agent.prompt.accepted", agentSessionId: request.agentSessionId };
|
|
9368
|
-
yield* turn;
|
|
9369
|
-
},
|
|
9370
|
-
async* "agent.prompt.steer.requested"({ agents }, request) {
|
|
9371
|
-
const turn = agents.requireSession(request.agentSessionId).prompt(request.content, "now");
|
|
9372
|
-
yield { type: "agent.prompt.accepted", agentSessionId: request.agentSessionId };
|
|
9373
|
-
yield* turn;
|
|
9374
|
-
},
|
|
9375
9568
|
async* "agent.prompt.cancel.requested"({ agents }, request) {
|
|
9376
9569
|
await agents.requireSession(request.agentSessionId).cancel();
|
|
9377
9570
|
yield { type: "agent.prompt.cancelled", agentSessionId: request.agentSessionId };
|
|
@@ -9455,12 +9648,16 @@ var agentHandlers = {
|
|
|
9455
9648
|
// packages/daemon/src/handlers/optionsHandlers.ts
|
|
9456
9649
|
var optionsHandlers = {
|
|
9457
9650
|
async* "options.load.requested"({ optionsPath }) {
|
|
9458
|
-
const { background } = await readOptions2(optionsPath);
|
|
9459
|
-
yield { type: "options.loaded", background };
|
|
9651
|
+
const { background, theme } = await readOptions2(optionsPath);
|
|
9652
|
+
yield { type: "options.loaded", background, theme };
|
|
9460
9653
|
},
|
|
9461
9654
|
async* "options.background.save.requested"({ optionsPath }, request) {
|
|
9462
9655
|
await saveBackground(optionsPath, request.color);
|
|
9463
9656
|
yield { type: "options.background.saved", color: request.color };
|
|
9657
|
+
},
|
|
9658
|
+
async* "options.theme.save.requested"({ optionsPath }, request) {
|
|
9659
|
+
await saveTheme(optionsPath, request.theme);
|
|
9660
|
+
yield { type: "options.theme.saved", theme: request.theme };
|
|
9464
9661
|
}
|
|
9465
9662
|
};
|
|
9466
9663
|
|
|
@@ -9496,14 +9693,14 @@ var sessionHandlers = {
|
|
|
9496
9693
|
};
|
|
9497
9694
|
|
|
9498
9695
|
// packages/daemon/src/workspace/readFileDiffs.ts
|
|
9499
|
-
import { relative, resolve as
|
|
9696
|
+
import { relative, resolve as resolve3 } from "path";
|
|
9500
9697
|
var isTracked = async (cwd, path) => (await Bun.$`git ls-files --error-unmatch -- ${path}`.cwd(cwd).quiet().nothrow()).exitCode === 0;
|
|
9501
9698
|
async function readPatch(cwd, path) {
|
|
9502
9699
|
const command = await isTracked(cwd, path) ? Bun.$`git diff --no-color HEAD -- ${path}` : Bun.$`git diff --no-color --no-index -- /dev/null ${path}`;
|
|
9503
9700
|
return (await command.cwd(cwd).quiet().nothrow()).text();
|
|
9504
9701
|
}
|
|
9505
9702
|
async function readFileDiff(cwd, path) {
|
|
9506
|
-
const absolute =
|
|
9703
|
+
const absolute = resolve3(cwd, path);
|
|
9507
9704
|
const patch = await readPatch(cwd, absolute);
|
|
9508
9705
|
return {
|
|
9509
9706
|
path: relative(cwd, absolute) || path,
|
|
@@ -11211,7 +11408,7 @@ async function startDaemon(port = DEFAULT_PORT, context) {
|
|
|
11211
11408
|
}
|
|
11212
11409
|
// apps/tui/src/startTui.ts
|
|
11213
11410
|
import {
|
|
11214
|
-
BoxRenderable as
|
|
11411
|
+
BoxRenderable as BoxRenderable19,
|
|
11215
11412
|
createCliRenderer,
|
|
11216
11413
|
createHostClipboard
|
|
11217
11414
|
} from "@opentui/core";
|
|
@@ -11253,7 +11450,7 @@ function buildPalette(colors, background = TRANSPARENT_BACKGROUND) {
|
|
|
11253
11450
|
},
|
|
11254
11451
|
fg: {
|
|
11255
11452
|
primary: hex("text"),
|
|
11256
|
-
secondary: rgbToHex2(tint(color("text"), color("textMuted"), SECONDARY_TEXT_WEIGHT)),
|
|
11453
|
+
secondary: hex("secondary") ?? rgbToHex2(tint(color("text"), color("textMuted"), SECONDARY_TEXT_WEIGHT)),
|
|
11257
11454
|
muted: hex("textMuted")
|
|
11258
11455
|
},
|
|
11259
11456
|
border: { subtle: hex("borderSubtle"), focus: hex("borderActive"), separator: hex("border") },
|
|
@@ -11264,7 +11461,38 @@ function buildPalette(colors, background = TRANSPARENT_BACKGROUND) {
|
|
|
11264
11461
|
warning: hex("warning"),
|
|
11265
11462
|
info: hex("info")
|
|
11266
11463
|
},
|
|
11267
|
-
diff: {
|
|
11464
|
+
diff: {
|
|
11465
|
+
addedBg: hex("diffAddedBg"),
|
|
11466
|
+
removedBg: hex("diffRemovedBg"),
|
|
11467
|
+
contextBg: hex("diffContextBg"),
|
|
11468
|
+
addedText: hex("diffAdded"),
|
|
11469
|
+
removedText: hex("diffRemoved"),
|
|
11470
|
+
contextText: hex("diffContext"),
|
|
11471
|
+
lineNumber: hex("diffLineNumber"),
|
|
11472
|
+
addedLineNumberBg: hex("diffAddedLineNumberBg"),
|
|
11473
|
+
removedLineNumberBg: hex("diffRemovedLineNumberBg")
|
|
11474
|
+
},
|
|
11475
|
+
syntax: {
|
|
11476
|
+
comment: hex("syntaxComment"),
|
|
11477
|
+
keyword: hex("syntaxKeyword"),
|
|
11478
|
+
function: hex("syntaxFunction"),
|
|
11479
|
+
variable: hex("syntaxVariable"),
|
|
11480
|
+
string: hex("syntaxString"),
|
|
11481
|
+
number: hex("syntaxNumber"),
|
|
11482
|
+
type: hex("syntaxType"),
|
|
11483
|
+
operator: hex("syntaxOperator"),
|
|
11484
|
+
punctuation: hex("syntaxPunctuation")
|
|
11485
|
+
},
|
|
11486
|
+
markdown: {
|
|
11487
|
+
heading: hex("markdownHeading"),
|
|
11488
|
+
strong: hex("markdownStrong"),
|
|
11489
|
+
emphasis: hex("markdownEmph"),
|
|
11490
|
+
listItem: hex("markdownListItem"),
|
|
11491
|
+
blockQuote: hex("markdownBlockQuote"),
|
|
11492
|
+
code: hex("markdownCode"),
|
|
11493
|
+
link: hex("markdownLink"),
|
|
11494
|
+
linkText: hex("markdownLinkText")
|
|
11495
|
+
}
|
|
11268
11496
|
};
|
|
11269
11497
|
}
|
|
11270
11498
|
// apps/tui/src/theme/assets/aura.json
|
|
@@ -18733,10 +18961,16 @@ var createDiffView = (renderer, syntaxStyle, patch, filetype) => new DiffRendera
|
|
|
18733
18961
|
syntaxStyle,
|
|
18734
18962
|
view: "unified",
|
|
18735
18963
|
showLineNumbers: true,
|
|
18964
|
+
fg: Theme.fg.primary,
|
|
18736
18965
|
addedBg: Theme.diff.addedBg,
|
|
18737
18966
|
removedBg: Theme.diff.removedBg,
|
|
18738
|
-
|
|
18739
|
-
|
|
18967
|
+
contextBg: Theme.diff.contextBg,
|
|
18968
|
+
lineNumberFg: Theme.diff.lineNumber,
|
|
18969
|
+
lineNumberBg: Theme.diff.contextBg,
|
|
18970
|
+
addedLineNumberBg: Theme.diff.addedLineNumberBg,
|
|
18971
|
+
removedLineNumberBg: Theme.diff.removedLineNumberBg,
|
|
18972
|
+
addedSignColor: Theme.diff.addedText,
|
|
18973
|
+
removedSignColor: Theme.diff.removedText,
|
|
18740
18974
|
flexShrink: 0
|
|
18741
18975
|
});
|
|
18742
18976
|
|
|
@@ -19025,11 +19259,11 @@ var buildImageBlock = (mediaType, bytes) => ({
|
|
|
19025
19259
|
// apps/tui/src/prompt/pastedPaths.ts
|
|
19026
19260
|
import { statSync } from "fs";
|
|
19027
19261
|
import { homedir as homedir6 } from "os";
|
|
19028
|
-
import { isAbsolute } from "path";
|
|
19262
|
+
import { isAbsolute as isAbsolute2 } from "path";
|
|
19029
19263
|
var unwrapPath = (raw) => raw.trim().replace(/^(['"])(.*)\1$/, "$2").replace(/^file:\/\//, "").replace(/^~(?=\/)/, homedir6()).replace(/\\(.)/g, "$1");
|
|
19030
19264
|
var isExistingFile = (path) => {
|
|
19031
19265
|
try {
|
|
19032
|
-
return
|
|
19266
|
+
return isAbsolute2(path) && statSync(path).isFile();
|
|
19033
19267
|
} catch {
|
|
19034
19268
|
return false;
|
|
19035
19269
|
}
|
|
@@ -19075,7 +19309,7 @@ function planPaste(event, attachments) {
|
|
|
19075
19309
|
|
|
19076
19310
|
// apps/tui/src/components/promptInput.ts
|
|
19077
19311
|
var MAX_INPUT_LINES = 8;
|
|
19078
|
-
var
|
|
19312
|
+
var BUSY_PLACEHOLDER = "Enter (steer) Ctrl+Q (queue)";
|
|
19079
19313
|
var ATTACHMENT_STYLE = "attachment";
|
|
19080
19314
|
var PLACEHOLDER = "Type your prompt, /slash command, or @file reference...";
|
|
19081
19315
|
var KEY_BINDINGS = [
|
|
@@ -19097,12 +19331,11 @@ class PromptInput {
|
|
|
19097
19331
|
constructor(renderer, handlers) {
|
|
19098
19332
|
this.renderable = new BoxRenderable5(renderer, {
|
|
19099
19333
|
border: ["top", "bottom"],
|
|
19334
|
+
borderColor: Theme.fg.muted,
|
|
19100
19335
|
borderStyle: "rounded",
|
|
19101
|
-
bottomTitleAlignment: "right",
|
|
19102
19336
|
flexDirection: "row",
|
|
19103
19337
|
height: 3,
|
|
19104
|
-
flexShrink: 0
|
|
19105
|
-
paddingLeft: 1
|
|
19338
|
+
flexShrink: 0
|
|
19106
19339
|
});
|
|
19107
19340
|
this.attachmentStyle = SyntaxStyle.create(renderer.nativeScene);
|
|
19108
19341
|
this.textarea = new TextareaRenderable(renderer, {
|
|
@@ -19163,16 +19396,15 @@ class PromptInput {
|
|
|
19163
19396
|
this.textarea.blur();
|
|
19164
19397
|
}
|
|
19165
19398
|
setBusy(busy) {
|
|
19166
|
-
const
|
|
19167
|
-
if (this.
|
|
19168
|
-
this.
|
|
19399
|
+
const placeholder = busy ? BUSY_PLACEHOLDER : PLACEHOLDER;
|
|
19400
|
+
if (this.textarea.placeholder !== placeholder)
|
|
19401
|
+
this.textarea.placeholder = placeholder;
|
|
19169
19402
|
}
|
|
19170
19403
|
setBorderColor(color) {
|
|
19171
19404
|
this.renderable.borderColor = color;
|
|
19172
19405
|
}
|
|
19173
19406
|
applyColors() {
|
|
19174
|
-
this.
|
|
19175
|
-
this.chevron.fg = Theme.accent.brand;
|
|
19407
|
+
this.chevron.fg = Theme.fg.muted;
|
|
19176
19408
|
this.textarea.placeholderColor = Theme.fg.muted;
|
|
19177
19409
|
this.textarea.textColor = Theme.fg.primary;
|
|
19178
19410
|
this.textarea.focusedTextColor = Theme.fg.primary;
|
|
@@ -19274,6 +19506,25 @@ class AssistantMessageView {
|
|
|
19274
19506
|
}
|
|
19275
19507
|
}
|
|
19276
19508
|
|
|
19509
|
+
// apps/tui/src/components/markdownNoticeView.ts
|
|
19510
|
+
import { MarkdownRenderable as MarkdownRenderable2 } from "@opentui/core";
|
|
19511
|
+
|
|
19512
|
+
class MarkdownNoticeView {
|
|
19513
|
+
renderable;
|
|
19514
|
+
constructor(renderer, mutedSyntaxStyle) {
|
|
19515
|
+
this.renderable = new MarkdownRenderable2(renderer, {
|
|
19516
|
+
content: "",
|
|
19517
|
+
syntaxStyle: mutedSyntaxStyle,
|
|
19518
|
+
marginTop: 1,
|
|
19519
|
+
flexShrink: 0
|
|
19520
|
+
});
|
|
19521
|
+
}
|
|
19522
|
+
update(entry) {
|
|
19523
|
+
if (this.renderable.content !== entry.text)
|
|
19524
|
+
this.renderable.content = entry.text;
|
|
19525
|
+
}
|
|
19526
|
+
}
|
|
19527
|
+
|
|
19277
19528
|
// apps/tui/src/components/noticeView.ts
|
|
19278
19529
|
import { fg as fg7, StyledText as StyledText6, TextRenderable as TextRenderable7 } from "@opentui/core";
|
|
19279
19530
|
class NoticeView {
|
|
@@ -19928,7 +20179,9 @@ var clipLines = (text, maxLines) => {
|
|
|
19928
20179
|
// apps/tui/src/format/toolInputText.ts
|
|
19929
20180
|
var VALUE_LENGTH = 200;
|
|
19930
20181
|
var formatInputValue = (value) => truncateText(typeof value === "string" ? value : JSON.stringify(value), VALUE_LENGTH);
|
|
19931
|
-
var
|
|
20182
|
+
var formatBatchEdit = ({ input }) => listBatchEditPaths(input).map((path, index) => `${index + 1}. ${formatInputValue(path)}`).join(`
|
|
20183
|
+
`);
|
|
20184
|
+
var formatToolInput = (call) => call.name === BATCH_EDIT_TOOL_NAME ? formatBatchEdit(call) : Object.entries(call.input).map(([key, value]) => `${key}: ${formatInputValue(value)}`).join(`
|
|
19932
20185
|
`);
|
|
19933
20186
|
|
|
19934
20187
|
// apps/tui/src/format/toolSummary.ts
|
|
@@ -19936,9 +20189,15 @@ var SUMMARY_LENGTH = 80;
|
|
|
19936
20189
|
var SUMMARY_KEYS = ["file_path", "path", "command", "pattern", "query", "url", "description"];
|
|
19937
20190
|
var SEARCH_TOOLS = new Set(["Glob", "Grep"]);
|
|
19938
20191
|
var summarizeSearch = ({ pattern, path }) => typeof path === "string" ? `${pattern} in ${path}` : String(pattern);
|
|
20192
|
+
var summarizeBatchEdit = (input) => {
|
|
20193
|
+
const paths = listBatchEditPaths(input);
|
|
20194
|
+
return `${paths.length} edits in ${new Set(paths).size} files`;
|
|
20195
|
+
};
|
|
19939
20196
|
function summarizeToolCall({ name, input, status, progress }) {
|
|
19940
20197
|
if (status === "running" && progress)
|
|
19941
20198
|
return truncateText(progress, SUMMARY_LENGTH);
|
|
20199
|
+
if (name === BATCH_EDIT_TOOL_NAME)
|
|
20200
|
+
return summarizeBatchEdit(input);
|
|
19942
20201
|
if (SEARCH_TOOLS.has(name) && typeof input.pattern === "string") {
|
|
19943
20202
|
return truncateText(summarizeSearch(input), SUMMARY_LENGTH);
|
|
19944
20203
|
}
|
|
@@ -19947,6 +20206,8 @@ function summarizeToolCall({ name, input, status, progress }) {
|
|
|
19947
20206
|
return truncateText(value, SUMMARY_LENGTH);
|
|
19948
20207
|
}
|
|
19949
20208
|
var describeApproval = ({ name, input }) => {
|
|
20209
|
+
if (name === BATCH_EDIT_TOOL_NAME)
|
|
20210
|
+
return `Apply ${summarizeBatchEdit(input)} with BatchEdit?`;
|
|
19950
20211
|
if (name === "Bash")
|
|
19951
20212
|
return `Run command \`${truncateText(String(input.command ?? ""), 60)}\`?`;
|
|
19952
20213
|
const path = input.file_path ?? input.notebook_path;
|
|
@@ -20192,7 +20453,7 @@ class ToolCallView {
|
|
|
20192
20453
|
const accent = this.hovered ? Theme.accent.brand : undefined;
|
|
20193
20454
|
this.title.content = new StyledText10([
|
|
20194
20455
|
fg11(accent ?? toolColor(call.status))(glyph),
|
|
20195
|
-
bold6(fg11(accent ?? Theme.fg.primary)(call.name)),
|
|
20456
|
+
bold6(fg11(accent ?? Theme.fg.primary)(stripCustomPrefix(call.name))),
|
|
20196
20457
|
fg11(Theme.fg.secondary)(` ${summarizeToolCall(call)}`),
|
|
20197
20458
|
fg11(Theme.fg.muted)(stats)
|
|
20198
20459
|
]);
|
|
@@ -20352,9 +20613,9 @@ class ScrollbackView {
|
|
|
20352
20613
|
else if (below > 0)
|
|
20353
20614
|
this.renderable.scrollBy(Math.min(below, above));
|
|
20354
20615
|
}
|
|
20355
|
-
reset(syntaxStyle) {
|
|
20616
|
+
reset(syntaxStyle, mutedSyntaxStyle) {
|
|
20356
20617
|
this.dropViews(() => true);
|
|
20357
|
-
this.options = { syntaxStyle, hooks: { ...this.options.hooks, syntaxStyle } };
|
|
20618
|
+
this.options = { syntaxStyle, mutedSyntaxStyle, hooks: { ...this.options.hooks, syntaxStyle } };
|
|
20358
20619
|
}
|
|
20359
20620
|
dropRemovedViews(state) {
|
|
20360
20621
|
const live = new Set(state.transcript.map((entry) => entry.id));
|
|
@@ -20376,14 +20637,14 @@ class ScrollbackView {
|
|
|
20376
20637
|
return view;
|
|
20377
20638
|
}
|
|
20378
20639
|
createView(entry) {
|
|
20379
|
-
const { syntaxStyle, hooks } = this.options;
|
|
20640
|
+
const { syntaxStyle, mutedSyntaxStyle, hooks } = this.options;
|
|
20380
20641
|
switch (entry.kind) {
|
|
20381
20642
|
case "user":
|
|
20382
20643
|
return new UserMessageView(this.renderer);
|
|
20383
20644
|
case "assistant":
|
|
20384
20645
|
return new AssistantMessageView(this.renderer, syntaxStyle);
|
|
20385
20646
|
case "notice":
|
|
20386
|
-
return new NoticeView(this.renderer);
|
|
20647
|
+
return entry.markdown ? new MarkdownNoticeView(this.renderer, mutedSyntaxStyle) : new NoticeView(this.renderer);
|
|
20387
20648
|
case "thought":
|
|
20388
20649
|
return new ThoughtView(this.renderer);
|
|
20389
20650
|
case "tools":
|
|
@@ -20462,15 +20723,14 @@ class SessionInfoBar {
|
|
|
20462
20723
|
limits;
|
|
20463
20724
|
constructor(renderer) {
|
|
20464
20725
|
this.renderable = new BoxRenderable13(renderer, {
|
|
20465
|
-
marginBottom: 1,
|
|
20466
20726
|
flexShrink: 0,
|
|
20467
20727
|
flexDirection: "row",
|
|
20468
20728
|
flexWrap: "wrap",
|
|
20469
20729
|
rowGap: 1,
|
|
20470
20730
|
columnGap: 0,
|
|
20471
20731
|
justifyContent: "space-between",
|
|
20472
|
-
paddingLeft:
|
|
20473
|
-
paddingRight:
|
|
20732
|
+
paddingLeft: 2,
|
|
20733
|
+
paddingRight: 2
|
|
20474
20734
|
});
|
|
20475
20735
|
this.info = new TextRenderable13(renderer, { content: "", wrapMode: "none", flexShrink: 0 });
|
|
20476
20736
|
this.limits = new TextRenderable13(renderer, {
|
|
@@ -20526,12 +20786,14 @@ class StatusLine {
|
|
|
20526
20786
|
constructor(renderer, onStop) {
|
|
20527
20787
|
this.renderable = new BoxRenderable14(renderer, {
|
|
20528
20788
|
height: 2,
|
|
20529
|
-
paddingTop: 1,
|
|
20530
20789
|
flexShrink: 0,
|
|
20531
20790
|
flexDirection: "row",
|
|
20532
20791
|
justifyContent: "space-between",
|
|
20792
|
+
border: ["top"],
|
|
20793
|
+
borderColor: Theme.border.subtle,
|
|
20533
20794
|
paddingLeft: 2,
|
|
20534
|
-
paddingRight: 2
|
|
20795
|
+
paddingRight: 2,
|
|
20796
|
+
visible: false
|
|
20535
20797
|
});
|
|
20536
20798
|
this.label = new TextRenderable14(renderer, { content: "", wrapMode: "none" });
|
|
20537
20799
|
this.stats = new TextRenderable14(renderer, {
|
|
@@ -20547,9 +20809,11 @@ class StatusLine {
|
|
|
20547
20809
|
update(state) {
|
|
20548
20810
|
if (state.status === "idle") {
|
|
20549
20811
|
this.label.content = state.lastRun ? new StyledText13(buildLastRunChunks(state.lastRun, readLastPrompt(state))) : "";
|
|
20812
|
+
this.renderable.visible = state.lastRun !== undefined;
|
|
20550
20813
|
this.stats.content = "";
|
|
20551
20814
|
return;
|
|
20552
20815
|
}
|
|
20816
|
+
this.renderable.visible = true;
|
|
20553
20817
|
const label = agentLabel(state.status);
|
|
20554
20818
|
const busy = label.icon === undefined;
|
|
20555
20819
|
const frame = SPINNER_FRAMES[Math.floor(state.now / SPINNER_STEP_MS) % SPINNER_FRAMES.length];
|
|
@@ -20566,26 +20830,96 @@ class StatusLine {
|
|
|
20566
20830
|
}
|
|
20567
20831
|
}
|
|
20568
20832
|
|
|
20833
|
+
// apps/tui/src/components/promptQueueView.ts
|
|
20834
|
+
import {
|
|
20835
|
+
BoxRenderable as BoxRenderable15,
|
|
20836
|
+
bold as bold9,
|
|
20837
|
+
dim as dim7,
|
|
20838
|
+
fg as fg16,
|
|
20839
|
+
StyledText as StyledText14,
|
|
20840
|
+
TextRenderable as TextRenderable15
|
|
20841
|
+
} from "@opentui/core";
|
|
20842
|
+
|
|
20843
|
+
// apps/tui/src/format/promptQueueRows.ts
|
|
20844
|
+
var MAX_QUEUE_ROWS = 5;
|
|
20845
|
+
var QUEUE_TEXT_LENGTH = 80;
|
|
20846
|
+
var buildQueueRows = (queued) => queued.slice(0, MAX_QUEUE_ROWS).map((content, index) => `${index + 1}. ${truncateText(readPromptText(content), QUEUE_TEXT_LENGTH)}`);
|
|
20847
|
+
var buildQueueHeader = (queued) => `Queued${SEPARATOR}${queued.length} waiting`;
|
|
20848
|
+
var countHiddenQueued = (queued) => Math.max(queued.length - MAX_QUEUE_ROWS, 0);
|
|
20849
|
+
|
|
20850
|
+
// apps/tui/src/components/promptQueueView.ts
|
|
20851
|
+
class PromptQueueView {
|
|
20852
|
+
renderable;
|
|
20853
|
+
header;
|
|
20854
|
+
rows;
|
|
20855
|
+
overflow;
|
|
20856
|
+
constructor(renderer) {
|
|
20857
|
+
this.renderable = new BoxRenderable15(renderer, {
|
|
20858
|
+
flexShrink: 0,
|
|
20859
|
+
paddingLeft: 2,
|
|
20860
|
+
paddingRight: 2,
|
|
20861
|
+
visible: false
|
|
20862
|
+
});
|
|
20863
|
+
this.header = new TextRenderable15(renderer, { content: "", wrapMode: "none" });
|
|
20864
|
+
this.overflow = new TextRenderable15(renderer, { content: "", wrapMode: "none" });
|
|
20865
|
+
this.rows = Array.from({ length: MAX_QUEUE_ROWS }, () => new TextRenderable15(renderer, { content: "", wrapMode: "none" }));
|
|
20866
|
+
this.renderable.add(this.header);
|
|
20867
|
+
for (const row of this.rows)
|
|
20868
|
+
this.renderable.add(row);
|
|
20869
|
+
this.renderable.add(this.overflow);
|
|
20870
|
+
}
|
|
20871
|
+
update({ queuedPrompts }) {
|
|
20872
|
+
this.renderable.visible = queuedPrompts.length > 0;
|
|
20873
|
+
if (queuedPrompts.length === 0)
|
|
20874
|
+
return;
|
|
20875
|
+
this.header.content = new StyledText14([
|
|
20876
|
+
bold9(fg16(Theme.fg.secondary)(buildQueueHeader(queuedPrompts)))
|
|
20877
|
+
]);
|
|
20878
|
+
const lines = buildQueueRows(queuedPrompts);
|
|
20879
|
+
this.rows.forEach((row, index) => {
|
|
20880
|
+
row.content = new StyledText14([fg16(Theme.fg.primary)(lines[index] ?? "")]);
|
|
20881
|
+
});
|
|
20882
|
+
const hidden = countHiddenQueued(queuedPrompts);
|
|
20883
|
+
this.overflow.content = hidden ? new StyledText14([dim7(fg16(Theme.fg.muted)(` +${hidden} more`))]) : "";
|
|
20884
|
+
}
|
|
20885
|
+
}
|
|
20886
|
+
|
|
20569
20887
|
// apps/tui/src/components/taskPanel.ts
|
|
20570
20888
|
import {
|
|
20571
|
-
BoxRenderable as
|
|
20572
|
-
bold as
|
|
20573
|
-
dim as
|
|
20574
|
-
fg as
|
|
20575
|
-
StyledText as
|
|
20576
|
-
TextRenderable as
|
|
20889
|
+
BoxRenderable as BoxRenderable17,
|
|
20890
|
+
bold as bold11,
|
|
20891
|
+
dim as dim9,
|
|
20892
|
+
fg as fg18,
|
|
20893
|
+
StyledText as StyledText16,
|
|
20894
|
+
TextRenderable as TextRenderable17
|
|
20577
20895
|
} from "@opentui/core";
|
|
20578
20896
|
|
|
20579
20897
|
// apps/tui/src/format/taskRows.ts
|
|
20580
20898
|
var MAX_TASK_ROWS = 5;
|
|
20581
|
-
var
|
|
20582
|
-
|
|
20899
|
+
var KIND_LABELS = { "general-purpose": "Agent", local_bash: "Bash" };
|
|
20900
|
+
var describeLastTool = ({ lastToolCall, lastToolName }) => {
|
|
20901
|
+
if (!lastToolCall)
|
|
20902
|
+
return lastToolName;
|
|
20903
|
+
const { name, input } = lastToolCall;
|
|
20904
|
+
const summary = summarizeToolCall({
|
|
20905
|
+
id: "",
|
|
20906
|
+
name,
|
|
20907
|
+
input,
|
|
20908
|
+
status: "running",
|
|
20909
|
+
expanded: false,
|
|
20910
|
+
startedAt: 0
|
|
20911
|
+
});
|
|
20912
|
+
return `${name} ${summary}`;
|
|
20913
|
+
};
|
|
20914
|
+
var readDetail = (task) => {
|
|
20915
|
+
if (task.paused)
|
|
20583
20916
|
return "Paused";
|
|
20584
|
-
return summary ??
|
|
20917
|
+
return task.summary ?? describeLastTool(task) ?? "Starting...";
|
|
20585
20918
|
};
|
|
20586
20919
|
var buildTaskRow = (task, now) => ({
|
|
20587
20920
|
taskId: task.id,
|
|
20588
|
-
kind: task.kind,
|
|
20921
|
+
kind: KIND_LABELS[task.kind] ?? task.kind,
|
|
20922
|
+
model: task.model ?? "",
|
|
20589
20923
|
title: task.description,
|
|
20590
20924
|
stats: [formatDuration(Math.max(now - task.startedAt, 0)), `\u2193${formatTokenCount(task.tokens)}`].join(SEPARATOR).trim(),
|
|
20591
20925
|
detail: readDetail(task)
|
|
@@ -20596,12 +20930,12 @@ var countHiddenTasks = (tasks) => Math.max(tasks.length - MAX_TASK_ROWS, 0);
|
|
|
20596
20930
|
|
|
20597
20931
|
// apps/tui/src/components/taskRowView.ts
|
|
20598
20932
|
import {
|
|
20599
|
-
BoxRenderable as
|
|
20600
|
-
bold as
|
|
20601
|
-
dim as
|
|
20602
|
-
fg as
|
|
20603
|
-
StyledText as
|
|
20604
|
-
TextRenderable as
|
|
20933
|
+
BoxRenderable as BoxRenderable16,
|
|
20934
|
+
bold as bold10,
|
|
20935
|
+
dim as dim8,
|
|
20936
|
+
fg as fg17,
|
|
20937
|
+
StyledText as StyledText15,
|
|
20938
|
+
TextRenderable as TextRenderable16
|
|
20605
20939
|
} from "@opentui/core";
|
|
20606
20940
|
var SPINNER_STEP_MS2 = 100;
|
|
20607
20941
|
|
|
@@ -20612,20 +20946,20 @@ class TaskRowView {
|
|
|
20612
20946
|
detail;
|
|
20613
20947
|
taskId = "";
|
|
20614
20948
|
constructor(renderer, onStop) {
|
|
20615
|
-
this.renderable = new
|
|
20616
|
-
const line = new
|
|
20949
|
+
this.renderable = new BoxRenderable16(renderer, { flexShrink: 0, visible: false });
|
|
20950
|
+
const line = new BoxRenderable16(renderer, {
|
|
20617
20951
|
flexDirection: "row",
|
|
20618
20952
|
justifyContent: "space-between"
|
|
20619
20953
|
});
|
|
20620
|
-
this.title = new
|
|
20621
|
-
this.stop = new
|
|
20954
|
+
this.title = new TextRenderable16(renderer, { content: "", wrapMode: "none" });
|
|
20955
|
+
this.stop = new TextRenderable16(renderer, {
|
|
20622
20956
|
content: "",
|
|
20623
20957
|
wrapMode: "none",
|
|
20624
20958
|
flexShrink: 0,
|
|
20625
20959
|
selectable: false,
|
|
20626
20960
|
onMouseDown: () => onStop(this.taskId)
|
|
20627
20961
|
});
|
|
20628
|
-
this.detail = new
|
|
20962
|
+
this.detail = new TextRenderable16(renderer, { content: "", wrapMode: "none" });
|
|
20629
20963
|
line.add(this.title);
|
|
20630
20964
|
line.add(this.stop);
|
|
20631
20965
|
this.renderable.add(line);
|
|
@@ -20637,16 +20971,17 @@ class TaskRowView {
|
|
|
20637
20971
|
return;
|
|
20638
20972
|
this.taskId = row.taskId;
|
|
20639
20973
|
const frame = SPINNER_FRAMES[Math.floor(now / SPINNER_STEP_MS2) % SPINNER_FRAMES.length];
|
|
20640
|
-
this.title.content = new
|
|
20641
|
-
|
|
20642
|
-
|
|
20643
|
-
|
|
20974
|
+
this.title.content = new StyledText15([
|
|
20975
|
+
fg17(Theme.status.success)(`${frame} `),
|
|
20976
|
+
bold10(fg17(Theme.fg.primary)(row.kind)),
|
|
20977
|
+
fg17(Theme.fg.muted)(row.model ? ` (${row.model})` : ""),
|
|
20978
|
+
fg17(Theme.fg.secondary)(` ${row.title}`)
|
|
20644
20979
|
]);
|
|
20645
|
-
this.stop.content = new
|
|
20646
|
-
|
|
20647
|
-
|
|
20980
|
+
this.stop.content = new StyledText15([
|
|
20981
|
+
fg17(Theme.fg.muted)(`${row.stats} `),
|
|
20982
|
+
bold10(fg17(Theme.fg.secondary)("[stop]"))
|
|
20648
20983
|
]);
|
|
20649
|
-
this.detail.content = new
|
|
20984
|
+
this.detail.content = new StyledText15([dim8(fg17(Theme.fg.muted)(` \u2514 ${row.detail}`))]);
|
|
20650
20985
|
}
|
|
20651
20986
|
}
|
|
20652
20987
|
|
|
@@ -20657,14 +20992,16 @@ class TaskPanel {
|
|
|
20657
20992
|
rows;
|
|
20658
20993
|
overflow;
|
|
20659
20994
|
constructor(renderer, onStop) {
|
|
20660
|
-
this.renderable = new
|
|
20995
|
+
this.renderable = new BoxRenderable17(renderer, {
|
|
20661
20996
|
flexShrink: 0,
|
|
20662
20997
|
paddingLeft: 2,
|
|
20663
20998
|
paddingRight: 2,
|
|
20999
|
+
border: ["top"],
|
|
21000
|
+
borderColor: Theme.border.subtle,
|
|
20664
21001
|
visible: false
|
|
20665
21002
|
});
|
|
20666
|
-
this.header = new
|
|
20667
|
-
this.overflow = new
|
|
21003
|
+
this.header = new TextRenderable17(renderer, { content: "", wrapMode: "none" });
|
|
21004
|
+
this.overflow = new TextRenderable17(renderer, { content: "", wrapMode: "none" });
|
|
20668
21005
|
this.rows = Array.from({ length: MAX_TASK_ROWS }, () => new TaskRowView(renderer, onStop));
|
|
20669
21006
|
this.renderable.add(this.header);
|
|
20670
21007
|
for (const row of this.rows)
|
|
@@ -20676,15 +21013,15 @@ class TaskPanel {
|
|
|
20676
21013
|
if (tasks.length === 0)
|
|
20677
21014
|
return;
|
|
20678
21015
|
const rows = buildTaskRows(tasks, now);
|
|
20679
|
-
this.header.content = new
|
|
21016
|
+
this.header.content = new StyledText16([bold11(fg18(Theme.fg.primary)(buildTaskHeader(tasks)))]);
|
|
20680
21017
|
this.rows.forEach((view, index) => view.update(rows[index], now));
|
|
20681
21018
|
const hidden = countHiddenTasks(tasks);
|
|
20682
|
-
this.overflow.content = hidden ? new
|
|
21019
|
+
this.overflow.content = hidden ? new StyledText16([dim9(fg18(Theme.fg.muted)(` +${hidden} more`))]) : "";
|
|
20683
21020
|
}
|
|
20684
21021
|
}
|
|
20685
21022
|
|
|
20686
21023
|
// apps/tui/src/components/toastView.ts
|
|
20687
|
-
import { BoxRenderable as
|
|
21024
|
+
import { BoxRenderable as BoxRenderable18, fg as fg19, StyledText as StyledText17, TextRenderable as TextRenderable18 } from "@opentui/core";
|
|
20688
21025
|
var TOAST_ICON = "\u25CF";
|
|
20689
21026
|
|
|
20690
21027
|
class ToastView {
|
|
@@ -20692,7 +21029,7 @@ class ToastView {
|
|
|
20692
21029
|
text;
|
|
20693
21030
|
toastId;
|
|
20694
21031
|
constructor(renderer) {
|
|
20695
|
-
this.renderable = new
|
|
21032
|
+
this.renderable = new BoxRenderable18(renderer, {
|
|
20696
21033
|
position: "absolute",
|
|
20697
21034
|
top: 1,
|
|
20698
21035
|
right: 2,
|
|
@@ -20703,7 +21040,7 @@ class ToastView {
|
|
|
20703
21040
|
borderStyle: "rounded",
|
|
20704
21041
|
visible: false
|
|
20705
21042
|
});
|
|
20706
|
-
this.text = new
|
|
21043
|
+
this.text = new TextRenderable18(renderer, { content: "", wrapMode: "none", selectable: false });
|
|
20707
21044
|
this.renderable.add(this.text);
|
|
20708
21045
|
}
|
|
20709
21046
|
update({ ui }) {
|
|
@@ -20714,9 +21051,9 @@ class ToastView {
|
|
|
20714
21051
|
this.toastId = toast.id;
|
|
20715
21052
|
this.renderable.borderColor = Theme.border.focus;
|
|
20716
21053
|
this.renderable.backgroundColor = Theme.bg.surface;
|
|
20717
|
-
this.text.content = new
|
|
20718
|
-
|
|
20719
|
-
|
|
21054
|
+
this.text.content = new StyledText17([
|
|
21055
|
+
fg19(Theme.status.success)(`${TOAST_ICON} `),
|
|
21056
|
+
fg19(Theme.fg.primary)(toast.text)
|
|
20720
21057
|
]);
|
|
20721
21058
|
}
|
|
20722
21059
|
}
|
|
@@ -20745,6 +21082,9 @@ function requestAgent(store, request, onMissing = "notify") {
|
|
|
20745
21082
|
return true;
|
|
20746
21083
|
}
|
|
20747
21084
|
|
|
21085
|
+
// apps/tui/src/input/themeActions.ts
|
|
21086
|
+
var saveTheme2 = (store, theme) => store.request({ type: "options.theme.save.requested", theme });
|
|
21087
|
+
|
|
20748
21088
|
// apps/tui/src/input/workflowCommands.ts
|
|
20749
21089
|
var postNotice = (store, text) => store.emit({ type: "ui.notice.posted", text });
|
|
20750
21090
|
var WORKFLOW_COMMANDS = {
|
|
@@ -20844,7 +21184,7 @@ var SLASH_COMMANDS = {
|
|
|
20844
21184
|
return store.emit({ type: "ui.theme.picker.opened" });
|
|
20845
21185
|
const parsed = themeNameSchema.safeParse(argument);
|
|
20846
21186
|
if (parsed.success)
|
|
20847
|
-
return store
|
|
21187
|
+
return saveTheme2(store, parsed.data);
|
|
20848
21188
|
store.emit({ type: "ui.notice.posted", text: `Unknown theme: ${argument}` });
|
|
20849
21189
|
}
|
|
20850
21190
|
},
|
|
@@ -20873,8 +21213,10 @@ var SLASH_COMMANDS = {
|
|
|
20873
21213
|
}
|
|
20874
21214
|
},
|
|
20875
21215
|
"/effort": {
|
|
20876
|
-
description: "
|
|
21216
|
+
description: "Pick a reasoning effort, or set one with /effort <level>",
|
|
20877
21217
|
run(store, level) {
|
|
21218
|
+
if (!level)
|
|
21219
|
+
return store.emit({ type: "ui.effort.picker.opened" });
|
|
20878
21220
|
const parsed = effortLevelSchema.safeParse(level);
|
|
20879
21221
|
if (parsed.success) {
|
|
20880
21222
|
return void requestAgent(store, {
|
|
@@ -20946,6 +21288,14 @@ function buildPickerView(state) {
|
|
|
20946
21288
|
}));
|
|
20947
21289
|
return { title: "Select a theme", rows, selected: picker.selected };
|
|
20948
21290
|
}
|
|
21291
|
+
if (picker.kind === "effort") {
|
|
21292
|
+
const current = state.effort || DEFAULT_EFFORT;
|
|
21293
|
+
const rows = effortLevelSchema.options.map((level) => ({
|
|
21294
|
+
name: `${level === current ? "\u25CF " : " "}${level}`,
|
|
21295
|
+
description: ""
|
|
21296
|
+
}));
|
|
21297
|
+
return { title: "Select an effort level", rows, selected: picker.selected };
|
|
21298
|
+
}
|
|
20949
21299
|
if (picker.kind === "rewind") {
|
|
20950
21300
|
const rows = listCheckpoints(state).map((entry) => ({
|
|
20951
21301
|
name: truncateText(entry.text.replace(/\s+/g, " "), CHECKPOINT_TEXT_LENGTH),
|
|
@@ -20963,7 +21313,6 @@ function buildPickerView(state) {
|
|
|
20963
21313
|
var buildListView = (state) => buildPickerView(state) ?? buildAutocompleteView(state);
|
|
20964
21314
|
|
|
20965
21315
|
// apps/tui/src/input/agentSessionActions.ts
|
|
20966
|
-
var DEFAULT_EFFORT = "high";
|
|
20967
21316
|
var DEFAULT_MODEL = "claude-haiku-5-5";
|
|
20968
21317
|
var buildSessionOptions = (store) => ({
|
|
20969
21318
|
model: store.state.model || DEFAULT_MODEL,
|
|
@@ -21142,23 +21491,22 @@ function runSlashCommand(store, line) {
|
|
|
21142
21491
|
}
|
|
21143
21492
|
|
|
21144
21493
|
// apps/tui/src/input/promptActions.ts
|
|
21145
|
-
var DELIVERY_REQUESTS = {
|
|
21146
|
-
send: "agent.prompt.requested",
|
|
21147
|
-
queue: "agent.prompt.queue.requested",
|
|
21148
|
-
steer: "agent.prompt.steer.requested"
|
|
21149
|
-
};
|
|
21150
|
-
var BUSY_NOTICE = "Agent is busy: Ctrl+Q queues, Ctrl+W steers, Esc Esc interrupts the turn";
|
|
21151
21494
|
var buildContent = (text, images) => images.length > 0 ? [{ type: "text", text }, ...images] : text;
|
|
21152
21495
|
function deliverPrompt(store, content, delivery, images) {
|
|
21153
|
-
const
|
|
21154
|
-
if (
|
|
21155
|
-
store.emit({ type: "ui.
|
|
21156
|
-
return
|
|
21496
|
+
const body = buildContent(content, images);
|
|
21497
|
+
if (delivery === "queue" && isAgentBusy(store)) {
|
|
21498
|
+
store.emit({ type: "ui.prompt.queued", content: body });
|
|
21499
|
+
return true;
|
|
21157
21500
|
}
|
|
21158
|
-
return requestAgent(store, {
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
|
|
21501
|
+
return requestAgent(store, { type: "agent.prompt.requested", content: body });
|
|
21502
|
+
}
|
|
21503
|
+
function sendNextQueuedPrompt(store) {
|
|
21504
|
+
const [next] = store.state.queuedPrompts;
|
|
21505
|
+
if (next === undefined || store.state.status !== "idle")
|
|
21506
|
+
return;
|
|
21507
|
+
const sent = requestAgent(store, { type: "agent.prompt.requested", content: next }, "ignore");
|
|
21508
|
+
if (sent)
|
|
21509
|
+
store.emit({ type: "ui.prompt.dequeued" });
|
|
21162
21510
|
}
|
|
21163
21511
|
function submitPrompt(store, text, delivery = "send", images = []) {
|
|
21164
21512
|
const content = text.trim();
|
|
@@ -21242,7 +21590,12 @@ var PICKER_CONFIRMS = {
|
|
|
21242
21590
|
theme(store, _state, selected) {
|
|
21243
21591
|
const theme = THEME_NAMES[selected];
|
|
21244
21592
|
if (theme)
|
|
21245
|
-
store
|
|
21593
|
+
saveTheme2(store, theme);
|
|
21594
|
+
},
|
|
21595
|
+
effort(store, _state, selected) {
|
|
21596
|
+
const effort = effortLevelSchema.options[selected];
|
|
21597
|
+
if (effort)
|
|
21598
|
+
requestAgent(store, { type: "agent.effort.set.requested", effort });
|
|
21246
21599
|
},
|
|
21247
21600
|
rewind(store, state, selected) {
|
|
21248
21601
|
const userMessageId = listCheckpoints(state)[selected]?.checkpointId;
|
|
@@ -21290,7 +21643,7 @@ var dismissQuestion = (store) => sendAnswers(store, {});
|
|
|
21290
21643
|
|
|
21291
21644
|
// apps/tui/src/input/routeKeys.ts
|
|
21292
21645
|
var createKeyPresses = () => ({ escapeAt: 0, ctrlCAt: 0 });
|
|
21293
|
-
var DELIVERY_KEYS = { q: "queue"
|
|
21646
|
+
var DELIVERY_KEYS = { q: "queue" };
|
|
21294
21647
|
var DOUBLE_ESCAPE_MS = 500;
|
|
21295
21648
|
var EXIT_CONFIRM_MS = 3000;
|
|
21296
21649
|
var EXIT_NOTICE = "Press Ctrl + C again to exit";
|
|
@@ -21635,21 +21988,70 @@ class AppStore {
|
|
|
21635
21988
|
|
|
21636
21989
|
// apps/tui/src/theme/syntaxStyle.ts
|
|
21637
21990
|
import { SyntaxStyle as SyntaxStyle2 } from "@opentui/core";
|
|
21638
|
-
|
|
21639
|
-
|
|
21640
|
-
|
|
21641
|
-
|
|
21642
|
-
|
|
21643
|
-
|
|
21644
|
-
|
|
21645
|
-
|
|
21646
|
-
|
|
21647
|
-
|
|
21648
|
-
|
|
21649
|
-
|
|
21650
|
-
|
|
21651
|
-
|
|
21652
|
-
|
|
21991
|
+
|
|
21992
|
+
// apps/tui/src/theme/syntaxRules.ts
|
|
21993
|
+
var rule = (scope, foreground, style = {}) => ({
|
|
21994
|
+
scope,
|
|
21995
|
+
style: { foreground, ...style }
|
|
21996
|
+
});
|
|
21997
|
+
var buildMutedSyntaxRules = (palette) => buildSyntaxRules(palette).map(({ scope, style }) => ({
|
|
21998
|
+
scope,
|
|
21999
|
+
style: { ...style, foreground: palette.fg.muted }
|
|
22000
|
+
}));
|
|
22001
|
+
var buildSyntaxRules = ({ fg, status, syntax, markdown, diff, bg }) => [
|
|
22002
|
+
rule(["default"], fg.primary),
|
|
22003
|
+
rule(["comment", "comment.documentation"], syntax.comment, { italic: true }),
|
|
22004
|
+
rule(["string", "symbol", "character.special", "character"], syntax.string),
|
|
22005
|
+
rule(["number", "boolean", "constant", "float"], syntax.number),
|
|
22006
|
+
rule(["keyword.return", "keyword.conditional", "keyword.repeat", "keyword.coroutine"], syntax.keyword, {
|
|
22007
|
+
italic: true
|
|
22008
|
+
}),
|
|
22009
|
+
rule(["keyword.type"], syntax.type, { bold: true, italic: true }),
|
|
22010
|
+
rule(["keyword.function", "function.method"], syntax.function),
|
|
22011
|
+
rule(["keyword"], syntax.keyword, { italic: true }),
|
|
22012
|
+
rule(["keyword.import", "string.escape", "string.regexp", "tag.attribute", "keyword.export"], syntax.keyword),
|
|
22013
|
+
rule(["operator", "keyword.operator", "punctuation.delimiter", "keyword.conditional.ternary"], syntax.operator),
|
|
22014
|
+
rule(["variable", "variable.parameter", "function.method.call", "function.call", "property", "parameter", "field"], syntax.variable),
|
|
22015
|
+
rule(["variable.member", "function", "constructor"], syntax.function),
|
|
22016
|
+
rule(["type", "module", "class", "namespace"], syntax.type),
|
|
22017
|
+
rule(["type.definition"], syntax.type, { bold: true }),
|
|
22018
|
+
rule(["punctuation", "punctuation.bracket"], syntax.punctuation),
|
|
22019
|
+
rule(["variable.builtin", "type.builtin", "function.builtin", "module.builtin", "constant.builtin", "variable.super"], status.danger),
|
|
22020
|
+
rule(["keyword.directive", "keyword.modifier", "keyword.exception"], syntax.keyword, { italic: true }),
|
|
22021
|
+
rule(["punctuation.special", "tag.delimiter"], syntax.operator),
|
|
22022
|
+
rule(["markup.heading", "markup.heading.2", "markup.heading.3", "markup.heading.4", "markup.heading.5", "markup.heading.6"], markdown.heading, { bold: true }),
|
|
22023
|
+
rule(["markup.heading.1"], markdown.heading, { bold: true, underline: true }),
|
|
22024
|
+
rule(["markup.bold", "markup.strong"], markdown.strong, { bold: true }),
|
|
22025
|
+
rule(["markup.italic"], markdown.emphasis, { italic: true }),
|
|
22026
|
+
rule(["markup.list"], markdown.listItem),
|
|
22027
|
+
rule(["markup.quote"], markdown.blockQuote, { italic: true }),
|
|
22028
|
+
rule(["markup.raw", "markup.raw.block"], markdown.code),
|
|
22029
|
+
rule(["markup.raw.inline"], markdown.code, { background: bg.surface }),
|
|
22030
|
+
rule(["markup.link", "markup.link.url", "string.special", "string.special.url"], markdown.link, {
|
|
22031
|
+
underline: true
|
|
22032
|
+
}),
|
|
22033
|
+
rule(["markup.link.label"], markdown.linkText, { underline: true }),
|
|
22034
|
+
rule(["label"], markdown.linkText),
|
|
22035
|
+
rule(["spell", "nospell"], fg.primary),
|
|
22036
|
+
rule(["markup.underline"], fg.primary, { underline: true }),
|
|
22037
|
+
rule(["comment.error"], status.danger, { italic: true, bold: true }),
|
|
22038
|
+
rule(["comment.warning"], status.warning, { italic: true, bold: true }),
|
|
22039
|
+
rule(["comment.todo", "comment.note"], status.info, { italic: true, bold: true }),
|
|
22040
|
+
rule(["attribute", "annotation"], status.warning),
|
|
22041
|
+
rule(["tag"], status.danger),
|
|
22042
|
+
rule(["markup.strikethrough", "markup.list.unchecked", "debug"], fg.muted),
|
|
22043
|
+
rule(["markup.list.checked"], status.success),
|
|
22044
|
+
rule(["diff.plus"], diff.addedText, { background: diff.addedBg }),
|
|
22045
|
+
rule(["diff.minus"], diff.removedText, { background: diff.removedBg }),
|
|
22046
|
+
rule(["diff.delta"], diff.contextText, { background: diff.contextBg }),
|
|
22047
|
+
rule(["error"], status.danger, { bold: true }),
|
|
22048
|
+
rule(["warning"], status.warning, { bold: true }),
|
|
22049
|
+
rule(["info"], status.info)
|
|
22050
|
+
];
|
|
22051
|
+
|
|
22052
|
+
// apps/tui/src/theme/syntaxStyle.ts
|
|
22053
|
+
var createSyntaxStyle = (renderer) => SyntaxStyle2.fromTheme(buildSyntaxRules(Theme), renderer.nativeScene);
|
|
22054
|
+
var createMutedSyntaxStyle = (renderer) => SyntaxStyle2.fromTheme(buildMutedSyntaxRules(Theme), renderer.nativeScene);
|
|
21653
22055
|
|
|
21654
22056
|
// apps/tui/src/startTui.ts
|
|
21655
22057
|
var CLOCK_INTERVAL_MS = 100;
|
|
@@ -21662,6 +22064,7 @@ async function startTui(client, options = {}) {
|
|
|
21662
22064
|
const store = new AppStore(client);
|
|
21663
22065
|
const clipboard = options.clipboard ?? createHostClipboard();
|
|
21664
22066
|
let syntaxStyle = createSyntaxStyle(activeRenderer);
|
|
22067
|
+
let mutedSyntaxStyle = createMutedSyntaxStyle(activeRenderer);
|
|
21665
22068
|
let appliedTheme = readShownTheme(store.state);
|
|
21666
22069
|
let appliedBackground = readShownBackground(store.state);
|
|
21667
22070
|
const header = new HeaderBar(activeRenderer);
|
|
@@ -21671,8 +22074,10 @@ async function startTui(client, options = {}) {
|
|
|
21671
22074
|
const toastView = new ToastView(activeRenderer);
|
|
21672
22075
|
const statusLine = new StatusLine(activeRenderer, () => cancelTurn(store));
|
|
21673
22076
|
const taskPanel = new TaskPanel(activeRenderer, (taskId) => stopTask(store, taskId));
|
|
22077
|
+
const promptQueue = new PromptQueueView(activeRenderer);
|
|
21674
22078
|
const scrollback = new ScrollbackView(activeRenderer, {
|
|
21675
22079
|
syntaxStyle,
|
|
22080
|
+
mutedSyntaxStyle,
|
|
21676
22081
|
hooks: {
|
|
21677
22082
|
syntaxStyle,
|
|
21678
22083
|
onDecision: (decision, id) => answerApproval(store, decision, id),
|
|
@@ -21705,7 +22110,7 @@ async function startTui(client, options = {}) {
|
|
|
21705
22110
|
saveDraft(text);
|
|
21706
22111
|
}
|
|
21707
22112
|
});
|
|
21708
|
-
const root = new
|
|
22113
|
+
const root = new BoxRenderable19(activeRenderer, {
|
|
21709
22114
|
width: "100%",
|
|
21710
22115
|
height: "100%",
|
|
21711
22116
|
flexDirection: "column",
|
|
@@ -21716,11 +22121,12 @@ async function startTui(client, options = {}) {
|
|
|
21716
22121
|
scrollback,
|
|
21717
22122
|
diffViewer,
|
|
21718
22123
|
statusLine,
|
|
21719
|
-
|
|
22124
|
+
promptQueue,
|
|
21720
22125
|
popover,
|
|
21721
22126
|
backgroundPanel,
|
|
21722
22127
|
input,
|
|
21723
|
-
infoBar
|
|
22128
|
+
infoBar,
|
|
22129
|
+
taskPanel
|
|
21724
22130
|
];
|
|
21725
22131
|
for (const part of parts)
|
|
21726
22132
|
root.add(part.renderable);
|
|
@@ -21747,11 +22153,13 @@ async function startTui(client, options = {}) {
|
|
|
21747
22153
|
appliedBackground = shownBackground;
|
|
21748
22154
|
applyTheme(shownTheme, shownBackground);
|
|
21749
22155
|
if (themeChanged) {
|
|
21750
|
-
const previous = syntaxStyle;
|
|
22156
|
+
const previous = [syntaxStyle, mutedSyntaxStyle];
|
|
21751
22157
|
syntaxStyle = createSyntaxStyle(activeRenderer);
|
|
21752
|
-
|
|
22158
|
+
mutedSyntaxStyle = createMutedSyntaxStyle(activeRenderer);
|
|
22159
|
+
scrollback.reset(syntaxStyle, mutedSyntaxStyle);
|
|
21753
22160
|
diffViewer.reset(syntaxStyle);
|
|
21754
|
-
previous
|
|
22161
|
+
for (const style of previous)
|
|
22162
|
+
style.destroy();
|
|
21755
22163
|
}
|
|
21756
22164
|
root.backgroundColor = Theme.bg.default;
|
|
21757
22165
|
input.applyColors();
|
|
@@ -21762,6 +22170,7 @@ async function startTui(client, options = {}) {
|
|
|
21762
22170
|
header.update(state);
|
|
21763
22171
|
statusLine.update(state);
|
|
21764
22172
|
taskPanel.update(state);
|
|
22173
|
+
promptQueue.update(state);
|
|
21765
22174
|
toastView.update(state);
|
|
21766
22175
|
infoBar.update(state);
|
|
21767
22176
|
scrollback.update(state);
|
|
@@ -21773,7 +22182,7 @@ async function startTui(client, options = {}) {
|
|
|
21773
22182
|
input.setFocused(inputFocused);
|
|
21774
22183
|
scrollback.setFocused(!inputFocused);
|
|
21775
22184
|
input.setBusy(isStatusBusy(state.status));
|
|
21776
|
-
input.setBorderColor(inputFocused ? Theme.
|
|
22185
|
+
input.setBorderColor(inputFocused ? Theme.fg.muted : Theme.border.separator);
|
|
21777
22186
|
const awaitingId = (findAwaitingCalls(state)[0] ?? findQuestionCalls(state)[0])?.id;
|
|
21778
22187
|
if (awaitingId && awaitingId !== revealedCallId) {
|
|
21779
22188
|
scrollback.revealEntry(findGroupId(state, awaitingId) ?? "");
|
|
@@ -21781,6 +22190,7 @@ async function startTui(client, options = {}) {
|
|
|
21781
22190
|
revealedCallId = awaitingId;
|
|
21782
22191
|
};
|
|
21783
22192
|
store.subscribe(render);
|
|
22193
|
+
store.subscribe(() => sendNextQueuedPrompt(store));
|
|
21784
22194
|
const notifier = new TurnNotifier(activeRenderer);
|
|
21785
22195
|
store.subscribeOwnEvents((event) => {
|
|
21786
22196
|
reactToEvent(store, event);
|