@couralabs/claudin 0.1.1 → 0.1.3
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 +323 -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,51 @@ 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
|
+
agentPushNotifEnabled: true,
|
|
7833
|
+
showMessageTimestamps: true,
|
|
7834
|
+
idleCompaction: false,
|
|
7835
|
+
autoCompactEnabled: true,
|
|
7836
|
+
showThinkingSummaries: true,
|
|
7837
|
+
autoMemoryEnabled: false,
|
|
7838
|
+
emojiCompletionEnabled: false,
|
|
7839
|
+
spinnerTipsEnabled: false,
|
|
7840
|
+
disableAgentView: true,
|
|
7841
|
+
allowAllClaudeAiMcps: false,
|
|
7842
|
+
includeGitInstructions: false,
|
|
7843
|
+
syncClaudeAiPlugins: false,
|
|
7844
|
+
syncClaudeAiSkills: false,
|
|
7845
|
+
enableAllProjectMcpServers: true,
|
|
7846
|
+
promptCacheTtl: "1h",
|
|
7847
|
+
subagentPromptCacheTtl: "5m",
|
|
7848
|
+
viewMode: "verbose",
|
|
7849
|
+
attribution: { commit: "", pr: "" }
|
|
7850
|
+
},
|
|
7851
|
+
settingSources: ["user", "project", "local"],
|
|
7852
|
+
skills: "all",
|
|
7853
|
+
agentProgressSummaries: true,
|
|
7854
|
+
includePartialMessages: true,
|
|
7855
|
+
includeHookEvents: true
|
|
7811
7856
|
};
|
|
7812
7857
|
|
|
7813
7858
|
// packages/agent/src/runtime/buildUserMessage.ts
|
|
7859
|
+
var isSlashCommand = (content) => readPromptText(content).trimStart().startsWith("/");
|
|
7814
7860
|
var buildUserMessage = (content, priority) => ({
|
|
7815
7861
|
type: "user",
|
|
7816
7862
|
message: { role: "user", content },
|
|
7817
7863
|
parent_tool_use_id: null,
|
|
7818
|
-
priority
|
|
7864
|
+
priority,
|
|
7865
|
+
client_composed: isSlashCommand(content) ? undefined : true
|
|
7819
7866
|
});
|
|
7820
7867
|
|
|
7821
7868
|
// packages/agent/src/session/pickNextModel.ts
|
|
@@ -7841,7 +7888,6 @@ class AgentSession {
|
|
|
7841
7888
|
this.query = runtime.open({
|
|
7842
7889
|
prompt: this.input,
|
|
7843
7890
|
options: {
|
|
7844
|
-
includePartialMessages: true,
|
|
7845
7891
|
...baseOptions,
|
|
7846
7892
|
...AGENT_PROFILE_OPTIONS,
|
|
7847
7893
|
canUseTool: this.gate.canUseTool
|
|
@@ -17616,9 +17662,7 @@ var readEffortColor = (effort) => ({
|
|
|
17616
17662
|
max: Theme.status.danger
|
|
17617
17663
|
})[effort] ?? Theme.fg.secondary;
|
|
17618
17664
|
var readPermissionColor = (mode) => ({
|
|
17619
|
-
default: Theme.fg.primary,
|
|
17620
17665
|
acceptEdits: Theme.status.success,
|
|
17621
|
-
plan: Theme.status.info,
|
|
17622
17666
|
auto: Theme.accent.highlight,
|
|
17623
17667
|
dontAsk: Theme.status.warning,
|
|
17624
17668
|
bypassPermissions: Theme.status.danger
|
|
@@ -17758,11 +17802,125 @@ class ListPopover {
|
|
|
17758
17802
|
// apps/tui/src/components/promptInput.ts
|
|
17759
17803
|
import {
|
|
17760
17804
|
BoxRenderable as BoxRenderable5,
|
|
17805
|
+
SyntaxStyle,
|
|
17761
17806
|
TextareaRenderable,
|
|
17762
17807
|
TextRenderable as TextRenderable5
|
|
17763
17808
|
} from "@opentui/core";
|
|
17809
|
+
|
|
17810
|
+
// apps/tui/src/prompt/pasteAttachments.ts
|
|
17811
|
+
class PasteAttachments {
|
|
17812
|
+
replacements = new Map;
|
|
17813
|
+
images = new Map;
|
|
17814
|
+
counter = 0;
|
|
17815
|
+
addText(text) {
|
|
17816
|
+
const lines = text.split(`
|
|
17817
|
+
`).length;
|
|
17818
|
+
return this.remember(`Pasted text #${this.next()} +${lines} lines`, text);
|
|
17819
|
+
}
|
|
17820
|
+
addFile(path) {
|
|
17821
|
+
const name = path.split("/").at(-1) ?? path;
|
|
17822
|
+
return this.remember(`File #${this.next()} ${name}`, path);
|
|
17823
|
+
}
|
|
17824
|
+
addImage(image) {
|
|
17825
|
+
const placeholder = `[Image #${this.next()}]`;
|
|
17826
|
+
this.images.set(placeholder, image);
|
|
17827
|
+
return placeholder;
|
|
17828
|
+
}
|
|
17829
|
+
compose(text) {
|
|
17830
|
+
let expanded = text;
|
|
17831
|
+
for (const [placeholder, value] of this.replacements) {
|
|
17832
|
+
expanded = expanded.replaceAll(placeholder, () => value);
|
|
17833
|
+
}
|
|
17834
|
+
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);
|
|
17835
|
+
return { text: expanded, images };
|
|
17836
|
+
}
|
|
17837
|
+
placeholders() {
|
|
17838
|
+
return [...this.replacements.keys(), ...this.images.keys()];
|
|
17839
|
+
}
|
|
17840
|
+
reset() {
|
|
17841
|
+
this.replacements.clear();
|
|
17842
|
+
this.images.clear();
|
|
17843
|
+
this.counter = 0;
|
|
17844
|
+
}
|
|
17845
|
+
remember(label, value) {
|
|
17846
|
+
const placeholder = `[${label}]`;
|
|
17847
|
+
this.replacements.set(placeholder, value);
|
|
17848
|
+
return placeholder;
|
|
17849
|
+
}
|
|
17850
|
+
next() {
|
|
17851
|
+
this.counter += 1;
|
|
17852
|
+
return this.counter;
|
|
17853
|
+
}
|
|
17854
|
+
}
|
|
17855
|
+
|
|
17856
|
+
// apps/tui/src/prompt/planPaste.ts
|
|
17857
|
+
import { readFileSync } from "fs";
|
|
17858
|
+
import { extname } from "path";
|
|
17859
|
+
import { decodePasteBytes } from "@opentui/core";
|
|
17860
|
+
|
|
17861
|
+
// apps/tui/src/prompt/imageBlock.ts
|
|
17862
|
+
var IMAGE_MEDIA_TYPES = ["image/gif", "image/jpeg", "image/png", "image/webp"];
|
|
17863
|
+
var readImageMediaType = (mediaType) => IMAGE_MEDIA_TYPES.find((known) => known === mediaType);
|
|
17864
|
+
var buildImageBlock = (mediaType, bytes) => ({
|
|
17865
|
+
type: "image",
|
|
17866
|
+
source: { type: "base64", media_type: mediaType, data: Buffer.from(bytes).toString("base64") }
|
|
17867
|
+
});
|
|
17868
|
+
|
|
17869
|
+
// apps/tui/src/prompt/pastedPaths.ts
|
|
17870
|
+
import { statSync } from "fs";
|
|
17871
|
+
import { homedir as homedir6 } from "os";
|
|
17872
|
+
import { isAbsolute } from "path";
|
|
17873
|
+
var unwrapPath = (raw) => raw.trim().replace(/^(['"])(.*)\1$/, "$2").replace(/^file:\/\//, "").replace(/^~(?=\/)/, homedir6()).replace(/\\(.)/g, "$1");
|
|
17874
|
+
var isExistingFile = (path) => {
|
|
17875
|
+
try {
|
|
17876
|
+
return isAbsolute(path) && statSync(path).isFile();
|
|
17877
|
+
} catch {
|
|
17878
|
+
return false;
|
|
17879
|
+
}
|
|
17880
|
+
};
|
|
17881
|
+
function parsePastedPaths(text) {
|
|
17882
|
+
const lines = text.split(`
|
|
17883
|
+
`).map((line) => line.trim()).filter(Boolean);
|
|
17884
|
+
const paths = lines.flatMap((line) => isExistingFile(unwrapPath(line)) ? [line] : line.split(/(?<!\\)\s+/)).map(unwrapPath);
|
|
17885
|
+
return paths.length > 0 && paths.every(isExistingFile) ? paths : [];
|
|
17886
|
+
}
|
|
17887
|
+
|
|
17888
|
+
// apps/tui/src/prompt/planPaste.ts
|
|
17889
|
+
var LONG_PASTE_LINES = 5;
|
|
17890
|
+
var LONG_PASTE_CHARS = 500;
|
|
17891
|
+
var IMAGE_TYPES = {
|
|
17892
|
+
".png": "image/png",
|
|
17893
|
+
".jpg": "image/jpeg",
|
|
17894
|
+
".jpeg": "image/jpeg",
|
|
17895
|
+
".gif": "image/gif",
|
|
17896
|
+
".webp": "image/webp"
|
|
17897
|
+
};
|
|
17898
|
+
var isLongPaste = (text) => text.length > LONG_PASTE_CHARS || text.split(`
|
|
17899
|
+
`).length > LONG_PASTE_LINES;
|
|
17900
|
+
function attachPath(path, attachments) {
|
|
17901
|
+
const mediaType = IMAGE_TYPES[extname(path).toLowerCase()];
|
|
17902
|
+
if (!mediaType)
|
|
17903
|
+
return attachments.addFile(path);
|
|
17904
|
+
return attachments.addImage(buildImageBlock(mediaType, readFileSync(path)));
|
|
17905
|
+
}
|
|
17906
|
+
function planPaste(event, attachments) {
|
|
17907
|
+
const mediaType = readImageMediaType(event.metadata?.mimeType);
|
|
17908
|
+
if (mediaType) {
|
|
17909
|
+
return attachments.addImage(buildImageBlock(mediaType, event.bytes));
|
|
17910
|
+
}
|
|
17911
|
+
if (event.metadata?.kind === "binary")
|
|
17912
|
+
return;
|
|
17913
|
+
const text = decodePasteBytes(event.bytes);
|
|
17914
|
+
const paths = parsePastedPaths(text);
|
|
17915
|
+
if (paths.length > 0)
|
|
17916
|
+
return paths.map((path) => attachPath(path, attachments)).join(" ");
|
|
17917
|
+
return isLongPaste(text) ? attachments.addText(text) : undefined;
|
|
17918
|
+
}
|
|
17919
|
+
|
|
17920
|
+
// apps/tui/src/components/promptInput.ts
|
|
17764
17921
|
var MAX_INPUT_LINES = 8;
|
|
17765
17922
|
var BUSY_TITLE = " Ctrl+Q (queue) Ctrl+W (steer) ";
|
|
17923
|
+
var ATTACHMENT_STYLE = "attachment";
|
|
17766
17924
|
var PLACEHOLDER = "Type your prompt, /slash command, or @file reference...";
|
|
17767
17925
|
var KEY_BINDINGS = [
|
|
17768
17926
|
{ name: "return", action: "submit" },
|
|
@@ -17776,6 +17934,9 @@ class PromptInput {
|
|
|
17776
17934
|
renderable;
|
|
17777
17935
|
textarea;
|
|
17778
17936
|
chevron;
|
|
17937
|
+
attachments = new PasteAttachments;
|
|
17938
|
+
attachmentStyle;
|
|
17939
|
+
attachmentStyleId = 0;
|
|
17779
17940
|
focused = false;
|
|
17780
17941
|
constructor(renderer, handlers) {
|
|
17781
17942
|
this.renderable = new BoxRenderable5(renderer, {
|
|
@@ -17787,14 +17948,18 @@ class PromptInput {
|
|
|
17787
17948
|
flexShrink: 0,
|
|
17788
17949
|
paddingLeft: 1
|
|
17789
17950
|
});
|
|
17951
|
+
this.attachmentStyle = SyntaxStyle.create(renderer.nativeScene);
|
|
17790
17952
|
this.textarea = new TextareaRenderable(renderer, {
|
|
17791
17953
|
flexGrow: 1,
|
|
17792
17954
|
height: 1,
|
|
17793
17955
|
placeholder: PLACEHOLDER,
|
|
17794
17956
|
wrapMode: "word",
|
|
17795
17957
|
keyBindings: KEY_BINDINGS,
|
|
17958
|
+
syntaxStyle: this.attachmentStyle,
|
|
17959
|
+
onPaste: (event) => this.insertPlaceholder(event),
|
|
17796
17960
|
onSubmit: () => handlers.onSubmit(this.text),
|
|
17797
17961
|
onContentChange: () => {
|
|
17962
|
+
this.markAttachments();
|
|
17798
17963
|
this.fitHeight();
|
|
17799
17964
|
handlers.onChange(this.text, this.textarea.cursorOffset);
|
|
17800
17965
|
}
|
|
@@ -17814,8 +17979,19 @@ class PromptInput {
|
|
|
17814
17979
|
this.textarea.setText(text);
|
|
17815
17980
|
this.textarea.cursorOffset = cursor;
|
|
17816
17981
|
}
|
|
17982
|
+
compose() {
|
|
17983
|
+
return this.attachments.compose(this.text);
|
|
17984
|
+
}
|
|
17985
|
+
insertPlaceholder(event) {
|
|
17986
|
+
const placeholder = planPaste(event, this.attachments);
|
|
17987
|
+
if (placeholder === undefined)
|
|
17988
|
+
return;
|
|
17989
|
+
event.preventDefault();
|
|
17990
|
+
this.textarea.insertText(placeholder);
|
|
17991
|
+
}
|
|
17817
17992
|
clear() {
|
|
17818
17993
|
this.textarea.setText("");
|
|
17994
|
+
this.attachments.reset();
|
|
17819
17995
|
}
|
|
17820
17996
|
setFocused(focused) {
|
|
17821
17997
|
if (focused === this.focused)
|
|
@@ -17842,6 +18018,26 @@ class PromptInput {
|
|
|
17842
18018
|
this.textarea.focusedTextColor = Theme.fg.primary;
|
|
17843
18019
|
this.textarea.backgroundColor = Theme.bg.default;
|
|
17844
18020
|
this.textarea.focusedBackgroundColor = Theme.bg.default;
|
|
18021
|
+
this.attachmentStyleId = this.attachmentStyle.registerStyle(ATTACHMENT_STYLE, {
|
|
18022
|
+
fg: Theme.accent.highlight,
|
|
18023
|
+
bold: true
|
|
18024
|
+
});
|
|
18025
|
+
this.markAttachments();
|
|
18026
|
+
}
|
|
18027
|
+
markAttachments() {
|
|
18028
|
+
const { extmarks } = this.textarea;
|
|
18029
|
+
extmarks.clear();
|
|
18030
|
+
const text = this.text;
|
|
18031
|
+
for (const placeholder of this.attachments.placeholders()) {
|
|
18032
|
+
for (let at = text.indexOf(placeholder);at >= 0; at = text.indexOf(placeholder, at + 1)) {
|
|
18033
|
+
extmarks.create({
|
|
18034
|
+
start: at,
|
|
18035
|
+
end: at + placeholder.length,
|
|
18036
|
+
virtual: true,
|
|
18037
|
+
styleId: this.attachmentStyleId
|
|
18038
|
+
});
|
|
18039
|
+
}
|
|
18040
|
+
}
|
|
17845
18041
|
}
|
|
17846
18042
|
fitHeight() {
|
|
17847
18043
|
const wanted = Math.max(this.textarea.lineCount, this.textarea.virtualLineCount, 1);
|
|
@@ -18580,7 +18776,9 @@ var SUMMARY_LENGTH = 80;
|
|
|
18580
18776
|
var SUMMARY_KEYS = ["file_path", "path", "command", "pattern", "query", "url", "description"];
|
|
18581
18777
|
var SEARCH_TOOLS = new Set(["Glob", "Grep"]);
|
|
18582
18778
|
var summarizeSearch = ({ pattern, path }) => typeof path === "string" ? `${pattern} in ${path}` : String(pattern);
|
|
18583
|
-
function summarizeToolCall({ name, input }) {
|
|
18779
|
+
function summarizeToolCall({ name, input, status, progress }) {
|
|
18780
|
+
if (status === "running" && progress)
|
|
18781
|
+
return truncateText(progress, SUMMARY_LENGTH);
|
|
18584
18782
|
if (SEARCH_TOOLS.has(name) && typeof input.pattern === "string") {
|
|
18585
18783
|
return truncateText(summarizeSearch(input), SUMMARY_LENGTH);
|
|
18586
18784
|
}
|
|
@@ -18875,6 +19073,8 @@ import {
|
|
|
18875
19073
|
StyledText as StyledText11,
|
|
18876
19074
|
TextRenderable as TextRenderable12
|
|
18877
19075
|
} from "@opentui/core";
|
|
19076
|
+
var USER_LINES = 10;
|
|
19077
|
+
|
|
18878
19078
|
class UserMessageView {
|
|
18879
19079
|
renderable;
|
|
18880
19080
|
text;
|
|
@@ -18903,7 +19103,7 @@ class UserMessageView {
|
|
|
18903
19103
|
this.entry = entry;
|
|
18904
19104
|
this.text.content = new StyledText11([
|
|
18905
19105
|
bold7(fg12(Theme.accent.brand)("\u276F ")),
|
|
18906
|
-
bold7(fg12(Theme.fg.primary)(entry.text))
|
|
19106
|
+
bold7(fg12(Theme.fg.primary)(clipLines(entry.text, USER_LINES)))
|
|
18907
19107
|
]);
|
|
18908
19108
|
this.clock.content = new StyledText11([fg12(Theme.fg.muted)(formatClock(entry.at))]);
|
|
18909
19109
|
}
|
|
@@ -19544,23 +19744,27 @@ var DELIVERY_REQUESTS = {
|
|
|
19544
19744
|
steer: "agent.prompt.steer.requested"
|
|
19545
19745
|
};
|
|
19546
19746
|
var BUSY_NOTICE = "Agent is busy: Ctrl+Q queues, Ctrl+W steers, Esc Esc interrupts the turn";
|
|
19547
|
-
|
|
19747
|
+
var buildContent = (text, images) => images.length > 0 ? [{ type: "text", text }, ...images] : text;
|
|
19748
|
+
function deliverPrompt(store, content, delivery, images) {
|
|
19548
19749
|
const busy = isAgentBusy(store);
|
|
19549
19750
|
if (busy && delivery === "send") {
|
|
19550
19751
|
store.emit({ type: "ui.notice.posted", text: BUSY_NOTICE });
|
|
19551
19752
|
return false;
|
|
19552
19753
|
}
|
|
19553
|
-
return requestAgent(store, {
|
|
19754
|
+
return requestAgent(store, {
|
|
19755
|
+
type: DELIVERY_REQUESTS[busy ? delivery : "send"],
|
|
19756
|
+
content: buildContent(content, images)
|
|
19757
|
+
});
|
|
19554
19758
|
}
|
|
19555
|
-
function submitPrompt(store, text, delivery = "send") {
|
|
19759
|
+
function submitPrompt(store, text, delivery = "send", images = []) {
|
|
19556
19760
|
const content = text.trim();
|
|
19557
|
-
if (!content)
|
|
19761
|
+
if (!content && images.length === 0)
|
|
19558
19762
|
return false;
|
|
19559
19763
|
if (content.startsWith("/") && !isAgentCommand(store.state, content)) {
|
|
19560
19764
|
runSlashCommand(store, content);
|
|
19561
19765
|
return true;
|
|
19562
19766
|
}
|
|
19563
|
-
return deliverPrompt(store, content, delivery);
|
|
19767
|
+
return deliverPrompt(store, content, delivery, images);
|
|
19564
19768
|
}
|
|
19565
19769
|
function answerApproval(store, decision, toolUseId) {
|
|
19566
19770
|
const target = toolUseId ?? findAwaitingCalls(store.state)[0]?.id;
|
|
@@ -19593,11 +19797,9 @@ var showHistoryText = (store, editor) => {
|
|
|
19593
19797
|
editor.replace(text);
|
|
19594
19798
|
};
|
|
19595
19799
|
function routeHistoryKey(key, store, editor) {
|
|
19596
|
-
|
|
19597
|
-
if (ui.focus !== "input" || key.name !== "up" && key.name !== "down")
|
|
19800
|
+
if (store.state.ui.focus !== "input" || !key.shift)
|
|
19598
19801
|
return false;
|
|
19599
|
-
|
|
19600
|
-
if (!ui.history && !starting)
|
|
19802
|
+
if (key.name !== "up" && key.name !== "down")
|
|
19601
19803
|
return false;
|
|
19602
19804
|
const delta = key.name === "up" ? -1 : 1;
|
|
19603
19805
|
store.emit({ type: "ui.history.moved", delta, draft: editor.read() });
|
|
@@ -19917,6 +20119,60 @@ class TurnNotifier {
|
|
|
19917
20119
|
}
|
|
19918
20120
|
}
|
|
19919
20121
|
|
|
20122
|
+
// apps/tui/src/prompt/historyFile.ts
|
|
20123
|
+
import { homedir as homedir7 } from "os";
|
|
20124
|
+
import { join as join6 } from "path";
|
|
20125
|
+
var HISTORY_ROOT = join6(homedir7(), ".claudin", "prompts");
|
|
20126
|
+
var buildHistoryPath = (cwd, root = HISTORY_ROOT) => join6(root, cwd.replace(/[^a-zA-Z0-9]/g, "-"), "history.jsonl");
|
|
20127
|
+
var parseLine = (line) => {
|
|
20128
|
+
try {
|
|
20129
|
+
const { text } = JSON.parse(line);
|
|
20130
|
+
return typeof text === "string" && text !== "" ? text : undefined;
|
|
20131
|
+
} catch {
|
|
20132
|
+
return;
|
|
20133
|
+
}
|
|
20134
|
+
};
|
|
20135
|
+
async function readHistoryFile(path) {
|
|
20136
|
+
const content = await Bun.file(path).text().catch(() => "");
|
|
20137
|
+
const entries = content.split(`
|
|
20138
|
+
`).flatMap((line) => parseLine(line) ?? []);
|
|
20139
|
+
return entries.slice(-MAX_PROMPT_HISTORY);
|
|
20140
|
+
}
|
|
20141
|
+
async function writeHistoryFile(path, entries) {
|
|
20142
|
+
const lines = entries.slice(-MAX_PROMPT_HISTORY).map((text) => JSON.stringify({ text }));
|
|
20143
|
+
await Bun.write(path, lines.length > 0 ? `${lines.join(`
|
|
20144
|
+
`)}
|
|
20145
|
+
` : "");
|
|
20146
|
+
}
|
|
20147
|
+
|
|
20148
|
+
// apps/tui/src/prompt/historySaver.ts
|
|
20149
|
+
var SAVE_DELAY_MS = 400;
|
|
20150
|
+
|
|
20151
|
+
class HistorySaver {
|
|
20152
|
+
path;
|
|
20153
|
+
delayMs;
|
|
20154
|
+
timer;
|
|
20155
|
+
pending;
|
|
20156
|
+
constructor(path, delayMs = SAVE_DELAY_MS) {
|
|
20157
|
+
this.path = path;
|
|
20158
|
+
this.delayMs = delayMs;
|
|
20159
|
+
}
|
|
20160
|
+
schedule(entries, draft) {
|
|
20161
|
+
this.pending = queuePromptHistory(entries, draft.trim());
|
|
20162
|
+
clearTimeout(this.timer);
|
|
20163
|
+
this.timer = setTimeout(() => void this.flush(), this.delayMs);
|
|
20164
|
+
}
|
|
20165
|
+
async flush() {
|
|
20166
|
+
clearTimeout(this.timer);
|
|
20167
|
+
const entries = this.pending;
|
|
20168
|
+
this.pending = undefined;
|
|
20169
|
+
if (entries)
|
|
20170
|
+
await writeHistoryFile(this.path, entries).catch(() => {
|
|
20171
|
+
return;
|
|
20172
|
+
});
|
|
20173
|
+
}
|
|
20174
|
+
}
|
|
20175
|
+
|
|
19920
20176
|
// apps/tui/src/store/appStore.ts
|
|
19921
20177
|
class AppStore {
|
|
19922
20178
|
client;
|
|
@@ -19958,8 +20214,8 @@ class AppStore {
|
|
|
19958
20214
|
}
|
|
19959
20215
|
|
|
19960
20216
|
// apps/tui/src/theme/syntaxStyle.ts
|
|
19961
|
-
import { SyntaxStyle } from "@opentui/core";
|
|
19962
|
-
var createSyntaxStyle = (renderer) =>
|
|
20217
|
+
import { SyntaxStyle as SyntaxStyle2 } from "@opentui/core";
|
|
20218
|
+
var createSyntaxStyle = (renderer) => SyntaxStyle2.fromStyles({
|
|
19963
20219
|
default: { fg: Theme.fg.primary },
|
|
19964
20220
|
"markup.heading": { fg: Theme.accent.brand, bold: true },
|
|
19965
20221
|
"markup.strong": { fg: Theme.fg.primary, bold: true },
|
|
@@ -20002,15 +20258,28 @@ async function startTui(client, options = {}) {
|
|
|
20002
20258
|
});
|
|
20003
20259
|
const diffViewer = new DiffViewerPanel(activeRenderer, syntaxStyle);
|
|
20004
20260
|
const submitInput = (delivery) => {
|
|
20005
|
-
|
|
20261
|
+
const draft = input.compose();
|
|
20262
|
+
if (!submitPrompt(store, draft.text, delivery, draft.images))
|
|
20006
20263
|
return;
|
|
20007
20264
|
input.clear();
|
|
20008
20265
|
if (store.state.ui.history)
|
|
20009
20266
|
store.emit({ type: "ui.history.reset" });
|
|
20010
20267
|
};
|
|
20268
|
+
const historyPath = options.historyPath ?? buildHistoryPath(process.cwd());
|
|
20269
|
+
const historySaver = new HistorySaver(historyPath);
|
|
20270
|
+
let destroyed = false;
|
|
20271
|
+
const saveDraft = (text) => {
|
|
20272
|
+
const { ui, promptHistory } = store.state;
|
|
20273
|
+
if (ui.history && text === readHistoryText(store.state))
|
|
20274
|
+
return;
|
|
20275
|
+
historySaver.schedule(promptHistory, text);
|
|
20276
|
+
};
|
|
20011
20277
|
const input = new PromptInput(activeRenderer, {
|
|
20012
20278
|
onSubmit: () => submitInput("send"),
|
|
20013
|
-
onChange: (text, cursor) =>
|
|
20279
|
+
onChange: (text, cursor) => {
|
|
20280
|
+
syncAutocomplete(store, text, cursor);
|
|
20281
|
+
saveDraft(text);
|
|
20282
|
+
}
|
|
20014
20283
|
});
|
|
20015
20284
|
const root = new BoxRenderable15(activeRenderer, {
|
|
20016
20285
|
width: "100%",
|
|
@@ -20124,9 +20393,15 @@ async function startTui(client, options = {}) {
|
|
|
20124
20393
|
activeRenderer.on("destroy", () => {
|
|
20125
20394
|
clearInterval(clock);
|
|
20126
20395
|
clearInterval(rateLimitPoll);
|
|
20396
|
+
destroyed = true;
|
|
20397
|
+
historySaver.flush();
|
|
20127
20398
|
options.onExit?.(store.state.sessionId);
|
|
20128
20399
|
store.close();
|
|
20129
20400
|
});
|
|
20401
|
+
readHistoryFile(historyPath).then((entries) => {
|
|
20402
|
+
if (!destroyed)
|
|
20403
|
+
store.emit({ type: "ui.history.loaded", entries });
|
|
20404
|
+
});
|
|
20130
20405
|
render(store.state);
|
|
20131
20406
|
input.setFocused(true);
|
|
20132
20407
|
if (options.attach)
|