@couralabs/claudin 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claudin.js +677 -195
- package/package.json +1 -1
package/claudin.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
+
|
|
4
|
+
// packages/daemon/src/auth/connectionCredentials.ts
|
|
5
|
+
import { randomBytes } from "crypto";
|
|
6
|
+
var createRunId = () => crypto.randomUUID();
|
|
7
|
+
var createAccessToken = () => randomBytes(32).toString("base64url");
|
|
8
|
+
function appendCredentials(url, { token, runId }) {
|
|
9
|
+
const target = new URL(url);
|
|
10
|
+
target.searchParams.set("token", token);
|
|
11
|
+
target.searchParams.set("runId", runId);
|
|
12
|
+
return target.toString();
|
|
13
|
+
}
|
|
3
14
|
// node_modules/.bun/zod@4.6.7/node_modules/zod/v4/core/util.js
|
|
4
15
|
function getEnumValues(entries) {
|
|
5
16
|
const numericValues = Object.values(entries).filter((v) => typeof v === "number");
|
|
@@ -5928,6 +5939,12 @@ var backgroundColorSchema = object({
|
|
|
5928
5939
|
a: channelSchema
|
|
5929
5940
|
});
|
|
5930
5941
|
var TRANSPARENT_BACKGROUND = { r: 0, g: 0, b: 0, a: 0 };
|
|
5942
|
+
// packages/events/src/models/customTools.ts
|
|
5943
|
+
var CUSTOM_SERVER_NAME = "claudin";
|
|
5944
|
+
var BATCH_EDIT_BASE_NAME = "BatchEdit";
|
|
5945
|
+
var BATCH_EDIT_TOOL_NAME = `mcp__${CUSTOM_SERVER_NAME}__${BATCH_EDIT_BASE_NAME}`;
|
|
5946
|
+
var CUSTOM_PREFIX = `mcp__${CUSTOM_SERVER_NAME}__`;
|
|
5947
|
+
var stripCustomPrefix = (toolName) => toolName.startsWith(CUSTOM_PREFIX) ? toolName.slice(CUSTOM_PREFIX.length) : toolName;
|
|
5931
5948
|
// packages/events/src/models/fileDiff.ts
|
|
5932
5949
|
var fileDiffSchema = object({
|
|
5933
5950
|
path: string2(),
|
|
@@ -6064,6 +6081,7 @@ function appendEntry(state, entry) {
|
|
|
6064
6081
|
};
|
|
6065
6082
|
}
|
|
6066
6083
|
var appendNotice = (state, text) => appendEntry(state, { kind: "notice", text });
|
|
6084
|
+
var appendMarkdownNotice = (state, text) => appendEntry(state, { kind: "notice", text, markdown: true });
|
|
6067
6085
|
|
|
6068
6086
|
// packages/events/src/reducers/reduceHistory.ts
|
|
6069
6087
|
var NO_MATCH_NOTICE = "No earlier prompt matches";
|
|
@@ -6111,6 +6129,7 @@ var agentSessionId = string2();
|
|
|
6111
6129
|
var content = sdkValue();
|
|
6112
6130
|
var agentOptions = sdkValue().optional();
|
|
6113
6131
|
var effortLevelSchema = _enum(["low", "medium", "high", "xhigh", "max"]);
|
|
6132
|
+
var DEFAULT_EFFORT = "high";
|
|
6114
6133
|
var permissionModeSchema = _enum(["auto", "acceptEdits", "bypassPermissions", "dontAsk"]);
|
|
6115
6134
|
var DEFAULT_PERMISSION_MODE = "bypassPermissions";
|
|
6116
6135
|
var PERMISSION_MODE_LABELS = {
|
|
@@ -6145,8 +6164,6 @@ var agentRequestSchemas = [
|
|
|
6145
6164
|
options: agentOptions
|
|
6146
6165
|
}),
|
|
6147
6166
|
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
6167
|
object({ type: literal("agent.prompt.cancel.requested"), agentSessionId }),
|
|
6151
6168
|
object({ type: literal("agent.task.stop.requested"), agentSessionId, taskId: string2() }),
|
|
6152
6169
|
object({
|
|
@@ -6218,6 +6235,7 @@ var createSessionState = (sessionId) => ({
|
|
|
6218
6235
|
models: [],
|
|
6219
6236
|
sessionList: [],
|
|
6220
6237
|
queuedTurns: 0,
|
|
6238
|
+
queuedPrompts: [],
|
|
6221
6239
|
tasks: [],
|
|
6222
6240
|
transcript: [],
|
|
6223
6241
|
entryCounter: 0,
|
|
@@ -6317,10 +6335,11 @@ function describeSystemMessage(message) {
|
|
|
6317
6335
|
var OPEN_STATUSES = new Set(["running", "awaiting_approval", "awaiting_answer"]);
|
|
6318
6336
|
var isToolsEntry = (entry) => entry.kind === "tools";
|
|
6319
6337
|
var listToolCalls = (state) => state.transcript.filter(isToolsEntry).flatMap((entry) => entry.calls);
|
|
6320
|
-
var EDIT_TOOLS = new Set(["Write", "Edit", "MultiEdit", "
|
|
6321
|
-
var
|
|
6338
|
+
var EDIT_TOOLS = new Set(["Write", "Edit", "MultiEdit", "mcp__claudin__BatchEdit"]);
|
|
6339
|
+
var listBatchEditPaths = (input) => Array.isArray(input.edits) ? input.edits.map((edit) => edit?.file_path) : [];
|
|
6340
|
+
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
6341
|
var listEditedFiles = (state) => [
|
|
6323
|
-
...new Set(listToolCalls(state).filter((call) =>
|
|
6342
|
+
...new Set(listToolCalls(state).filter((call) => call.status === "completed").flatMap(readEditedPaths).filter((path) => typeof path === "string"))
|
|
6324
6343
|
];
|
|
6325
6344
|
function countTurnTools(state) {
|
|
6326
6345
|
const lastUser = state.transcript.findLastIndex((entry) => entry.kind === "user");
|
|
@@ -6519,6 +6538,43 @@ function reduceStreamEvent(state, event) {
|
|
|
6519
6538
|
}
|
|
6520
6539
|
}
|
|
6521
6540
|
|
|
6541
|
+
// packages/events/src/reducers/reduceTaskModel.ts
|
|
6542
|
+
var readMessageModel = (message) => {
|
|
6543
|
+
if (message.type === "assistant")
|
|
6544
|
+
return message.message.model;
|
|
6545
|
+
if (message.type !== "stream_event")
|
|
6546
|
+
return;
|
|
6547
|
+
const event = message.event;
|
|
6548
|
+
return event.type === "message_start" ? event.message?.model : undefined;
|
|
6549
|
+
};
|
|
6550
|
+
var readRequestedModel = (state, toolUseId) => {
|
|
6551
|
+
const model = listToolCalls(state).find((call) => call.id === toolUseId)?.input.model;
|
|
6552
|
+
return typeof model === "string" ? model : undefined;
|
|
6553
|
+
};
|
|
6554
|
+
function reduceTaskModel(state, message) {
|
|
6555
|
+
if (message.type !== "assistant" && message.type !== "stream_event")
|
|
6556
|
+
return state;
|
|
6557
|
+
const model = readMessageModel(message);
|
|
6558
|
+
const parentId = message.parent_tool_use_id;
|
|
6559
|
+
const stale = (task) => task.toolUseId === parentId && task.model !== model;
|
|
6560
|
+
if (!model || !parentId || !state.tasks.some(stale))
|
|
6561
|
+
return state;
|
|
6562
|
+
const tasks = state.tasks.map((task) => stale(task) ? { ...task, model } : task);
|
|
6563
|
+
return { ...state, tasks };
|
|
6564
|
+
}
|
|
6565
|
+
|
|
6566
|
+
// packages/events/src/reducers/reduceTaskToolUse.ts
|
|
6567
|
+
function reduceTaskToolUse(state, message) {
|
|
6568
|
+
if (message.type !== "assistant" || !message.parent_tool_use_id)
|
|
6569
|
+
return state;
|
|
6570
|
+
const call = message.message.content.findLast((block) => block.type === "tool_use");
|
|
6571
|
+
if (call?.type !== "tool_use")
|
|
6572
|
+
return state;
|
|
6573
|
+
const lastToolCall = { name: call.name, input: call.input ?? {} };
|
|
6574
|
+
const tasks = state.tasks.map((task) => task.toolUseId === message.parent_tool_use_id ? { ...task, lastToolCall } : task);
|
|
6575
|
+
return { ...state, tasks };
|
|
6576
|
+
}
|
|
6577
|
+
|
|
6522
6578
|
// packages/events/src/reducers/reduceTaskProgress.ts
|
|
6523
6579
|
function reduceTaskProgress(state, message) {
|
|
6524
6580
|
const { tool_use_id: toolUseId, summary } = message;
|
|
@@ -6539,6 +6595,8 @@ var startTask = (state, message) => {
|
|
|
6539
6595
|
kind: message.subagent_type ?? message.task_type ?? "task",
|
|
6540
6596
|
description: message.description,
|
|
6541
6597
|
startedAt: state.now,
|
|
6598
|
+
toolUseId: message.tool_use_id,
|
|
6599
|
+
model: readRequestedModel(state, message.tool_use_id),
|
|
6542
6600
|
tokens: 0,
|
|
6543
6601
|
paused: false
|
|
6544
6602
|
};
|
|
@@ -6609,9 +6667,12 @@ function reduceAgentMessage(state, message) {
|
|
|
6609
6667
|
};
|
|
6610
6668
|
case "stream_event":
|
|
6611
6669
|
if (message.parent_tool_use_id)
|
|
6612
|
-
return state;
|
|
6670
|
+
return reduceTaskModel(state, message);
|
|
6613
6671
|
return reduceStreamEvent(state, message.event);
|
|
6614
6672
|
case "assistant":
|
|
6673
|
+
if (message.parent_tool_use_id) {
|
|
6674
|
+
return reduceTaskToolUse(reduceTaskModel(state, message), message);
|
|
6675
|
+
}
|
|
6615
6676
|
return reduceAssistant(state, message);
|
|
6616
6677
|
case "user":
|
|
6617
6678
|
return isPromptEcho(message) ? reduceCheckpoint(state, message) : reduceToolResults(state, message);
|
|
@@ -6628,7 +6689,8 @@ function reduceTaskMessage(state, message) {
|
|
|
6628
6689
|
return reduceTaskProgress(state, message);
|
|
6629
6690
|
}
|
|
6630
6691
|
if (message.type === "system" && message.subtype === "task_notification") {
|
|
6631
|
-
|
|
6692
|
+
const text = describeSystemMessage(message);
|
|
6693
|
+
return text ? appendMarkdownNotice(state, text) : state;
|
|
6632
6694
|
}
|
|
6633
6695
|
return state;
|
|
6634
6696
|
}
|
|
@@ -6812,6 +6874,23 @@ function changeQuestionCustom(state, text) {
|
|
|
6812
6874
|
return question ? withDraft(state, { ...question, custom: text }) : state;
|
|
6813
6875
|
}
|
|
6814
6876
|
|
|
6877
|
+
// packages/events/src/reducers/reduceTheme.ts
|
|
6878
|
+
var applyLoadedTheme = (state, theme = state.theme) => ({
|
|
6879
|
+
...state,
|
|
6880
|
+
theme
|
|
6881
|
+
});
|
|
6882
|
+
var applySavedTheme = (state, theme) => appendNotice({ ...state, theme }, `Theme set to ${theme}`);
|
|
6883
|
+
|
|
6884
|
+
// packages/events/src/reducers/reducePromptQueue.ts
|
|
6885
|
+
var queuePrompt = (state, content) => ({
|
|
6886
|
+
...state,
|
|
6887
|
+
queuedPrompts: [...state.queuedPrompts, content]
|
|
6888
|
+
});
|
|
6889
|
+
var dequeuePrompt = (state) => ({
|
|
6890
|
+
...state,
|
|
6891
|
+
queuedPrompts: state.queuedPrompts.slice(1)
|
|
6892
|
+
});
|
|
6893
|
+
|
|
6815
6894
|
// packages/events/src/reducers/reduceToast.ts
|
|
6816
6895
|
var withToast = (state, toast) => ({
|
|
6817
6896
|
...state,
|
|
@@ -6839,6 +6918,8 @@ var pickerSize = (state, kind) => {
|
|
|
6839
6918
|
return state.models.length;
|
|
6840
6919
|
if (kind === "theme")
|
|
6841
6920
|
return THEME_NAMES.length;
|
|
6921
|
+
if (kind === "effort")
|
|
6922
|
+
return effortLevelSchema.options.length;
|
|
6842
6923
|
if (kind === "rewind")
|
|
6843
6924
|
return listCheckpoints(state).length;
|
|
6844
6925
|
return state.sessionList.length;
|
|
@@ -6857,6 +6938,11 @@ var openThemePicker = (state) => {
|
|
|
6857
6938
|
const selected = Math.max(THEME_NAMES.indexOf(state.theme), 0);
|
|
6858
6939
|
return { ...state, ui: { ...state.ui, picker: { kind: "theme", selected } } };
|
|
6859
6940
|
};
|
|
6941
|
+
var openEffortPicker = (state) => {
|
|
6942
|
+
const current = state.effort || DEFAULT_EFFORT;
|
|
6943
|
+
const selected = Math.max(effortLevelSchema.options.findIndex((level) => level === current), 0);
|
|
6944
|
+
return { ...state, ui: { ...state.ui, picker: { kind: "effort", selected } } };
|
|
6945
|
+
};
|
|
6860
6946
|
function openRewindPicker(state) {
|
|
6861
6947
|
const size = listCheckpoints(state).length;
|
|
6862
6948
|
if (size === 0)
|
|
@@ -6881,8 +6967,12 @@ function reduceUi(state, event) {
|
|
|
6881
6967
|
return { ...state, ui: { ...state.ui, picker: null } };
|
|
6882
6968
|
case "ui.theme.picker.opened":
|
|
6883
6969
|
return openThemePicker(state);
|
|
6884
|
-
case "ui.
|
|
6885
|
-
return
|
|
6970
|
+
case "ui.effort.picker.opened":
|
|
6971
|
+
return openEffortPicker(state);
|
|
6972
|
+
case "ui.prompt.queued":
|
|
6973
|
+
return queuePrompt(state, event.content);
|
|
6974
|
+
case "ui.prompt.dequeued":
|
|
6975
|
+
return dequeuePrompt(state);
|
|
6886
6976
|
case "ui.rewind.picker.opened":
|
|
6887
6977
|
return openRewindPicker(state);
|
|
6888
6978
|
case "ui.history.moved":
|
|
@@ -6961,9 +7051,6 @@ var reduceTimedEvent = (state, event, at) => reduceSessionState({ ...state, now:
|
|
|
6961
7051
|
function reduceSessionState(state, event) {
|
|
6962
7052
|
switch (event.type) {
|
|
6963
7053
|
case "agent.prompt.requested":
|
|
6964
|
-
return reducePrompt(state, event.content, false);
|
|
6965
|
-
case "agent.prompt.queue.requested":
|
|
6966
|
-
case "agent.prompt.steer.requested":
|
|
6967
7054
|
return reducePrompt(state, event.content, state.status !== "idle");
|
|
6968
7055
|
case "agent.message.received":
|
|
6969
7056
|
return reduceAgentMessage(state, event.message);
|
|
@@ -7040,9 +7127,11 @@ function reduceSessionState(state, event) {
|
|
|
7040
7127
|
case "workspace.info.received":
|
|
7041
7128
|
return { ...state, cwd: event.cwd, gitBranch: event.gitBranch, gitStats: event.gitStats };
|
|
7042
7129
|
case "options.loaded":
|
|
7043
|
-
return applyLoadedBackground(state, event.background);
|
|
7130
|
+
return applyLoadedTheme(applyLoadedBackground(state, event.background), event.theme);
|
|
7044
7131
|
case "options.background.saved":
|
|
7045
7132
|
return applySavedBackground(state, event.color);
|
|
7133
|
+
case "options.theme.saved":
|
|
7134
|
+
return applySavedTheme(state, event.theme);
|
|
7046
7135
|
case "workspace.files.received":
|
|
7047
7136
|
return updateFileMatches(state, event.query, event.matches);
|
|
7048
7137
|
default:
|
|
@@ -7055,13 +7144,22 @@ var optionsRequestSchemas = [
|
|
|
7055
7144
|
object({
|
|
7056
7145
|
type: literal("options.background.save.requested"),
|
|
7057
7146
|
color: backgroundColorSchema
|
|
7058
|
-
})
|
|
7147
|
+
}),
|
|
7148
|
+
object({ type: literal("options.theme.save.requested"), theme: themeNameSchema })
|
|
7059
7149
|
];
|
|
7060
7150
|
var optionsResponseSchemas = [
|
|
7061
|
-
object({
|
|
7062
|
-
|
|
7151
|
+
object({
|
|
7152
|
+
type: literal("options.loaded"),
|
|
7153
|
+
background: backgroundColorSchema.optional(),
|
|
7154
|
+
theme: themeNameSchema.optional()
|
|
7155
|
+
}),
|
|
7156
|
+
object({ type: literal("options.background.saved"), color: backgroundColorSchema }),
|
|
7157
|
+
object({ type: literal("options.theme.saved"), theme: themeNameSchema })
|
|
7063
7158
|
];
|
|
7064
|
-
var optionsFileSchema = looseObject({
|
|
7159
|
+
var optionsFileSchema = looseObject({
|
|
7160
|
+
background: backgroundColorSchema.optional(),
|
|
7161
|
+
theme: themeNameSchema.optional()
|
|
7162
|
+
});
|
|
7065
7163
|
// packages/events/src/requests/sessionRequestEvents.ts
|
|
7066
7164
|
var sessionRequestSchemas = [
|
|
7067
7165
|
object({ type: literal("session.create.requested") }),
|
|
@@ -7122,7 +7220,6 @@ var agentResponseSchemas = [
|
|
|
7122
7220
|
}),
|
|
7123
7221
|
object({ type: literal("agent.session.created"), agentSessionId: agentSessionId2 }),
|
|
7124
7222
|
object({ type: literal("agent.message.received"), message: unknown() }),
|
|
7125
|
-
object({ type: literal("agent.prompt.accepted"), agentSessionId: agentSessionId2 }),
|
|
7126
7223
|
object({ type: literal("agent.prompt.cancelled"), agentSessionId: agentSessionId2 }),
|
|
7127
7224
|
object({
|
|
7128
7225
|
type: literal("agent.tool.approval.required"),
|
|
@@ -7464,8 +7561,8 @@ class DaemonClient {
|
|
|
7464
7561
|
this.socket = socket;
|
|
7465
7562
|
socket.addEventListener("message", (event) => this.notifyListeners(String(event.data)));
|
|
7466
7563
|
}
|
|
7467
|
-
static async connect(url) {
|
|
7468
|
-
const socket = new WebSocket(url);
|
|
7564
|
+
static async connect(url, credentials) {
|
|
7565
|
+
const socket = new WebSocket(appendCredentials(url, credentials));
|
|
7469
7566
|
await new Promise((resolve, reject) => {
|
|
7470
7567
|
socket.addEventListener("open", () => resolve(), { once: true });
|
|
7471
7568
|
socket.addEventListener("error", () => reject(new Error(`Cannot reach ${url}`)), {
|
|
@@ -7532,11 +7629,10 @@ var sdkRuntime = {
|
|
|
7532
7629
|
};
|
|
7533
7630
|
// packages/agent/src/runtime/buildUserMessage.ts
|
|
7534
7631
|
var isSlashCommand = (content) => readPromptText(content).trimStart().startsWith("/");
|
|
7535
|
-
var buildUserMessage = (content
|
|
7632
|
+
var buildUserMessage = (content) => ({
|
|
7536
7633
|
type: "user",
|
|
7537
7634
|
message: { role: "user", content },
|
|
7538
7635
|
parent_tool_use_id: null,
|
|
7539
|
-
priority,
|
|
7540
7636
|
client_composed: isSlashCommand(content) ? undefined : true
|
|
7541
7637
|
});
|
|
7542
7638
|
// node_modules/.bun/p-defer@4.0.1/node_modules/p-defer/index.js
|
|
@@ -8731,8 +8827,10 @@ class PermissionGate {
|
|
|
8731
8827
|
}
|
|
8732
8828
|
open(kind, toolUseId, input, signal, announcement) {
|
|
8733
8829
|
return new Promise((settle) => {
|
|
8734
|
-
this.
|
|
8735
|
-
|
|
8830
|
+
const onAbort = () => this.dismiss(kind, toolUseId);
|
|
8831
|
+
const detach = () => signal.removeEventListener("abort", onAbort);
|
|
8832
|
+
this.pending.set(toolUseId, { kind, input, settle, detach });
|
|
8833
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
8736
8834
|
this.emit(announcement);
|
|
8737
8835
|
});
|
|
8738
8836
|
}
|
|
@@ -8747,6 +8845,7 @@ class PermissionGate {
|
|
|
8747
8845
|
if (pending?.kind !== kind)
|
|
8748
8846
|
return;
|
|
8749
8847
|
this.pending.delete(toolUseId);
|
|
8848
|
+
pending.detach();
|
|
8750
8849
|
return pending;
|
|
8751
8850
|
}
|
|
8752
8851
|
listIds(kind) {
|
|
@@ -8761,6 +8860,110 @@ class PermissionGate {
|
|
|
8761
8860
|
}
|
|
8762
8861
|
}
|
|
8763
8862
|
|
|
8863
|
+
// packages/agent/src/tools/customToolsServer.ts
|
|
8864
|
+
import { createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
|
|
8865
|
+
|
|
8866
|
+
// packages/agent/src/tools/batchEdit/batchEditTool.ts
|
|
8867
|
+
import { tool } from "@anthropic-ai/claude-agent-sdk";
|
|
8868
|
+
|
|
8869
|
+
// packages/agent/src/tools/batchEdit/batchEditSchema.ts
|
|
8870
|
+
var textEditSchema = object({
|
|
8871
|
+
file_path: string2().describe("Absolute path of the file to modify"),
|
|
8872
|
+
old_string: string2().describe("Exact text to replace; empty only to create a new file with new_string"),
|
|
8873
|
+
new_string: string2().describe("Replacement text; must differ from old_string"),
|
|
8874
|
+
replace_all: boolean2().optional().describe("Replace every occurrence of old_string")
|
|
8875
|
+
});
|
|
8876
|
+
var batchEditShape = {
|
|
8877
|
+
edits: array(textEditSchema).min(1).describe("Edits applied in order; edits to one file see the result of earlier ones")
|
|
8878
|
+
};
|
|
8879
|
+
|
|
8880
|
+
// packages/agent/src/tools/batchEdit/stageEdits.ts
|
|
8881
|
+
import { isAbsolute, resolve } from "path";
|
|
8882
|
+
|
|
8883
|
+
// packages/agent/src/tools/batchEdit/applyTextEdit.ts
|
|
8884
|
+
var failEdit = (reason) => ({ ok: false, reason });
|
|
8885
|
+
function applyTextEdit(content, edit) {
|
|
8886
|
+
const { old_string: oldText, new_string: newText, replace_all: replaceAll } = edit;
|
|
8887
|
+
if (oldText === newText)
|
|
8888
|
+
return failEdit("old_string and new_string are identical");
|
|
8889
|
+
if (oldText === "") {
|
|
8890
|
+
return content === "" ? { ok: true, content: newText, replacements: 1 } : failEdit("old_string is empty but the file already has content");
|
|
8891
|
+
}
|
|
8892
|
+
const parts = content.split(oldText);
|
|
8893
|
+
const matches = parts.length - 1;
|
|
8894
|
+
if (matches === 0)
|
|
8895
|
+
return failEdit("old_string was not found in the file");
|
|
8896
|
+
if (matches > 1 && !replaceAll) {
|
|
8897
|
+
return failEdit(`old_string matches ${matches} times; add context or set replace_all`);
|
|
8898
|
+
}
|
|
8899
|
+
return { ok: true, content: parts.join(newText), replacements: matches };
|
|
8900
|
+
}
|
|
8901
|
+
|
|
8902
|
+
// packages/agent/src/tools/batchEdit/stageEdits.ts
|
|
8903
|
+
var failStage = (index, edit, reason) => ({
|
|
8904
|
+
ok: false,
|
|
8905
|
+
message: `Edit ${index + 1} (${edit.file_path}): ${reason}`
|
|
8906
|
+
});
|
|
8907
|
+
async function stageEdits(edits, readFile) {
|
|
8908
|
+
const files = new Map;
|
|
8909
|
+
for (const [index, edit] of edits.entries()) {
|
|
8910
|
+
if (!isAbsolute(edit.file_path))
|
|
8911
|
+
return failStage(index, edit, "file_path must be absolute");
|
|
8912
|
+
const path = resolve(edit.file_path);
|
|
8913
|
+
const current = files.get(path)?.content ?? await readFile(path);
|
|
8914
|
+
if (current === undefined && edit.old_string !== "") {
|
|
8915
|
+
return failStage(index, edit, "the file does not exist");
|
|
8916
|
+
}
|
|
8917
|
+
const outcome = applyTextEdit(current ?? "", edit);
|
|
8918
|
+
if (!outcome.ok)
|
|
8919
|
+
return failStage(index, edit, outcome.reason);
|
|
8920
|
+
const replacements = (files.get(path)?.replacements ?? 0) + outcome.replacements;
|
|
8921
|
+
files.set(path, { content: outcome.content, replacements });
|
|
8922
|
+
}
|
|
8923
|
+
return { ok: true, files };
|
|
8924
|
+
}
|
|
8925
|
+
|
|
8926
|
+
// packages/agent/src/tools/batchEdit/runBatchEdit.ts
|
|
8927
|
+
var readFileText = async (path) => {
|
|
8928
|
+
const file = Bun.file(path);
|
|
8929
|
+
return await file.exists() ? file.text() : undefined;
|
|
8930
|
+
};
|
|
8931
|
+
var describeFiles = (files) => [...files].map(([path, { replacements }]) => `- ${path}: ${replacements} replacement(s)`).join(`
|
|
8932
|
+
`);
|
|
8933
|
+
async function runBatchEdit(edits, readFile = readFileText) {
|
|
8934
|
+
const staged = await stageEdits(edits, readFile);
|
|
8935
|
+
if (!staged.ok) {
|
|
8936
|
+
return { isError: true, text: `${staged.message}
|
|
8937
|
+
No files were changed.` };
|
|
8938
|
+
}
|
|
8939
|
+
try {
|
|
8940
|
+
await Promise.all([...staged.files].map(([path, { content }]) => Bun.write(path, content)));
|
|
8941
|
+
} catch (error) {
|
|
8942
|
+
return { isError: true, text: `Writing failed, files may be partly changed: ${error}` };
|
|
8943
|
+
}
|
|
8944
|
+
return {
|
|
8945
|
+
isError: false,
|
|
8946
|
+
text: `Applied ${edits.length} edit(s) to ${staged.files.size} file(s):
|
|
8947
|
+
${describeFiles(staged.files)}`
|
|
8948
|
+
};
|
|
8949
|
+
}
|
|
8950
|
+
|
|
8951
|
+
// packages/agent/src/tools/batchEdit/batchEditTool.ts
|
|
8952
|
+
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.`;
|
|
8953
|
+
var batchEditTool = tool(BATCH_EDIT_BASE_NAME, DESCRIPTION, batchEditShape, async ({ edits }) => {
|
|
8954
|
+
const { isError, text } = await runBatchEdit(edits);
|
|
8955
|
+
return { isError, content: [{ type: "text", text }] };
|
|
8956
|
+
});
|
|
8957
|
+
|
|
8958
|
+
// packages/agent/src/tools/customToolsServer.ts
|
|
8959
|
+
var CUSTOM_MCP_SERVERS = {
|
|
8960
|
+
[CUSTOM_SERVER_NAME]: createSdkMcpServer({
|
|
8961
|
+
name: CUSTOM_SERVER_NAME,
|
|
8962
|
+
tools: [batchEditTool],
|
|
8963
|
+
alwaysLoad: true
|
|
8964
|
+
})
|
|
8965
|
+
};
|
|
8966
|
+
|
|
8764
8967
|
// packages/agent/src/profile/adhdSystemPrompt.ts
|
|
8765
8968
|
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
8969
|
|
|
@@ -8875,8 +9078,7 @@ var AGENT_TOOLS = [
|
|
|
8875
9078
|
"TodoWrite",
|
|
8876
9079
|
"AskUserQuestion",
|
|
8877
9080
|
"Write",
|
|
8878
|
-
"Edit"
|
|
8879
|
-
"NotebookEdit"
|
|
9081
|
+
"Edit"
|
|
8880
9082
|
];
|
|
8881
9083
|
var AGENT_DISALLOWED_TOOLS = [
|
|
8882
9084
|
"Agent(Explore)",
|
|
@@ -8903,11 +9105,12 @@ var TOOL_USAGE = {
|
|
|
8903
9105
|
AskUserQuestion: "ask the user",
|
|
8904
9106
|
Write: "create new files with content",
|
|
8905
9107
|
Edit: "update files",
|
|
8906
|
-
|
|
9108
|
+
mcp__claudin__BatchEdit: "update files mutiples files or multiple replaces in same file"
|
|
8907
9109
|
};
|
|
8908
9110
|
var TOOL_GUIDANCE = `Always use the dedicated tool, never a workaround:
|
|
8909
9111
|
${AGENT_TOOLS.map((tool) => `- Use *${tool}* to ${TOOL_USAGE[tool]}`).join(`
|
|
8910
|
-
`)}
|
|
9112
|
+
`)}
|
|
9113
|
+
- Use *${BATCH_EDIT_TOOL_NAME}* instead of repeated *Edit* calls to make several edits, across one or many files, in one call`;
|
|
8911
9114
|
|
|
8912
9115
|
// packages/agent/src/profile/agentSystemPrompt.ts
|
|
8913
9116
|
var AGENT_SYSTEM_PROMPT = [ADHD_SYSTEM_PROMPT, TOOL_GUIDANCE, SUBAGENT_GUIDANCE].join(`
|
|
@@ -8917,6 +9120,8 @@ var AGENT_SYSTEM_PROMPT = [ADHD_SYSTEM_PROMPT, TOOL_GUIDANCE, SUBAGENT_GUIDANCE]
|
|
|
8917
9120
|
// packages/agent/src/profile/agentProfile.ts
|
|
8918
9121
|
var AGENT_PROFILE_OPTIONS = {
|
|
8919
9122
|
tools: AGENT_TOOLS,
|
|
9123
|
+
mcpServers: CUSTOM_MCP_SERVERS,
|
|
9124
|
+
toolAliases: { [BATCH_EDIT_BASE_NAME]: BATCH_EDIT_TOOL_NAME },
|
|
8920
9125
|
disallowedTools: AGENT_DISALLOWED_TOOLS,
|
|
8921
9126
|
systemPrompt: AGENT_SYSTEM_PROMPT,
|
|
8922
9127
|
agents: AGENT_SUBAGENTS,
|
|
@@ -8951,11 +9156,25 @@ var AGENT_PROFILE_OPTIONS = {
|
|
|
8951
9156
|
includeHookEvents: true
|
|
8952
9157
|
};
|
|
8953
9158
|
|
|
8954
|
-
// packages/agent/src/session/
|
|
8955
|
-
|
|
8956
|
-
|
|
9159
|
+
// packages/agent/src/session/readLiveTaskIds.ts
|
|
9160
|
+
var FINISHED_STATUSES2 = ["completed", "failed", "killed"];
|
|
9161
|
+
var withTask = (current, id) => new Set([...current, id]);
|
|
9162
|
+
var withoutTask = (current, id) => new Set([...current].filter((taskId) => taskId !== id));
|
|
9163
|
+
function readLiveTaskIds(message, current) {
|
|
9164
|
+
if (message.type !== "system")
|
|
8957
9165
|
return current;
|
|
8958
|
-
|
|
9166
|
+
switch (message.subtype) {
|
|
9167
|
+
case "background_tasks_changed":
|
|
9168
|
+
return new Set(message.tasks.filter((task) => !task.ambient).map((task) => task.task_id));
|
|
9169
|
+
case "task_started":
|
|
9170
|
+
return message.ambient ? current : withTask(current, message.task_id);
|
|
9171
|
+
case "task_updated":
|
|
9172
|
+
return FINISHED_STATUSES2.includes(message.patch.status ?? "") ? withoutTask(current, message.task_id) : current;
|
|
9173
|
+
case "task_notification":
|
|
9174
|
+
return withoutTask(current, message.task_id);
|
|
9175
|
+
default:
|
|
9176
|
+
return current;
|
|
9177
|
+
}
|
|
8959
9178
|
}
|
|
8960
9179
|
|
|
8961
9180
|
// packages/agent/src/session/agentSession.ts
|
|
@@ -8972,7 +9191,7 @@ class AgentSession {
|
|
|
8972
9191
|
elicitations;
|
|
8973
9192
|
query;
|
|
8974
9193
|
pendingTurns = 0;
|
|
8975
|
-
|
|
9194
|
+
liveTaskIds = new Set;
|
|
8976
9195
|
pumping = false;
|
|
8977
9196
|
constructor(agentSessionId, baseOptions, runtime) {
|
|
8978
9197
|
this.baseOptions = baseOptions;
|
|
@@ -8988,13 +9207,13 @@ class AgentSession {
|
|
|
8988
9207
|
}
|
|
8989
9208
|
});
|
|
8990
9209
|
}
|
|
8991
|
-
prompt(content
|
|
8992
|
-
this.send(content
|
|
9210
|
+
prompt(content) {
|
|
9211
|
+
this.send(content);
|
|
8993
9212
|
return this.streamTurn();
|
|
8994
9213
|
}
|
|
8995
|
-
send(content
|
|
9214
|
+
send(content) {
|
|
8996
9215
|
this.pendingTurns += 1;
|
|
8997
|
-
this.input.push(buildUserMessage(content
|
|
9216
|
+
this.input.push(buildUserMessage(content));
|
|
8998
9217
|
}
|
|
8999
9218
|
async* streamTurn() {
|
|
9000
9219
|
if (this.pumping)
|
|
@@ -9006,7 +9225,6 @@ class AgentSession {
|
|
|
9006
9225
|
try {
|
|
9007
9226
|
yield* sink;
|
|
9008
9227
|
} finally {
|
|
9009
|
-
this.pumping = false;
|
|
9010
9228
|
this.listenGates(() => {});
|
|
9011
9229
|
}
|
|
9012
9230
|
}
|
|
@@ -9094,16 +9312,18 @@ class AgentSession {
|
|
|
9094
9312
|
if (done)
|
|
9095
9313
|
break;
|
|
9096
9314
|
sink.push({ type: "agent.message.received", message: value });
|
|
9097
|
-
this.
|
|
9315
|
+
this.liveTaskIds = readLiveTaskIds(value, this.liveTaskIds);
|
|
9098
9316
|
if (value.type !== "result")
|
|
9099
9317
|
continue;
|
|
9100
9318
|
this.pendingTurns = Math.max(this.pendingTurns - 1, 0);
|
|
9101
|
-
if (this.pendingTurns === 0 && this.
|
|
9319
|
+
if (this.pendingTurns === 0 && this.liveTaskIds.size === 0)
|
|
9102
9320
|
break;
|
|
9103
9321
|
}
|
|
9322
|
+
this.pumping = false;
|
|
9104
9323
|
sink.end();
|
|
9105
9324
|
} catch (error) {
|
|
9106
9325
|
this.pendingTurns = 0;
|
|
9326
|
+
this.pumping = false;
|
|
9107
9327
|
sink.end(error);
|
|
9108
9328
|
}
|
|
9109
9329
|
}
|
|
@@ -9127,14 +9347,13 @@ class AgentSessionManager {
|
|
|
9127
9347
|
}
|
|
9128
9348
|
createSession(options = {}) {
|
|
9129
9349
|
const sessionId = options.sessionId ?? crypto.randomUUID();
|
|
9130
|
-
this.
|
|
9350
|
+
this.replaceSession(sessionId, { ...options, sessionId });
|
|
9131
9351
|
return sessionId;
|
|
9132
9352
|
}
|
|
9133
9353
|
async resumeSession(sessionId, options = {}) {
|
|
9134
9354
|
if (!await this.runtime.getInfo(sessionId))
|
|
9135
9355
|
return this.createSession({ ...options, sessionId });
|
|
9136
|
-
|
|
9137
|
-
this.sessions.set(sessionId, resumed);
|
|
9356
|
+
this.replaceSession(sessionId, { ...options, resume: sessionId });
|
|
9138
9357
|
return sessionId;
|
|
9139
9358
|
}
|
|
9140
9359
|
async forkSession(sessionId, forkOptions, options = {}) {
|
|
@@ -9149,6 +9368,10 @@ class AgentSessionManager {
|
|
|
9149
9368
|
for (const sessionId of [...this.sessions.keys()])
|
|
9150
9369
|
this.closeSession(sessionId);
|
|
9151
9370
|
}
|
|
9371
|
+
replaceSession(sessionId, options) {
|
|
9372
|
+
this.closeSession(sessionId);
|
|
9373
|
+
this.sessions.set(sessionId, new AgentSession(sessionId, options, this.runtime));
|
|
9374
|
+
}
|
|
9152
9375
|
requireSession(sessionId) {
|
|
9153
9376
|
const session = this.sessions.get(sessionId);
|
|
9154
9377
|
if (!session)
|
|
@@ -9165,19 +9388,21 @@ async function readOptions2(path) {
|
|
|
9165
9388
|
const parsed = optionsFileSchema.safeParse(stored);
|
|
9166
9389
|
return parsed.success ? parsed.data : {};
|
|
9167
9390
|
}
|
|
9168
|
-
async
|
|
9169
|
-
await Bun.write(path, JSON.stringify({ ...await readOptions2(path),
|
|
9170
|
-
}
|
|
9391
|
+
var saveOption = async (path, option) => {
|
|
9392
|
+
await Bun.write(path, JSON.stringify({ ...await readOptions2(path), ...option }, null, 2));
|
|
9393
|
+
};
|
|
9394
|
+
var saveBackground = (path, background) => saveOption(path, { background });
|
|
9395
|
+
var saveTheme = (path, theme) => saveOption(path, { theme });
|
|
9171
9396
|
|
|
9172
9397
|
// packages/daemon/src/workspace/resolvePath.ts
|
|
9173
9398
|
import { stat } from "fs/promises";
|
|
9174
9399
|
import { homedir as homedir2 } from "os";
|
|
9175
|
-
import { join as join3, resolve } from "path";
|
|
9400
|
+
import { join as join3, resolve as resolve2 } from "path";
|
|
9176
9401
|
var isDirectory = async (path) => (await stat(path).catch(() => {
|
|
9177
9402
|
return;
|
|
9178
9403
|
}))?.isDirectory() ?? false;
|
|
9179
9404
|
var expandHome = (path) => path === "~" || path.startsWith("~/") ? join3(homedir2(), path.slice(1)) : path;
|
|
9180
|
-
var resolveUserPath = (base, path) =>
|
|
9405
|
+
var resolveUserPath = (base, path) => resolve2(base, expandHome(path.trim()));
|
|
9181
9406
|
|
|
9182
9407
|
// packages/daemon/src/server/daemonContext.ts
|
|
9183
9408
|
var SESSIONS_DIRECTORY = join4(homedir3(), ".claudin", "sessions");
|
|
@@ -9245,11 +9470,7 @@ async function createDaemonContext(store = new FileSessionStore(SESSIONS_DIRECTO
|
|
|
9245
9470
|
// packages/daemon/src/client/replayClient.ts
|
|
9246
9471
|
var MAX_GAP_MS = 1500;
|
|
9247
9472
|
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
|
-
]);
|
|
9473
|
+
var PROMPT_TYPES = new Set(["agent.prompt.requested"]);
|
|
9253
9474
|
|
|
9254
9475
|
class ReplayClient {
|
|
9255
9476
|
stored;
|
|
@@ -9300,6 +9521,31 @@ class ReplayClient {
|
|
|
9300
9521
|
import { once } from "events";
|
|
9301
9522
|
import { WebSocketServer } from "ws";
|
|
9302
9523
|
|
|
9524
|
+
// packages/daemon/src/auth/checkConnection.ts
|
|
9525
|
+
import { timingSafeEqual } from "crypto";
|
|
9526
|
+
var isSameSecret = (given, expected) => {
|
|
9527
|
+
const givenBytes = Buffer.from(given);
|
|
9528
|
+
const expectedBytes = Buffer.from(expected);
|
|
9529
|
+
return givenBytes.length === expectedBytes.length && timingSafeEqual(givenBytes, expectedBytes);
|
|
9530
|
+
};
|
|
9531
|
+
function readRunId(request) {
|
|
9532
|
+
return new URL(request.url ?? "/", "ws://127.0.0.1").searchParams.get("runId");
|
|
9533
|
+
}
|
|
9534
|
+
function checkConnection(request, token, liveRunIds) {
|
|
9535
|
+
if (request.headers.origin)
|
|
9536
|
+
return { status: 403, reason: "Browser origins are not allowed" };
|
|
9537
|
+
const params = new URL(request.url ?? "/", "ws://127.0.0.1").searchParams;
|
|
9538
|
+
if (!isSameSecret(params.get("token") ?? "", token)) {
|
|
9539
|
+
return { status: 401, reason: "Invalid access token" };
|
|
9540
|
+
}
|
|
9541
|
+
const runId = params.get("runId");
|
|
9542
|
+
if (!runId)
|
|
9543
|
+
return { status: 400, reason: "Missing run id" };
|
|
9544
|
+
if (liveRunIds.has(runId))
|
|
9545
|
+
return { status: 409, reason: "Run id already connected" };
|
|
9546
|
+
return;
|
|
9547
|
+
}
|
|
9548
|
+
|
|
9303
9549
|
// packages/daemon/src/persistence/rateLimitCache.ts
|
|
9304
9550
|
import { mkdir as mkdir2, readFile, writeFile } from "fs/promises";
|
|
9305
9551
|
import { homedir as homedir4 } from "os";
|
|
@@ -9362,16 +9608,6 @@ var agentHandlers = {
|
|
|
9362
9608
|
async* "agent.prompt.requested"({ agents }, request) {
|
|
9363
9609
|
yield* agents.requireSession(request.agentSessionId).prompt(request.content);
|
|
9364
9610
|
},
|
|
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
9611
|
async* "agent.prompt.cancel.requested"({ agents }, request) {
|
|
9376
9612
|
await agents.requireSession(request.agentSessionId).cancel();
|
|
9377
9613
|
yield { type: "agent.prompt.cancelled", agentSessionId: request.agentSessionId };
|
|
@@ -9455,12 +9691,16 @@ var agentHandlers = {
|
|
|
9455
9691
|
// packages/daemon/src/handlers/optionsHandlers.ts
|
|
9456
9692
|
var optionsHandlers = {
|
|
9457
9693
|
async* "options.load.requested"({ optionsPath }) {
|
|
9458
|
-
const { background } = await readOptions2(optionsPath);
|
|
9459
|
-
yield { type: "options.loaded", background };
|
|
9694
|
+
const { background, theme } = await readOptions2(optionsPath);
|
|
9695
|
+
yield { type: "options.loaded", background, theme };
|
|
9460
9696
|
},
|
|
9461
9697
|
async* "options.background.save.requested"({ optionsPath }, request) {
|
|
9462
9698
|
await saveBackground(optionsPath, request.color);
|
|
9463
9699
|
yield { type: "options.background.saved", color: request.color };
|
|
9700
|
+
},
|
|
9701
|
+
async* "options.theme.save.requested"({ optionsPath }, request) {
|
|
9702
|
+
await saveTheme(optionsPath, request.theme);
|
|
9703
|
+
yield { type: "options.theme.saved", theme: request.theme };
|
|
9464
9704
|
}
|
|
9465
9705
|
};
|
|
9466
9706
|
|
|
@@ -9496,14 +9736,14 @@ var sessionHandlers = {
|
|
|
9496
9736
|
};
|
|
9497
9737
|
|
|
9498
9738
|
// packages/daemon/src/workspace/readFileDiffs.ts
|
|
9499
|
-
import { relative, resolve as
|
|
9739
|
+
import { relative, resolve as resolve3 } from "path";
|
|
9500
9740
|
var isTracked = async (cwd, path) => (await Bun.$`git ls-files --error-unmatch -- ${path}`.cwd(cwd).quiet().nothrow()).exitCode === 0;
|
|
9501
9741
|
async function readPatch(cwd, path) {
|
|
9502
9742
|
const command = await isTracked(cwd, path) ? Bun.$`git diff --no-color HEAD -- ${path}` : Bun.$`git diff --no-color --no-index -- /dev/null ${path}`;
|
|
9503
9743
|
return (await command.cwd(cwd).quiet().nothrow()).text();
|
|
9504
9744
|
}
|
|
9505
9745
|
async function readFileDiff(cwd, path) {
|
|
9506
|
-
const absolute =
|
|
9746
|
+
const absolute = resolve3(cwd, path);
|
|
9507
9747
|
const patch = await readPatch(cwd, absolute);
|
|
9508
9748
|
return {
|
|
9509
9749
|
path: relative(cwd, absolute) || path,
|
|
@@ -11163,11 +11403,18 @@ var workspaceHandlers = {
|
|
|
11163
11403
|
|
|
11164
11404
|
// packages/daemon/src/server/handleRequest.ts
|
|
11165
11405
|
var handlers = { ...sessionHandlers, ...agentHandlers, ...workspaceHandlers, ...optionsHandlers };
|
|
11406
|
+
var SESSION_SWITCH_TYPES = new Set([
|
|
11407
|
+
"session.created",
|
|
11408
|
+
"session.restored",
|
|
11409
|
+
"session.forked"
|
|
11410
|
+
]);
|
|
11166
11411
|
async function* handleRequest(context, request) {
|
|
11167
|
-
|
|
11412
|
+
const origin = context.session;
|
|
11413
|
+
await origin.dispatch(request);
|
|
11168
11414
|
const handler = handlers[request.type];
|
|
11169
11415
|
for await (const response of handler(context, request)) {
|
|
11170
|
-
|
|
11416
|
+
const target = SESSION_SWITCH_TYPES.has(response.type) ? context.session : origin;
|
|
11417
|
+
await target.dispatch(response);
|
|
11171
11418
|
yield response;
|
|
11172
11419
|
}
|
|
11173
11420
|
}
|
|
@@ -11185,7 +11432,12 @@ function publishEvent(clients, origin, event, toOrigin = true) {
|
|
|
11185
11432
|
}
|
|
11186
11433
|
|
|
11187
11434
|
// packages/daemon/src/server/startDaemon.ts
|
|
11188
|
-
var
|
|
11435
|
+
var LOOPBACK_HOST = "127.0.0.1";
|
|
11436
|
+
async function reportFailure(context, server, socket, error) {
|
|
11437
|
+
const failure = { type: "request.failed", reason: String(error) };
|
|
11438
|
+
await context.session.dispatch(failure).catch(() => {});
|
|
11439
|
+
publishEvent(server.clients, socket, failure);
|
|
11440
|
+
}
|
|
11189
11441
|
async function answerMessage(context, server, socket, data) {
|
|
11190
11442
|
try {
|
|
11191
11443
|
const request = requestEventSchema.parse(JSON.parse(data));
|
|
@@ -11194,15 +11446,27 @@ async function answerMessage(context, server, socket, data) {
|
|
|
11194
11446
|
publishEvent(server.clients, socket, response);
|
|
11195
11447
|
}
|
|
11196
11448
|
} catch (error) {
|
|
11197
|
-
|
|
11198
|
-
await context.session.dispatch(failure);
|
|
11199
|
-
publishEvent(server.clients, socket, failure);
|
|
11449
|
+
await reportFailure(context, server, socket, error);
|
|
11200
11450
|
}
|
|
11201
11451
|
}
|
|
11202
|
-
async function startDaemon(port
|
|
11452
|
+
async function startDaemon(port, token, context) {
|
|
11203
11453
|
const daemonContext = context ?? await createDaemonContext();
|
|
11204
|
-
const
|
|
11205
|
-
server
|
|
11454
|
+
const liveRunIds = new Set;
|
|
11455
|
+
const server = new WebSocketServer({
|
|
11456
|
+
port,
|
|
11457
|
+
host: LOOPBACK_HOST,
|
|
11458
|
+
verifyClient: ({ req }, respond) => {
|
|
11459
|
+
const rejection = checkConnection(req, token, liveRunIds);
|
|
11460
|
+
if (rejection)
|
|
11461
|
+
respond(false, rejection.status, rejection.reason);
|
|
11462
|
+
else
|
|
11463
|
+
respond(true);
|
|
11464
|
+
}
|
|
11465
|
+
});
|
|
11466
|
+
server.on("connection", (socket, request) => {
|
|
11467
|
+
const runId = readRunId(request) ?? "";
|
|
11468
|
+
liveRunIds.add(runId);
|
|
11469
|
+
socket.once("close", () => liveRunIds.delete(runId));
|
|
11206
11470
|
socket.on("message", (data) => answerMessage(daemonContext, server, socket, data.toString()));
|
|
11207
11471
|
});
|
|
11208
11472
|
server.once("close", () => daemonContext.agents.closeAll());
|
|
@@ -11211,7 +11475,7 @@ async function startDaemon(port = DEFAULT_PORT, context) {
|
|
|
11211
11475
|
}
|
|
11212
11476
|
// apps/tui/src/startTui.ts
|
|
11213
11477
|
import {
|
|
11214
|
-
BoxRenderable as
|
|
11478
|
+
BoxRenderable as BoxRenderable19,
|
|
11215
11479
|
createCliRenderer,
|
|
11216
11480
|
createHostClipboard
|
|
11217
11481
|
} from "@opentui/core";
|
|
@@ -11253,7 +11517,7 @@ function buildPalette(colors, background = TRANSPARENT_BACKGROUND) {
|
|
|
11253
11517
|
},
|
|
11254
11518
|
fg: {
|
|
11255
11519
|
primary: hex("text"),
|
|
11256
|
-
secondary: rgbToHex2(tint(color("text"), color("textMuted"), SECONDARY_TEXT_WEIGHT)),
|
|
11520
|
+
secondary: hex("secondary") ?? rgbToHex2(tint(color("text"), color("textMuted"), SECONDARY_TEXT_WEIGHT)),
|
|
11257
11521
|
muted: hex("textMuted")
|
|
11258
11522
|
},
|
|
11259
11523
|
border: { subtle: hex("borderSubtle"), focus: hex("borderActive"), separator: hex("border") },
|
|
@@ -11264,7 +11528,38 @@ function buildPalette(colors, background = TRANSPARENT_BACKGROUND) {
|
|
|
11264
11528
|
warning: hex("warning"),
|
|
11265
11529
|
info: hex("info")
|
|
11266
11530
|
},
|
|
11267
|
-
diff: {
|
|
11531
|
+
diff: {
|
|
11532
|
+
addedBg: hex("diffAddedBg"),
|
|
11533
|
+
removedBg: hex("diffRemovedBg"),
|
|
11534
|
+
contextBg: hex("diffContextBg"),
|
|
11535
|
+
addedText: hex("diffAdded"),
|
|
11536
|
+
removedText: hex("diffRemoved"),
|
|
11537
|
+
contextText: hex("diffContext"),
|
|
11538
|
+
lineNumber: hex("diffLineNumber"),
|
|
11539
|
+
addedLineNumberBg: hex("diffAddedLineNumberBg"),
|
|
11540
|
+
removedLineNumberBg: hex("diffRemovedLineNumberBg")
|
|
11541
|
+
},
|
|
11542
|
+
syntax: {
|
|
11543
|
+
comment: hex("syntaxComment"),
|
|
11544
|
+
keyword: hex("syntaxKeyword"),
|
|
11545
|
+
function: hex("syntaxFunction"),
|
|
11546
|
+
variable: hex("syntaxVariable"),
|
|
11547
|
+
string: hex("syntaxString"),
|
|
11548
|
+
number: hex("syntaxNumber"),
|
|
11549
|
+
type: hex("syntaxType"),
|
|
11550
|
+
operator: hex("syntaxOperator"),
|
|
11551
|
+
punctuation: hex("syntaxPunctuation")
|
|
11552
|
+
},
|
|
11553
|
+
markdown: {
|
|
11554
|
+
heading: hex("markdownHeading"),
|
|
11555
|
+
strong: hex("markdownStrong"),
|
|
11556
|
+
emphasis: hex("markdownEmph"),
|
|
11557
|
+
listItem: hex("markdownListItem"),
|
|
11558
|
+
blockQuote: hex("markdownBlockQuote"),
|
|
11559
|
+
code: hex("markdownCode"),
|
|
11560
|
+
link: hex("markdownLink"),
|
|
11561
|
+
linkText: hex("markdownLinkText")
|
|
11562
|
+
}
|
|
11268
11563
|
};
|
|
11269
11564
|
}
|
|
11270
11565
|
// apps/tui/src/theme/assets/aura.json
|
|
@@ -18733,10 +19028,16 @@ var createDiffView = (renderer, syntaxStyle, patch, filetype) => new DiffRendera
|
|
|
18733
19028
|
syntaxStyle,
|
|
18734
19029
|
view: "unified",
|
|
18735
19030
|
showLineNumbers: true,
|
|
19031
|
+
fg: Theme.fg.primary,
|
|
18736
19032
|
addedBg: Theme.diff.addedBg,
|
|
18737
19033
|
removedBg: Theme.diff.removedBg,
|
|
18738
|
-
|
|
18739
|
-
|
|
19034
|
+
contextBg: Theme.diff.contextBg,
|
|
19035
|
+
lineNumberFg: Theme.diff.lineNumber,
|
|
19036
|
+
lineNumberBg: Theme.diff.contextBg,
|
|
19037
|
+
addedLineNumberBg: Theme.diff.addedLineNumberBg,
|
|
19038
|
+
removedLineNumberBg: Theme.diff.removedLineNumberBg,
|
|
19039
|
+
addedSignColor: Theme.diff.addedText,
|
|
19040
|
+
removedSignColor: Theme.diff.removedText,
|
|
18740
19041
|
flexShrink: 0
|
|
18741
19042
|
});
|
|
18742
19043
|
|
|
@@ -19025,11 +19326,11 @@ var buildImageBlock = (mediaType, bytes) => ({
|
|
|
19025
19326
|
// apps/tui/src/prompt/pastedPaths.ts
|
|
19026
19327
|
import { statSync } from "fs";
|
|
19027
19328
|
import { homedir as homedir6 } from "os";
|
|
19028
|
-
import { isAbsolute } from "path";
|
|
19329
|
+
import { isAbsolute as isAbsolute2 } from "path";
|
|
19029
19330
|
var unwrapPath = (raw) => raw.trim().replace(/^(['"])(.*)\1$/, "$2").replace(/^file:\/\//, "").replace(/^~(?=\/)/, homedir6()).replace(/\\(.)/g, "$1");
|
|
19030
19331
|
var isExistingFile = (path) => {
|
|
19031
19332
|
try {
|
|
19032
|
-
return
|
|
19333
|
+
return isAbsolute2(path) && statSync(path).isFile();
|
|
19033
19334
|
} catch {
|
|
19034
19335
|
return false;
|
|
19035
19336
|
}
|
|
@@ -19075,7 +19376,7 @@ function planPaste(event, attachments) {
|
|
|
19075
19376
|
|
|
19076
19377
|
// apps/tui/src/components/promptInput.ts
|
|
19077
19378
|
var MAX_INPUT_LINES = 8;
|
|
19078
|
-
var
|
|
19379
|
+
var BUSY_PLACEHOLDER = "Enter (steer) Ctrl+Q (queue)";
|
|
19079
19380
|
var ATTACHMENT_STYLE = "attachment";
|
|
19080
19381
|
var PLACEHOLDER = "Type your prompt, /slash command, or @file reference...";
|
|
19081
19382
|
var KEY_BINDINGS = [
|
|
@@ -19097,12 +19398,11 @@ class PromptInput {
|
|
|
19097
19398
|
constructor(renderer, handlers) {
|
|
19098
19399
|
this.renderable = new BoxRenderable5(renderer, {
|
|
19099
19400
|
border: ["top", "bottom"],
|
|
19401
|
+
borderColor: Theme.fg.muted,
|
|
19100
19402
|
borderStyle: "rounded",
|
|
19101
|
-
bottomTitleAlignment: "right",
|
|
19102
19403
|
flexDirection: "row",
|
|
19103
19404
|
height: 3,
|
|
19104
|
-
flexShrink: 0
|
|
19105
|
-
paddingLeft: 1
|
|
19405
|
+
flexShrink: 0
|
|
19106
19406
|
});
|
|
19107
19407
|
this.attachmentStyle = SyntaxStyle.create(renderer.nativeScene);
|
|
19108
19408
|
this.textarea = new TextareaRenderable(renderer, {
|
|
@@ -19163,16 +19463,15 @@ class PromptInput {
|
|
|
19163
19463
|
this.textarea.blur();
|
|
19164
19464
|
}
|
|
19165
19465
|
setBusy(busy) {
|
|
19166
|
-
const
|
|
19167
|
-
if (this.
|
|
19168
|
-
this.
|
|
19466
|
+
const placeholder = busy ? BUSY_PLACEHOLDER : PLACEHOLDER;
|
|
19467
|
+
if (this.textarea.placeholder !== placeholder)
|
|
19468
|
+
this.textarea.placeholder = placeholder;
|
|
19169
19469
|
}
|
|
19170
19470
|
setBorderColor(color) {
|
|
19171
19471
|
this.renderable.borderColor = color;
|
|
19172
19472
|
}
|
|
19173
19473
|
applyColors() {
|
|
19174
|
-
this.
|
|
19175
|
-
this.chevron.fg = Theme.accent.brand;
|
|
19474
|
+
this.chevron.fg = Theme.fg.muted;
|
|
19176
19475
|
this.textarea.placeholderColor = Theme.fg.muted;
|
|
19177
19476
|
this.textarea.textColor = Theme.fg.primary;
|
|
19178
19477
|
this.textarea.focusedTextColor = Theme.fg.primary;
|
|
@@ -19274,6 +19573,25 @@ class AssistantMessageView {
|
|
|
19274
19573
|
}
|
|
19275
19574
|
}
|
|
19276
19575
|
|
|
19576
|
+
// apps/tui/src/components/markdownNoticeView.ts
|
|
19577
|
+
import { MarkdownRenderable as MarkdownRenderable2 } from "@opentui/core";
|
|
19578
|
+
|
|
19579
|
+
class MarkdownNoticeView {
|
|
19580
|
+
renderable;
|
|
19581
|
+
constructor(renderer, mutedSyntaxStyle) {
|
|
19582
|
+
this.renderable = new MarkdownRenderable2(renderer, {
|
|
19583
|
+
content: "",
|
|
19584
|
+
syntaxStyle: mutedSyntaxStyle,
|
|
19585
|
+
marginTop: 1,
|
|
19586
|
+
flexShrink: 0
|
|
19587
|
+
});
|
|
19588
|
+
}
|
|
19589
|
+
update(entry) {
|
|
19590
|
+
if (this.renderable.content !== entry.text)
|
|
19591
|
+
this.renderable.content = entry.text;
|
|
19592
|
+
}
|
|
19593
|
+
}
|
|
19594
|
+
|
|
19277
19595
|
// apps/tui/src/components/noticeView.ts
|
|
19278
19596
|
import { fg as fg7, StyledText as StyledText6, TextRenderable as TextRenderable7 } from "@opentui/core";
|
|
19279
19597
|
class NoticeView {
|
|
@@ -19928,7 +20246,9 @@ var clipLines = (text, maxLines) => {
|
|
|
19928
20246
|
// apps/tui/src/format/toolInputText.ts
|
|
19929
20247
|
var VALUE_LENGTH = 200;
|
|
19930
20248
|
var formatInputValue = (value) => truncateText(typeof value === "string" ? value : JSON.stringify(value), VALUE_LENGTH);
|
|
19931
|
-
var
|
|
20249
|
+
var formatBatchEdit = ({ input }) => listBatchEditPaths(input).map((path, index) => `${index + 1}. ${formatInputValue(path)}`).join(`
|
|
20250
|
+
`);
|
|
20251
|
+
var formatToolInput = (call) => call.name === BATCH_EDIT_TOOL_NAME ? formatBatchEdit(call) : Object.entries(call.input).map(([key, value]) => `${key}: ${formatInputValue(value)}`).join(`
|
|
19932
20252
|
`);
|
|
19933
20253
|
|
|
19934
20254
|
// apps/tui/src/format/toolSummary.ts
|
|
@@ -19936,9 +20256,15 @@ var SUMMARY_LENGTH = 80;
|
|
|
19936
20256
|
var SUMMARY_KEYS = ["file_path", "path", "command", "pattern", "query", "url", "description"];
|
|
19937
20257
|
var SEARCH_TOOLS = new Set(["Glob", "Grep"]);
|
|
19938
20258
|
var summarizeSearch = ({ pattern, path }) => typeof path === "string" ? `${pattern} in ${path}` : String(pattern);
|
|
20259
|
+
var summarizeBatchEdit = (input) => {
|
|
20260
|
+
const paths = listBatchEditPaths(input);
|
|
20261
|
+
return `${paths.length} edits in ${new Set(paths).size} files`;
|
|
20262
|
+
};
|
|
19939
20263
|
function summarizeToolCall({ name, input, status, progress }) {
|
|
19940
20264
|
if (status === "running" && progress)
|
|
19941
20265
|
return truncateText(progress, SUMMARY_LENGTH);
|
|
20266
|
+
if (name === BATCH_EDIT_TOOL_NAME)
|
|
20267
|
+
return summarizeBatchEdit(input);
|
|
19942
20268
|
if (SEARCH_TOOLS.has(name) && typeof input.pattern === "string") {
|
|
19943
20269
|
return truncateText(summarizeSearch(input), SUMMARY_LENGTH);
|
|
19944
20270
|
}
|
|
@@ -19947,6 +20273,8 @@ function summarizeToolCall({ name, input, status, progress }) {
|
|
|
19947
20273
|
return truncateText(value, SUMMARY_LENGTH);
|
|
19948
20274
|
}
|
|
19949
20275
|
var describeApproval = ({ name, input }) => {
|
|
20276
|
+
if (name === BATCH_EDIT_TOOL_NAME)
|
|
20277
|
+
return `Apply ${summarizeBatchEdit(input)} with BatchEdit?`;
|
|
19950
20278
|
if (name === "Bash")
|
|
19951
20279
|
return `Run command \`${truncateText(String(input.command ?? ""), 60)}\`?`;
|
|
19952
20280
|
const path = input.file_path ?? input.notebook_path;
|
|
@@ -20192,7 +20520,7 @@ class ToolCallView {
|
|
|
20192
20520
|
const accent = this.hovered ? Theme.accent.brand : undefined;
|
|
20193
20521
|
this.title.content = new StyledText10([
|
|
20194
20522
|
fg11(accent ?? toolColor(call.status))(glyph),
|
|
20195
|
-
bold6(fg11(accent ?? Theme.fg.primary)(call.name)),
|
|
20523
|
+
bold6(fg11(accent ?? Theme.fg.primary)(stripCustomPrefix(call.name))),
|
|
20196
20524
|
fg11(Theme.fg.secondary)(` ${summarizeToolCall(call)}`),
|
|
20197
20525
|
fg11(Theme.fg.muted)(stats)
|
|
20198
20526
|
]);
|
|
@@ -20352,9 +20680,9 @@ class ScrollbackView {
|
|
|
20352
20680
|
else if (below > 0)
|
|
20353
20681
|
this.renderable.scrollBy(Math.min(below, above));
|
|
20354
20682
|
}
|
|
20355
|
-
reset(syntaxStyle) {
|
|
20683
|
+
reset(syntaxStyle, mutedSyntaxStyle) {
|
|
20356
20684
|
this.dropViews(() => true);
|
|
20357
|
-
this.options = { syntaxStyle, hooks: { ...this.options.hooks, syntaxStyle } };
|
|
20685
|
+
this.options = { syntaxStyle, mutedSyntaxStyle, hooks: { ...this.options.hooks, syntaxStyle } };
|
|
20358
20686
|
}
|
|
20359
20687
|
dropRemovedViews(state) {
|
|
20360
20688
|
const live = new Set(state.transcript.map((entry) => entry.id));
|
|
@@ -20376,14 +20704,14 @@ class ScrollbackView {
|
|
|
20376
20704
|
return view;
|
|
20377
20705
|
}
|
|
20378
20706
|
createView(entry) {
|
|
20379
|
-
const { syntaxStyle, hooks } = this.options;
|
|
20707
|
+
const { syntaxStyle, mutedSyntaxStyle, hooks } = this.options;
|
|
20380
20708
|
switch (entry.kind) {
|
|
20381
20709
|
case "user":
|
|
20382
20710
|
return new UserMessageView(this.renderer);
|
|
20383
20711
|
case "assistant":
|
|
20384
20712
|
return new AssistantMessageView(this.renderer, syntaxStyle);
|
|
20385
20713
|
case "notice":
|
|
20386
|
-
return new NoticeView(this.renderer);
|
|
20714
|
+
return entry.markdown ? new MarkdownNoticeView(this.renderer, mutedSyntaxStyle) : new NoticeView(this.renderer);
|
|
20387
20715
|
case "thought":
|
|
20388
20716
|
return new ThoughtView(this.renderer);
|
|
20389
20717
|
case "tools":
|
|
@@ -20462,15 +20790,14 @@ class SessionInfoBar {
|
|
|
20462
20790
|
limits;
|
|
20463
20791
|
constructor(renderer) {
|
|
20464
20792
|
this.renderable = new BoxRenderable13(renderer, {
|
|
20465
|
-
marginBottom: 1,
|
|
20466
20793
|
flexShrink: 0,
|
|
20467
20794
|
flexDirection: "row",
|
|
20468
20795
|
flexWrap: "wrap",
|
|
20469
20796
|
rowGap: 1,
|
|
20470
20797
|
columnGap: 0,
|
|
20471
20798
|
justifyContent: "space-between",
|
|
20472
|
-
paddingLeft:
|
|
20473
|
-
paddingRight:
|
|
20799
|
+
paddingLeft: 2,
|
|
20800
|
+
paddingRight: 2
|
|
20474
20801
|
});
|
|
20475
20802
|
this.info = new TextRenderable13(renderer, { content: "", wrapMode: "none", flexShrink: 0 });
|
|
20476
20803
|
this.limits = new TextRenderable13(renderer, {
|
|
@@ -20526,12 +20853,14 @@ class StatusLine {
|
|
|
20526
20853
|
constructor(renderer, onStop) {
|
|
20527
20854
|
this.renderable = new BoxRenderable14(renderer, {
|
|
20528
20855
|
height: 2,
|
|
20529
|
-
paddingTop: 1,
|
|
20530
20856
|
flexShrink: 0,
|
|
20531
20857
|
flexDirection: "row",
|
|
20532
20858
|
justifyContent: "space-between",
|
|
20859
|
+
border: ["top"],
|
|
20860
|
+
borderColor: Theme.border.subtle,
|
|
20533
20861
|
paddingLeft: 2,
|
|
20534
|
-
paddingRight: 2
|
|
20862
|
+
paddingRight: 2,
|
|
20863
|
+
visible: false
|
|
20535
20864
|
});
|
|
20536
20865
|
this.label = new TextRenderable14(renderer, { content: "", wrapMode: "none" });
|
|
20537
20866
|
this.stats = new TextRenderable14(renderer, {
|
|
@@ -20547,9 +20876,11 @@ class StatusLine {
|
|
|
20547
20876
|
update(state) {
|
|
20548
20877
|
if (state.status === "idle") {
|
|
20549
20878
|
this.label.content = state.lastRun ? new StyledText13(buildLastRunChunks(state.lastRun, readLastPrompt(state))) : "";
|
|
20879
|
+
this.renderable.visible = state.lastRun !== undefined;
|
|
20550
20880
|
this.stats.content = "";
|
|
20551
20881
|
return;
|
|
20552
20882
|
}
|
|
20883
|
+
this.renderable.visible = true;
|
|
20553
20884
|
const label = agentLabel(state.status);
|
|
20554
20885
|
const busy = label.icon === undefined;
|
|
20555
20886
|
const frame = SPINNER_FRAMES[Math.floor(state.now / SPINNER_STEP_MS) % SPINNER_FRAMES.length];
|
|
@@ -20566,26 +20897,96 @@ class StatusLine {
|
|
|
20566
20897
|
}
|
|
20567
20898
|
}
|
|
20568
20899
|
|
|
20900
|
+
// apps/tui/src/components/promptQueueView.ts
|
|
20901
|
+
import {
|
|
20902
|
+
BoxRenderable as BoxRenderable15,
|
|
20903
|
+
bold as bold9,
|
|
20904
|
+
dim as dim7,
|
|
20905
|
+
fg as fg16,
|
|
20906
|
+
StyledText as StyledText14,
|
|
20907
|
+
TextRenderable as TextRenderable15
|
|
20908
|
+
} from "@opentui/core";
|
|
20909
|
+
|
|
20910
|
+
// apps/tui/src/format/promptQueueRows.ts
|
|
20911
|
+
var MAX_QUEUE_ROWS = 5;
|
|
20912
|
+
var QUEUE_TEXT_LENGTH = 80;
|
|
20913
|
+
var buildQueueRows = (queued) => queued.slice(0, MAX_QUEUE_ROWS).map((content, index) => `${index + 1}. ${truncateText(readPromptText(content), QUEUE_TEXT_LENGTH)}`);
|
|
20914
|
+
var buildQueueHeader = (queued) => `Queued${SEPARATOR}${queued.length} waiting`;
|
|
20915
|
+
var countHiddenQueued = (queued) => Math.max(queued.length - MAX_QUEUE_ROWS, 0);
|
|
20916
|
+
|
|
20917
|
+
// apps/tui/src/components/promptQueueView.ts
|
|
20918
|
+
class PromptQueueView {
|
|
20919
|
+
renderable;
|
|
20920
|
+
header;
|
|
20921
|
+
rows;
|
|
20922
|
+
overflow;
|
|
20923
|
+
constructor(renderer) {
|
|
20924
|
+
this.renderable = new BoxRenderable15(renderer, {
|
|
20925
|
+
flexShrink: 0,
|
|
20926
|
+
paddingLeft: 2,
|
|
20927
|
+
paddingRight: 2,
|
|
20928
|
+
visible: false
|
|
20929
|
+
});
|
|
20930
|
+
this.header = new TextRenderable15(renderer, { content: "", wrapMode: "none" });
|
|
20931
|
+
this.overflow = new TextRenderable15(renderer, { content: "", wrapMode: "none" });
|
|
20932
|
+
this.rows = Array.from({ length: MAX_QUEUE_ROWS }, () => new TextRenderable15(renderer, { content: "", wrapMode: "none" }));
|
|
20933
|
+
this.renderable.add(this.header);
|
|
20934
|
+
for (const row of this.rows)
|
|
20935
|
+
this.renderable.add(row);
|
|
20936
|
+
this.renderable.add(this.overflow);
|
|
20937
|
+
}
|
|
20938
|
+
update({ queuedPrompts }) {
|
|
20939
|
+
this.renderable.visible = queuedPrompts.length > 0;
|
|
20940
|
+
if (queuedPrompts.length === 0)
|
|
20941
|
+
return;
|
|
20942
|
+
this.header.content = new StyledText14([
|
|
20943
|
+
bold9(fg16(Theme.fg.secondary)(buildQueueHeader(queuedPrompts)))
|
|
20944
|
+
]);
|
|
20945
|
+
const lines = buildQueueRows(queuedPrompts);
|
|
20946
|
+
this.rows.forEach((row, index) => {
|
|
20947
|
+
row.content = new StyledText14([fg16(Theme.fg.primary)(lines[index] ?? "")]);
|
|
20948
|
+
});
|
|
20949
|
+
const hidden = countHiddenQueued(queuedPrompts);
|
|
20950
|
+
this.overflow.content = hidden ? new StyledText14([dim7(fg16(Theme.fg.muted)(` +${hidden} more`))]) : "";
|
|
20951
|
+
}
|
|
20952
|
+
}
|
|
20953
|
+
|
|
20569
20954
|
// apps/tui/src/components/taskPanel.ts
|
|
20570
20955
|
import {
|
|
20571
|
-
BoxRenderable as
|
|
20572
|
-
bold as
|
|
20573
|
-
dim as
|
|
20574
|
-
fg as
|
|
20575
|
-
StyledText as
|
|
20576
|
-
TextRenderable as
|
|
20956
|
+
BoxRenderable as BoxRenderable17,
|
|
20957
|
+
bold as bold11,
|
|
20958
|
+
dim as dim9,
|
|
20959
|
+
fg as fg18,
|
|
20960
|
+
StyledText as StyledText16,
|
|
20961
|
+
TextRenderable as TextRenderable17
|
|
20577
20962
|
} from "@opentui/core";
|
|
20578
20963
|
|
|
20579
20964
|
// apps/tui/src/format/taskRows.ts
|
|
20580
20965
|
var MAX_TASK_ROWS = 5;
|
|
20581
|
-
var
|
|
20582
|
-
|
|
20966
|
+
var KIND_LABELS = { "general-purpose": "Agent", local_bash: "Bash" };
|
|
20967
|
+
var describeLastTool = ({ lastToolCall, lastToolName }) => {
|
|
20968
|
+
if (!lastToolCall)
|
|
20969
|
+
return lastToolName;
|
|
20970
|
+
const { name, input } = lastToolCall;
|
|
20971
|
+
const summary = summarizeToolCall({
|
|
20972
|
+
id: "",
|
|
20973
|
+
name,
|
|
20974
|
+
input,
|
|
20975
|
+
status: "running",
|
|
20976
|
+
expanded: false,
|
|
20977
|
+
startedAt: 0
|
|
20978
|
+
});
|
|
20979
|
+
return `${name} ${summary}`;
|
|
20980
|
+
};
|
|
20981
|
+
var readDetail = (task) => {
|
|
20982
|
+
if (task.paused)
|
|
20583
20983
|
return "Paused";
|
|
20584
|
-
return summary ??
|
|
20984
|
+
return task.summary ?? describeLastTool(task) ?? "Starting...";
|
|
20585
20985
|
};
|
|
20586
20986
|
var buildTaskRow = (task, now) => ({
|
|
20587
20987
|
taskId: task.id,
|
|
20588
|
-
kind: task.kind,
|
|
20988
|
+
kind: KIND_LABELS[task.kind] ?? task.kind,
|
|
20989
|
+
model: task.model ?? "",
|
|
20589
20990
|
title: task.description,
|
|
20590
20991
|
stats: [formatDuration(Math.max(now - task.startedAt, 0)), `\u2193${formatTokenCount(task.tokens)}`].join(SEPARATOR).trim(),
|
|
20591
20992
|
detail: readDetail(task)
|
|
@@ -20596,12 +20997,12 @@ var countHiddenTasks = (tasks) => Math.max(tasks.length - MAX_TASK_ROWS, 0);
|
|
|
20596
20997
|
|
|
20597
20998
|
// apps/tui/src/components/taskRowView.ts
|
|
20598
20999
|
import {
|
|
20599
|
-
BoxRenderable as
|
|
20600
|
-
bold as
|
|
20601
|
-
dim as
|
|
20602
|
-
fg as
|
|
20603
|
-
StyledText as
|
|
20604
|
-
TextRenderable as
|
|
21000
|
+
BoxRenderable as BoxRenderable16,
|
|
21001
|
+
bold as bold10,
|
|
21002
|
+
dim as dim8,
|
|
21003
|
+
fg as fg17,
|
|
21004
|
+
StyledText as StyledText15,
|
|
21005
|
+
TextRenderable as TextRenderable16
|
|
20605
21006
|
} from "@opentui/core";
|
|
20606
21007
|
var SPINNER_STEP_MS2 = 100;
|
|
20607
21008
|
|
|
@@ -20612,20 +21013,20 @@ class TaskRowView {
|
|
|
20612
21013
|
detail;
|
|
20613
21014
|
taskId = "";
|
|
20614
21015
|
constructor(renderer, onStop) {
|
|
20615
|
-
this.renderable = new
|
|
20616
|
-
const line = new
|
|
21016
|
+
this.renderable = new BoxRenderable16(renderer, { flexShrink: 0, visible: false });
|
|
21017
|
+
const line = new BoxRenderable16(renderer, {
|
|
20617
21018
|
flexDirection: "row",
|
|
20618
21019
|
justifyContent: "space-between"
|
|
20619
21020
|
});
|
|
20620
|
-
this.title = new
|
|
20621
|
-
this.stop = new
|
|
21021
|
+
this.title = new TextRenderable16(renderer, { content: "", wrapMode: "none" });
|
|
21022
|
+
this.stop = new TextRenderable16(renderer, {
|
|
20622
21023
|
content: "",
|
|
20623
21024
|
wrapMode: "none",
|
|
20624
21025
|
flexShrink: 0,
|
|
20625
21026
|
selectable: false,
|
|
20626
21027
|
onMouseDown: () => onStop(this.taskId)
|
|
20627
21028
|
});
|
|
20628
|
-
this.detail = new
|
|
21029
|
+
this.detail = new TextRenderable16(renderer, { content: "", wrapMode: "none" });
|
|
20629
21030
|
line.add(this.title);
|
|
20630
21031
|
line.add(this.stop);
|
|
20631
21032
|
this.renderable.add(line);
|
|
@@ -20637,16 +21038,17 @@ class TaskRowView {
|
|
|
20637
21038
|
return;
|
|
20638
21039
|
this.taskId = row.taskId;
|
|
20639
21040
|
const frame = SPINNER_FRAMES[Math.floor(now / SPINNER_STEP_MS2) % SPINNER_FRAMES.length];
|
|
20640
|
-
this.title.content = new
|
|
20641
|
-
|
|
20642
|
-
|
|
20643
|
-
|
|
21041
|
+
this.title.content = new StyledText15([
|
|
21042
|
+
fg17(Theme.status.success)(`${frame} `),
|
|
21043
|
+
bold10(fg17(Theme.fg.primary)(row.kind)),
|
|
21044
|
+
fg17(Theme.fg.muted)(row.model ? ` (${row.model})` : ""),
|
|
21045
|
+
fg17(Theme.fg.secondary)(` ${row.title}`)
|
|
20644
21046
|
]);
|
|
20645
|
-
this.stop.content = new
|
|
20646
|
-
|
|
20647
|
-
|
|
21047
|
+
this.stop.content = new StyledText15([
|
|
21048
|
+
fg17(Theme.fg.muted)(`${row.stats} `),
|
|
21049
|
+
bold10(fg17(Theme.fg.secondary)("[stop]"))
|
|
20648
21050
|
]);
|
|
20649
|
-
this.detail.content = new
|
|
21051
|
+
this.detail.content = new StyledText15([dim8(fg17(Theme.fg.muted)(` \u2514 ${row.detail}`))]);
|
|
20650
21052
|
}
|
|
20651
21053
|
}
|
|
20652
21054
|
|
|
@@ -20657,14 +21059,16 @@ class TaskPanel {
|
|
|
20657
21059
|
rows;
|
|
20658
21060
|
overflow;
|
|
20659
21061
|
constructor(renderer, onStop) {
|
|
20660
|
-
this.renderable = new
|
|
21062
|
+
this.renderable = new BoxRenderable17(renderer, {
|
|
20661
21063
|
flexShrink: 0,
|
|
20662
21064
|
paddingLeft: 2,
|
|
20663
21065
|
paddingRight: 2,
|
|
21066
|
+
border: ["top"],
|
|
21067
|
+
borderColor: Theme.border.subtle,
|
|
20664
21068
|
visible: false
|
|
20665
21069
|
});
|
|
20666
|
-
this.header = new
|
|
20667
|
-
this.overflow = new
|
|
21070
|
+
this.header = new TextRenderable17(renderer, { content: "", wrapMode: "none" });
|
|
21071
|
+
this.overflow = new TextRenderable17(renderer, { content: "", wrapMode: "none" });
|
|
20668
21072
|
this.rows = Array.from({ length: MAX_TASK_ROWS }, () => new TaskRowView(renderer, onStop));
|
|
20669
21073
|
this.renderable.add(this.header);
|
|
20670
21074
|
for (const row of this.rows)
|
|
@@ -20676,15 +21080,15 @@ class TaskPanel {
|
|
|
20676
21080
|
if (tasks.length === 0)
|
|
20677
21081
|
return;
|
|
20678
21082
|
const rows = buildTaskRows(tasks, now);
|
|
20679
|
-
this.header.content = new
|
|
21083
|
+
this.header.content = new StyledText16([bold11(fg18(Theme.fg.primary)(buildTaskHeader(tasks)))]);
|
|
20680
21084
|
this.rows.forEach((view, index) => view.update(rows[index], now));
|
|
20681
21085
|
const hidden = countHiddenTasks(tasks);
|
|
20682
|
-
this.overflow.content = hidden ? new
|
|
21086
|
+
this.overflow.content = hidden ? new StyledText16([dim9(fg18(Theme.fg.muted)(` +${hidden} more`))]) : "";
|
|
20683
21087
|
}
|
|
20684
21088
|
}
|
|
20685
21089
|
|
|
20686
21090
|
// apps/tui/src/components/toastView.ts
|
|
20687
|
-
import { BoxRenderable as
|
|
21091
|
+
import { BoxRenderable as BoxRenderable18, fg as fg19, StyledText as StyledText17, TextRenderable as TextRenderable18 } from "@opentui/core";
|
|
20688
21092
|
var TOAST_ICON = "\u25CF";
|
|
20689
21093
|
|
|
20690
21094
|
class ToastView {
|
|
@@ -20692,7 +21096,7 @@ class ToastView {
|
|
|
20692
21096
|
text;
|
|
20693
21097
|
toastId;
|
|
20694
21098
|
constructor(renderer) {
|
|
20695
|
-
this.renderable = new
|
|
21099
|
+
this.renderable = new BoxRenderable18(renderer, {
|
|
20696
21100
|
position: "absolute",
|
|
20697
21101
|
top: 1,
|
|
20698
21102
|
right: 2,
|
|
@@ -20703,7 +21107,7 @@ class ToastView {
|
|
|
20703
21107
|
borderStyle: "rounded",
|
|
20704
21108
|
visible: false
|
|
20705
21109
|
});
|
|
20706
|
-
this.text = new
|
|
21110
|
+
this.text = new TextRenderable18(renderer, { content: "", wrapMode: "none", selectable: false });
|
|
20707
21111
|
this.renderable.add(this.text);
|
|
20708
21112
|
}
|
|
20709
21113
|
update({ ui }) {
|
|
@@ -20714,9 +21118,9 @@ class ToastView {
|
|
|
20714
21118
|
this.toastId = toast.id;
|
|
20715
21119
|
this.renderable.borderColor = Theme.border.focus;
|
|
20716
21120
|
this.renderable.backgroundColor = Theme.bg.surface;
|
|
20717
|
-
this.text.content = new
|
|
20718
|
-
|
|
20719
|
-
|
|
21121
|
+
this.text.content = new StyledText17([
|
|
21122
|
+
fg19(Theme.status.success)(`${TOAST_ICON} `),
|
|
21123
|
+
fg19(Theme.fg.primary)(toast.text)
|
|
20720
21124
|
]);
|
|
20721
21125
|
}
|
|
20722
21126
|
}
|
|
@@ -20745,6 +21149,9 @@ function requestAgent(store, request, onMissing = "notify") {
|
|
|
20745
21149
|
return true;
|
|
20746
21150
|
}
|
|
20747
21151
|
|
|
21152
|
+
// apps/tui/src/input/themeActions.ts
|
|
21153
|
+
var saveTheme2 = (store, theme) => store.request({ type: "options.theme.save.requested", theme });
|
|
21154
|
+
|
|
20748
21155
|
// apps/tui/src/input/workflowCommands.ts
|
|
20749
21156
|
var postNotice = (store, text) => store.emit({ type: "ui.notice.posted", text });
|
|
20750
21157
|
var WORKFLOW_COMMANDS = {
|
|
@@ -20844,7 +21251,7 @@ var SLASH_COMMANDS = {
|
|
|
20844
21251
|
return store.emit({ type: "ui.theme.picker.opened" });
|
|
20845
21252
|
const parsed = themeNameSchema.safeParse(argument);
|
|
20846
21253
|
if (parsed.success)
|
|
20847
|
-
return store
|
|
21254
|
+
return saveTheme2(store, parsed.data);
|
|
20848
21255
|
store.emit({ type: "ui.notice.posted", text: `Unknown theme: ${argument}` });
|
|
20849
21256
|
}
|
|
20850
21257
|
},
|
|
@@ -20873,8 +21280,10 @@ var SLASH_COMMANDS = {
|
|
|
20873
21280
|
}
|
|
20874
21281
|
},
|
|
20875
21282
|
"/effort": {
|
|
20876
|
-
description: "
|
|
21283
|
+
description: "Pick a reasoning effort, or set one with /effort <level>",
|
|
20877
21284
|
run(store, level) {
|
|
21285
|
+
if (!level)
|
|
21286
|
+
return store.emit({ type: "ui.effort.picker.opened" });
|
|
20878
21287
|
const parsed = effortLevelSchema.safeParse(level);
|
|
20879
21288
|
if (parsed.success) {
|
|
20880
21289
|
return void requestAgent(store, {
|
|
@@ -20946,6 +21355,14 @@ function buildPickerView(state) {
|
|
|
20946
21355
|
}));
|
|
20947
21356
|
return { title: "Select a theme", rows, selected: picker.selected };
|
|
20948
21357
|
}
|
|
21358
|
+
if (picker.kind === "effort") {
|
|
21359
|
+
const current = state.effort || DEFAULT_EFFORT;
|
|
21360
|
+
const rows = effortLevelSchema.options.map((level) => ({
|
|
21361
|
+
name: `${level === current ? "\u25CF " : " "}${level}`,
|
|
21362
|
+
description: ""
|
|
21363
|
+
}));
|
|
21364
|
+
return { title: "Select an effort level", rows, selected: picker.selected };
|
|
21365
|
+
}
|
|
20949
21366
|
if (picker.kind === "rewind") {
|
|
20950
21367
|
const rows = listCheckpoints(state).map((entry) => ({
|
|
20951
21368
|
name: truncateText(entry.text.replace(/\s+/g, " "), CHECKPOINT_TEXT_LENGTH),
|
|
@@ -20963,7 +21380,6 @@ function buildPickerView(state) {
|
|
|
20963
21380
|
var buildListView = (state) => buildPickerView(state) ?? buildAutocompleteView(state);
|
|
20964
21381
|
|
|
20965
21382
|
// apps/tui/src/input/agentSessionActions.ts
|
|
20966
|
-
var DEFAULT_EFFORT = "high";
|
|
20967
21383
|
var DEFAULT_MODEL = "claude-haiku-5-5";
|
|
20968
21384
|
var buildSessionOptions = (store) => ({
|
|
20969
21385
|
model: store.state.model || DEFAULT_MODEL,
|
|
@@ -21142,23 +21558,22 @@ function runSlashCommand(store, line) {
|
|
|
21142
21558
|
}
|
|
21143
21559
|
|
|
21144
21560
|
// 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
21561
|
var buildContent = (text, images) => images.length > 0 ? [{ type: "text", text }, ...images] : text;
|
|
21152
21562
|
function deliverPrompt(store, content, delivery, images) {
|
|
21153
|
-
const
|
|
21154
|
-
if (
|
|
21155
|
-
store.emit({ type: "ui.
|
|
21156
|
-
return
|
|
21563
|
+
const body = buildContent(content, images);
|
|
21564
|
+
if (delivery === "queue" && isAgentBusy(store)) {
|
|
21565
|
+
store.emit({ type: "ui.prompt.queued", content: body });
|
|
21566
|
+
return true;
|
|
21157
21567
|
}
|
|
21158
|
-
return requestAgent(store, {
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
|
|
21568
|
+
return requestAgent(store, { type: "agent.prompt.requested", content: body });
|
|
21569
|
+
}
|
|
21570
|
+
function sendNextQueuedPrompt(store) {
|
|
21571
|
+
const [next] = store.state.queuedPrompts;
|
|
21572
|
+
if (next === undefined || store.state.status !== "idle")
|
|
21573
|
+
return;
|
|
21574
|
+
const sent = requestAgent(store, { type: "agent.prompt.requested", content: next }, "ignore");
|
|
21575
|
+
if (sent)
|
|
21576
|
+
store.emit({ type: "ui.prompt.dequeued" });
|
|
21162
21577
|
}
|
|
21163
21578
|
function submitPrompt(store, text, delivery = "send", images = []) {
|
|
21164
21579
|
const content = text.trim();
|
|
@@ -21242,7 +21657,12 @@ var PICKER_CONFIRMS = {
|
|
|
21242
21657
|
theme(store, _state, selected) {
|
|
21243
21658
|
const theme = THEME_NAMES[selected];
|
|
21244
21659
|
if (theme)
|
|
21245
|
-
store
|
|
21660
|
+
saveTheme2(store, theme);
|
|
21661
|
+
},
|
|
21662
|
+
effort(store, _state, selected) {
|
|
21663
|
+
const effort = effortLevelSchema.options[selected];
|
|
21664
|
+
if (effort)
|
|
21665
|
+
requestAgent(store, { type: "agent.effort.set.requested", effort });
|
|
21246
21666
|
},
|
|
21247
21667
|
rewind(store, state, selected) {
|
|
21248
21668
|
const userMessageId = listCheckpoints(state)[selected]?.checkpointId;
|
|
@@ -21290,7 +21710,7 @@ var dismissQuestion = (store) => sendAnswers(store, {});
|
|
|
21290
21710
|
|
|
21291
21711
|
// apps/tui/src/input/routeKeys.ts
|
|
21292
21712
|
var createKeyPresses = () => ({ escapeAt: 0, ctrlCAt: 0 });
|
|
21293
|
-
var DELIVERY_KEYS = { q: "queue"
|
|
21713
|
+
var DELIVERY_KEYS = { q: "queue" };
|
|
21294
21714
|
var DOUBLE_ESCAPE_MS = 500;
|
|
21295
21715
|
var EXIT_CONFIRM_MS = 3000;
|
|
21296
21716
|
var EXIT_NOTICE = "Press Ctrl + C again to exit";
|
|
@@ -21635,21 +22055,70 @@ class AppStore {
|
|
|
21635
22055
|
|
|
21636
22056
|
// apps/tui/src/theme/syntaxStyle.ts
|
|
21637
22057
|
import { SyntaxStyle as SyntaxStyle2 } from "@opentui/core";
|
|
21638
|
-
|
|
21639
|
-
|
|
21640
|
-
|
|
21641
|
-
|
|
21642
|
-
|
|
21643
|
-
|
|
21644
|
-
|
|
21645
|
-
|
|
21646
|
-
|
|
21647
|
-
|
|
21648
|
-
|
|
21649
|
-
|
|
21650
|
-
|
|
21651
|
-
|
|
21652
|
-
|
|
22058
|
+
|
|
22059
|
+
// apps/tui/src/theme/syntaxRules.ts
|
|
22060
|
+
var rule = (scope, foreground, style = {}) => ({
|
|
22061
|
+
scope,
|
|
22062
|
+
style: { foreground, ...style }
|
|
22063
|
+
});
|
|
22064
|
+
var buildMutedSyntaxRules = (palette) => buildSyntaxRules(palette).map(({ scope, style }) => ({
|
|
22065
|
+
scope,
|
|
22066
|
+
style: { ...style, foreground: palette.fg.muted }
|
|
22067
|
+
}));
|
|
22068
|
+
var buildSyntaxRules = ({ fg, status, syntax, markdown, diff, bg }) => [
|
|
22069
|
+
rule(["default"], fg.primary),
|
|
22070
|
+
rule(["comment", "comment.documentation"], syntax.comment, { italic: true }),
|
|
22071
|
+
rule(["string", "symbol", "character.special", "character"], syntax.string),
|
|
22072
|
+
rule(["number", "boolean", "constant", "float"], syntax.number),
|
|
22073
|
+
rule(["keyword.return", "keyword.conditional", "keyword.repeat", "keyword.coroutine"], syntax.keyword, {
|
|
22074
|
+
italic: true
|
|
22075
|
+
}),
|
|
22076
|
+
rule(["keyword.type"], syntax.type, { bold: true, italic: true }),
|
|
22077
|
+
rule(["keyword.function", "function.method"], syntax.function),
|
|
22078
|
+
rule(["keyword"], syntax.keyword, { italic: true }),
|
|
22079
|
+
rule(["keyword.import", "string.escape", "string.regexp", "tag.attribute", "keyword.export"], syntax.keyword),
|
|
22080
|
+
rule(["operator", "keyword.operator", "punctuation.delimiter", "keyword.conditional.ternary"], syntax.operator),
|
|
22081
|
+
rule(["variable", "variable.parameter", "function.method.call", "function.call", "property", "parameter", "field"], syntax.variable),
|
|
22082
|
+
rule(["variable.member", "function", "constructor"], syntax.function),
|
|
22083
|
+
rule(["type", "module", "class", "namespace"], syntax.type),
|
|
22084
|
+
rule(["type.definition"], syntax.type, { bold: true }),
|
|
22085
|
+
rule(["punctuation", "punctuation.bracket"], syntax.punctuation),
|
|
22086
|
+
rule(["variable.builtin", "type.builtin", "function.builtin", "module.builtin", "constant.builtin", "variable.super"], status.danger),
|
|
22087
|
+
rule(["keyword.directive", "keyword.modifier", "keyword.exception"], syntax.keyword, { italic: true }),
|
|
22088
|
+
rule(["punctuation.special", "tag.delimiter"], syntax.operator),
|
|
22089
|
+
rule(["markup.heading", "markup.heading.2", "markup.heading.3", "markup.heading.4", "markup.heading.5", "markup.heading.6"], markdown.heading, { bold: true }),
|
|
22090
|
+
rule(["markup.heading.1"], markdown.heading, { bold: true, underline: true }),
|
|
22091
|
+
rule(["markup.bold", "markup.strong"], markdown.strong, { bold: true }),
|
|
22092
|
+
rule(["markup.italic"], markdown.emphasis, { italic: true }),
|
|
22093
|
+
rule(["markup.list"], markdown.listItem),
|
|
22094
|
+
rule(["markup.quote"], markdown.blockQuote, { italic: true }),
|
|
22095
|
+
rule(["markup.raw", "markup.raw.block"], markdown.code),
|
|
22096
|
+
rule(["markup.raw.inline"], markdown.code, { background: bg.surface }),
|
|
22097
|
+
rule(["markup.link", "markup.link.url", "string.special", "string.special.url"], markdown.link, {
|
|
22098
|
+
underline: true
|
|
22099
|
+
}),
|
|
22100
|
+
rule(["markup.link.label"], markdown.linkText, { underline: true }),
|
|
22101
|
+
rule(["label"], markdown.linkText),
|
|
22102
|
+
rule(["spell", "nospell"], fg.primary),
|
|
22103
|
+
rule(["markup.underline"], fg.primary, { underline: true }),
|
|
22104
|
+
rule(["comment.error"], status.danger, { italic: true, bold: true }),
|
|
22105
|
+
rule(["comment.warning"], status.warning, { italic: true, bold: true }),
|
|
22106
|
+
rule(["comment.todo", "comment.note"], status.info, { italic: true, bold: true }),
|
|
22107
|
+
rule(["attribute", "annotation"], status.warning),
|
|
22108
|
+
rule(["tag"], status.danger),
|
|
22109
|
+
rule(["markup.strikethrough", "markup.list.unchecked", "debug"], fg.muted),
|
|
22110
|
+
rule(["markup.list.checked"], status.success),
|
|
22111
|
+
rule(["diff.plus"], diff.addedText, { background: diff.addedBg }),
|
|
22112
|
+
rule(["diff.minus"], diff.removedText, { background: diff.removedBg }),
|
|
22113
|
+
rule(["diff.delta"], diff.contextText, { background: diff.contextBg }),
|
|
22114
|
+
rule(["error"], status.danger, { bold: true }),
|
|
22115
|
+
rule(["warning"], status.warning, { bold: true }),
|
|
22116
|
+
rule(["info"], status.info)
|
|
22117
|
+
];
|
|
22118
|
+
|
|
22119
|
+
// apps/tui/src/theme/syntaxStyle.ts
|
|
22120
|
+
var createSyntaxStyle = (renderer) => SyntaxStyle2.fromTheme(buildSyntaxRules(Theme), renderer.nativeScene);
|
|
22121
|
+
var createMutedSyntaxStyle = (renderer) => SyntaxStyle2.fromTheme(buildMutedSyntaxRules(Theme), renderer.nativeScene);
|
|
21653
22122
|
|
|
21654
22123
|
// apps/tui/src/startTui.ts
|
|
21655
22124
|
var CLOCK_INTERVAL_MS = 100;
|
|
@@ -21662,6 +22131,7 @@ async function startTui(client, options = {}) {
|
|
|
21662
22131
|
const store = new AppStore(client);
|
|
21663
22132
|
const clipboard = options.clipboard ?? createHostClipboard();
|
|
21664
22133
|
let syntaxStyle = createSyntaxStyle(activeRenderer);
|
|
22134
|
+
let mutedSyntaxStyle = createMutedSyntaxStyle(activeRenderer);
|
|
21665
22135
|
let appliedTheme = readShownTheme(store.state);
|
|
21666
22136
|
let appliedBackground = readShownBackground(store.state);
|
|
21667
22137
|
const header = new HeaderBar(activeRenderer);
|
|
@@ -21671,8 +22141,10 @@ async function startTui(client, options = {}) {
|
|
|
21671
22141
|
const toastView = new ToastView(activeRenderer);
|
|
21672
22142
|
const statusLine = new StatusLine(activeRenderer, () => cancelTurn(store));
|
|
21673
22143
|
const taskPanel = new TaskPanel(activeRenderer, (taskId) => stopTask(store, taskId));
|
|
22144
|
+
const promptQueue = new PromptQueueView(activeRenderer);
|
|
21674
22145
|
const scrollback = new ScrollbackView(activeRenderer, {
|
|
21675
22146
|
syntaxStyle,
|
|
22147
|
+
mutedSyntaxStyle,
|
|
21676
22148
|
hooks: {
|
|
21677
22149
|
syntaxStyle,
|
|
21678
22150
|
onDecision: (decision, id) => answerApproval(store, decision, id),
|
|
@@ -21705,7 +22177,7 @@ async function startTui(client, options = {}) {
|
|
|
21705
22177
|
saveDraft(text);
|
|
21706
22178
|
}
|
|
21707
22179
|
});
|
|
21708
|
-
const root = new
|
|
22180
|
+
const root = new BoxRenderable19(activeRenderer, {
|
|
21709
22181
|
width: "100%",
|
|
21710
22182
|
height: "100%",
|
|
21711
22183
|
flexDirection: "column",
|
|
@@ -21716,11 +22188,12 @@ async function startTui(client, options = {}) {
|
|
|
21716
22188
|
scrollback,
|
|
21717
22189
|
diffViewer,
|
|
21718
22190
|
statusLine,
|
|
21719
|
-
|
|
22191
|
+
promptQueue,
|
|
21720
22192
|
popover,
|
|
21721
22193
|
backgroundPanel,
|
|
21722
22194
|
input,
|
|
21723
|
-
infoBar
|
|
22195
|
+
infoBar,
|
|
22196
|
+
taskPanel
|
|
21724
22197
|
];
|
|
21725
22198
|
for (const part of parts)
|
|
21726
22199
|
root.add(part.renderable);
|
|
@@ -21747,11 +22220,13 @@ async function startTui(client, options = {}) {
|
|
|
21747
22220
|
appliedBackground = shownBackground;
|
|
21748
22221
|
applyTheme(shownTheme, shownBackground);
|
|
21749
22222
|
if (themeChanged) {
|
|
21750
|
-
const previous = syntaxStyle;
|
|
22223
|
+
const previous = [syntaxStyle, mutedSyntaxStyle];
|
|
21751
22224
|
syntaxStyle = createSyntaxStyle(activeRenderer);
|
|
21752
|
-
|
|
22225
|
+
mutedSyntaxStyle = createMutedSyntaxStyle(activeRenderer);
|
|
22226
|
+
scrollback.reset(syntaxStyle, mutedSyntaxStyle);
|
|
21753
22227
|
diffViewer.reset(syntaxStyle);
|
|
21754
|
-
previous
|
|
22228
|
+
for (const style of previous)
|
|
22229
|
+
style.destroy();
|
|
21755
22230
|
}
|
|
21756
22231
|
root.backgroundColor = Theme.bg.default;
|
|
21757
22232
|
input.applyColors();
|
|
@@ -21762,6 +22237,7 @@ async function startTui(client, options = {}) {
|
|
|
21762
22237
|
header.update(state);
|
|
21763
22238
|
statusLine.update(state);
|
|
21764
22239
|
taskPanel.update(state);
|
|
22240
|
+
promptQueue.update(state);
|
|
21765
22241
|
toastView.update(state);
|
|
21766
22242
|
infoBar.update(state);
|
|
21767
22243
|
scrollback.update(state);
|
|
@@ -21773,7 +22249,7 @@ async function startTui(client, options = {}) {
|
|
|
21773
22249
|
input.setFocused(inputFocused);
|
|
21774
22250
|
scrollback.setFocused(!inputFocused);
|
|
21775
22251
|
input.setBusy(isStatusBusy(state.status));
|
|
21776
|
-
input.setBorderColor(inputFocused ? Theme.
|
|
22252
|
+
input.setBorderColor(inputFocused ? Theme.fg.muted : Theme.border.separator);
|
|
21777
22253
|
const awaitingId = (findAwaitingCalls(state)[0] ?? findQuestionCalls(state)[0])?.id;
|
|
21778
22254
|
if (awaitingId && awaitingId !== revealedCallId) {
|
|
21779
22255
|
scrollback.revealEntry(findGroupId(state, awaitingId) ?? "");
|
|
@@ -21781,6 +22257,7 @@ async function startTui(client, options = {}) {
|
|
|
21781
22257
|
revealedCallId = awaitingId;
|
|
21782
22258
|
};
|
|
21783
22259
|
store.subscribe(render);
|
|
22260
|
+
store.subscribe(() => sendNextQueuedPrompt(store));
|
|
21784
22261
|
const notifier = new TurnNotifier(activeRenderer);
|
|
21785
22262
|
store.subscribeOwnEvents((event) => {
|
|
21786
22263
|
reactToEvent(store, event);
|
|
@@ -23892,7 +24369,8 @@ function useColor() {
|
|
|
23892
24369
|
var program = new Command;
|
|
23893
24370
|
|
|
23894
24371
|
// apps/cli/src/index.ts
|
|
23895
|
-
var
|
|
24372
|
+
var DEFAULT_PORT = "7777";
|
|
24373
|
+
var runId = createRunId();
|
|
23896
24374
|
var program2 = new Command().name("claudin").enablePositionalOptions();
|
|
23897
24375
|
var printResumeHint = (sessionId) => {
|
|
23898
24376
|
if (!sessionId)
|
|
@@ -23906,10 +24384,12 @@ var exitOnDestroy = (renderer) => {
|
|
|
23906
24384
|
renderer.on("destroy", () => process.exit(0));
|
|
23907
24385
|
};
|
|
23908
24386
|
var openContext = (sessionId) => createDaemonContext(undefined, sessionId).catch((error) => program2.error(error.message));
|
|
23909
|
-
var daemonUrl = (port) => `ws://
|
|
23910
|
-
program2.option("-p, --port <port>", "daemon port",
|
|
23911
|
-
const
|
|
23912
|
-
const
|
|
24387
|
+
var daemonUrl = (port) => `ws://127.0.0.1:${Number(port)}`;
|
|
24388
|
+
program2.option("-p, --port <port>", "daemon port", DEFAULT_PORT).option("-s, --session <id>", "resume a previous session").action(async (opts) => {
|
|
24389
|
+
const token = createAccessToken();
|
|
24390
|
+
const server = await startDaemon(Number(opts.port), token, await openContext(opts.session));
|
|
24391
|
+
const client = await DaemonClient.connect(daemonUrl(opts.port), { token, runId });
|
|
24392
|
+
const renderer = await startTui(client, {
|
|
23913
24393
|
resumeSessionId: opts.session,
|
|
23914
24394
|
onExit: printResumeHint
|
|
23915
24395
|
});
|
|
@@ -23919,14 +24399,16 @@ program2.option("-p, --port <port>", "daemon port", DEFAULT_PORT2).option("-s, -
|
|
|
23919
24399
|
server.close(() => process.exit(0));
|
|
23920
24400
|
});
|
|
23921
24401
|
});
|
|
23922
|
-
program2.command("daemon").description("Run the daemon without a UI so terminals can attach to it").option("-p, --port <port>", "daemon port",
|
|
23923
|
-
|
|
23924
|
-
|
|
23925
|
-
|
|
24402
|
+
program2.command("daemon").description("Run the daemon without a UI so terminals can attach to it").option("-p, --port <port>", "daemon port", DEFAULT_PORT).option("-s, --session <id>", "serve a previous session").action(async (opts) => {
|
|
24403
|
+
const token = createAccessToken();
|
|
24404
|
+
await startDaemon(Number(opts.port), token, await openContext(opts.session));
|
|
24405
|
+
process.stdout.write(`Daemon on ${daemonUrl(opts.port)} (run ${runId})
|
|
24406
|
+
Attach with: claudin attach -p ${opts.port} --token ${token}
|
|
23926
24407
|
`);
|
|
23927
24408
|
});
|
|
23928
|
-
program2.command("attach").description("Attach another terminal to a running daemon's live session").option("-p, --port <port>", "daemon port",
|
|
23929
|
-
const
|
|
24409
|
+
program2.command("attach").description("Attach another terminal to a running daemon's live session").option("-p, --port <port>", "daemon port", DEFAULT_PORT).option("-t, --token <token>", "access token printed by the daemon (or CLAUDIN_TOKEN)").action(async (opts) => {
|
|
24410
|
+
const token = opts.token ?? process.env.CLAUDIN_TOKEN ?? program2.error("An access token is required: pass --token or set CLAUDIN_TOKEN");
|
|
24411
|
+
const client = await DaemonClient.connect(daemonUrl(opts.port), { token, runId }).catch((error) => program2.error(error.message));
|
|
23930
24412
|
const renderer = await startTui(client, { attach: true, onExit: printResumeHint });
|
|
23931
24413
|
client.onDisconnect(() => renderer.destroy());
|
|
23932
24414
|
exitOnDestroy(renderer);
|