@couralabs/claudin 0.1.1 → 0.1.2
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 +308 -48
- package/package.json +1 -1
package/claudin.js
CHANGED
|
@@ -5950,6 +5950,18 @@ function formatModelName(model) {
|
|
|
5950
5950
|
const version = parts.filter((part) => NUMERIC_PART.test(part)).join(".");
|
|
5951
5951
|
return ["Claude", ...words, version].filter(Boolean).join(" ");
|
|
5952
5952
|
}
|
|
5953
|
+
// packages/events/src/models/messageText.ts
|
|
5954
|
+
var MAX_OUTPUT_LENGTH = 20000;
|
|
5955
|
+
function joinBlocks(content) {
|
|
5956
|
+
if (typeof content === "string")
|
|
5957
|
+
return content;
|
|
5958
|
+
if (!Array.isArray(content))
|
|
5959
|
+
return content === undefined ? "" : JSON.stringify(content);
|
|
5960
|
+
return content.map((block) => block.type === "text" ? block.text ?? "" : `[${block.type}]`).join(`
|
|
5961
|
+
`);
|
|
5962
|
+
}
|
|
5963
|
+
var readPromptText = (content) => joinBlocks(content);
|
|
5964
|
+
var clipOutput = (text) => text.slice(0, MAX_OUTPUT_LENGTH);
|
|
5953
5965
|
// packages/events/src/models/modelLabel.ts
|
|
5954
5966
|
function readModelLabel({ model, models }) {
|
|
5955
5967
|
const row = models.find((candidate) => candidate.value === model);
|
|
@@ -6026,19 +6038,6 @@ var THEME_NAMES = [
|
|
|
6026
6038
|
];
|
|
6027
6039
|
var themeNameSchema = _enum(THEME_NAMES);
|
|
6028
6040
|
var DEFAULT_THEME_NAME = "vesper";
|
|
6029
|
-
// packages/events/src/models/messageText.ts
|
|
6030
|
-
var MAX_OUTPUT_LENGTH = 20000;
|
|
6031
|
-
function joinBlocks(content) {
|
|
6032
|
-
if (typeof content === "string")
|
|
6033
|
-
return content;
|
|
6034
|
-
if (!Array.isArray(content))
|
|
6035
|
-
return content === undefined ? "" : JSON.stringify(content);
|
|
6036
|
-
return content.map((block) => block.type === "text" ? block.text ?? "" : `[${block.type}]`).join(`
|
|
6037
|
-
`);
|
|
6038
|
-
}
|
|
6039
|
-
var readPromptText = (content) => joinBlocks(content);
|
|
6040
|
-
var clipOutput = (text) => text.slice(0, MAX_OUTPUT_LENGTH);
|
|
6041
|
-
|
|
6042
6041
|
// packages/events/src/reducers/reduceCheckpoint.ts
|
|
6043
6042
|
var isUserEntry = (entry) => entry.kind === "user";
|
|
6044
6043
|
var hasToolResults = (content) => Array.isArray(content) && content.some((block) => block?.type === "tool_result");
|
|
@@ -6068,7 +6067,13 @@ var appendNotice = (state, text) => appendEntry(state, { kind: "notice", text })
|
|
|
6068
6067
|
|
|
6069
6068
|
// packages/events/src/reducers/reduceHistory.ts
|
|
6070
6069
|
var NO_MATCH_NOTICE = "No earlier prompt matches";
|
|
6071
|
-
var
|
|
6070
|
+
var MAX_PROMPT_HISTORY = 10;
|
|
6071
|
+
var queuePromptHistory = (entries, text) => text === "" || entries.at(-1) === text ? entries : [...entries, text].slice(-MAX_PROMPT_HISTORY);
|
|
6072
|
+
var listPromptTexts = (state) => state.promptHistory;
|
|
6073
|
+
var loadHistory = (state, entries) => ({
|
|
6074
|
+
...state,
|
|
6075
|
+
promptHistory: [...entries, ...state.promptHistory].slice(-MAX_PROMPT_HISTORY)
|
|
6076
|
+
});
|
|
6072
6077
|
function readHistoryText(state) {
|
|
6073
6078
|
const { history } = state.ui;
|
|
6074
6079
|
if (!history)
|
|
@@ -6076,7 +6081,7 @@ function readHistoryText(state) {
|
|
|
6076
6081
|
return listPromptTexts(state)[history.index] ?? history.draft;
|
|
6077
6082
|
}
|
|
6078
6083
|
function browsingPosition(state, draft) {
|
|
6079
|
-
const size = state.
|
|
6084
|
+
const size = state.promptHistory.length;
|
|
6080
6085
|
const { history } = state.ui;
|
|
6081
6086
|
const browsing = history !== null && history.index < size;
|
|
6082
6087
|
return { size, index: browsing ? history.index : size, draft: browsing ? history.draft : draft };
|
|
@@ -6106,20 +6111,11 @@ var agentSessionId = string2();
|
|
|
6106
6111
|
var content = sdkValue();
|
|
6107
6112
|
var agentOptions = sdkValue().optional();
|
|
6108
6113
|
var effortLevelSchema = _enum(["low", "medium", "high", "xhigh", "max"]);
|
|
6109
|
-
var permissionModeSchema = _enum([
|
|
6110
|
-
|
|
6111
|
-
"acceptEdits",
|
|
6112
|
-
"bypassPermissions",
|
|
6113
|
-
"plan",
|
|
6114
|
-
"dontAsk",
|
|
6115
|
-
"auto"
|
|
6116
|
-
]);
|
|
6117
|
-
var DEFAULT_PERMISSION_MODE = "auto";
|
|
6114
|
+
var permissionModeSchema = _enum(["auto", "acceptEdits", "bypassPermissions", "dontAsk"]);
|
|
6115
|
+
var DEFAULT_PERMISSION_MODE = "bypassPermissions";
|
|
6118
6116
|
var PERMISSION_MODE_LABELS = {
|
|
6119
|
-
default: "Default Permission",
|
|
6120
6117
|
acceptEdits: "Accept Edits Permission",
|
|
6121
6118
|
bypassPermissions: "Bypass Permissions",
|
|
6122
|
-
plan: "Plan Permission",
|
|
6123
6119
|
dontAsk: "Don't Ask Permission",
|
|
6124
6120
|
auto: "Automatic Permissions"
|
|
6125
6121
|
};
|
|
@@ -6194,6 +6190,7 @@ var DEFAULT_CONTEXT_WINDOW = 200000;
|
|
|
6194
6190
|
var createSessionState = (sessionId) => ({
|
|
6195
6191
|
sessionId,
|
|
6196
6192
|
prompts: [],
|
|
6193
|
+
promptHistory: [],
|
|
6197
6194
|
status: "idle",
|
|
6198
6195
|
model: "",
|
|
6199
6196
|
permissionMode: DEFAULT_PERMISSION_MODE,
|
|
@@ -6225,7 +6222,14 @@ var createSessionState = (sessionId) => ({
|
|
|
6225
6222
|
});
|
|
6226
6223
|
|
|
6227
6224
|
// packages/events/src/reducers/carryOver.ts
|
|
6228
|
-
var DEVICE_KEYS = [
|
|
6225
|
+
var DEVICE_KEYS = [
|
|
6226
|
+
"theme",
|
|
6227
|
+
"background",
|
|
6228
|
+
"slashCommands",
|
|
6229
|
+
"models",
|
|
6230
|
+
"rateLimits",
|
|
6231
|
+
"promptHistory"
|
|
6232
|
+
];
|
|
6229
6233
|
var WORKSPACE_KEYS = [
|
|
6230
6234
|
"model",
|
|
6231
6235
|
"effort",
|
|
@@ -6502,6 +6506,14 @@ function reduceStreamEvent(state, event) {
|
|
|
6502
6506
|
}
|
|
6503
6507
|
}
|
|
6504
6508
|
|
|
6509
|
+
// packages/events/src/reducers/reduceTaskProgress.ts
|
|
6510
|
+
function reduceTaskProgress(state, message) {
|
|
6511
|
+
const { tool_use_id: toolUseId, summary } = message;
|
|
6512
|
+
if (!toolUseId || !summary)
|
|
6513
|
+
return state;
|
|
6514
|
+
return updateToolCall(state, toolUseId, (call) => ({ ...call, progress: summary }));
|
|
6515
|
+
}
|
|
6516
|
+
|
|
6505
6517
|
// packages/events/src/reducers/reduceToolResults.ts
|
|
6506
6518
|
function applyResult(state, block) {
|
|
6507
6519
|
if (block.type !== "tool_result" || !block.tool_use_id)
|
|
@@ -6521,6 +6533,8 @@ function reduceToolResults(state, message) {
|
|
|
6521
6533
|
function reduceAgentMessage(state, message) {
|
|
6522
6534
|
switch (message.type) {
|
|
6523
6535
|
case "system":
|
|
6536
|
+
if (message.subtype === "task_progress")
|
|
6537
|
+
return reduceTaskProgress(state, message);
|
|
6524
6538
|
if (message.subtype !== "init")
|
|
6525
6539
|
return reduceNoticeMessage(state, message);
|
|
6526
6540
|
return {
|
|
@@ -6651,6 +6665,7 @@ function reducePrompt(state, content, isFollowUp) {
|
|
|
6651
6665
|
return {
|
|
6652
6666
|
...withUser,
|
|
6653
6667
|
prompts: [...state.prompts, content],
|
|
6668
|
+
promptHistory: queuePromptHistory(state.promptHistory, readPromptText(content)),
|
|
6654
6669
|
status: "thinking",
|
|
6655
6670
|
queuedTurns: isFollowUp ? state.queuedTurns + 1 : state.queuedTurns,
|
|
6656
6671
|
turnStartedAt: isFollowUp ? state.turnStartedAt ?? state.now : state.now,
|
|
@@ -6784,6 +6799,8 @@ function reduceUi(state, event) {
|
|
|
6784
6799
|
return moveHistory(state, event.delta, event.draft);
|
|
6785
6800
|
case "ui.history.searched":
|
|
6786
6801
|
return searchHistory(state, event.draft);
|
|
6802
|
+
case "ui.history.loaded":
|
|
6803
|
+
return loadHistory(state, event.entries);
|
|
6787
6804
|
case "ui.history.reset":
|
|
6788
6805
|
return resetHistory(state);
|
|
6789
6806
|
case "ui.diff.viewer.moved":
|
|
@@ -7801,21 +7818,36 @@ var AGENT_TOOLS = [
|
|
|
7801
7818
|
"TodoWrite",
|
|
7802
7819
|
"AskUserQuestion",
|
|
7803
7820
|
"Write",
|
|
7804
|
-
"Edit"
|
|
7821
|
+
"Edit",
|
|
7822
|
+
"NotebookEdit"
|
|
7805
7823
|
];
|
|
7806
7824
|
var AGENT_PROFILE_OPTIONS = {
|
|
7807
7825
|
tools: AGENT_TOOLS,
|
|
7808
7826
|
systemPrompt: ADHD_SYSTEM_PROMPT,
|
|
7809
7827
|
enableFileCheckpointing: true,
|
|
7810
|
-
extraArgs: { "replay-user-messages": null }
|
|
7828
|
+
extraArgs: { "replay-user-messages": null },
|
|
7829
|
+
permissionMode: DEFAULT_PERMISSION_MODE,
|
|
7830
|
+
allowDangerouslySkipPermissions: true,
|
|
7831
|
+
settings: {
|
|
7832
|
+
promptCacheTtl: "1h",
|
|
7833
|
+
subagentPromptCacheTtl: "1h",
|
|
7834
|
+
attribution: { commit: "", pr: "" }
|
|
7835
|
+
},
|
|
7836
|
+
settingSources: ["user", "project", "local"],
|
|
7837
|
+
skills: "all",
|
|
7838
|
+
agentProgressSummaries: true,
|
|
7839
|
+
includePartialMessages: true,
|
|
7840
|
+
includeHookEvents: true
|
|
7811
7841
|
};
|
|
7812
7842
|
|
|
7813
7843
|
// packages/agent/src/runtime/buildUserMessage.ts
|
|
7844
|
+
var isSlashCommand = (content) => readPromptText(content).trimStart().startsWith("/");
|
|
7814
7845
|
var buildUserMessage = (content, priority) => ({
|
|
7815
7846
|
type: "user",
|
|
7816
7847
|
message: { role: "user", content },
|
|
7817
7848
|
parent_tool_use_id: null,
|
|
7818
|
-
priority
|
|
7849
|
+
priority,
|
|
7850
|
+
client_composed: isSlashCommand(content) ? undefined : true
|
|
7819
7851
|
});
|
|
7820
7852
|
|
|
7821
7853
|
// packages/agent/src/session/pickNextModel.ts
|
|
@@ -7841,7 +7873,6 @@ class AgentSession {
|
|
|
7841
7873
|
this.query = runtime.open({
|
|
7842
7874
|
prompt: this.input,
|
|
7843
7875
|
options: {
|
|
7844
|
-
includePartialMessages: true,
|
|
7845
7876
|
...baseOptions,
|
|
7846
7877
|
...AGENT_PROFILE_OPTIONS,
|
|
7847
7878
|
canUseTool: this.gate.canUseTool
|
|
@@ -17616,9 +17647,7 @@ var readEffortColor = (effort) => ({
|
|
|
17616
17647
|
max: Theme.status.danger
|
|
17617
17648
|
})[effort] ?? Theme.fg.secondary;
|
|
17618
17649
|
var readPermissionColor = (mode) => ({
|
|
17619
|
-
default: Theme.fg.primary,
|
|
17620
17650
|
acceptEdits: Theme.status.success,
|
|
17621
|
-
plan: Theme.status.info,
|
|
17622
17651
|
auto: Theme.accent.highlight,
|
|
17623
17652
|
dontAsk: Theme.status.warning,
|
|
17624
17653
|
bypassPermissions: Theme.status.danger
|
|
@@ -17758,11 +17787,125 @@ class ListPopover {
|
|
|
17758
17787
|
// apps/tui/src/components/promptInput.ts
|
|
17759
17788
|
import {
|
|
17760
17789
|
BoxRenderable as BoxRenderable5,
|
|
17790
|
+
SyntaxStyle,
|
|
17761
17791
|
TextareaRenderable,
|
|
17762
17792
|
TextRenderable as TextRenderable5
|
|
17763
17793
|
} from "@opentui/core";
|
|
17794
|
+
|
|
17795
|
+
// apps/tui/src/prompt/pasteAttachments.ts
|
|
17796
|
+
class PasteAttachments {
|
|
17797
|
+
replacements = new Map;
|
|
17798
|
+
images = new Map;
|
|
17799
|
+
counter = 0;
|
|
17800
|
+
addText(text) {
|
|
17801
|
+
const lines = text.split(`
|
|
17802
|
+
`).length;
|
|
17803
|
+
return this.remember(`Pasted text #${this.next()} +${lines} lines`, text);
|
|
17804
|
+
}
|
|
17805
|
+
addFile(path) {
|
|
17806
|
+
const name = path.split("/").at(-1) ?? path;
|
|
17807
|
+
return this.remember(`File #${this.next()} ${name}`, path);
|
|
17808
|
+
}
|
|
17809
|
+
addImage(image) {
|
|
17810
|
+
const placeholder = `[Image #${this.next()}]`;
|
|
17811
|
+
this.images.set(placeholder, image);
|
|
17812
|
+
return placeholder;
|
|
17813
|
+
}
|
|
17814
|
+
compose(text) {
|
|
17815
|
+
let expanded = text;
|
|
17816
|
+
for (const [placeholder, value] of this.replacements) {
|
|
17817
|
+
expanded = expanded.replaceAll(placeholder, () => value);
|
|
17818
|
+
}
|
|
17819
|
+
const images = [...this.images].map(([placeholder, image]) => ({ at: text.indexOf(placeholder), image })).filter(({ at }) => at >= 0).sort((left, right) => left.at - right.at).map(({ image }) => image);
|
|
17820
|
+
return { text: expanded, images };
|
|
17821
|
+
}
|
|
17822
|
+
placeholders() {
|
|
17823
|
+
return [...this.replacements.keys(), ...this.images.keys()];
|
|
17824
|
+
}
|
|
17825
|
+
reset() {
|
|
17826
|
+
this.replacements.clear();
|
|
17827
|
+
this.images.clear();
|
|
17828
|
+
this.counter = 0;
|
|
17829
|
+
}
|
|
17830
|
+
remember(label, value) {
|
|
17831
|
+
const placeholder = `[${label}]`;
|
|
17832
|
+
this.replacements.set(placeholder, value);
|
|
17833
|
+
return placeholder;
|
|
17834
|
+
}
|
|
17835
|
+
next() {
|
|
17836
|
+
this.counter += 1;
|
|
17837
|
+
return this.counter;
|
|
17838
|
+
}
|
|
17839
|
+
}
|
|
17840
|
+
|
|
17841
|
+
// apps/tui/src/prompt/planPaste.ts
|
|
17842
|
+
import { readFileSync } from "fs";
|
|
17843
|
+
import { extname } from "path";
|
|
17844
|
+
import { decodePasteBytes } from "@opentui/core";
|
|
17845
|
+
|
|
17846
|
+
// apps/tui/src/prompt/imageBlock.ts
|
|
17847
|
+
var IMAGE_MEDIA_TYPES = ["image/gif", "image/jpeg", "image/png", "image/webp"];
|
|
17848
|
+
var readImageMediaType = (mediaType) => IMAGE_MEDIA_TYPES.find((known) => known === mediaType);
|
|
17849
|
+
var buildImageBlock = (mediaType, bytes) => ({
|
|
17850
|
+
type: "image",
|
|
17851
|
+
source: { type: "base64", media_type: mediaType, data: Buffer.from(bytes).toString("base64") }
|
|
17852
|
+
});
|
|
17853
|
+
|
|
17854
|
+
// apps/tui/src/prompt/pastedPaths.ts
|
|
17855
|
+
import { statSync } from "fs";
|
|
17856
|
+
import { homedir as homedir6 } from "os";
|
|
17857
|
+
import { isAbsolute } from "path";
|
|
17858
|
+
var unwrapPath = (raw) => raw.trim().replace(/^(['"])(.*)\1$/, "$2").replace(/^file:\/\//, "").replace(/^~(?=\/)/, homedir6()).replace(/\\(.)/g, "$1");
|
|
17859
|
+
var isExistingFile = (path) => {
|
|
17860
|
+
try {
|
|
17861
|
+
return isAbsolute(path) && statSync(path).isFile();
|
|
17862
|
+
} catch {
|
|
17863
|
+
return false;
|
|
17864
|
+
}
|
|
17865
|
+
};
|
|
17866
|
+
function parsePastedPaths(text) {
|
|
17867
|
+
const lines = text.split(`
|
|
17868
|
+
`).map((line) => line.trim()).filter(Boolean);
|
|
17869
|
+
const paths = lines.flatMap((line) => isExistingFile(unwrapPath(line)) ? [line] : line.split(/(?<!\\)\s+/)).map(unwrapPath);
|
|
17870
|
+
return paths.length > 0 && paths.every(isExistingFile) ? paths : [];
|
|
17871
|
+
}
|
|
17872
|
+
|
|
17873
|
+
// apps/tui/src/prompt/planPaste.ts
|
|
17874
|
+
var LONG_PASTE_LINES = 5;
|
|
17875
|
+
var LONG_PASTE_CHARS = 500;
|
|
17876
|
+
var IMAGE_TYPES = {
|
|
17877
|
+
".png": "image/png",
|
|
17878
|
+
".jpg": "image/jpeg",
|
|
17879
|
+
".jpeg": "image/jpeg",
|
|
17880
|
+
".gif": "image/gif",
|
|
17881
|
+
".webp": "image/webp"
|
|
17882
|
+
};
|
|
17883
|
+
var isLongPaste = (text) => text.length > LONG_PASTE_CHARS || text.split(`
|
|
17884
|
+
`).length > LONG_PASTE_LINES;
|
|
17885
|
+
function attachPath(path, attachments) {
|
|
17886
|
+
const mediaType = IMAGE_TYPES[extname(path).toLowerCase()];
|
|
17887
|
+
if (!mediaType)
|
|
17888
|
+
return attachments.addFile(path);
|
|
17889
|
+
return attachments.addImage(buildImageBlock(mediaType, readFileSync(path)));
|
|
17890
|
+
}
|
|
17891
|
+
function planPaste(event, attachments) {
|
|
17892
|
+
const mediaType = readImageMediaType(event.metadata?.mimeType);
|
|
17893
|
+
if (mediaType) {
|
|
17894
|
+
return attachments.addImage(buildImageBlock(mediaType, event.bytes));
|
|
17895
|
+
}
|
|
17896
|
+
if (event.metadata?.kind === "binary")
|
|
17897
|
+
return;
|
|
17898
|
+
const text = decodePasteBytes(event.bytes);
|
|
17899
|
+
const paths = parsePastedPaths(text);
|
|
17900
|
+
if (paths.length > 0)
|
|
17901
|
+
return paths.map((path) => attachPath(path, attachments)).join(" ");
|
|
17902
|
+
return isLongPaste(text) ? attachments.addText(text) : undefined;
|
|
17903
|
+
}
|
|
17904
|
+
|
|
17905
|
+
// apps/tui/src/components/promptInput.ts
|
|
17764
17906
|
var MAX_INPUT_LINES = 8;
|
|
17765
17907
|
var BUSY_TITLE = " Ctrl+Q (queue) Ctrl+W (steer) ";
|
|
17908
|
+
var ATTACHMENT_STYLE = "attachment";
|
|
17766
17909
|
var PLACEHOLDER = "Type your prompt, /slash command, or @file reference...";
|
|
17767
17910
|
var KEY_BINDINGS = [
|
|
17768
17911
|
{ name: "return", action: "submit" },
|
|
@@ -17776,6 +17919,9 @@ class PromptInput {
|
|
|
17776
17919
|
renderable;
|
|
17777
17920
|
textarea;
|
|
17778
17921
|
chevron;
|
|
17922
|
+
attachments = new PasteAttachments;
|
|
17923
|
+
attachmentStyle;
|
|
17924
|
+
attachmentStyleId = 0;
|
|
17779
17925
|
focused = false;
|
|
17780
17926
|
constructor(renderer, handlers) {
|
|
17781
17927
|
this.renderable = new BoxRenderable5(renderer, {
|
|
@@ -17787,14 +17933,18 @@ class PromptInput {
|
|
|
17787
17933
|
flexShrink: 0,
|
|
17788
17934
|
paddingLeft: 1
|
|
17789
17935
|
});
|
|
17936
|
+
this.attachmentStyle = SyntaxStyle.create(renderer.nativeScene);
|
|
17790
17937
|
this.textarea = new TextareaRenderable(renderer, {
|
|
17791
17938
|
flexGrow: 1,
|
|
17792
17939
|
height: 1,
|
|
17793
17940
|
placeholder: PLACEHOLDER,
|
|
17794
17941
|
wrapMode: "word",
|
|
17795
17942
|
keyBindings: KEY_BINDINGS,
|
|
17943
|
+
syntaxStyle: this.attachmentStyle,
|
|
17944
|
+
onPaste: (event) => this.insertPlaceholder(event),
|
|
17796
17945
|
onSubmit: () => handlers.onSubmit(this.text),
|
|
17797
17946
|
onContentChange: () => {
|
|
17947
|
+
this.markAttachments();
|
|
17798
17948
|
this.fitHeight();
|
|
17799
17949
|
handlers.onChange(this.text, this.textarea.cursorOffset);
|
|
17800
17950
|
}
|
|
@@ -17814,8 +17964,19 @@ class PromptInput {
|
|
|
17814
17964
|
this.textarea.setText(text);
|
|
17815
17965
|
this.textarea.cursorOffset = cursor;
|
|
17816
17966
|
}
|
|
17967
|
+
compose() {
|
|
17968
|
+
return this.attachments.compose(this.text);
|
|
17969
|
+
}
|
|
17970
|
+
insertPlaceholder(event) {
|
|
17971
|
+
const placeholder = planPaste(event, this.attachments);
|
|
17972
|
+
if (placeholder === undefined)
|
|
17973
|
+
return;
|
|
17974
|
+
event.preventDefault();
|
|
17975
|
+
this.textarea.insertText(placeholder);
|
|
17976
|
+
}
|
|
17817
17977
|
clear() {
|
|
17818
17978
|
this.textarea.setText("");
|
|
17979
|
+
this.attachments.reset();
|
|
17819
17980
|
}
|
|
17820
17981
|
setFocused(focused) {
|
|
17821
17982
|
if (focused === this.focused)
|
|
@@ -17842,6 +18003,26 @@ class PromptInput {
|
|
|
17842
18003
|
this.textarea.focusedTextColor = Theme.fg.primary;
|
|
17843
18004
|
this.textarea.backgroundColor = Theme.bg.default;
|
|
17844
18005
|
this.textarea.focusedBackgroundColor = Theme.bg.default;
|
|
18006
|
+
this.attachmentStyleId = this.attachmentStyle.registerStyle(ATTACHMENT_STYLE, {
|
|
18007
|
+
fg: Theme.accent.highlight,
|
|
18008
|
+
bold: true
|
|
18009
|
+
});
|
|
18010
|
+
this.markAttachments();
|
|
18011
|
+
}
|
|
18012
|
+
markAttachments() {
|
|
18013
|
+
const { extmarks } = this.textarea;
|
|
18014
|
+
extmarks.clear();
|
|
18015
|
+
const text = this.text;
|
|
18016
|
+
for (const placeholder of this.attachments.placeholders()) {
|
|
18017
|
+
for (let at = text.indexOf(placeholder);at >= 0; at = text.indexOf(placeholder, at + 1)) {
|
|
18018
|
+
extmarks.create({
|
|
18019
|
+
start: at,
|
|
18020
|
+
end: at + placeholder.length,
|
|
18021
|
+
virtual: true,
|
|
18022
|
+
styleId: this.attachmentStyleId
|
|
18023
|
+
});
|
|
18024
|
+
}
|
|
18025
|
+
}
|
|
17845
18026
|
}
|
|
17846
18027
|
fitHeight() {
|
|
17847
18028
|
const wanted = Math.max(this.textarea.lineCount, this.textarea.virtualLineCount, 1);
|
|
@@ -18580,7 +18761,9 @@ var SUMMARY_LENGTH = 80;
|
|
|
18580
18761
|
var SUMMARY_KEYS = ["file_path", "path", "command", "pattern", "query", "url", "description"];
|
|
18581
18762
|
var SEARCH_TOOLS = new Set(["Glob", "Grep"]);
|
|
18582
18763
|
var summarizeSearch = ({ pattern, path }) => typeof path === "string" ? `${pattern} in ${path}` : String(pattern);
|
|
18583
|
-
function summarizeToolCall({ name, input }) {
|
|
18764
|
+
function summarizeToolCall({ name, input, status, progress }) {
|
|
18765
|
+
if (status === "running" && progress)
|
|
18766
|
+
return truncateText(progress, SUMMARY_LENGTH);
|
|
18584
18767
|
if (SEARCH_TOOLS.has(name) && typeof input.pattern === "string") {
|
|
18585
18768
|
return truncateText(summarizeSearch(input), SUMMARY_LENGTH);
|
|
18586
18769
|
}
|
|
@@ -18875,6 +19058,8 @@ import {
|
|
|
18875
19058
|
StyledText as StyledText11,
|
|
18876
19059
|
TextRenderable as TextRenderable12
|
|
18877
19060
|
} from "@opentui/core";
|
|
19061
|
+
var USER_LINES = 10;
|
|
19062
|
+
|
|
18878
19063
|
class UserMessageView {
|
|
18879
19064
|
renderable;
|
|
18880
19065
|
text;
|
|
@@ -18903,7 +19088,7 @@ class UserMessageView {
|
|
|
18903
19088
|
this.entry = entry;
|
|
18904
19089
|
this.text.content = new StyledText11([
|
|
18905
19090
|
bold7(fg12(Theme.accent.brand)("\u276F ")),
|
|
18906
|
-
bold7(fg12(Theme.fg.primary)(entry.text))
|
|
19091
|
+
bold7(fg12(Theme.fg.primary)(clipLines(entry.text, USER_LINES)))
|
|
18907
19092
|
]);
|
|
18908
19093
|
this.clock.content = new StyledText11([fg12(Theme.fg.muted)(formatClock(entry.at))]);
|
|
18909
19094
|
}
|
|
@@ -19544,23 +19729,27 @@ var DELIVERY_REQUESTS = {
|
|
|
19544
19729
|
steer: "agent.prompt.steer.requested"
|
|
19545
19730
|
};
|
|
19546
19731
|
var BUSY_NOTICE = "Agent is busy: Ctrl+Q queues, Ctrl+W steers, Esc Esc interrupts the turn";
|
|
19547
|
-
|
|
19732
|
+
var buildContent = (text, images) => images.length > 0 ? [{ type: "text", text }, ...images] : text;
|
|
19733
|
+
function deliverPrompt(store, content, delivery, images) {
|
|
19548
19734
|
const busy = isAgentBusy(store);
|
|
19549
19735
|
if (busy && delivery === "send") {
|
|
19550
19736
|
store.emit({ type: "ui.notice.posted", text: BUSY_NOTICE });
|
|
19551
19737
|
return false;
|
|
19552
19738
|
}
|
|
19553
|
-
return requestAgent(store, {
|
|
19739
|
+
return requestAgent(store, {
|
|
19740
|
+
type: DELIVERY_REQUESTS[busy ? delivery : "send"],
|
|
19741
|
+
content: buildContent(content, images)
|
|
19742
|
+
});
|
|
19554
19743
|
}
|
|
19555
|
-
function submitPrompt(store, text, delivery = "send") {
|
|
19744
|
+
function submitPrompt(store, text, delivery = "send", images = []) {
|
|
19556
19745
|
const content = text.trim();
|
|
19557
|
-
if (!content)
|
|
19746
|
+
if (!content && images.length === 0)
|
|
19558
19747
|
return false;
|
|
19559
19748
|
if (content.startsWith("/") && !isAgentCommand(store.state, content)) {
|
|
19560
19749
|
runSlashCommand(store, content);
|
|
19561
19750
|
return true;
|
|
19562
19751
|
}
|
|
19563
|
-
return deliverPrompt(store, content, delivery);
|
|
19752
|
+
return deliverPrompt(store, content, delivery, images);
|
|
19564
19753
|
}
|
|
19565
19754
|
function answerApproval(store, decision, toolUseId) {
|
|
19566
19755
|
const target = toolUseId ?? findAwaitingCalls(store.state)[0]?.id;
|
|
@@ -19593,11 +19782,9 @@ var showHistoryText = (store, editor) => {
|
|
|
19593
19782
|
editor.replace(text);
|
|
19594
19783
|
};
|
|
19595
19784
|
function routeHistoryKey(key, store, editor) {
|
|
19596
|
-
|
|
19597
|
-
if (ui.focus !== "input" || key.name !== "up" && key.name !== "down")
|
|
19785
|
+
if (store.state.ui.focus !== "input" || !key.shift)
|
|
19598
19786
|
return false;
|
|
19599
|
-
|
|
19600
|
-
if (!ui.history && !starting)
|
|
19787
|
+
if (key.name !== "up" && key.name !== "down")
|
|
19601
19788
|
return false;
|
|
19602
19789
|
const delta = key.name === "up" ? -1 : 1;
|
|
19603
19790
|
store.emit({ type: "ui.history.moved", delta, draft: editor.read() });
|
|
@@ -19917,6 +20104,60 @@ class TurnNotifier {
|
|
|
19917
20104
|
}
|
|
19918
20105
|
}
|
|
19919
20106
|
|
|
20107
|
+
// apps/tui/src/prompt/historyFile.ts
|
|
20108
|
+
import { homedir as homedir7 } from "os";
|
|
20109
|
+
import { join as join6 } from "path";
|
|
20110
|
+
var HISTORY_ROOT = join6(homedir7(), ".claudin", "prompts");
|
|
20111
|
+
var buildHistoryPath = (cwd, root = HISTORY_ROOT) => join6(root, cwd.replace(/[^a-zA-Z0-9]/g, "-"), "history.jsonl");
|
|
20112
|
+
var parseLine = (line) => {
|
|
20113
|
+
try {
|
|
20114
|
+
const { text } = JSON.parse(line);
|
|
20115
|
+
return typeof text === "string" && text !== "" ? text : undefined;
|
|
20116
|
+
} catch {
|
|
20117
|
+
return;
|
|
20118
|
+
}
|
|
20119
|
+
};
|
|
20120
|
+
async function readHistoryFile(path) {
|
|
20121
|
+
const content = await Bun.file(path).text().catch(() => "");
|
|
20122
|
+
const entries = content.split(`
|
|
20123
|
+
`).flatMap((line) => parseLine(line) ?? []);
|
|
20124
|
+
return entries.slice(-MAX_PROMPT_HISTORY);
|
|
20125
|
+
}
|
|
20126
|
+
async function writeHistoryFile(path, entries) {
|
|
20127
|
+
const lines = entries.slice(-MAX_PROMPT_HISTORY).map((text) => JSON.stringify({ text }));
|
|
20128
|
+
await Bun.write(path, lines.length > 0 ? `${lines.join(`
|
|
20129
|
+
`)}
|
|
20130
|
+
` : "");
|
|
20131
|
+
}
|
|
20132
|
+
|
|
20133
|
+
// apps/tui/src/prompt/historySaver.ts
|
|
20134
|
+
var SAVE_DELAY_MS = 400;
|
|
20135
|
+
|
|
20136
|
+
class HistorySaver {
|
|
20137
|
+
path;
|
|
20138
|
+
delayMs;
|
|
20139
|
+
timer;
|
|
20140
|
+
pending;
|
|
20141
|
+
constructor(path, delayMs = SAVE_DELAY_MS) {
|
|
20142
|
+
this.path = path;
|
|
20143
|
+
this.delayMs = delayMs;
|
|
20144
|
+
}
|
|
20145
|
+
schedule(entries, draft) {
|
|
20146
|
+
this.pending = queuePromptHistory(entries, draft.trim());
|
|
20147
|
+
clearTimeout(this.timer);
|
|
20148
|
+
this.timer = setTimeout(() => void this.flush(), this.delayMs);
|
|
20149
|
+
}
|
|
20150
|
+
async flush() {
|
|
20151
|
+
clearTimeout(this.timer);
|
|
20152
|
+
const entries = this.pending;
|
|
20153
|
+
this.pending = undefined;
|
|
20154
|
+
if (entries)
|
|
20155
|
+
await writeHistoryFile(this.path, entries).catch(() => {
|
|
20156
|
+
return;
|
|
20157
|
+
});
|
|
20158
|
+
}
|
|
20159
|
+
}
|
|
20160
|
+
|
|
19920
20161
|
// apps/tui/src/store/appStore.ts
|
|
19921
20162
|
class AppStore {
|
|
19922
20163
|
client;
|
|
@@ -19958,8 +20199,8 @@ class AppStore {
|
|
|
19958
20199
|
}
|
|
19959
20200
|
|
|
19960
20201
|
// apps/tui/src/theme/syntaxStyle.ts
|
|
19961
|
-
import { SyntaxStyle } from "@opentui/core";
|
|
19962
|
-
var createSyntaxStyle = (renderer) =>
|
|
20202
|
+
import { SyntaxStyle as SyntaxStyle2 } from "@opentui/core";
|
|
20203
|
+
var createSyntaxStyle = (renderer) => SyntaxStyle2.fromStyles({
|
|
19963
20204
|
default: { fg: Theme.fg.primary },
|
|
19964
20205
|
"markup.heading": { fg: Theme.accent.brand, bold: true },
|
|
19965
20206
|
"markup.strong": { fg: Theme.fg.primary, bold: true },
|
|
@@ -20002,15 +20243,28 @@ async function startTui(client, options = {}) {
|
|
|
20002
20243
|
});
|
|
20003
20244
|
const diffViewer = new DiffViewerPanel(activeRenderer, syntaxStyle);
|
|
20004
20245
|
const submitInput = (delivery) => {
|
|
20005
|
-
|
|
20246
|
+
const draft = input.compose();
|
|
20247
|
+
if (!submitPrompt(store, draft.text, delivery, draft.images))
|
|
20006
20248
|
return;
|
|
20007
20249
|
input.clear();
|
|
20008
20250
|
if (store.state.ui.history)
|
|
20009
20251
|
store.emit({ type: "ui.history.reset" });
|
|
20010
20252
|
};
|
|
20253
|
+
const historyPath = options.historyPath ?? buildHistoryPath(process.cwd());
|
|
20254
|
+
const historySaver = new HistorySaver(historyPath);
|
|
20255
|
+
let destroyed = false;
|
|
20256
|
+
const saveDraft = (text) => {
|
|
20257
|
+
const { ui, promptHistory } = store.state;
|
|
20258
|
+
if (ui.history && text === readHistoryText(store.state))
|
|
20259
|
+
return;
|
|
20260
|
+
historySaver.schedule(promptHistory, text);
|
|
20261
|
+
};
|
|
20011
20262
|
const input = new PromptInput(activeRenderer, {
|
|
20012
20263
|
onSubmit: () => submitInput("send"),
|
|
20013
|
-
onChange: (text, cursor) =>
|
|
20264
|
+
onChange: (text, cursor) => {
|
|
20265
|
+
syncAutocomplete(store, text, cursor);
|
|
20266
|
+
saveDraft(text);
|
|
20267
|
+
}
|
|
20014
20268
|
});
|
|
20015
20269
|
const root = new BoxRenderable15(activeRenderer, {
|
|
20016
20270
|
width: "100%",
|
|
@@ -20124,9 +20378,15 @@ async function startTui(client, options = {}) {
|
|
|
20124
20378
|
activeRenderer.on("destroy", () => {
|
|
20125
20379
|
clearInterval(clock);
|
|
20126
20380
|
clearInterval(rateLimitPoll);
|
|
20381
|
+
destroyed = true;
|
|
20382
|
+
historySaver.flush();
|
|
20127
20383
|
options.onExit?.(store.state.sessionId);
|
|
20128
20384
|
store.close();
|
|
20129
20385
|
});
|
|
20386
|
+
readHistoryFile(historyPath).then((entries) => {
|
|
20387
|
+
if (!destroyed)
|
|
20388
|
+
store.emit({ type: "ui.history.loaded", entries });
|
|
20389
|
+
});
|
|
20130
20390
|
render(store.state);
|
|
20131
20391
|
input.setFocused(true);
|
|
20132
20392
|
if (options.attach)
|