@hasna/coders 0.1.9 → 0.2.0
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/dist/cli.mjs +2004 -368
- package/dist/cli.mjs.map +4 -4
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -7548,7 +7548,7 @@ var init_settings = __esm({
|
|
|
7548
7548
|
alwaysThinkingEnabled: external_exports.boolean().optional(),
|
|
7549
7549
|
// Permissions
|
|
7550
7550
|
permissions: external_exports.object({
|
|
7551
|
-
defaultMode: external_exports.enum(["default", "plan", "acceptEdits", "dontAsk", "auto"]).optional(),
|
|
7551
|
+
defaultMode: external_exports.enum(["default", "plan", "acceptEdits", "dontAsk", "auto", "bypassPermissions"]).optional(),
|
|
7552
7552
|
allow: external_exports.array(PermissionRuleSchema).optional(),
|
|
7553
7553
|
deny: external_exports.array(PermissionRuleSchema).optional()
|
|
7554
7554
|
}).optional(),
|
|
@@ -7598,13 +7598,19 @@ var init_settings = __esm({
|
|
|
7598
7598
|
// Teammate mode
|
|
7599
7599
|
teammateMode: external_exports.enum(["auto", "tmux", "in-process"]).optional(),
|
|
7600
7600
|
// Remote control
|
|
7601
|
-
remoteControlAtStartup: external_exports.boolean().optional()
|
|
7601
|
+
remoteControlAtStartup: external_exports.boolean().optional(),
|
|
7602
|
+
// Custom status line — run an external command to render the status bar
|
|
7603
|
+
statusLine: external_exports.object({
|
|
7604
|
+
type: external_exports.literal("command"),
|
|
7605
|
+
command: external_exports.string(),
|
|
7606
|
+
padding: external_exports.number().optional()
|
|
7607
|
+
}).optional()
|
|
7602
7608
|
}).passthrough();
|
|
7603
7609
|
DEFAULT_SETTINGS = {
|
|
7604
7610
|
model: null,
|
|
7605
7611
|
alwaysThinkingEnabled: void 0,
|
|
7606
7612
|
permissions: {
|
|
7607
|
-
defaultMode: "
|
|
7613
|
+
defaultMode: "bypassPermissions",
|
|
7608
7614
|
allow: [],
|
|
7609
7615
|
deny: []
|
|
7610
7616
|
},
|
|
@@ -7653,16 +7659,6 @@ function getUserSettingsPath() {
|
|
|
7653
7659
|
function getUserConfigPath() {
|
|
7654
7660
|
return join(getConfigDir(), ".config.json");
|
|
7655
7661
|
}
|
|
7656
|
-
function getTeamsDir() {
|
|
7657
|
-
const dir = join(getConfigDir(), "teams");
|
|
7658
|
-
ensureDir(dir);
|
|
7659
|
-
return dir;
|
|
7660
|
-
}
|
|
7661
|
-
function getTasksDir() {
|
|
7662
|
-
const dir = join(getConfigDir(), "tasks");
|
|
7663
|
-
ensureDir(dir);
|
|
7664
|
-
return dir;
|
|
7665
|
-
}
|
|
7666
7662
|
function getPluginsDir() {
|
|
7667
7663
|
const dir = join(getConfigDir(), "plugins");
|
|
7668
7664
|
ensureDir(dir);
|
|
@@ -10168,7 +10164,7 @@ var require_react_development = __commonJS({
|
|
|
10168
10164
|
var dispatcher = resolveDispatcher();
|
|
10169
10165
|
return dispatcher.useReducer(reducer, initialArg, init);
|
|
10170
10166
|
}
|
|
10171
|
-
function
|
|
10167
|
+
function useRef2(initialValue) {
|
|
10172
10168
|
var dispatcher = resolveDispatcher();
|
|
10173
10169
|
return dispatcher.useRef(initialValue);
|
|
10174
10170
|
}
|
|
@@ -10962,7 +10958,7 @@ var require_react_development = __commonJS({
|
|
|
10962
10958
|
exports.useLayoutEffect = useLayoutEffect2;
|
|
10963
10959
|
exports.useMemo = useMemo3;
|
|
10964
10960
|
exports.useReducer = useReducer;
|
|
10965
|
-
exports.useRef =
|
|
10961
|
+
exports.useRef = useRef2;
|
|
10966
10962
|
exports.useState = useState3;
|
|
10967
10963
|
exports.useSyncExternalStore = useSyncExternalStore;
|
|
10968
10964
|
exports.useTransition = useTransition;
|
|
@@ -39039,7 +39035,7 @@ var require_backend = __commonJS({
|
|
|
39039
39035
|
return [initialArg, function() {
|
|
39040
39036
|
}];
|
|
39041
39037
|
},
|
|
39042
|
-
useRef: function
|
|
39038
|
+
useRef: function useRef2(initialValue) {
|
|
39043
39039
|
var hook = nextHook();
|
|
39044
39040
|
initialValue = null !== hook ? hook.memoizedState : {
|
|
39045
39041
|
current: initialValue
|
|
@@ -59191,6 +59187,73 @@ var init_models = __esm({
|
|
|
59191
59187
|
maxOutput: 32768,
|
|
59192
59188
|
supportsThinking: true,
|
|
59193
59189
|
supportsVision: true
|
|
59190
|
+
},
|
|
59191
|
+
// ── xAI Grok models ──────────────────────────────────────────────
|
|
59192
|
+
grok3: {
|
|
59193
|
+
alias: "grok3",
|
|
59194
|
+
variants: {
|
|
59195
|
+
firstParty: "grok-3",
|
|
59196
|
+
bedrock: "grok-3",
|
|
59197
|
+
vertex: "grok-3",
|
|
59198
|
+
xai: "grok-3"
|
|
59199
|
+
},
|
|
59200
|
+
contextWindow: 131072,
|
|
59201
|
+
maxOutput: 16384,
|
|
59202
|
+
supportsThinking: true,
|
|
59203
|
+
supportsVision: false
|
|
59204
|
+
},
|
|
59205
|
+
grok3mini: {
|
|
59206
|
+
alias: "grok3mini",
|
|
59207
|
+
variants: {
|
|
59208
|
+
firstParty: "grok-3-mini",
|
|
59209
|
+
bedrock: "grok-3-mini",
|
|
59210
|
+
vertex: "grok-3-mini",
|
|
59211
|
+
xai: "grok-3-mini"
|
|
59212
|
+
},
|
|
59213
|
+
contextWindow: 131072,
|
|
59214
|
+
maxOutput: 16384,
|
|
59215
|
+
supportsThinking: true,
|
|
59216
|
+
supportsVision: false
|
|
59217
|
+
},
|
|
59218
|
+
grok2: {
|
|
59219
|
+
alias: "grok2",
|
|
59220
|
+
variants: {
|
|
59221
|
+
firstParty: "grok-2",
|
|
59222
|
+
bedrock: "grok-2",
|
|
59223
|
+
vertex: "grok-2",
|
|
59224
|
+
xai: "grok-2"
|
|
59225
|
+
},
|
|
59226
|
+
contextWindow: 131072,
|
|
59227
|
+
maxOutput: 8192,
|
|
59228
|
+
supportsThinking: false,
|
|
59229
|
+
supportsVision: true
|
|
59230
|
+
},
|
|
59231
|
+
// ── Google Gemini models ──────────────────────────────────────────
|
|
59232
|
+
gemini25pro: {
|
|
59233
|
+
alias: "gemini25pro",
|
|
59234
|
+
variants: {
|
|
59235
|
+
firstParty: "gemini-2.5-pro",
|
|
59236
|
+
bedrock: "gemini-2.5-pro",
|
|
59237
|
+
vertex: "gemini-2.5-pro",
|
|
59238
|
+
gemini: "gemini-2.5-pro"
|
|
59239
|
+
},
|
|
59240
|
+
contextWindow: 1e6,
|
|
59241
|
+
maxOutput: 65536,
|
|
59242
|
+
supportsThinking: true,
|
|
59243
|
+
supportsVision: true
|
|
59244
|
+
},
|
|
59245
|
+
gemini25flash: {
|
|
59246
|
+
alias: "gemini25flash",
|
|
59247
|
+
variants: {
|
|
59248
|
+
firstParty: "gemini-2.5-flash",
|
|
59249
|
+
bedrock: "gemini-2.5-flash",
|
|
59250
|
+
vertex: "gemini-2.5-flash",
|
|
59251
|
+
gemini: "gemini-2.5-flash"
|
|
59252
|
+
},
|
|
59253
|
+
contextWindow: 1e6,
|
|
59254
|
+
maxOutput: 65536,
|
|
59255
|
+
supportsThinking: true,
|
|
59256
|
+
supportsVision: true
|
|
59194
59257
|
}
|
|
59195
59258
|
};
|
|
59196
59259
|
USER_ALIASES = {
|
|
@@ -59198,7 +59261,18 @@ var init_models = __esm({
|
|
|
59198
59261
|
sonnet: "sonnet46",
|
|
59199
59262
|
opus: "opus46",
|
|
59200
59263
|
"sonnet[1m]": "sonnet46",
|
|
59201
|
-
"opus[1m]": "opus46"
|
|
59264
|
+
"opus[1m]": "opus46",
|
|
59265
|
+
// xAI Grok aliases
|
|
59266
|
+
grok: "grok3",
|
|
59267
|
+
"grok-3": "grok3",
|
|
59268
|
+
"grok-3-mini": "grok3mini",
|
|
59269
|
+
"grok-2": "grok2",
|
|
59270
|
+
// Gemini aliases
|
|
59271
|
+
gemini: "gemini25pro",
|
|
59272
|
+
"gemini-pro": "gemini25pro",
|
|
59273
|
+
"gemini-flash": "gemini25flash",
|
|
59274
|
+
"gemini-2.5-pro": "gemini25pro",
|
|
59275
|
+
"gemini-2.5-flash": "gemini25flash"
|
|
59202
59276
|
};
|
|
59203
59277
|
}
|
|
59204
59278
|
});
|
|
@@ -59893,6 +59967,151 @@ var init_session = __esm({
|
|
|
59893
59967
|
}
|
|
59894
59968
|
});
|
|
59895
59969
|
|
|
59970
|
+
// src/core/background-tasks.ts
|
|
59971
|
+
var background_tasks_exports = {};
|
|
59972
|
+
__export(background_tasks_exports, {
|
|
59973
|
+
completeTask: () => completeTask,
|
|
59974
|
+
createTask: () => createTask,
|
|
59975
|
+
failTask: () => failTask,
|
|
59976
|
+
getAllTasks: () => getAllTasks,
|
|
59977
|
+
getOutputPath: () => getOutputPath,
|
|
59978
|
+
getRecentlyCompletedTasks: () => getRecentlyCompletedTasks,
|
|
59979
|
+
getRunningTasks: () => getRunningTasks,
|
|
59980
|
+
getTask: () => getTask,
|
|
59981
|
+
killTask: () => killTask,
|
|
59982
|
+
readTaskOutput: () => readTaskOutput,
|
|
59983
|
+
updateTask: () => updateTask,
|
|
59984
|
+
writeTaskOutput: () => writeTaskOutput
|
|
59985
|
+
});
|
|
59986
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync4, appendFileSync, readFileSync as readFileSync7, existsSync as existsSync8 } from "fs";
|
|
59987
|
+
import { join as join6 } from "path";
|
|
59988
|
+
import { homedir as homedir2 } from "os";
|
|
59989
|
+
function ensureTasksDir() {
|
|
59990
|
+
try {
|
|
59991
|
+
mkdirSync5(TASKS_DIR, { recursive: true });
|
|
59992
|
+
} catch {
|
|
59993
|
+
}
|
|
59994
|
+
}
|
|
59995
|
+
function createTask(type, description) {
|
|
59996
|
+
const id = type === "bash" ? `bg-${nextBashId++}` : `agent-${nextAgentId++}`;
|
|
59997
|
+
ensureTasksDir();
|
|
59998
|
+
const outputPath = getOutputPath(id);
|
|
59999
|
+
const task = {
|
|
60000
|
+
id,
|
|
60001
|
+
type,
|
|
60002
|
+
description,
|
|
60003
|
+
status: "running",
|
|
60004
|
+
startTime: Date.now(),
|
|
60005
|
+
output: "",
|
|
60006
|
+
outputPath
|
|
60007
|
+
};
|
|
60008
|
+
if (type === "agent") {
|
|
60009
|
+
task.progress = { tokenCount: 0 };
|
|
60010
|
+
}
|
|
60011
|
+
tasks.set(id, task);
|
|
60012
|
+
try {
|
|
60013
|
+
writeFileSync4(outputPath, "", "utf-8");
|
|
60014
|
+
} catch {
|
|
60015
|
+
}
|
|
60016
|
+
return task;
|
|
60017
|
+
}
|
|
60018
|
+
function updateTask(id, updates) {
|
|
60019
|
+
const task = tasks.get(id);
|
|
60020
|
+
if (!task) return;
|
|
60021
|
+
Object.assign(task, updates);
|
|
60022
|
+
}
|
|
60023
|
+
function completeTask(id, output, exitCode) {
|
|
60024
|
+
const task = tasks.get(id);
|
|
60025
|
+
if (!task) return;
|
|
60026
|
+
task.status = "completed";
|
|
60027
|
+
task.output = output;
|
|
60028
|
+
task.exitCode = exitCode ?? null;
|
|
60029
|
+
task.endTime = Date.now();
|
|
60030
|
+
if (task.outputPath) {
|
|
60031
|
+
try {
|
|
60032
|
+
writeFileSync4(task.outputPath, output, "utf-8");
|
|
60033
|
+
} catch {
|
|
60034
|
+
}
|
|
60035
|
+
}
|
|
60036
|
+
}
|
|
60037
|
+
function failTask(id, error2) {
|
|
60038
|
+
const task = tasks.get(id);
|
|
60039
|
+
if (!task) return;
|
|
60040
|
+
task.status = "failed";
|
|
60041
|
+
task.error = error2;
|
|
60042
|
+
task.endTime = Date.now();
|
|
60043
|
+
if (task.outputPath) {
|
|
60044
|
+
try {
|
|
60045
|
+
appendFileSync(task.outputPath, `
|
|
60046
|
+
|
|
60047
|
+
--- ERROR ---
|
|
60048
|
+
${error2}
|
|
60049
|
+
`, "utf-8");
|
|
60050
|
+
} catch {
|
|
60051
|
+
}
|
|
60052
|
+
}
|
|
60053
|
+
}
|
|
60054
|
+
function killTask(id) {
|
|
60055
|
+
const task = tasks.get(id);
|
|
60056
|
+
if (!task) return;
|
|
60057
|
+
task.status = "killed";
|
|
60058
|
+
task.endTime = Date.now();
|
|
60059
|
+
}
|
|
60060
|
+
function getTask(id) {
|
|
60061
|
+
return tasks.get(id);
|
|
60062
|
+
}
|
|
60063
|
+
function getAllTasks() {
|
|
60064
|
+
return [...tasks.values()];
|
|
60065
|
+
}
|
|
60066
|
+
function getRunningTasks() {
|
|
60067
|
+
return [...tasks.values()].filter((t) => t.status === "running");
|
|
60068
|
+
}
|
|
60069
|
+
function getRecentlyCompletedTasks(withinMs = 6e4) {
|
|
60070
|
+
const cutoff = Date.now() - withinMs;
|
|
60071
|
+
return [...tasks.values()].filter(
|
|
60072
|
+
(t) => t.status !== "running" && t.endTime != null && t.endTime >= cutoff
|
|
60073
|
+
);
|
|
60074
|
+
}
|
|
60075
|
+
function getOutputPath(taskId) {
|
|
60076
|
+
return join6(TASKS_DIR, `${taskId}.output`);
|
|
60077
|
+
}
|
|
60078
|
+
function writeTaskOutput(taskId, chunk) {
|
|
60079
|
+
const task = tasks.get(taskId);
|
|
60080
|
+
if (!task) return;
|
|
60081
|
+
task.output += chunk;
|
|
60082
|
+
if (task.outputPath) {
|
|
60083
|
+
try {
|
|
60084
|
+
appendFileSync(task.outputPath, chunk, "utf-8");
|
|
60085
|
+
} catch {
|
|
60086
|
+
}
|
|
60087
|
+
}
|
|
60088
|
+
}
|
|
60089
|
+
function readTaskOutput(taskId) {
|
|
60090
|
+
const task = tasks.get(taskId);
|
|
60091
|
+
if (task?.output) {
|
|
60092
|
+
return task.output;
|
|
60093
|
+
}
|
|
60094
|
+
const path = getOutputPath(taskId);
|
|
60095
|
+
if (existsSync8(path)) {
|
|
60096
|
+
try {
|
|
60097
|
+
return readFileSync7(path, "utf-8");
|
|
60098
|
+
} catch {
|
|
60099
|
+
return "";
|
|
60100
|
+
}
|
|
60101
|
+
}
|
|
60102
|
+
return "";
|
|
60103
|
+
}
|
|
60104
|
+
var tasks, nextBashId, nextAgentId, TASKS_DIR;
|
|
60105
|
+
var init_background_tasks = __esm({
|
|
60106
|
+
"src/core/background-tasks.ts"() {
|
|
60107
|
+
"use strict";
|
|
60108
|
+
tasks = /* @__PURE__ */ new Map();
|
|
60109
|
+
nextBashId = 1;
|
|
60110
|
+
nextAgentId = 1;
|
|
60111
|
+
TASKS_DIR = join6(homedir2(), ".coders", "tasks");
|
|
60112
|
+
}
|
|
60113
|
+
});
|
|
60114
|
+
|
|
59896
60115
|
// src/ui/screen/terminal.ts
|
|
59897
60116
|
var terminal_exports = {};
|
|
59898
60117
|
__export(terminal_exports, {
|
|
@@ -60018,8 +60237,82 @@ var init_terminal = __esm({
|
|
|
60018
60237
|
}
|
|
60019
60238
|
});
|
|
60020
60239
|
|
|
60240
|
+
// src/ui/themes.ts
|
|
60241
|
+
var themes_exports = {};
|
|
60242
|
+
__export(themes_exports, {
|
|
60243
|
+
DARK_THEME: () => DARK_THEME,
|
|
60244
|
+
DEFAULT_THEME: () => DEFAULT_THEME,
|
|
60245
|
+
LIGHT_THEME: () => LIGHT_THEME,
|
|
60246
|
+
getAvailableThemes: () => getAvailableThemes,
|
|
60247
|
+
getTheme: () => getTheme
|
|
60248
|
+
});
|
|
60249
|
+
function getTheme(name) {
|
|
60250
|
+
return THEMES[name] ?? DEFAULT_THEME;
|
|
60251
|
+
}
|
|
60252
|
+
function getAvailableThemes() {
|
|
60253
|
+
return Object.keys(THEMES);
|
|
60254
|
+
}
|
|
60255
|
+
var DEFAULT_THEME, DARK_THEME, LIGHT_THEME, THEMES;
|
|
60256
|
+
var init_themes = __esm({
|
|
60257
|
+
"src/ui/themes.ts"() {
|
|
60258
|
+
"use strict";
|
|
60259
|
+
DEFAULT_THEME = {
|
|
60260
|
+
name: "default",
|
|
60261
|
+
colors: {
|
|
60262
|
+
primary: "cyan",
|
|
60263
|
+
secondary: "blue",
|
|
60264
|
+
success: "green",
|
|
60265
|
+
error: "red",
|
|
60266
|
+
warning: "yellow",
|
|
60267
|
+
info: "blue",
|
|
60268
|
+
muted: "gray",
|
|
60269
|
+
plan: "magenta",
|
|
60270
|
+
tool: "yellow",
|
|
60271
|
+
thinking: "gray"
|
|
60272
|
+
}
|
|
60273
|
+
};
|
|
60274
|
+
DARK_THEME = {
|
|
60275
|
+
name: "dark",
|
|
60276
|
+
colors: {
|
|
60277
|
+
primary: "#61afef",
|
|
60278
|
+
secondary: "#c678dd",
|
|
60279
|
+
success: "#98c379",
|
|
60280
|
+
error: "#e06c75",
|
|
60281
|
+
warning: "#e5c07b",
|
|
60282
|
+
info: "#56b6c2",
|
|
60283
|
+
muted: "#5c6370",
|
|
60284
|
+
plan: "#c678dd",
|
|
60285
|
+
tool: "#e5c07b",
|
|
60286
|
+
thinking: "#5c6370"
|
|
60287
|
+
}
|
|
60288
|
+
};
|
|
60289
|
+
LIGHT_THEME = {
|
|
60290
|
+
name: "light",
|
|
60291
|
+
colors: {
|
|
60292
|
+
primary: "#0184bc",
|
|
60293
|
+
secondary: "#a626a4",
|
|
60294
|
+
success: "#50a14f",
|
|
60295
|
+
error: "#e45649",
|
|
60296
|
+
warning: "#c18401",
|
|
60297
|
+
info: "#0184bc",
|
|
60298
|
+
muted: "#a0a1a7",
|
|
60299
|
+
plan: "#a626a4",
|
|
60300
|
+
tool: "#c18401",
|
|
60301
|
+
thinking: "#a0a1a7"
|
|
60302
|
+
}
|
|
60303
|
+
};
|
|
60304
|
+
THEMES = {
|
|
60305
|
+
default: DEFAULT_THEME,
|
|
60306
|
+
dark: DARK_THEME,
|
|
60307
|
+
light: LIGHT_THEME
|
|
60308
|
+
};
|
|
60309
|
+
}
|
|
60310
|
+
});
|
|
60311
|
+
|
|
60021
60312
|
// src/core/slash-commands.ts
|
|
60022
|
-
import { writeFileSync as
|
|
60313
|
+
import { writeFileSync as writeFileSync5, existsSync as existsSync9, readdirSync as readdirSync2 } from "fs";
|
|
60314
|
+
import { join as join7 } from "path";
|
|
60315
|
+
import { execSync as execSync3 } from "child_process";
|
|
60023
60316
|
function registerSlashCommand(cmd) {
|
|
60024
60317
|
commands.set(cmd.name, cmd);
|
|
60025
60318
|
if (cmd.aliases) {
|
|
@@ -60070,8 +60363,12 @@ ${lines.join("\n")}` };
|
|
|
60070
60363
|
registerSlashCommand({
|
|
60071
60364
|
name: "compact",
|
|
60072
60365
|
category: "core",
|
|
60073
|
-
description: "Compact conversation context",
|
|
60074
|
-
handler: () => ({
|
|
60366
|
+
description: "Compact conversation context [instructions]",
|
|
60367
|
+
handler: (args) => ({
|
|
60368
|
+
action: "compact",
|
|
60369
|
+
data: args.trim() || void 0,
|
|
60370
|
+
output: args.trim() ? `Context compacted with instructions: ${args.trim()}` : "Context compacted."
|
|
60371
|
+
})
|
|
60075
60372
|
});
|
|
60076
60373
|
registerSlashCommand({
|
|
60077
60374
|
name: "exit",
|
|
@@ -60091,15 +60388,15 @@ ${lines.join("\n")}` };
|
|
|
60091
60388
|
category: "mode",
|
|
60092
60389
|
description: "View or change the current model",
|
|
60093
60390
|
handler: (args) => {
|
|
60094
|
-
if (args) return { action: "
|
|
60391
|
+
if (args) return { action: "model", data: args.trim(), output: `Model set to: ${args.trim()}` };
|
|
60095
60392
|
return { output: "Current model \u2014 use /model <name> to change." };
|
|
60096
60393
|
}
|
|
60097
60394
|
});
|
|
60098
60395
|
registerSlashCommand({
|
|
60099
60396
|
name: "fast",
|
|
60100
60397
|
category: "mode",
|
|
60101
|
-
description: "Toggle fast mode",
|
|
60102
|
-
handler: () => ({ output: "Fast mode toggled." })
|
|
60398
|
+
description: "Toggle fast mode (switch between current model and haiku)",
|
|
60399
|
+
handler: () => ({ action: "fast", output: "Fast mode toggled." })
|
|
60103
60400
|
});
|
|
60104
60401
|
registerSlashCommand({
|
|
60105
60402
|
name: "verbose",
|
|
@@ -60135,14 +60432,44 @@ ${lines.join("\n")}` };
|
|
|
60135
60432
|
name: "tasks",
|
|
60136
60433
|
aliases: ["todo", "todos"],
|
|
60137
60434
|
category: "task",
|
|
60138
|
-
description: "
|
|
60139
|
-
handler: () =>
|
|
60435
|
+
description: "List all background tasks with their status",
|
|
60436
|
+
handler: () => {
|
|
60437
|
+
try {
|
|
60438
|
+
const { getAllTasks: getAllTasks2 } = (init_background_tasks(), __toCommonJS(background_tasks_exports));
|
|
60439
|
+
const tasks2 = getAllTasks2();
|
|
60440
|
+
if (tasks2.length === 0) return { output: "No background tasks." };
|
|
60441
|
+
const lines = tasks2.map((t) => {
|
|
60442
|
+
const elapsed = t.endTime ? `${((t.endTime - t.startTime) / 1e3).toFixed(1)}s` : `${((Date.now() - t.startTime) / 1e3).toFixed(1)}s`;
|
|
60443
|
+
const status = t.status === "running" ? "running" : t.status === "completed" ? "done" : t.status;
|
|
60444
|
+
return ` ${t.id.padEnd(12)} ${status.padEnd(10)} ${elapsed.padEnd(8)} ${t.description}`;
|
|
60445
|
+
});
|
|
60446
|
+
return { output: `Background tasks:
|
|
60447
|
+
${"ID".padEnd(12)} ${"Status".padEnd(10)} ${"Time".padEnd(8)} Description
|
|
60448
|
+
${lines.join("\n")}` };
|
|
60449
|
+
} catch {
|
|
60450
|
+
return { output: "No background tasks." };
|
|
60451
|
+
}
|
|
60452
|
+
}
|
|
60140
60453
|
});
|
|
60141
60454
|
registerSlashCommand({
|
|
60142
60455
|
name: "diff",
|
|
60143
60456
|
category: "git",
|
|
60144
|
-
description: "Show git
|
|
60145
|
-
handler: () =>
|
|
60457
|
+
description: "Show uncommitted git changes",
|
|
60458
|
+
handler: () => {
|
|
60459
|
+
try {
|
|
60460
|
+
const unstaged = execSync3("git diff", { encoding: "utf-8", timeout: 1e4 }).trim();
|
|
60461
|
+
const staged = execSync3("git diff --cached", { encoding: "utf-8", timeout: 1e4 }).trim();
|
|
60462
|
+
const parts = [];
|
|
60463
|
+
if (staged) parts.push(`\u2500\u2500 Staged changes \u2500\u2500
|
|
60464
|
+
${staged}`);
|
|
60465
|
+
if (unstaged) parts.push(`\u2500\u2500 Unstaged changes \u2500\u2500
|
|
60466
|
+
${unstaged}`);
|
|
60467
|
+
if (parts.length === 0) return { output: "No uncommitted changes." };
|
|
60468
|
+
return { output: parts.join("\n\n") };
|
|
60469
|
+
} catch (e) {
|
|
60470
|
+
return { output: `Failed to get diff: ${e instanceof Error ? e.message : String(e)}` };
|
|
60471
|
+
}
|
|
60472
|
+
}
|
|
60146
60473
|
});
|
|
60147
60474
|
registerSlashCommand({
|
|
60148
60475
|
name: "pr",
|
|
@@ -60207,7 +60534,7 @@ ${lines.join("\n")}` };
|
|
|
60207
60534
|
if (!isNaN(choice) && choice >= 1 && choice <= checkpoints.length) {
|
|
60208
60535
|
const cp = checkpoints[choice - 1];
|
|
60209
60536
|
try {
|
|
60210
|
-
|
|
60537
|
+
writeFileSync5(cp.file_path, cp.original_content, "utf-8");
|
|
60211
60538
|
const op = cp.edit_operation ? JSON.parse(cp.edit_operation) : null;
|
|
60212
60539
|
const summary = op?.old_string ? `Reverted edit: "${truncate(op.old_string, 40)}" -> "${truncate(op.new_string, 40)}"` : "Restored original content";
|
|
60213
60540
|
return { output: `Restored checkpoint #${choice}: ${cp.file_path}
|
|
@@ -60306,6 +60633,181 @@ Use /restore latest or /restore <number> or /restore <id-prefix>`
|
|
|
60306
60633
|
return { output: `No checkpoint found matching "${arg}". Use /restore to list available checkpoints.` };
|
|
60307
60634
|
}
|
|
60308
60635
|
});
|
|
60636
|
+
registerSlashCommand({
|
|
60637
|
+
name: "cost",
|
|
60638
|
+
category: "system",
|
|
60639
|
+
description: "Show session cost, token usage, and duration",
|
|
60640
|
+
handler: () => {
|
|
60641
|
+
const sessionId = getCurrentSessionId();
|
|
60642
|
+
if (!sessionId) return { output: "No active session." };
|
|
60643
|
+
try {
|
|
60644
|
+
const row = dbGet(
|
|
60645
|
+
`SELECT created_at,
|
|
60646
|
+
COALESCE(SUM(tokens_in), 0) AS total_in,
|
|
60647
|
+
COALESCE(SUM(tokens_out), 0) AS total_out,
|
|
60648
|
+
COALESCE(SUM(cost_usd), 0) AS total_cost
|
|
60649
|
+
FROM messages WHERE session_id = ?`,
|
|
60650
|
+
[sessionId]
|
|
60651
|
+
);
|
|
60652
|
+
const session = dbGet(`SELECT created_at FROM sessions WHERE id = ?`, [sessionId]);
|
|
60653
|
+
const startTime = session?.created_at ? new Date(session.created_at).getTime() : Date.now();
|
|
60654
|
+
const durationMs = Date.now() - startTime;
|
|
60655
|
+
const durationMin = Math.floor(durationMs / 6e4);
|
|
60656
|
+
const durationSec = Math.floor(durationMs % 6e4 / 1e3);
|
|
60657
|
+
const totalIn = row?.total_in ?? 0;
|
|
60658
|
+
const totalOut = row?.total_out ?? 0;
|
|
60659
|
+
const totalCost = row?.total_cost ?? 0;
|
|
60660
|
+
const lines = [
|
|
60661
|
+
`Session cost:`,
|
|
60662
|
+
` Duration: ${durationMin}m ${durationSec}s`,
|
|
60663
|
+
` Input tokens: ${totalIn.toLocaleString()}`,
|
|
60664
|
+
` Output tokens: ${totalOut.toLocaleString()}`,
|
|
60665
|
+
` Total tokens: ${(totalIn + totalOut).toLocaleString()}`,
|
|
60666
|
+
` Total cost: $${totalCost.toFixed(4)}`
|
|
60667
|
+
];
|
|
60668
|
+
return { output: lines.join("\n") };
|
|
60669
|
+
} catch (e) {
|
|
60670
|
+
return { output: `Failed to get cost info: ${e instanceof Error ? e.message : String(e)}` };
|
|
60671
|
+
}
|
|
60672
|
+
}
|
|
60673
|
+
});
|
|
60674
|
+
registerSlashCommand({
|
|
60675
|
+
name: "files",
|
|
60676
|
+
category: "system",
|
|
60677
|
+
description: "List files read/written in this session",
|
|
60678
|
+
handler: () => {
|
|
60679
|
+
const sessionId = getCurrentSessionId();
|
|
60680
|
+
if (!sessionId) return { output: "No active session." };
|
|
60681
|
+
try {
|
|
60682
|
+
const rows = dbAll(
|
|
60683
|
+
`SELECT DISTINCT file_path, edit_operation FROM checkpoints WHERE session_id = ? OR 1=1 ORDER BY created_at DESC LIMIT 50`
|
|
60684
|
+
);
|
|
60685
|
+
const msgRows = dbAll(
|
|
60686
|
+
`SELECT tool_uses FROM messages WHERE session_id = ? AND tool_uses IS NOT NULL`,
|
|
60687
|
+
[sessionId]
|
|
60688
|
+
);
|
|
60689
|
+
const filesRead = /* @__PURE__ */ new Set();
|
|
60690
|
+
const filesWritten = /* @__PURE__ */ new Set();
|
|
60691
|
+
for (const r of msgRows) {
|
|
60692
|
+
try {
|
|
60693
|
+
const uses = JSON.parse(r.tool_uses);
|
|
60694
|
+
if (Array.isArray(uses)) {
|
|
60695
|
+
for (const u of uses) {
|
|
60696
|
+
if (u.name === "Read" && u.input?.file_path) filesRead.add(u.input.file_path);
|
|
60697
|
+
if ((u.name === "Edit" || u.name === "Write") && u.input?.file_path) filesWritten.add(u.input.file_path);
|
|
60698
|
+
}
|
|
60699
|
+
}
|
|
60700
|
+
} catch {
|
|
60701
|
+
}
|
|
60702
|
+
}
|
|
60703
|
+
const parts = [];
|
|
60704
|
+
if (filesRead.size > 0) {
|
|
60705
|
+
parts.push(`Files read (${filesRead.size}):
|
|
60706
|
+
${Array.from(filesRead).map((f) => ` ${f}`).join("\n")}`);
|
|
60707
|
+
}
|
|
60708
|
+
if (filesWritten.size > 0) {
|
|
60709
|
+
parts.push(`Files written (${filesWritten.size}):
|
|
60710
|
+
${Array.from(filesWritten).map((f) => ` ${f}`).join("\n")}`);
|
|
60711
|
+
}
|
|
60712
|
+
if (parts.length === 0) return { output: "No files tracked in this session." };
|
|
60713
|
+
return { output: parts.join("\n\n") };
|
|
60714
|
+
} catch (e) {
|
|
60715
|
+
return { output: `Failed to list files: ${e instanceof Error ? e.message : String(e)}` };
|
|
60716
|
+
}
|
|
60717
|
+
}
|
|
60718
|
+
});
|
|
60719
|
+
registerSlashCommand({
|
|
60720
|
+
name: "export",
|
|
60721
|
+
category: "core",
|
|
60722
|
+
description: "Export conversation to a file [path]",
|
|
60723
|
+
handler: (args) => {
|
|
60724
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
60725
|
+
const path = args.trim() || join7(process.cwd(), `coders-export-${timestamp}.md`);
|
|
60726
|
+
return { action: "export", data: path, output: `Exporting conversation to: ${path}` };
|
|
60727
|
+
}
|
|
60728
|
+
});
|
|
60729
|
+
registerSlashCommand({
|
|
60730
|
+
name: "theme",
|
|
60731
|
+
category: "mode",
|
|
60732
|
+
description: "Change UI theme [name]",
|
|
60733
|
+
handler: (args) => {
|
|
60734
|
+
if (!args.trim()) {
|
|
60735
|
+
try {
|
|
60736
|
+
const { getAvailableThemes: getAvailableThemes2 } = (init_themes(), __toCommonJS(themes_exports));
|
|
60737
|
+
const themes = getAvailableThemes2();
|
|
60738
|
+
return { output: `Available themes: ${themes.join(", ")}
|
|
60739
|
+
Use /theme <name> to switch.` };
|
|
60740
|
+
} catch {
|
|
60741
|
+
return { output: "Available themes: default, dark, light\nUse /theme <name> to switch." };
|
|
60742
|
+
}
|
|
60743
|
+
}
|
|
60744
|
+
return { action: "theme", data: args.trim(), output: `Theme set to: ${args.trim()}` };
|
|
60745
|
+
}
|
|
60746
|
+
});
|
|
60747
|
+
registerSlashCommand({
|
|
60748
|
+
name: "effort",
|
|
60749
|
+
category: "mode",
|
|
60750
|
+
description: "Set effort level [low|medium|high]",
|
|
60751
|
+
handler: (args) => {
|
|
60752
|
+
const level = args.trim().toLowerCase();
|
|
60753
|
+
if (!level) return { output: "Usage: /effort <low|medium|high>" };
|
|
60754
|
+
if (!["low", "medium", "high"].includes(level)) {
|
|
60755
|
+
return { output: `Invalid effort level: "${level}". Must be one of: low, medium, high` };
|
|
60756
|
+
}
|
|
60757
|
+
return { action: "effort", data: level, output: `Effort level set to: ${level}` };
|
|
60758
|
+
}
|
|
60759
|
+
});
|
|
60760
|
+
registerSlashCommand({
|
|
60761
|
+
name: "skills",
|
|
60762
|
+
category: "system",
|
|
60763
|
+
description: "List available skills from .coders/skills/ and .claude/skills/",
|
|
60764
|
+
handler: () => {
|
|
60765
|
+
const skillDirs = [
|
|
60766
|
+
join7(process.cwd(), ".coders", "skills"),
|
|
60767
|
+
join7(process.cwd(), ".claude", "skills")
|
|
60768
|
+
];
|
|
60769
|
+
const skills = [];
|
|
60770
|
+
for (const dir of skillDirs) {
|
|
60771
|
+
if (!existsSync9(dir)) continue;
|
|
60772
|
+
try {
|
|
60773
|
+
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
60774
|
+
for (const entry of entries) {
|
|
60775
|
+
if (entry.isDirectory()) {
|
|
60776
|
+
const skillMd = join7(dir, entry.name, "SKILL.md");
|
|
60777
|
+
if (existsSync9(skillMd)) {
|
|
60778
|
+
skills.push(` ${entry.name} (${dir}/${entry.name}/SKILL.md)`);
|
|
60779
|
+
}
|
|
60780
|
+
}
|
|
60781
|
+
}
|
|
60782
|
+
} catch {
|
|
60783
|
+
}
|
|
60784
|
+
}
|
|
60785
|
+
if (skills.length === 0) return { output: "No skills found. Place SKILL.md files in .coders/skills/<name>/ or .claude/skills/<name>/." };
|
|
60786
|
+
return { output: `Available skills (${skills.length}):
|
|
60787
|
+
${skills.join("\n")}` };
|
|
60788
|
+
}
|
|
60789
|
+
});
|
|
60790
|
+
registerSlashCommand({
|
|
60791
|
+
name: "rename",
|
|
60792
|
+
category: "core",
|
|
60793
|
+
description: "Rename the current session [name]",
|
|
60794
|
+
handler: (args) => {
|
|
60795
|
+
if (!args.trim()) return { output: "Usage: /rename <name>" };
|
|
60796
|
+
return { action: "rename", data: args.trim(), output: `Session renamed to: ${args.trim()}` };
|
|
60797
|
+
}
|
|
60798
|
+
});
|
|
60799
|
+
registerSlashCommand({
|
|
60800
|
+
name: "resume",
|
|
60801
|
+
category: "navigation",
|
|
60802
|
+
description: "Resume the last session",
|
|
60803
|
+
handler: () => ({ action: "resume", output: "Resuming last session..." })
|
|
60804
|
+
});
|
|
60805
|
+
registerSlashCommand({
|
|
60806
|
+
name: "vim",
|
|
60807
|
+
category: "mode",
|
|
60808
|
+
description: "Toggle vim keybinding mode",
|
|
60809
|
+
handler: () => ({ action: "vim", output: "Vim mode toggled." })
|
|
60810
|
+
});
|
|
60309
60811
|
registerSlashCommand({
|
|
60310
60812
|
name: "undo",
|
|
60311
60813
|
category: "core",
|
|
@@ -60318,7 +60820,7 @@ Use /restore latest or /restore <number> or /restore <id-prefix>`
|
|
|
60318
60820
|
return { output: "No checkpoints found. Nothing to undo." };
|
|
60319
60821
|
}
|
|
60320
60822
|
try {
|
|
60321
|
-
|
|
60823
|
+
writeFileSync5(cp.file_path, cp.original_content, "utf-8");
|
|
60322
60824
|
const op = cp.edit_operation ? JSON.parse(cp.edit_operation) : null;
|
|
60323
60825
|
const summary = op?.old_string ? `Reverted: "${truncate(op.old_string, 50)}" -> "${truncate(op.new_string, 50)}"` : op?.type === "write_overwrite" ? "Restored file before overwrite" : "Restored original content";
|
|
60324
60826
|
return { output: `Undo successful: ${cp.file_path}
|
|
@@ -63023,8 +63525,8 @@ var init_permissions = __esm({
|
|
|
63023
63525
|
});
|
|
63024
63526
|
|
|
63025
63527
|
// src/memory/files.ts
|
|
63026
|
-
import { readFileSync as
|
|
63027
|
-
import { join as
|
|
63528
|
+
import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
|
|
63529
|
+
import { join as join8 } from "path";
|
|
63028
63530
|
function getInstructionsContent(projectDir) {
|
|
63029
63531
|
const cached2 = _cache.get(projectDir);
|
|
63030
63532
|
if (cached2 !== void 0) return cached2 || null;
|
|
@@ -63034,7 +63536,7 @@ function getInstructionsContent(projectDir) {
|
|
|
63034
63536
|
return null;
|
|
63035
63537
|
}
|
|
63036
63538
|
try {
|
|
63037
|
-
let content =
|
|
63539
|
+
let content = readFileSync8(filePath, "utf-8");
|
|
63038
63540
|
content = stripHtmlComments(content);
|
|
63039
63541
|
_cache.set(projectDir, content);
|
|
63040
63542
|
return content;
|
|
@@ -63045,11 +63547,11 @@ function getInstructionsContent(projectDir) {
|
|
|
63045
63547
|
}
|
|
63046
63548
|
function getGlobalInstructions() {
|
|
63047
63549
|
const configDir = getConfigDir();
|
|
63048
|
-
const primary =
|
|
63049
|
-
const path =
|
|
63550
|
+
const primary = join8(configDir, "CODERS.md");
|
|
63551
|
+
const path = existsSync10(primary) ? primary : null;
|
|
63050
63552
|
if (!path) return null;
|
|
63051
63553
|
try {
|
|
63052
|
-
return stripHtmlComments(
|
|
63554
|
+
return stripHtmlComments(readFileSync8(path, "utf-8"));
|
|
63053
63555
|
} catch {
|
|
63054
63556
|
return null;
|
|
63055
63557
|
}
|
|
@@ -63064,13 +63566,13 @@ ${global2}`);
|
|
|
63064
63566
|
if (project) parts.push(`# Project Instructions
|
|
63065
63567
|
|
|
63066
63568
|
${project}`);
|
|
63067
|
-
const rulesDir =
|
|
63068
|
-
if (
|
|
63569
|
+
const rulesDir = join8(projectDir, ".coders", "rules");
|
|
63570
|
+
if (existsSync10(rulesDir)) {
|
|
63069
63571
|
try {
|
|
63070
|
-
const { readdirSync:
|
|
63071
|
-
for (const file of
|
|
63572
|
+
const { readdirSync: readdirSync4 } = __require("fs");
|
|
63573
|
+
for (const file of readdirSync4(rulesDir)) {
|
|
63072
63574
|
if (!file.endsWith(".md")) continue;
|
|
63073
|
-
const content =
|
|
63575
|
+
const content = readFileSync8(join8(rulesDir, file), "utf-8");
|
|
63074
63576
|
parts.push(`# Rule: ${file}
|
|
63075
63577
|
|
|
63076
63578
|
${stripHtmlComments(content)}`);
|
|
@@ -63092,6 +63594,257 @@ var init_files = __esm({
|
|
|
63092
63594
|
}
|
|
63093
63595
|
});
|
|
63094
63596
|
|
|
63597
|
+
// src/core/constants.ts
|
|
63598
|
+
var BASH_TOOL, READ_TOOL, EDIT_TOOL, WRITE_TOOL, GLOB_TOOL, GREP_TOOL, AGENT_TOOL, WEB_FETCH_TOOL, WEB_SEARCH_TOOL, NOTEBOOK_EDIT_TOOL, LSP_TOOL, TASK_CREATE_TOOL, TASK_GET_TOOL, TASK_LIST_TOOL, TASK_UPDATE_TOOL, TASK_STOP_TOOL, TASK_OUTPUT_TOOL, ENTER_PLAN_MODE_TOOL, EXIT_PLAN_MODE_TOOL, ASK_USER_QUESTION_TOOL, CRON_CREATE_TOOL, CRON_DELETE_TOOL, CRON_LIST_TOOL, ENTER_WORKTREE_TOOL, EXIT_WORKTREE_TOOL, TOOL_SEARCH_TOOL, SEND_MESSAGE_TOOL, CONFIG_TOOL, LIST_MCP_RESOURCES_TOOL, READ_MCP_RESOURCE_TOOL, DEFAULT_BASH_TIMEOUT_MS, MAX_BASH_TIMEOUT_MS, DEFAULT_READ_LINE_LIMIT, DEFAULT_MAX_RESULT_SIZE_CHARS;
|
|
63599
|
+
var init_constants = __esm({
|
|
63600
|
+
"src/core/constants.ts"() {
|
|
63601
|
+
"use strict";
|
|
63602
|
+
BASH_TOOL = "Bash";
|
|
63603
|
+
READ_TOOL = "Read";
|
|
63604
|
+
EDIT_TOOL = "Edit";
|
|
63605
|
+
WRITE_TOOL = "Write";
|
|
63606
|
+
GLOB_TOOL = "Glob";
|
|
63607
|
+
GREP_TOOL = "Grep";
|
|
63608
|
+
AGENT_TOOL = "Agent";
|
|
63609
|
+
WEB_FETCH_TOOL = "WebFetch";
|
|
63610
|
+
WEB_SEARCH_TOOL = "WebSearch";
|
|
63611
|
+
NOTEBOOK_EDIT_TOOL = "NotebookEdit";
|
|
63612
|
+
LSP_TOOL = "LSP";
|
|
63613
|
+
TASK_CREATE_TOOL = "TaskCreate";
|
|
63614
|
+
TASK_GET_TOOL = "TaskGet";
|
|
63615
|
+
TASK_LIST_TOOL = "TaskList";
|
|
63616
|
+
TASK_UPDATE_TOOL = "TaskUpdate";
|
|
63617
|
+
TASK_STOP_TOOL = "TaskStop";
|
|
63618
|
+
TASK_OUTPUT_TOOL = "TaskOutput";
|
|
63619
|
+
ENTER_PLAN_MODE_TOOL = "EnterPlanMode";
|
|
63620
|
+
EXIT_PLAN_MODE_TOOL = "ExitPlanMode";
|
|
63621
|
+
ASK_USER_QUESTION_TOOL = "AskUserQuestion";
|
|
63622
|
+
CRON_CREATE_TOOL = "CronCreate";
|
|
63623
|
+
CRON_DELETE_TOOL = "CronDelete";
|
|
63624
|
+
CRON_LIST_TOOL = "CronList";
|
|
63625
|
+
ENTER_WORKTREE_TOOL = "EnterWorktree";
|
|
63626
|
+
EXIT_WORKTREE_TOOL = "ExitWorktree";
|
|
63627
|
+
TOOL_SEARCH_TOOL = "ToolSearch";
|
|
63628
|
+
SEND_MESSAGE_TOOL = "SendMessage";
|
|
63629
|
+
CONFIG_TOOL = "Config";
|
|
63630
|
+
LIST_MCP_RESOURCES_TOOL = "ListMcpResourcesTool";
|
|
63631
|
+
READ_MCP_RESOURCE_TOOL = "ReadMcpResourceTool";
|
|
63632
|
+
DEFAULT_BASH_TIMEOUT_MS = 12e4;
|
|
63633
|
+
MAX_BASH_TIMEOUT_MS = 6e5;
|
|
63634
|
+
DEFAULT_READ_LINE_LIMIT = 2e3;
|
|
63635
|
+
DEFAULT_MAX_RESULT_SIZE_CHARS = 1e5;
|
|
63636
|
+
}
|
|
63637
|
+
});
|
|
63638
|
+
|
|
63639
|
+
// src/tools/builtin/skill.ts
|
|
63640
|
+
import { readFileSync as readFileSync9, readdirSync as readdirSync3, existsSync as existsSync11, statSync } from "fs";
|
|
63641
|
+
import { join as join9 } from "path";
|
|
63642
|
+
import { homedir as homedir3 } from "os";
|
|
63643
|
+
function parseFrontmatter(content) {
|
|
63644
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
63645
|
+
if (!match) {
|
|
63646
|
+
return { frontmatter: {}, body: content };
|
|
63647
|
+
}
|
|
63648
|
+
const rawYaml = match[1];
|
|
63649
|
+
const body = match[2];
|
|
63650
|
+
const frontmatter = {};
|
|
63651
|
+
for (const line of rawYaml.split("\n")) {
|
|
63652
|
+
const trimmed = line.trim();
|
|
63653
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
63654
|
+
const colonIdx = trimmed.indexOf(":");
|
|
63655
|
+
if (colonIdx === -1) continue;
|
|
63656
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
63657
|
+
let value = trimmed.slice(colonIdx + 1).trim();
|
|
63658
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
63659
|
+
value = value.slice(1, -1);
|
|
63660
|
+
}
|
|
63661
|
+
frontmatter[key] = value;
|
|
63662
|
+
}
|
|
63663
|
+
return { frontmatter, body };
|
|
63664
|
+
}
|
|
63665
|
+
function parseSkillFile(filePath, dirName) {
|
|
63666
|
+
try {
|
|
63667
|
+
const content = readFileSync9(filePath, "utf-8");
|
|
63668
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
63669
|
+
return {
|
|
63670
|
+
name: frontmatter.name || dirName,
|
|
63671
|
+
description: frontmatter.description || "",
|
|
63672
|
+
body: body.trim()
|
|
63673
|
+
};
|
|
63674
|
+
} catch {
|
|
63675
|
+
return null;
|
|
63676
|
+
}
|
|
63677
|
+
}
|
|
63678
|
+
function scanSkillsDir(baseDir, source) {
|
|
63679
|
+
if (!existsSync11(baseDir)) return [];
|
|
63680
|
+
const skills = [];
|
|
63681
|
+
try {
|
|
63682
|
+
const entries = readdirSync3(baseDir);
|
|
63683
|
+
for (const entry of entries) {
|
|
63684
|
+
const entryPath = join9(baseDir, entry);
|
|
63685
|
+
try {
|
|
63686
|
+
if (!statSync(entryPath).isDirectory()) continue;
|
|
63687
|
+
} catch {
|
|
63688
|
+
continue;
|
|
63689
|
+
}
|
|
63690
|
+
const skillFile = join9(entryPath, "SKILL.md");
|
|
63691
|
+
if (!existsSync11(skillFile)) continue;
|
|
63692
|
+
const parsed = parseSkillFile(skillFile, entry);
|
|
63693
|
+
if (!parsed) continue;
|
|
63694
|
+
skills.push({
|
|
63695
|
+
name: parsed.name,
|
|
63696
|
+
description: parsed.description,
|
|
63697
|
+
path: skillFile,
|
|
63698
|
+
source
|
|
63699
|
+
});
|
|
63700
|
+
}
|
|
63701
|
+
} catch {
|
|
63702
|
+
}
|
|
63703
|
+
return skills;
|
|
63704
|
+
}
|
|
63705
|
+
function discoverSkills(cwd2) {
|
|
63706
|
+
const projectDir = cwd2 ?? process.cwd();
|
|
63707
|
+
const home = homedir3();
|
|
63708
|
+
const projectCoders = scanSkillsDir(join9(projectDir, ".coders", "skills"), "project");
|
|
63709
|
+
const projectClaude = scanSkillsDir(join9(projectDir, ".claude", "skills"), "project");
|
|
63710
|
+
const userCoders = scanSkillsDir(join9(home, ".coders", "skills"), "user");
|
|
63711
|
+
const userClaude = scanSkillsDir(join9(home, ".claude", "skills"), "user");
|
|
63712
|
+
const seen = /* @__PURE__ */ new Set();
|
|
63713
|
+
const all = [];
|
|
63714
|
+
for (const list2 of [projectCoders, projectClaude, userCoders, userClaude]) {
|
|
63715
|
+
for (const skill of list2) {
|
|
63716
|
+
const key = skill.name.toLowerCase();
|
|
63717
|
+
if (seen.has(key)) continue;
|
|
63718
|
+
seen.add(key);
|
|
63719
|
+
all.push(skill);
|
|
63720
|
+
}
|
|
63721
|
+
}
|
|
63722
|
+
return all;
|
|
63723
|
+
}
|
|
63724
|
+
var SKILL_TOOL, skillInputSchema, skillTool;
|
|
63725
|
+
var init_skill = __esm({
|
|
63726
|
+
"src/tools/builtin/skill.ts"() {
|
|
63727
|
+
"use strict";
|
|
63728
|
+
init_zod();
|
|
63729
|
+
init_constants();
|
|
63730
|
+
SKILL_TOOL = "Skill";
|
|
63731
|
+
skillInputSchema = external_exports.strictObject({
|
|
63732
|
+
skill: external_exports.string().describe("The skill name to invoke (e.g. 'commit', 'review-pr', 'test')"),
|
|
63733
|
+
args: external_exports.string().optional().describe("Optional arguments to pass to the skill prompt")
|
|
63734
|
+
});
|
|
63735
|
+
skillTool = {
|
|
63736
|
+
name: SKILL_TOOL,
|
|
63737
|
+
searchHint: "invoke user-defined skill from SKILL.md",
|
|
63738
|
+
maxResultSizeChars: DEFAULT_MAX_RESULT_SIZE_CHARS,
|
|
63739
|
+
shouldDefer: false,
|
|
63740
|
+
strict: false,
|
|
63741
|
+
async description() {
|
|
63742
|
+
return "Execute a skill within the main conversation. Skills are user-defined prompts in .coders/skills/ or .claude/skills/ directories.";
|
|
63743
|
+
},
|
|
63744
|
+
async prompt() {
|
|
63745
|
+
return `Invoke a user-defined skill from .coders/skills/ or .claude/skills/ directories.
|
|
63746
|
+
Skills are directories containing a SKILL.md file with YAML frontmatter (name, description) and a markdown prompt body.
|
|
63747
|
+
When invoked, the skill's prompt is returned with {{args}} replaced by the provided args.
|
|
63748
|
+
Use this tool when the user references a skill by name or uses a "/<skill-name>" slash command pattern.`;
|
|
63749
|
+
},
|
|
63750
|
+
get inputSchema() {
|
|
63751
|
+
return skillInputSchema;
|
|
63752
|
+
},
|
|
63753
|
+
get outputSchema() {
|
|
63754
|
+
return external_exports.any();
|
|
63755
|
+
},
|
|
63756
|
+
userFacingName() {
|
|
63757
|
+
return SKILL_TOOL;
|
|
63758
|
+
},
|
|
63759
|
+
isEnabled() {
|
|
63760
|
+
return true;
|
|
63761
|
+
},
|
|
63762
|
+
isConcurrencySafe() {
|
|
63763
|
+
return true;
|
|
63764
|
+
},
|
|
63765
|
+
isReadOnly() {
|
|
63766
|
+
return true;
|
|
63767
|
+
},
|
|
63768
|
+
toAutoClassifierInput(input) {
|
|
63769
|
+
return `skill:${input.skill}${input.args ? ` ${input.args}` : ""}`;
|
|
63770
|
+
},
|
|
63771
|
+
getActivityDescription(input) {
|
|
63772
|
+
return `Running skill: ${input.skill}`;
|
|
63773
|
+
},
|
|
63774
|
+
getToolUseSummary(input) {
|
|
63775
|
+
return input.skill;
|
|
63776
|
+
},
|
|
63777
|
+
async checkPermissions(input) {
|
|
63778
|
+
return { behavior: "allow", updatedInput: input };
|
|
63779
|
+
},
|
|
63780
|
+
async validateInput(input) {
|
|
63781
|
+
if (!input.skill || typeof input.skill !== "string") {
|
|
63782
|
+
return { result: false, message: "skill name is required" };
|
|
63783
|
+
}
|
|
63784
|
+
return { result: true };
|
|
63785
|
+
},
|
|
63786
|
+
async call(input) {
|
|
63787
|
+
const skillName = input.skill.trim().toLowerCase();
|
|
63788
|
+
const skills = discoverSkills();
|
|
63789
|
+
const match = skills.find((s) => s.name.toLowerCase() === skillName);
|
|
63790
|
+
if (!match) {
|
|
63791
|
+
const available = skills.map((s) => s.name).join(", ");
|
|
63792
|
+
const errorMsg = available ? `Skill "${input.skill}" not found. Available skills: ${available}` : `Skill "${input.skill}" not found. No skills are installed. Create a skill directory with a SKILL.md file in .coders/skills/ or .claude/skills/.`;
|
|
63793
|
+
return {
|
|
63794
|
+
data: {
|
|
63795
|
+
skill: input.skill,
|
|
63796
|
+
prompt: "",
|
|
63797
|
+
source: "project",
|
|
63798
|
+
error: errorMsg
|
|
63799
|
+
}
|
|
63800
|
+
};
|
|
63801
|
+
}
|
|
63802
|
+
const parsed = parseSkillFile(match.path, match.name);
|
|
63803
|
+
if (!parsed || !parsed.body) {
|
|
63804
|
+
return {
|
|
63805
|
+
data: {
|
|
63806
|
+
skill: input.skill,
|
|
63807
|
+
prompt: "",
|
|
63808
|
+
source: match.source,
|
|
63809
|
+
error: `Skill "${match.name}" has an empty or invalid SKILL.md file at ${match.path}`
|
|
63810
|
+
}
|
|
63811
|
+
};
|
|
63812
|
+
}
|
|
63813
|
+
let prompt = parsed.body;
|
|
63814
|
+
if (input.args) {
|
|
63815
|
+
prompt = prompt.replace(/\{\{args\}\}/g, input.args);
|
|
63816
|
+
} else {
|
|
63817
|
+
prompt = prompt.replace(/\{\{args\}\}/g, "");
|
|
63818
|
+
}
|
|
63819
|
+
return {
|
|
63820
|
+
data: {
|
|
63821
|
+
skill: match.name,
|
|
63822
|
+
prompt: prompt.trim(),
|
|
63823
|
+
source: match.source
|
|
63824
|
+
}
|
|
63825
|
+
};
|
|
63826
|
+
},
|
|
63827
|
+
mapToolResultToToolResultBlockParam(result, toolUseId) {
|
|
63828
|
+
if (result.error) {
|
|
63829
|
+
return {
|
|
63830
|
+
type: "tool_result",
|
|
63831
|
+
tool_use_id: toolUseId,
|
|
63832
|
+
content: result.error,
|
|
63833
|
+
is_error: true
|
|
63834
|
+
};
|
|
63835
|
+
}
|
|
63836
|
+
return {
|
|
63837
|
+
type: "tool_result",
|
|
63838
|
+
tool_use_id: toolUseId,
|
|
63839
|
+
content: `<command-name>${result.skill}</command-name>
|
|
63840
|
+
|
|
63841
|
+
${result.prompt}`
|
|
63842
|
+
};
|
|
63843
|
+
}
|
|
63844
|
+
};
|
|
63845
|
+
}
|
|
63846
|
+
});
|
|
63847
|
+
|
|
63095
63848
|
// src/core/system-prompt.ts
|
|
63096
63849
|
function buildSystemPrompt(ctx) {
|
|
63097
63850
|
const sections = [];
|
|
@@ -63120,6 +63873,28 @@ ${t.prompt}`).join("\n\n");
|
|
|
63120
63873
|
${toolSection}`);
|
|
63121
63874
|
}
|
|
63122
63875
|
}
|
|
63876
|
+
if (ctx.deferredTools && ctx.deferredTools.length > 0) {
|
|
63877
|
+
const deferredList = ctx.deferredTools.map((t) => `- **${t.name}**: ${t.description}`).join("\n");
|
|
63878
|
+
sections.push(`
|
|
63879
|
+
# Deferred Tools
|
|
63880
|
+
|
|
63881
|
+
The following tools are available but not loaded by default. Use the ToolSearch tool to fetch their full schemas before calling them. Once you call ToolSearch for a tool, you can use it normally.
|
|
63882
|
+
|
|
63883
|
+
${deferredList}`);
|
|
63884
|
+
}
|
|
63885
|
+
try {
|
|
63886
|
+
const skills = discoverSkills(ctx.projectDir);
|
|
63887
|
+
if (skills.length > 0) {
|
|
63888
|
+
const skillList = skills.map((s) => `- **${s.name}**${s.description ? `: ${s.description}` : ""} _(${s.source})_`).join("\n");
|
|
63889
|
+
sections.push(`
|
|
63890
|
+
# Available Skills
|
|
63891
|
+
|
|
63892
|
+
The following skills are available via the Skill tool. When a user references a skill by name or uses "/<skill-name>", invoke it with the Skill tool.
|
|
63893
|
+
|
|
63894
|
+
${skillList}`);
|
|
63895
|
+
}
|
|
63896
|
+
} catch {
|
|
63897
|
+
}
|
|
63123
63898
|
const ctxParts = [];
|
|
63124
63899
|
ctxParts.push(`Working directory: ${ctx.projectDir}`);
|
|
63125
63900
|
ctxParts.push(`Model: ${ctx.model}`);
|
|
@@ -63147,6 +63922,7 @@ var init_system_prompt = __esm({
|
|
|
63147
63922
|
"src/core/system-prompt.ts"() {
|
|
63148
63923
|
"use strict";
|
|
63149
63924
|
init_files();
|
|
63925
|
+
init_skill();
|
|
63150
63926
|
CORE_INSTRUCTIONS = `You are Coders, an open-source interactive CLI agent built by Hasna for software engineering.
|
|
63151
63927
|
You are an interactive agent that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
|
63152
63928
|
|
|
@@ -63190,44 +63966,6 @@ You are an interactive agent that helps users with software engineering tasks. U
|
|
|
63190
63966
|
}
|
|
63191
63967
|
});
|
|
63192
63968
|
|
|
63193
|
-
// src/core/constants.ts
|
|
63194
|
-
var BASH_TOOL, READ_TOOL, EDIT_TOOL, WRITE_TOOL, GLOB_TOOL, GREP_TOOL, AGENT_TOOL, WEB_FETCH_TOOL, WEB_SEARCH_TOOL, NOTEBOOK_EDIT_TOOL, LSP_TOOL, TASK_CREATE_TOOL, TASK_GET_TOOL, TASK_LIST_TOOL, TASK_UPDATE_TOOL, ENTER_PLAN_MODE_TOOL, EXIT_PLAN_MODE_TOOL, ASK_USER_QUESTION_TOOL, CRON_CREATE_TOOL, CRON_DELETE_TOOL, CRON_LIST_TOOL, ENTER_WORKTREE_TOOL, EXIT_WORKTREE_TOOL, TOOL_SEARCH_TOOL, SEND_MESSAGE_TOOL, CONFIG_TOOL, DEFAULT_BASH_TIMEOUT_MS, MAX_BASH_TIMEOUT_MS, DEFAULT_READ_LINE_LIMIT, DEFAULT_MAX_RESULT_SIZE_CHARS;
|
|
63195
|
-
var init_constants = __esm({
|
|
63196
|
-
"src/core/constants.ts"() {
|
|
63197
|
-
"use strict";
|
|
63198
|
-
BASH_TOOL = "Bash";
|
|
63199
|
-
READ_TOOL = "Read";
|
|
63200
|
-
EDIT_TOOL = "Edit";
|
|
63201
|
-
WRITE_TOOL = "Write";
|
|
63202
|
-
GLOB_TOOL = "Glob";
|
|
63203
|
-
GREP_TOOL = "Grep";
|
|
63204
|
-
AGENT_TOOL = "Agent";
|
|
63205
|
-
WEB_FETCH_TOOL = "WebFetch";
|
|
63206
|
-
WEB_SEARCH_TOOL = "WebSearch";
|
|
63207
|
-
NOTEBOOK_EDIT_TOOL = "NotebookEdit";
|
|
63208
|
-
LSP_TOOL = "LSP";
|
|
63209
|
-
TASK_CREATE_TOOL = "TaskCreate";
|
|
63210
|
-
TASK_GET_TOOL = "TaskGet";
|
|
63211
|
-
TASK_LIST_TOOL = "TaskList";
|
|
63212
|
-
TASK_UPDATE_TOOL = "TaskUpdate";
|
|
63213
|
-
ENTER_PLAN_MODE_TOOL = "EnterPlanMode";
|
|
63214
|
-
EXIT_PLAN_MODE_TOOL = "ExitPlanMode";
|
|
63215
|
-
ASK_USER_QUESTION_TOOL = "AskUserQuestion";
|
|
63216
|
-
CRON_CREATE_TOOL = "CronCreate";
|
|
63217
|
-
CRON_DELETE_TOOL = "CronDelete";
|
|
63218
|
-
CRON_LIST_TOOL = "CronList";
|
|
63219
|
-
ENTER_WORKTREE_TOOL = "EnterWorktree";
|
|
63220
|
-
EXIT_WORKTREE_TOOL = "ExitWorktree";
|
|
63221
|
-
TOOL_SEARCH_TOOL = "ToolSearch";
|
|
63222
|
-
SEND_MESSAGE_TOOL = "SendMessage";
|
|
63223
|
-
CONFIG_TOOL = "Config";
|
|
63224
|
-
DEFAULT_BASH_TIMEOUT_MS = 12e4;
|
|
63225
|
-
MAX_BASH_TIMEOUT_MS = 6e5;
|
|
63226
|
-
DEFAULT_READ_LINE_LIMIT = 2e3;
|
|
63227
|
-
DEFAULT_MAX_RESULT_SIZE_CHARS = 1e5;
|
|
63228
|
-
}
|
|
63229
|
-
});
|
|
63230
|
-
|
|
63231
63969
|
// src/tools/builtin/bash.ts
|
|
63232
63970
|
import { spawn } from "child_process";
|
|
63233
63971
|
function isDangerousCommand(command) {
|
|
@@ -63342,13 +64080,14 @@ function truncateOutput(output, maxChars = DEFAULT_MAX_RESULT_SIZE_CHARS) {
|
|
|
63342
64080
|
|
|
63343
64081
|
` + output.slice(-half);
|
|
63344
64082
|
}
|
|
63345
|
-
var DANGEROUS_PATTERNS, BashInputSchema, BashOutputSchema, READ_ONLY_COMMANDS, READ_ONLY_KEYWORDS, GIT_READ_ONLY_SUBCOMMANDS, NPM_READ_ONLY_SUBCOMMANDS, DOCKER_READ_ONLY_SUBCOMMANDS, backgroundTasks,
|
|
64083
|
+
var DANGEROUS_PATTERNS, BashInputSchema, BashOutputSchema, READ_ONLY_COMMANDS, READ_ONLY_KEYWORDS, GIT_READ_ONLY_SUBCOMMANDS, NPM_READ_ONLY_SUBCOMMANDS, DOCKER_READ_ONLY_SUBCOMMANDS, backgroundTasks, bashTool, BASH_PROMPT;
|
|
63346
64084
|
var init_bash = __esm({
|
|
63347
64085
|
"src/tools/builtin/bash.ts"() {
|
|
63348
64086
|
"use strict";
|
|
63349
64087
|
init_zod();
|
|
63350
64088
|
init_constants();
|
|
63351
64089
|
init_db();
|
|
64090
|
+
init_background_tasks();
|
|
63352
64091
|
DANGEROUS_PATTERNS = [
|
|
63353
64092
|
{ pattern: /\brm\s+-rf\s+\/\s*$/, reason: "Recursive delete of root filesystem" },
|
|
63354
64093
|
{ pattern: /\brm\s+-rf\s+~\//, reason: "Recursive delete of home directory" },
|
|
@@ -63541,7 +64280,6 @@ var init_bash = __esm({
|
|
|
63541
64280
|
"version"
|
|
63542
64281
|
]);
|
|
63543
64282
|
backgroundTasks = /* @__PURE__ */ new Map();
|
|
63544
|
-
nextBgId = 1;
|
|
63545
64283
|
bashTool = {
|
|
63546
64284
|
name: BASH_TOOL,
|
|
63547
64285
|
searchHint: "execute shell commands in the terminal",
|
|
@@ -63612,7 +64350,8 @@ var init_bash = __esm({
|
|
|
63612
64350
|
const timeoutMs = timeout ?? getDefaultTimeout();
|
|
63613
64351
|
const startTime = performance.now();
|
|
63614
64352
|
if (run_in_background) {
|
|
63615
|
-
const
|
|
64353
|
+
const bgTask = createTask("bash", command);
|
|
64354
|
+
const taskId = bgTask.id;
|
|
63616
64355
|
const child = spawn(command, [], {
|
|
63617
64356
|
shell: getShell(),
|
|
63618
64357
|
cwd: process.cwd(),
|
|
@@ -63621,10 +64360,14 @@ var init_bash = __esm({
|
|
|
63621
64360
|
});
|
|
63622
64361
|
let output = "";
|
|
63623
64362
|
child.stdout?.on("data", (data) => {
|
|
63624
|
-
|
|
64363
|
+
const chunk = data.toString();
|
|
64364
|
+
output += chunk;
|
|
64365
|
+
writeTaskOutput(taskId, chunk);
|
|
63625
64366
|
});
|
|
63626
64367
|
child.stderr?.on("data", (data) => {
|
|
63627
|
-
|
|
64368
|
+
const chunk = data.toString();
|
|
64369
|
+
output += chunk;
|
|
64370
|
+
writeTaskOutput(taskId, chunk);
|
|
63628
64371
|
});
|
|
63629
64372
|
const task = { process: child, output: "", done: false, exitCode: null };
|
|
63630
64373
|
backgroundTasks.set(taskId, task);
|
|
@@ -63632,10 +64375,16 @@ var init_bash = __esm({
|
|
|
63632
64375
|
task.output = output;
|
|
63633
64376
|
task.done = true;
|
|
63634
64377
|
task.exitCode = code;
|
|
64378
|
+
completeTask(taskId, output, code ?? void 0);
|
|
64379
|
+
});
|
|
64380
|
+
child.on("error", (err) => {
|
|
64381
|
+
task.done = true;
|
|
64382
|
+
task.exitCode = 1;
|
|
64383
|
+
failTask(taskId, err.message);
|
|
63635
64384
|
});
|
|
63636
64385
|
return {
|
|
63637
64386
|
data: {
|
|
63638
|
-
stdout: `Background task started with ID: ${taskId}
|
|
64387
|
+
stdout: `Background task started with ID: ${taskId}. Use TaskOutput to check its status.`,
|
|
63639
64388
|
stderr: "",
|
|
63640
64389
|
exitCode: null,
|
|
63641
64390
|
interrupted: false,
|
|
@@ -63748,7 +64497,7 @@ Instructions:
|
|
|
63748
64497
|
});
|
|
63749
64498
|
|
|
63750
64499
|
// src/tools/builtin/read.ts
|
|
63751
|
-
import { readFileSync as
|
|
64500
|
+
import { readFileSync as readFileSync10, statSync as statSync2, existsSync as existsSync12 } from "fs";
|
|
63752
64501
|
import { extname, isAbsolute, resolve as resolve2 } from "path";
|
|
63753
64502
|
function hasFileBeenRead(filePath) {
|
|
63754
64503
|
return readFiles.has(resolve2(filePath));
|
|
@@ -63757,7 +64506,7 @@ function markFileAsRead(filePath) {
|
|
|
63757
64506
|
readFiles.add(resolve2(filePath));
|
|
63758
64507
|
}
|
|
63759
64508
|
function readTextFile(filePath, input) {
|
|
63760
|
-
const rawContent =
|
|
64509
|
+
const rawContent = readFileSync10(filePath, "utf-8");
|
|
63761
64510
|
const allLines = rawContent.split("\n");
|
|
63762
64511
|
const totalLines = allLines.length;
|
|
63763
64512
|
const startLine = input.offset ?? 1;
|
|
@@ -63780,7 +64529,7 @@ function readTextFile(filePath, input) {
|
|
|
63780
64529
|
};
|
|
63781
64530
|
}
|
|
63782
64531
|
function readImageFile(filePath, input) {
|
|
63783
|
-
const stat =
|
|
64532
|
+
const stat = statSync2(filePath);
|
|
63784
64533
|
const ext = extname(filePath).toLowerCase();
|
|
63785
64534
|
const content = `[Image file: ${filePath} (${ext}, ${formatBytes(stat.size)})]`;
|
|
63786
64535
|
return {
|
|
@@ -63794,7 +64543,7 @@ function readImageFile(filePath, input) {
|
|
|
63794
64543
|
};
|
|
63795
64544
|
}
|
|
63796
64545
|
function readPdfFile(filePath, input) {
|
|
63797
|
-
const stat =
|
|
64546
|
+
const stat = statSync2(filePath);
|
|
63798
64547
|
const pages = input.pages ?? "1-5";
|
|
63799
64548
|
const content = `[PDF file: ${filePath} (${formatBytes(stat.size)}, requested pages: ${pages}). PDF reading requires pdf-parse library \u2014 install to enable.]`;
|
|
63800
64549
|
return {
|
|
@@ -63809,7 +64558,7 @@ function readPdfFile(filePath, input) {
|
|
|
63809
64558
|
}
|
|
63810
64559
|
function readNotebookFile(filePath, input) {
|
|
63811
64560
|
try {
|
|
63812
|
-
const rawContent =
|
|
64561
|
+
const rawContent = readFileSync10(filePath, "utf-8");
|
|
63813
64562
|
const notebook = JSON.parse(rawContent);
|
|
63814
64563
|
if (!notebook.cells || !Array.isArray(notebook.cells)) {
|
|
63815
64564
|
return {
|
|
@@ -63929,11 +64678,11 @@ var init_read = __esm({
|
|
|
63929
64678
|
return { result: false, message: "file_path is required", errorCode: 1 };
|
|
63930
64679
|
}
|
|
63931
64680
|
const resolved = resolvePath(input.file_path);
|
|
63932
|
-
if (!
|
|
64681
|
+
if (!existsSync12(resolved)) {
|
|
63933
64682
|
return { result: false, message: `File does not exist: ${input.file_path}`, errorCode: 2 };
|
|
63934
64683
|
}
|
|
63935
64684
|
try {
|
|
63936
|
-
const stat =
|
|
64685
|
+
const stat = statSync2(resolved);
|
|
63937
64686
|
if (stat.isDirectory()) {
|
|
63938
64687
|
return { result: false, message: `Path is a directory, not a file: ${input.file_path}. Use Bash with ls to list directory contents.`, errorCode: 3 };
|
|
63939
64688
|
}
|
|
@@ -63986,7 +64735,7 @@ Usage:
|
|
|
63986
64735
|
});
|
|
63987
64736
|
|
|
63988
64737
|
// src/tools/builtin/edit.ts
|
|
63989
|
-
import { readFileSync as
|
|
64738
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, existsSync as existsSync13, statSync as statSync3 } from "fs";
|
|
63990
64739
|
import { resolve as resolve3, isAbsolute as isAbsolute2 } from "path";
|
|
63991
64740
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
63992
64741
|
function resolvePath2(filePath) {
|
|
@@ -64126,7 +64875,7 @@ var init_edit = __esm({
|
|
|
64126
64875
|
return { result: false, message: "old_string and new_string must be different", errorCode: 2 };
|
|
64127
64876
|
}
|
|
64128
64877
|
const resolved = resolvePath2(input.file_path);
|
|
64129
|
-
if (!
|
|
64878
|
+
if (!existsSync13(resolved)) {
|
|
64130
64879
|
return { result: false, message: `File does not exist: ${input.file_path}`, errorCode: 3 };
|
|
64131
64880
|
}
|
|
64132
64881
|
if (!hasFileBeenRead(resolved)) {
|
|
@@ -64136,7 +64885,7 @@ var init_edit = __esm({
|
|
|
64136
64885
|
errorCode: 4
|
|
64137
64886
|
};
|
|
64138
64887
|
}
|
|
64139
|
-
const content =
|
|
64888
|
+
const content = readFileSync11(resolved, "utf-8");
|
|
64140
64889
|
const count = countOccurrences(content, input.old_string);
|
|
64141
64890
|
if (count === 0) {
|
|
64142
64891
|
return {
|
|
@@ -64167,7 +64916,7 @@ var init_edit = __esm({
|
|
|
64167
64916
|
const resolved = resolvePath2(input.file_path);
|
|
64168
64917
|
const MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
64169
64918
|
try {
|
|
64170
|
-
const fileSize =
|
|
64919
|
+
const fileSize = statSync3(resolved).size;
|
|
64171
64920
|
if (fileSize > MAX_FILE_SIZE) {
|
|
64172
64921
|
return {
|
|
64173
64922
|
data: {
|
|
@@ -64182,7 +64931,7 @@ var init_edit = __esm({
|
|
|
64182
64931
|
}
|
|
64183
64932
|
} catch {
|
|
64184
64933
|
}
|
|
64185
|
-
const originalContent =
|
|
64934
|
+
const originalContent = readFileSync11(resolved, "utf-8");
|
|
64186
64935
|
let newContent;
|
|
64187
64936
|
let replacements;
|
|
64188
64937
|
if (input.replace_all) {
|
|
@@ -64213,7 +64962,7 @@ var init_edit = __esm({
|
|
|
64213
64962
|
);
|
|
64214
64963
|
} catch {
|
|
64215
64964
|
}
|
|
64216
|
-
|
|
64965
|
+
writeFileSync6(resolved, newContent, "utf-8");
|
|
64217
64966
|
markFileAsRead(resolved);
|
|
64218
64967
|
const gitDiff = generateUnifiedDiff(originalContent, newContent, input.file_path);
|
|
64219
64968
|
return {
|
|
@@ -64251,7 +65000,7 @@ Usage:
|
|
|
64251
65000
|
});
|
|
64252
65001
|
|
|
64253
65002
|
// src/tools/builtin/write.ts
|
|
64254
|
-
import { writeFileSync as
|
|
65003
|
+
import { writeFileSync as writeFileSync7, readFileSync as readFileSync12, existsSync as existsSync14, mkdirSync as mkdirSync6 } from "fs";
|
|
64255
65004
|
import { dirname as dirname3, resolve as resolve4, isAbsolute as isAbsolute3 } from "path";
|
|
64256
65005
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
64257
65006
|
function resolvePath3(filePath) {
|
|
@@ -64324,14 +65073,14 @@ var init_write = __esm({
|
|
|
64324
65073
|
return { data: { filePath: "", bytesWritten: 0, created: false } };
|
|
64325
65074
|
}
|
|
64326
65075
|
const resolved = resolvePath3(input.file_path);
|
|
64327
|
-
const created = !
|
|
65076
|
+
const created = !existsSync14(resolved);
|
|
64328
65077
|
const dir = dirname3(resolved);
|
|
64329
|
-
if (!
|
|
64330
|
-
|
|
65078
|
+
if (!existsSync14(dir)) {
|
|
65079
|
+
mkdirSync6(dir, { recursive: true });
|
|
64331
65080
|
}
|
|
64332
65081
|
if (!created) {
|
|
64333
65082
|
try {
|
|
64334
|
-
const originalContent =
|
|
65083
|
+
const originalContent = readFileSync12(resolved, "utf-8");
|
|
64335
65084
|
const cpId = randomUUID3().slice(0, 8);
|
|
64336
65085
|
dbRun(
|
|
64337
65086
|
"INSERT INTO checkpoints (id, session_id, file_path, original_content, edit_operation) VALUES (?, ?, ?, ?, ?)",
|
|
@@ -64340,7 +65089,7 @@ var init_write = __esm({
|
|
|
64340
65089
|
} catch {
|
|
64341
65090
|
}
|
|
64342
65091
|
}
|
|
64343
|
-
|
|
65092
|
+
writeFileSync7(resolved, input.content, "utf-8");
|
|
64344
65093
|
markFileAsRead(resolved);
|
|
64345
65094
|
return {
|
|
64346
65095
|
data: {
|
|
@@ -67805,18 +68554,18 @@ var require_tasks = __commonJS({
|
|
|
67805
68554
|
return patterns.map((pattern) => utils.pattern.removeDuplicateSlashes(pattern));
|
|
67806
68555
|
}
|
|
67807
68556
|
function convertPatternsToTasks(positive, negative, dynamic) {
|
|
67808
|
-
const
|
|
68557
|
+
const tasks2 = [];
|
|
67809
68558
|
const patternsOutsideCurrentDirectory = utils.pattern.getPatternsOutsideCurrentDirectory(positive);
|
|
67810
68559
|
const patternsInsideCurrentDirectory = utils.pattern.getPatternsInsideCurrentDirectory(positive);
|
|
67811
68560
|
const outsideCurrentDirectoryGroup = groupPatternsByBaseDirectory(patternsOutsideCurrentDirectory);
|
|
67812
68561
|
const insideCurrentDirectoryGroup = groupPatternsByBaseDirectory(patternsInsideCurrentDirectory);
|
|
67813
|
-
|
|
68562
|
+
tasks2.push(...convertPatternGroupsToTasks(outsideCurrentDirectoryGroup, negative, dynamic));
|
|
67814
68563
|
if ("." in insideCurrentDirectoryGroup) {
|
|
67815
|
-
|
|
68564
|
+
tasks2.push(convertPatternGroupToTask(".", patternsInsideCurrentDirectory, negative, dynamic));
|
|
67816
68565
|
} else {
|
|
67817
|
-
|
|
68566
|
+
tasks2.push(...convertPatternGroupsToTasks(insideCurrentDirectoryGroup, negative, dynamic));
|
|
67818
68567
|
}
|
|
67819
|
-
return
|
|
68568
|
+
return tasks2;
|
|
67820
68569
|
}
|
|
67821
68570
|
exports.convertPatternsToTasks = convertPatternsToTasks;
|
|
67822
68571
|
function getPositivePatterns(patterns) {
|
|
@@ -67994,11 +68743,11 @@ var require_out = __commonJS({
|
|
|
67994
68743
|
async.read(path, getSettings2(optionsOrSettingsOrCallback), callback);
|
|
67995
68744
|
}
|
|
67996
68745
|
exports.stat = stat;
|
|
67997
|
-
function
|
|
68746
|
+
function statSync5(path, optionsOrSettings) {
|
|
67998
68747
|
const settings = getSettings2(optionsOrSettings);
|
|
67999
68748
|
return sync.read(path, settings);
|
|
68000
68749
|
}
|
|
68001
|
-
exports.statSync =
|
|
68750
|
+
exports.statSync = statSync5;
|
|
68002
68751
|
function getSettings2(settingsOrOptions = {}) {
|
|
68003
68752
|
if (settingsOrOptions instanceof settings_1.default) {
|
|
68004
68753
|
return settingsOrOptions;
|
|
@@ -68023,14 +68772,14 @@ var require_run_parallel = __commonJS({
|
|
|
68023
68772
|
"node_modules/run-parallel/index.js"(exports, module) {
|
|
68024
68773
|
module.exports = runParallel;
|
|
68025
68774
|
var queueMicrotask2 = require_queue_microtask();
|
|
68026
|
-
function runParallel(
|
|
68775
|
+
function runParallel(tasks2, cb) {
|
|
68027
68776
|
let results, pending, keys;
|
|
68028
68777
|
let isSync = true;
|
|
68029
|
-
if (Array.isArray(
|
|
68778
|
+
if (Array.isArray(tasks2)) {
|
|
68030
68779
|
results = [];
|
|
68031
|
-
pending =
|
|
68780
|
+
pending = tasks2.length;
|
|
68032
68781
|
} else {
|
|
68033
|
-
keys = Object.keys(
|
|
68782
|
+
keys = Object.keys(tasks2);
|
|
68034
68783
|
results = {};
|
|
68035
68784
|
pending = keys.length;
|
|
68036
68785
|
}
|
|
@@ -68052,12 +68801,12 @@ var require_run_parallel = __commonJS({
|
|
|
68052
68801
|
done(null);
|
|
68053
68802
|
} else if (keys) {
|
|
68054
68803
|
keys.forEach(function(key) {
|
|
68055
|
-
|
|
68804
|
+
tasks2[key](function(err, result) {
|
|
68056
68805
|
each(key, err, result);
|
|
68057
68806
|
});
|
|
68058
68807
|
});
|
|
68059
68808
|
} else {
|
|
68060
|
-
|
|
68809
|
+
tasks2.forEach(function(task, i) {
|
|
68061
68810
|
task(function(err, result) {
|
|
68062
68811
|
each(i, err, result);
|
|
68063
68812
|
});
|
|
@@ -68174,8 +68923,8 @@ var require_async2 = __commonJS({
|
|
|
68174
68923
|
callSuccessCallback(callback, entries);
|
|
68175
68924
|
return;
|
|
68176
68925
|
}
|
|
68177
|
-
const
|
|
68178
|
-
rpl(
|
|
68926
|
+
const tasks2 = entries.map((entry) => makeRplTaskEntry(entry, settings));
|
|
68927
|
+
rpl(tasks2, (rplError, rplEntries) => {
|
|
68179
68928
|
if (rplError !== null) {
|
|
68180
68929
|
callFailureCallback(callback, rplError);
|
|
68181
68930
|
return;
|
|
@@ -68211,7 +68960,7 @@ var require_async2 = __commonJS({
|
|
|
68211
68960
|
callFailureCallback(callback, readdirError);
|
|
68212
68961
|
return;
|
|
68213
68962
|
}
|
|
68214
|
-
const
|
|
68963
|
+
const tasks2 = names.map((name) => {
|
|
68215
68964
|
const path = common.joinPathSegments(directory, name, settings.pathSegmentSeparator);
|
|
68216
68965
|
return (done) => {
|
|
68217
68966
|
fsStat.stat(path, settings.fsStatSettings, (error2, stats) => {
|
|
@@ -68231,7 +68980,7 @@ var require_async2 = __commonJS({
|
|
|
68231
68980
|
});
|
|
68232
68981
|
};
|
|
68233
68982
|
});
|
|
68234
|
-
rpl(
|
|
68983
|
+
rpl(tasks2, (rplError, entries) => {
|
|
68235
68984
|
if (rplError !== null) {
|
|
68236
68985
|
callFailureCallback(callback, rplError);
|
|
68237
68986
|
return;
|
|
@@ -68496,12 +69245,12 @@ var require_queue = __commonJS({
|
|
|
68496
69245
|
}
|
|
68497
69246
|
function getQueue() {
|
|
68498
69247
|
var current = queueHead;
|
|
68499
|
-
var
|
|
69248
|
+
var tasks2 = [];
|
|
68500
69249
|
while (current) {
|
|
68501
|
-
|
|
69250
|
+
tasks2.push(current.value);
|
|
68502
69251
|
current = current.next;
|
|
68503
69252
|
}
|
|
68504
|
-
return
|
|
69253
|
+
return tasks2;
|
|
68505
69254
|
}
|
|
68506
69255
|
function resume() {
|
|
68507
69256
|
if (!self2.paused) return;
|
|
@@ -69867,9 +70616,9 @@ var require_out4 = __commonJS({
|
|
|
69867
70616
|
function getWorks(source, _Provider, options2) {
|
|
69868
70617
|
const patterns = [].concat(source);
|
|
69869
70618
|
const settings = new settings_1.default(options2);
|
|
69870
|
-
const
|
|
70619
|
+
const tasks2 = taskManager.generate(patterns, settings);
|
|
69871
70620
|
const provider = new _Provider(settings);
|
|
69872
|
-
return
|
|
70621
|
+
return tasks2.map(provider.read, provider);
|
|
69873
70622
|
}
|
|
69874
70623
|
function assertPatternsInput(input) {
|
|
69875
70624
|
const source = [].concat(input);
|
|
@@ -69883,7 +70632,7 @@ var require_out4 = __commonJS({
|
|
|
69883
70632
|
});
|
|
69884
70633
|
|
|
69885
70634
|
// src/tools/builtin/glob.ts
|
|
69886
|
-
import { statSync as
|
|
70635
|
+
import { statSync as statSync4, existsSync as existsSync15 } from "fs";
|
|
69887
70636
|
import { resolve as resolve5, isAbsolute as isAbsolute4 } from "path";
|
|
69888
70637
|
function resolvePath4(p) {
|
|
69889
70638
|
if (isAbsolute4(p)) return p;
|
|
@@ -69949,7 +70698,7 @@ var init_glob = __esm({
|
|
|
69949
70698
|
},
|
|
69950
70699
|
async call(input, context) {
|
|
69951
70700
|
const cwd2 = input.path ? resolvePath4(input.path) : process.cwd();
|
|
69952
|
-
if (input.path && !
|
|
70701
|
+
if (input.path && !existsSync15(cwd2)) {
|
|
69953
70702
|
return {
|
|
69954
70703
|
data: {
|
|
69955
70704
|
files: [],
|
|
@@ -69980,7 +70729,7 @@ var init_glob = __esm({
|
|
|
69980
70729
|
});
|
|
69981
70730
|
const withStats = allFiles.map((f) => {
|
|
69982
70731
|
try {
|
|
69983
|
-
const stat =
|
|
70732
|
+
const stat = statSync4(f);
|
|
69984
70733
|
return { path: f, mtime: stat.mtimeMs };
|
|
69985
70734
|
} catch {
|
|
69986
70735
|
return { path: f, mtime: 0 };
|
|
@@ -70282,7 +71031,7 @@ function filterToolsForAgentType(tools, typeDef) {
|
|
|
70282
71031
|
const excluded = new Set(typeDef.excludedTools ?? []);
|
|
70283
71032
|
return tools.filter((t) => allowed.has(t.name) && !excluded.has(t.name));
|
|
70284
71033
|
}
|
|
70285
|
-
function buildSubAgentSystemPrompt(
|
|
71034
|
+
function buildSubAgentSystemPrompt(_agentType, typeDef) {
|
|
70286
71035
|
return `You are a ${typeDef.description}
|
|
70287
71036
|
|
|
70288
71037
|
You are a sub-agent spawned to handle a specific task. Complete the task thoroughly and return your findings/results.
|
|
@@ -70301,7 +71050,7 @@ function extractText(message) {
|
|
|
70301
71050
|
}
|
|
70302
71051
|
return "(no text content)";
|
|
70303
71052
|
}
|
|
70304
|
-
function runAgentInBackground(agentId, record2, input, tools, systemPrompt, model, parentContext) {
|
|
71053
|
+
function runAgentInBackground(agentId, bgTaskId, record2, input, tools, systemPrompt, model, parentContext) {
|
|
70305
71054
|
const abortController = new AbortController();
|
|
70306
71055
|
runAgentLoop(
|
|
70307
71056
|
[{ role: "user", content: input.prompt }],
|
|
@@ -70314,22 +71063,40 @@ function runAgentInBackground(agentId, record2, input, tools, systemPrompt, mode
|
|
|
70314
71063
|
signal: abortController.signal,
|
|
70315
71064
|
permissionContext: parentContext.getAppState().toolPermissionContext,
|
|
70316
71065
|
agentId,
|
|
70317
|
-
maxTurns: 25
|
|
71066
|
+
maxTurns: 25,
|
|
71067
|
+
onTextDelta: (_text) => {
|
|
71068
|
+
updateTask(bgTaskId, {
|
|
71069
|
+
progress: {
|
|
71070
|
+
lastActivity: (/* @__PURE__ */ new Date()).toISOString()
|
|
71071
|
+
}
|
|
71072
|
+
});
|
|
71073
|
+
}
|
|
70318
71074
|
}
|
|
70319
71075
|
).then((result) => {
|
|
70320
71076
|
const lastAssistant = [...result.messages].reverse().find((m) => m.role === "assistant");
|
|
71077
|
+
const resultText = extractText(lastAssistant);
|
|
70321
71078
|
record2.status = "completed";
|
|
70322
|
-
record2.result =
|
|
71079
|
+
record2.result = resultText;
|
|
71080
|
+
const totalTokens = result.usage.totalInputTokens + result.usage.totalOutputTokens;
|
|
71081
|
+
updateTask(bgTaskId, {
|
|
71082
|
+
progress: {
|
|
71083
|
+
tokenCount: totalTokens,
|
|
71084
|
+
lastActivity: (/* @__PURE__ */ new Date()).toISOString()
|
|
71085
|
+
}
|
|
71086
|
+
});
|
|
71087
|
+
completeTask(bgTaskId, resultText);
|
|
70323
71088
|
}).catch((error2) => {
|
|
71089
|
+
const errorMsg = error2 instanceof Error ? error2.message : String(error2);
|
|
70324
71090
|
record2.status = "failed";
|
|
70325
|
-
record2.error =
|
|
71091
|
+
record2.error = errorMsg;
|
|
71092
|
+
failTask(bgTaskId, errorMsg);
|
|
70326
71093
|
});
|
|
70327
71094
|
}
|
|
70328
71095
|
function truncate3(str, maxLen) {
|
|
70329
71096
|
if (str.length <= maxLen) return str;
|
|
70330
71097
|
return str.slice(0, maxLen - 100) + "\n\n... (truncated)";
|
|
70331
71098
|
}
|
|
70332
|
-
var BUILTIN_AGENT_TYPES, AgentInputSchema, AgentOutputSchema,
|
|
71099
|
+
var BUILTIN_AGENT_TYPES, AgentInputSchema, AgentOutputSchema, nextAgentId2, runningAgents, agentTool, AGENT_PROMPT;
|
|
70333
71100
|
var init_agent = __esm({
|
|
70334
71101
|
"src/tools/builtin/agent.ts"() {
|
|
70335
71102
|
"use strict";
|
|
@@ -70337,6 +71104,7 @@ var init_agent = __esm({
|
|
|
70337
71104
|
init_constants();
|
|
70338
71105
|
init_agent_loop();
|
|
70339
71106
|
init_client();
|
|
71107
|
+
init_background_tasks();
|
|
70340
71108
|
BUILTIN_AGENT_TYPES = {
|
|
70341
71109
|
"general-purpose": {
|
|
70342
71110
|
name: "general-purpose",
|
|
@@ -70379,7 +71147,7 @@ var init_agent = __esm({
|
|
|
70379
71147
|
usage: external_exports.object({ inputTokens: external_exports.number(), outputTokens: external_exports.number() }),
|
|
70380
71148
|
backgrounded: external_exports.boolean().optional()
|
|
70381
71149
|
});
|
|
70382
|
-
|
|
71150
|
+
nextAgentId2 = 1;
|
|
70383
71151
|
runningAgents = /* @__PURE__ */ new Map();
|
|
70384
71152
|
agentTool = {
|
|
70385
71153
|
name: AGENT_TOOL,
|
|
@@ -70427,7 +71195,7 @@ var init_agent = __esm({
|
|
|
70427
71195
|
return { behavior: "allow", updatedInput: input };
|
|
70428
71196
|
},
|
|
70429
71197
|
async call(input, context) {
|
|
70430
|
-
const agentId = `agent-${
|
|
71198
|
+
const agentId = `agent-${nextAgentId2++}`;
|
|
70431
71199
|
const agentType = input.subagent_type ?? "general-purpose";
|
|
70432
71200
|
const typeDef = BUILTIN_AGENT_TYPES[agentType] ?? BUILTIN_AGENT_TYPES["general-purpose"];
|
|
70433
71201
|
const model = input.model ?? "sonnet";
|
|
@@ -70448,17 +71216,18 @@ var init_agent = __esm({
|
|
|
70448
71216
|
inputSchema: { type: "object", properties: {} },
|
|
70449
71217
|
isReadOnly: t.isReadOnly(),
|
|
70450
71218
|
isConcurrencySafe: t.isConcurrencySafe(),
|
|
70451
|
-
call: async (toolInput,
|
|
71219
|
+
call: async (toolInput, _toolCtx) => {
|
|
70452
71220
|
const result = await t.call(toolInput, context);
|
|
70453
71221
|
return { data: result.data };
|
|
70454
71222
|
}
|
|
70455
71223
|
}));
|
|
70456
71224
|
const systemPrompt = buildSubAgentSystemPrompt(agentType, typeDef);
|
|
70457
71225
|
if (input.run_in_background) {
|
|
70458
|
-
|
|
71226
|
+
const bgTask = createTask("agent", input.prompt.slice(0, 100));
|
|
71227
|
+
runAgentInBackground(agentId, bgTask.id, agentRecord, input, toolHandlers, systemPrompt, model, context);
|
|
70459
71228
|
return {
|
|
70460
71229
|
data: {
|
|
70461
|
-
result: `Agent ${agentId} (${agentType}) started in background.
|
|
71230
|
+
result: `Agent ${agentId} (${agentType}) started in background. Task ID: ${bgTask.id}. Use TaskOutput to check its status.`,
|
|
70462
71231
|
agentId,
|
|
70463
71232
|
agentType,
|
|
70464
71233
|
model,
|
|
@@ -70494,7 +71263,10 @@ var init_agent = __esm({
|
|
|
70494
71263
|
agentType,
|
|
70495
71264
|
model,
|
|
70496
71265
|
totalTurns: loopResult.totalTurns,
|
|
70497
|
-
usage:
|
|
71266
|
+
usage: {
|
|
71267
|
+
inputTokens: loopResult.usage.totalInputTokens,
|
|
71268
|
+
outputTokens: loopResult.usage.totalOutputTokens
|
|
71269
|
+
}
|
|
70498
71270
|
}
|
|
70499
71271
|
};
|
|
70500
71272
|
} catch (error2) {
|
|
@@ -70645,11 +71417,11 @@ var init_todos = __esm({
|
|
|
70645
71417
|
});
|
|
70646
71418
|
return result.map(mapFromHasna);
|
|
70647
71419
|
}
|
|
70648
|
-
let
|
|
71420
|
+
let tasks2 = [...this.fallbackStore.values()];
|
|
70649
71421
|
if (filter?.status) {
|
|
70650
|
-
|
|
71422
|
+
tasks2 = tasks2.filter((t) => t.status === filter.status);
|
|
70651
71423
|
}
|
|
70652
|
-
return
|
|
71424
|
+
return tasks2;
|
|
70653
71425
|
}
|
|
70654
71426
|
async updateTask(id, params) {
|
|
70655
71427
|
if (this.hasnaTodos) {
|
|
@@ -70722,23 +71494,23 @@ var init_todos = __esm({
|
|
|
70722
71494
|
await this.hasnaTodos.sync({ taskListId: this.taskListId, direction: "push" });
|
|
70723
71495
|
return;
|
|
70724
71496
|
}
|
|
70725
|
-
const { writeFileSync: writeFileSync10, mkdirSync: mkdirSync9, existsSync:
|
|
70726
|
-
const { join:
|
|
70727
|
-
if (!
|
|
70728
|
-
const
|
|
70729
|
-
for (const task of
|
|
70730
|
-
const filePath =
|
|
71497
|
+
const { writeFileSync: writeFileSync10, mkdirSync: mkdirSync9, existsSync: existsSync19 } = await import("fs");
|
|
71498
|
+
const { join: join12 } = await import("path");
|
|
71499
|
+
if (!existsSync19(dir)) mkdirSync9(dir, { recursive: true });
|
|
71500
|
+
const tasks2 = await this.listTasks();
|
|
71501
|
+
for (const task of tasks2) {
|
|
71502
|
+
const filePath = join12(dir, `${task.id}.json`);
|
|
70731
71503
|
writeFileSync10(filePath, JSON.stringify(task, null, 2), "utf-8");
|
|
70732
71504
|
}
|
|
70733
71505
|
}
|
|
70734
71506
|
// ── Stats ──────────────────────────────────────────────────────
|
|
70735
71507
|
async getStats() {
|
|
70736
|
-
const
|
|
71508
|
+
const tasks2 = await this.listTasks();
|
|
70737
71509
|
return {
|
|
70738
|
-
total:
|
|
70739
|
-
pending:
|
|
70740
|
-
inProgress:
|
|
70741
|
-
completed:
|
|
71510
|
+
total: tasks2.length,
|
|
71511
|
+
pending: tasks2.filter((t) => t.status === "pending").length,
|
|
71512
|
+
inProgress: tasks2.filter((t) => t.status === "in_progress").length,
|
|
71513
|
+
completed: tasks2.filter((t) => t.status === "completed").length
|
|
70742
71514
|
};
|
|
70743
71515
|
}
|
|
70744
71516
|
};
|
|
@@ -70922,8 +71694,8 @@ var init_tasks = __esm({
|
|
|
70922
71694
|
},
|
|
70923
71695
|
async call() {
|
|
70924
71696
|
const todos = getTodosIntegration();
|
|
70925
|
-
const
|
|
70926
|
-
return { data: { tasks } };
|
|
71697
|
+
const tasks2 = await todos.listTasks();
|
|
71698
|
+
return { data: { tasks: tasks2 } };
|
|
70927
71699
|
},
|
|
70928
71700
|
mapToolResultToToolResultBlockParam(result, toolUseId) {
|
|
70929
71701
|
if (result.tasks.length === 0) {
|
|
@@ -71065,6 +71837,251 @@ var init_tasks = __esm({
|
|
|
71065
71837
|
}
|
|
71066
71838
|
});
|
|
71067
71839
|
|
|
71840
|
+
// src/tools/builtin/task-output.ts
|
|
71841
|
+
var MAX_OUTPUT_CHARS, TaskOutputInputSchema, TaskOutputOutputSchema, taskOutputTool, TaskStopInputSchema, TaskStopOutputSchema, taskStopTool, TASK_OUTPUT_PROMPT, TASK_STOP_PROMPT;
|
|
71842
|
+
var init_task_output = __esm({
|
|
71843
|
+
"src/tools/builtin/task-output.ts"() {
|
|
71844
|
+
"use strict";
|
|
71845
|
+
init_zod();
|
|
71846
|
+
init_constants();
|
|
71847
|
+
init_background_tasks();
|
|
71848
|
+
MAX_OUTPUT_CHARS = 3e4;
|
|
71849
|
+
TaskOutputInputSchema = external_exports.strictObject({
|
|
71850
|
+
task_id: external_exports.string().describe("The ID of the background task to check (e.g. 'bg-1', 'agent-2')")
|
|
71851
|
+
});
|
|
71852
|
+
TaskOutputOutputSchema = external_exports.object({
|
|
71853
|
+
task_id: external_exports.string(),
|
|
71854
|
+
status: external_exports.string(),
|
|
71855
|
+
output: external_exports.string(),
|
|
71856
|
+
exitCode: external_exports.number().nullable().optional(),
|
|
71857
|
+
durationMs: external_exports.number().optional(),
|
|
71858
|
+
error: external_exports.string().optional(),
|
|
71859
|
+
progress: external_exports.object({
|
|
71860
|
+
tokenCount: external_exports.number().optional(),
|
|
71861
|
+
lastActivity: external_exports.string().optional()
|
|
71862
|
+
}).optional()
|
|
71863
|
+
});
|
|
71864
|
+
taskOutputTool = {
|
|
71865
|
+
name: TASK_OUTPUT_TOOL,
|
|
71866
|
+
searchHint: "check status and output of a background task",
|
|
71867
|
+
maxResultSizeChars: DEFAULT_MAX_RESULT_SIZE_CHARS,
|
|
71868
|
+
shouldDefer: true,
|
|
71869
|
+
async description() {
|
|
71870
|
+
return "Check the status and output of a background task";
|
|
71871
|
+
},
|
|
71872
|
+
async prompt() {
|
|
71873
|
+
return TASK_OUTPUT_PROMPT;
|
|
71874
|
+
},
|
|
71875
|
+
get inputSchema() {
|
|
71876
|
+
return TaskOutputInputSchema;
|
|
71877
|
+
},
|
|
71878
|
+
get outputSchema() {
|
|
71879
|
+
return TaskOutputOutputSchema;
|
|
71880
|
+
},
|
|
71881
|
+
userFacingName() {
|
|
71882
|
+
return "TaskOutput";
|
|
71883
|
+
},
|
|
71884
|
+
isEnabled() {
|
|
71885
|
+
return true;
|
|
71886
|
+
},
|
|
71887
|
+
isConcurrencySafe() {
|
|
71888
|
+
return true;
|
|
71889
|
+
},
|
|
71890
|
+
isReadOnly() {
|
|
71891
|
+
return true;
|
|
71892
|
+
},
|
|
71893
|
+
toAutoClassifierInput(input) {
|
|
71894
|
+
return input.task_id;
|
|
71895
|
+
},
|
|
71896
|
+
getActivityDescription(input) {
|
|
71897
|
+
return `Checking task ${input.task_id}`;
|
|
71898
|
+
},
|
|
71899
|
+
async validateInput(input) {
|
|
71900
|
+
if (!input.task_id || !input.task_id.trim()) {
|
|
71901
|
+
return { result: false, message: "task_id is required", errorCode: 1 };
|
|
71902
|
+
}
|
|
71903
|
+
return { result: true };
|
|
71904
|
+
},
|
|
71905
|
+
async checkPermissions(input) {
|
|
71906
|
+
return { behavior: "allow", updatedInput: input };
|
|
71907
|
+
},
|
|
71908
|
+
async call(input) {
|
|
71909
|
+
const task = getTask(input.task_id);
|
|
71910
|
+
if (!task) {
|
|
71911
|
+
return {
|
|
71912
|
+
data: {
|
|
71913
|
+
task_id: input.task_id,
|
|
71914
|
+
status: "not_found",
|
|
71915
|
+
output: `No background task found with ID "${input.task_id}". Use TaskList or check the ID returned when you started the background task.`,
|
|
71916
|
+
error: `Task "${input.task_id}" not found`
|
|
71917
|
+
}
|
|
71918
|
+
};
|
|
71919
|
+
}
|
|
71920
|
+
let output = readTaskOutput(task.id);
|
|
71921
|
+
if (!output && task.output) output = task.output;
|
|
71922
|
+
if (output.length > MAX_OUTPUT_CHARS) {
|
|
71923
|
+
const half = Math.floor(MAX_OUTPUT_CHARS / 2);
|
|
71924
|
+
output = output.slice(0, half) + `
|
|
71925
|
+
|
|
71926
|
+
... (${output.length - MAX_OUTPUT_CHARS} characters truncated) ...
|
|
71927
|
+
|
|
71928
|
+
` + output.slice(-half);
|
|
71929
|
+
}
|
|
71930
|
+
const durationMs = task.endTime ? task.endTime - task.startTime : Date.now() - task.startTime;
|
|
71931
|
+
return {
|
|
71932
|
+
data: {
|
|
71933
|
+
task_id: task.id,
|
|
71934
|
+
status: task.status,
|
|
71935
|
+
output: output || "(no output yet)",
|
|
71936
|
+
exitCode: task.exitCode,
|
|
71937
|
+
durationMs,
|
|
71938
|
+
error: task.error,
|
|
71939
|
+
progress: task.progress
|
|
71940
|
+
}
|
|
71941
|
+
};
|
|
71942
|
+
},
|
|
71943
|
+
mapToolResultToToolResultBlockParam(result, toolUseId) {
|
|
71944
|
+
const parts = [];
|
|
71945
|
+
parts.push(`Task: ${result.task_id}`);
|
|
71946
|
+
parts.push(`Status: ${result.status}`);
|
|
71947
|
+
if (result.durationMs != null) {
|
|
71948
|
+
const sec = (result.durationMs / 1e3).toFixed(1);
|
|
71949
|
+
parts.push(`Duration: ${sec}s`);
|
|
71950
|
+
}
|
|
71951
|
+
if (result.exitCode != null) {
|
|
71952
|
+
parts.push(`Exit code: ${result.exitCode}`);
|
|
71953
|
+
}
|
|
71954
|
+
if (result.progress?.tokenCount) {
|
|
71955
|
+
parts.push(`Tokens: ${result.progress.tokenCount}`);
|
|
71956
|
+
}
|
|
71957
|
+
if (result.progress?.lastActivity) {
|
|
71958
|
+
parts.push(`Last activity: ${result.progress.lastActivity}`);
|
|
71959
|
+
}
|
|
71960
|
+
if (result.error) {
|
|
71961
|
+
parts.push(`Error: ${result.error}`);
|
|
71962
|
+
}
|
|
71963
|
+
parts.push("");
|
|
71964
|
+
parts.push(result.output);
|
|
71965
|
+
return {
|
|
71966
|
+
type: "tool_result",
|
|
71967
|
+
tool_use_id: toolUseId,
|
|
71968
|
+
content: parts.join("\n"),
|
|
71969
|
+
is_error: result.status === "not_found"
|
|
71970
|
+
};
|
|
71971
|
+
}
|
|
71972
|
+
};
|
|
71973
|
+
TaskStopInputSchema = external_exports.strictObject({
|
|
71974
|
+
task_id: external_exports.string().describe("The ID of the background task to stop (e.g. 'bg-1', 'agent-2')")
|
|
71975
|
+
});
|
|
71976
|
+
TaskStopOutputSchema = external_exports.object({
|
|
71977
|
+
task_id: external_exports.string(),
|
|
71978
|
+
status: external_exports.string(),
|
|
71979
|
+
message: external_exports.string()
|
|
71980
|
+
});
|
|
71981
|
+
taskStopTool = {
|
|
71982
|
+
name: TASK_STOP_TOOL,
|
|
71983
|
+
searchHint: "stop kill a running background task",
|
|
71984
|
+
maxResultSizeChars: DEFAULT_MAX_RESULT_SIZE_CHARS,
|
|
71985
|
+
shouldDefer: true,
|
|
71986
|
+
async description() {
|
|
71987
|
+
return "Stop a running background task";
|
|
71988
|
+
},
|
|
71989
|
+
async prompt() {
|
|
71990
|
+
return TASK_STOP_PROMPT;
|
|
71991
|
+
},
|
|
71992
|
+
get inputSchema() {
|
|
71993
|
+
return TaskStopInputSchema;
|
|
71994
|
+
},
|
|
71995
|
+
get outputSchema() {
|
|
71996
|
+
return TaskStopOutputSchema;
|
|
71997
|
+
},
|
|
71998
|
+
userFacingName() {
|
|
71999
|
+
return "TaskStop";
|
|
72000
|
+
},
|
|
72001
|
+
isEnabled() {
|
|
72002
|
+
return true;
|
|
72003
|
+
},
|
|
72004
|
+
isConcurrencySafe() {
|
|
72005
|
+
return true;
|
|
72006
|
+
},
|
|
72007
|
+
isReadOnly() {
|
|
72008
|
+
return false;
|
|
72009
|
+
},
|
|
72010
|
+
toAutoClassifierInput(input) {
|
|
72011
|
+
return input.task_id;
|
|
72012
|
+
},
|
|
72013
|
+
getActivityDescription(input) {
|
|
72014
|
+
return `Stopping task ${input.task_id}`;
|
|
72015
|
+
},
|
|
72016
|
+
async validateInput(input) {
|
|
72017
|
+
if (!input.task_id || !input.task_id.trim()) {
|
|
72018
|
+
return { result: false, message: "task_id is required", errorCode: 1 };
|
|
72019
|
+
}
|
|
72020
|
+
return { result: true };
|
|
72021
|
+
},
|
|
72022
|
+
async checkPermissions(input) {
|
|
72023
|
+
return { behavior: "allow", updatedInput: input };
|
|
72024
|
+
},
|
|
72025
|
+
async call(input) {
|
|
72026
|
+
const task = getTask(input.task_id);
|
|
72027
|
+
if (!task) {
|
|
72028
|
+
return {
|
|
72029
|
+
data: {
|
|
72030
|
+
task_id: input.task_id,
|
|
72031
|
+
status: "not_found",
|
|
72032
|
+
message: `No background task found with ID "${input.task_id}".`
|
|
72033
|
+
}
|
|
72034
|
+
};
|
|
72035
|
+
}
|
|
72036
|
+
if (task.status !== "running") {
|
|
72037
|
+
return {
|
|
72038
|
+
data: {
|
|
72039
|
+
task_id: task.id,
|
|
72040
|
+
status: task.status,
|
|
72041
|
+
message: `Task ${task.id} is already ${task.status} \u2014 cannot stop.`
|
|
72042
|
+
}
|
|
72043
|
+
};
|
|
72044
|
+
}
|
|
72045
|
+
killTask(task.id);
|
|
72046
|
+
return {
|
|
72047
|
+
data: {
|
|
72048
|
+
task_id: task.id,
|
|
72049
|
+
status: "killed",
|
|
72050
|
+
message: `Task ${task.id} has been killed.`
|
|
72051
|
+
}
|
|
72052
|
+
};
|
|
72053
|
+
},
|
|
72054
|
+
mapToolResultToToolResultBlockParam(result, toolUseId) {
|
|
72055
|
+
return {
|
|
72056
|
+
type: "tool_result",
|
|
72057
|
+
tool_use_id: toolUseId,
|
|
72058
|
+
content: result.message,
|
|
72059
|
+
is_error: result.status === "not_found"
|
|
72060
|
+
};
|
|
72061
|
+
}
|
|
72062
|
+
};
|
|
72063
|
+
TASK_OUTPUT_PROMPT = `Check the status and output of a background task.
|
|
72064
|
+
|
|
72065
|
+
Use this tool when you have previously started a bash command or agent with run_in_background:true
|
|
72066
|
+
and need to check whether it has completed, and retrieve its output.
|
|
72067
|
+
|
|
72068
|
+
The task_id is returned when you start a background task (e.g., "bg-1" for bash, "agent-1" for agents).
|
|
72069
|
+
|
|
72070
|
+
The tool returns:
|
|
72071
|
+
- status: "running", "completed", "failed", or "killed"
|
|
72072
|
+
- output: The stdout/stderr from the task (truncated to 30000 chars)
|
|
72073
|
+
- exitCode: The exit code (for bash tasks)
|
|
72074
|
+
- durationMs: How long the task has been running or ran
|
|
72075
|
+
- progress: For agents, includes tokenCount and lastActivity`;
|
|
72076
|
+
TASK_STOP_PROMPT = `Stop a running background task.
|
|
72077
|
+
|
|
72078
|
+
Use this tool to kill a background bash command or agent that is still running.
|
|
72079
|
+
The task will be marked as "killed" and its process terminated.
|
|
72080
|
+
|
|
72081
|
+
The task_id is returned when you start a background task (e.g., "bg-1" for bash, "agent-1" for agents).`;
|
|
72082
|
+
}
|
|
72083
|
+
});
|
|
72084
|
+
|
|
71068
72085
|
// src/tools/builtin/ask-user.ts
|
|
71069
72086
|
var OptionSchema, QuestionSchema, AskUserInputSchema, AskUserOutputSchema, askUserQuestionTool, ASK_USER_PROMPT;
|
|
71070
72087
|
var init_ask_user = __esm({
|
|
@@ -71471,17 +72488,17 @@ LSP servers must be configured for the file type.`;
|
|
|
71471
72488
|
});
|
|
71472
72489
|
|
|
71473
72490
|
// src/tools/builtin/plan-mode.ts
|
|
71474
|
-
import { readFileSync as
|
|
71475
|
-
import { join as
|
|
72491
|
+
import { readFileSync as readFileSync13, existsSync as existsSync16 } from "fs";
|
|
72492
|
+
import { join as join10 } from "path";
|
|
71476
72493
|
function getPlanFilePath(agentId) {
|
|
71477
72494
|
const dir = getPlansDir();
|
|
71478
72495
|
const name = agentId ? `plan-${agentId}.md` : "plan.md";
|
|
71479
|
-
return
|
|
72496
|
+
return join10(dir, name);
|
|
71480
72497
|
}
|
|
71481
72498
|
function readPlanFile(agentId) {
|
|
71482
72499
|
const path = getPlanFilePath(agentId);
|
|
71483
|
-
if (!
|
|
71484
|
-
return
|
|
72500
|
+
if (!existsSync16(path)) return null;
|
|
72501
|
+
return readFileSync13(path, "utf-8");
|
|
71485
72502
|
}
|
|
71486
72503
|
var _hasExitedPlanMode, EnterPlanInputSchema, EnterPlanOutputSchema, enterPlanModeTool, ExitPlanInputSchema, ExitPlanOutputSchema, exitPlanModeTool, ENTER_PLAN_PROMPT, EXIT_PLAN_PROMPT;
|
|
71487
72504
|
var init_plan_mode = __esm({
|
|
@@ -71709,8 +72726,43 @@ function getEnabledTools() {
|
|
|
71709
72726
|
}
|
|
71710
72727
|
return tools;
|
|
71711
72728
|
}
|
|
71712
|
-
function
|
|
71713
|
-
|
|
72729
|
+
function setDeferredToolSchemas(schemas) {
|
|
72730
|
+
for (const s of schemas) {
|
|
72731
|
+
deferredToolSchemas.set(s.name, s);
|
|
72732
|
+
}
|
|
72733
|
+
}
|
|
72734
|
+
function getAllDeferredToolSchemas() {
|
|
72735
|
+
return [...deferredToolSchemas.values()];
|
|
72736
|
+
}
|
|
72737
|
+
function searchDeferredToolSchemas(query, maxResults = 5) {
|
|
72738
|
+
const queryLower = query.toLowerCase();
|
|
72739
|
+
const queryTerms = queryLower.split(/\s+/);
|
|
72740
|
+
if (queryLower.startsWith("select:")) {
|
|
72741
|
+
const names = query.slice(7).split(",").map((n) => n.trim());
|
|
72742
|
+
return names.map((n) => deferredToolSchemas.get(n)).filter((s) => s !== void 0);
|
|
72743
|
+
}
|
|
72744
|
+
const requiredTerms = queryTerms.filter((t) => t.startsWith("+")).map((t) => t.slice(1));
|
|
72745
|
+
const searchTerms = queryTerms.filter((t) => !t.startsWith("+"));
|
|
72746
|
+
const results = [];
|
|
72747
|
+
for (const schema of deferredToolSchemas.values()) {
|
|
72748
|
+
const nameLower = schema.name.toLowerCase();
|
|
72749
|
+
const descLower = schema.description.toLowerCase();
|
|
72750
|
+
if (requiredTerms.length > 0 && !requiredTerms.every((rt) => nameLower.includes(rt))) {
|
|
72751
|
+
continue;
|
|
72752
|
+
}
|
|
72753
|
+
let score = 0;
|
|
72754
|
+
const allTerms = searchTerms.length > 0 ? searchTerms : requiredTerms;
|
|
72755
|
+
for (const term of allTerms) {
|
|
72756
|
+
if (nameLower === term) score += 10;
|
|
72757
|
+
else if (nameLower.includes(term)) score += 5;
|
|
72758
|
+
if (descLower.includes(term)) score += 3;
|
|
72759
|
+
}
|
|
72760
|
+
if (score > 0) {
|
|
72761
|
+
results.push({ schema, score });
|
|
72762
|
+
}
|
|
72763
|
+
}
|
|
72764
|
+
results.sort((a, b) => b.score - a.score);
|
|
72765
|
+
return results.slice(0, maxResults).map((r) => r.schema);
|
|
71714
72766
|
}
|
|
71715
72767
|
function searchTools(query, maxResults = 5) {
|
|
71716
72768
|
const results = [];
|
|
@@ -71748,7 +72800,7 @@ function matchScore(name, hint, queryTerms) {
|
|
|
71748
72800
|
}
|
|
71749
72801
|
return score;
|
|
71750
72802
|
}
|
|
71751
|
-
var registeredTools, deferredTools, disabledTools, mcpTools;
|
|
72803
|
+
var registeredTools, deferredTools, disabledTools, mcpTools, deferredToolSchemas;
|
|
71752
72804
|
var init_registry2 = __esm({
|
|
71753
72805
|
"src/tools/registry.ts"() {
|
|
71754
72806
|
"use strict";
|
|
@@ -71757,6 +72809,7 @@ var init_registry2 = __esm({
|
|
|
71757
72809
|
deferredTools = /* @__PURE__ */ new Map();
|
|
71758
72810
|
disabledTools = /* @__PURE__ */ new Set();
|
|
71759
72811
|
mcpTools = /* @__PURE__ */ new Map();
|
|
72812
|
+
deferredToolSchemas = /* @__PURE__ */ new Map();
|
|
71760
72813
|
}
|
|
71761
72814
|
});
|
|
71762
72815
|
|
|
@@ -71804,6 +72857,24 @@ function simpleTool(opts) {
|
|
|
71804
72857
|
mapToolResultToToolResultBlockParam: opts.mapResult
|
|
71805
72858
|
};
|
|
71806
72859
|
}
|
|
72860
|
+
function toNotebookSource(text) {
|
|
72861
|
+
const lines = text.split("\n");
|
|
72862
|
+
return lines.map(
|
|
72863
|
+
(l, i) => i < lines.length - 1 ? l + "\n" : l
|
|
72864
|
+
);
|
|
72865
|
+
}
|
|
72866
|
+
function createCell(cellType, source) {
|
|
72867
|
+
const base = {
|
|
72868
|
+
cell_type: cellType,
|
|
72869
|
+
metadata: {},
|
|
72870
|
+
source: toNotebookSource(source)
|
|
72871
|
+
};
|
|
72872
|
+
if (cellType === "code") {
|
|
72873
|
+
base.execution_count = null;
|
|
72874
|
+
base.outputs = [];
|
|
72875
|
+
}
|
|
72876
|
+
return base;
|
|
72877
|
+
}
|
|
71807
72878
|
var toolSearchTool, cronCreateTool, cronDeleteTool, cronListTool, enterWorktreeTool, exitWorktreeTool, notebookEditTool, configTool, sendMessageTool;
|
|
71808
72879
|
var init_misc = __esm({
|
|
71809
72880
|
"src/tools/builtin/misc.ts"() {
|
|
@@ -71813,30 +72884,68 @@ var init_misc = __esm({
|
|
|
71813
72884
|
init_constants();
|
|
71814
72885
|
toolSearchTool = simpleTool({
|
|
71815
72886
|
name: TOOL_SEARCH_TOOL,
|
|
71816
|
-
hint: "find available tools by keyword",
|
|
72887
|
+
hint: "find available tools by keyword \u2014 fetches full schemas for deferred tools",
|
|
71817
72888
|
inputSchema: external_exports.strictObject({
|
|
71818
|
-
query: external_exports.string().describe(
|
|
71819
|
-
|
|
72889
|
+
query: external_exports.string().describe(
|
|
72890
|
+
'Query to find deferred tools. Use "select:Read,Edit,Grep" for exact names, or keywords to search. Use "+slack send" to require "slack" in name.'
|
|
72891
|
+
),
|
|
72892
|
+
max_results: external_exports.number().default(5).describe("Maximum number of results to return (default: 5)")
|
|
71820
72893
|
}),
|
|
71821
72894
|
readOnly: true,
|
|
71822
72895
|
concurrent: true,
|
|
71823
72896
|
defer: false,
|
|
71824
|
-
prompt:
|
|
72897
|
+
prompt: `Fetches full schema definitions for deferred tools so they can be called.
|
|
72898
|
+
|
|
72899
|
+
Deferred tools appear by name in the "Deferred Tools" section of the system prompt. Until fetched, only the name is known \u2014 there is no parameter schema, so the tool cannot be invoked. This tool takes a query, matches it against the deferred tool list, and returns the matched tools' complete JSONSchema definitions inside a <functions> block. Once a tool's schema appears in that result, it is callable exactly like any tool defined at the top of the prompt.
|
|
72900
|
+
|
|
72901
|
+
Result format: each matched tool appears as one <function>{"description": "...", "name": "...", "parameters": {...}}</function> line inside the <functions> block \u2014 the same encoding as the tool list at the top of this prompt.
|
|
72902
|
+
|
|
72903
|
+
Query forms:
|
|
72904
|
+
- "select:Read,Edit,Grep" \u2014 fetch these exact tools by name
|
|
72905
|
+
- "notebook jupyter" \u2014 keyword search, up to max_results best matches
|
|
72906
|
+
- "+slack send" \u2014 require "slack" in the name, rank by remaining terms`,
|
|
71825
72907
|
async call(input) {
|
|
71826
|
-
const
|
|
71827
|
-
const
|
|
72908
|
+
const matchedSchemas = searchDeferredToolSchemas(input.query, input.max_results);
|
|
72909
|
+
const registryResults = searchTools(input.query, input.max_results);
|
|
72910
|
+
const allDeferred = getAllDeferredToolSchemas();
|
|
71828
72911
|
return {
|
|
71829
72912
|
data: {
|
|
71830
|
-
|
|
71831
|
-
|
|
72913
|
+
matchedSchemas,
|
|
72914
|
+
registryResults,
|
|
72915
|
+
totalDeferredCount: allDeferred.length
|
|
71832
72916
|
}
|
|
71833
72917
|
};
|
|
71834
72918
|
},
|
|
71835
72919
|
mapResult(result, id) {
|
|
71836
|
-
const
|
|
71837
|
-
|
|
71838
|
-
)
|
|
71839
|
-
|
|
72920
|
+
const sections = [];
|
|
72921
|
+
const schemas = result.matchedSchemas;
|
|
72922
|
+
if (schemas && schemas.length > 0) {
|
|
72923
|
+
const functionDefs = schemas.map(
|
|
72924
|
+
(s) => `<function>{"description": ${JSON.stringify(s.description)}, "name": ${JSON.stringify(s.name)}, "parameters": ${JSON.stringify(s.inputSchema)}}</function>`
|
|
72925
|
+
).join("\n");
|
|
72926
|
+
sections.push(`<functions>
|
|
72927
|
+
${functionDefs}
|
|
72928
|
+
</functions>`);
|
|
72929
|
+
}
|
|
72930
|
+
const registryResults = result.registryResults;
|
|
72931
|
+
if (registryResults && registryResults.length > 0) {
|
|
72932
|
+
const extraHits = registryResults.filter(
|
|
72933
|
+
(r) => !schemas?.some((s) => s.name === r.name)
|
|
72934
|
+
);
|
|
72935
|
+
if (extraHits.length > 0) {
|
|
72936
|
+
const lines = extraHits.map(
|
|
72937
|
+
(r) => `${r.name}${r.deferred ? " (deferred)" : ""}: ${r.hint}`
|
|
72938
|
+
);
|
|
72939
|
+
sections.push(lines.join("\n"));
|
|
72940
|
+
}
|
|
72941
|
+
}
|
|
72942
|
+
if (sections.length === 0) {
|
|
72943
|
+
return { type: "tool_result", tool_use_id: id, content: "No tools found matching the query." };
|
|
72944
|
+
}
|
|
72945
|
+
const footer = `
|
|
72946
|
+
|
|
72947
|
+
${result.totalDeferredCount} deferred tool(s) available. Use ToolSearch to fetch schemas for any listed tool.`;
|
|
72948
|
+
return { type: "tool_result", tool_use_id: id, content: sections.join("\n\n") + footer };
|
|
71840
72949
|
}
|
|
71841
72950
|
});
|
|
71842
72951
|
cronCreateTool = simpleTool({
|
|
@@ -71924,34 +73033,134 @@ var init_misc = __esm({
|
|
|
71924
73033
|
});
|
|
71925
73034
|
notebookEditTool = simpleTool({
|
|
71926
73035
|
name: NOTEBOOK_EDIT_TOOL,
|
|
71927
|
-
hint: "edit Jupyter notebook cells",
|
|
73036
|
+
hint: "edit Jupyter notebook cells \u2014 insert, replace, delete, move, change type",
|
|
71928
73037
|
inputSchema: external_exports.strictObject({
|
|
71929
73038
|
notebook_path: external_exports.string().describe("Path to the .ipynb file"),
|
|
71930
|
-
|
|
71931
|
-
|
|
73039
|
+
command: external_exports.enum(["insert_cell", "replace_cell", "delete_cell", "move_cell", "change_cell_type"]).describe("Operation to perform"),
|
|
73040
|
+
cell_index: external_exports.number().optional().describe("Cell index to operate on (0-based). For insert_cell, position to insert at (omit to append)."),
|
|
73041
|
+
cell_type: external_exports.enum(["code", "markdown", "raw"]).optional().describe("Cell type \u2014 required for insert_cell and change_cell_type"),
|
|
73042
|
+
new_source: external_exports.string().optional().describe("New cell content \u2014 required for insert_cell and replace_cell"),
|
|
73043
|
+
target_index: external_exports.number().optional().describe("Destination index for move_cell")
|
|
71932
73044
|
}),
|
|
71933
73045
|
readOnly: false,
|
|
71934
73046
|
concurrent: false,
|
|
71935
|
-
defer:
|
|
71936
|
-
prompt:
|
|
73047
|
+
defer: false,
|
|
73048
|
+
prompt: `Edit Jupyter notebook (.ipynb) cells. Supports 5 commands:
|
|
73049
|
+
|
|
73050
|
+
- insert_cell: Insert a new cell at cell_index (or end if omitted). Requires cell_type and new_source.
|
|
73051
|
+
- replace_cell: Replace the source of the cell at cell_index with new_source. Requires cell_index and new_source.
|
|
73052
|
+
- delete_cell: Delete the cell at cell_index. Requires cell_index.
|
|
73053
|
+
- move_cell: Move cell from cell_index to target_index. Requires cell_index and target_index.
|
|
73054
|
+
- change_cell_type: Change the type of cell at cell_index to cell_type. Requires cell_index and cell_type.
|
|
73055
|
+
|
|
73056
|
+
All metadata, outputs, and kernel info are preserved. Cell indices are 0-based.`,
|
|
71937
73057
|
async call(input) {
|
|
71938
|
-
const { readFileSync:
|
|
73058
|
+
const { readFileSync: readFileSync15, writeFileSync: writeFileSync10 } = await import("fs");
|
|
73059
|
+
const { resolve: resolve8 } = await import("path");
|
|
73060
|
+
const notebookPath = resolve8(input.notebook_path);
|
|
71939
73061
|
try {
|
|
71940
|
-
const
|
|
71941
|
-
|
|
71942
|
-
|
|
71943
|
-
|
|
71944
|
-
|
|
71945
|
-
|
|
71946
|
-
|
|
73062
|
+
const raw = readFileSync15(notebookPath, "utf-8");
|
|
73063
|
+
const notebook = JSON.parse(raw);
|
|
73064
|
+
if (!notebook.cells || !Array.isArray(notebook.cells)) {
|
|
73065
|
+
return { data: { success: false, error: "Invalid notebook: no cells array found" } };
|
|
73066
|
+
}
|
|
73067
|
+
const cells = notebook.cells;
|
|
73068
|
+
const totalCells = cells.length;
|
|
73069
|
+
switch (input.command) {
|
|
73070
|
+
case "insert_cell": {
|
|
73071
|
+
if (!input.cell_type) return { data: { success: false, error: "insert_cell requires cell_type" } };
|
|
73072
|
+
const source = input.new_source ?? "";
|
|
73073
|
+
const newCell = createCell(input.cell_type, source);
|
|
73074
|
+
const idx = input.cell_index ?? totalCells;
|
|
73075
|
+
if (idx < 0 || idx > totalCells) {
|
|
73076
|
+
return { data: { success: false, error: `cell_index ${idx} out of range (0-${totalCells})` } };
|
|
73077
|
+
}
|
|
73078
|
+
cells.splice(idx, 0, newCell);
|
|
73079
|
+
notebook.cells = cells;
|
|
73080
|
+
writeFileSync10(notebookPath, JSON.stringify(notebook, null, 1), "utf-8");
|
|
73081
|
+
return { data: { success: true, message: `Inserted ${input.cell_type} cell at index ${idx} (notebook now has ${cells.length} cells)` } };
|
|
73082
|
+
}
|
|
73083
|
+
case "replace_cell": {
|
|
73084
|
+
if (input.cell_index == null) return { data: { success: false, error: "replace_cell requires cell_index" } };
|
|
73085
|
+
if (input.new_source == null) return { data: { success: false, error: "replace_cell requires new_source" } };
|
|
73086
|
+
if (input.cell_index < 0 || input.cell_index >= totalCells) {
|
|
73087
|
+
return { data: { success: false, error: `cell_index ${input.cell_index} out of range (0-${totalCells - 1})` } };
|
|
73088
|
+
}
|
|
73089
|
+
const cell = cells[input.cell_index];
|
|
73090
|
+
cell.source = toNotebookSource(input.new_source);
|
|
73091
|
+
if (cell.cell_type === "code") {
|
|
73092
|
+
cell.outputs = [];
|
|
73093
|
+
cell.execution_count = null;
|
|
73094
|
+
}
|
|
73095
|
+
writeFileSync10(notebookPath, JSON.stringify(notebook, null, 1), "utf-8");
|
|
73096
|
+
return { data: { success: true, message: `Replaced source of cell ${input.cell_index} (${cell.cell_type})` } };
|
|
73097
|
+
}
|
|
73098
|
+
case "delete_cell": {
|
|
73099
|
+
if (input.cell_index == null) return { data: { success: false, error: "delete_cell requires cell_index" } };
|
|
73100
|
+
if (input.cell_index < 0 || input.cell_index >= totalCells) {
|
|
73101
|
+
return { data: { success: false, error: `cell_index ${input.cell_index} out of range (0-${totalCells - 1})` } };
|
|
73102
|
+
}
|
|
73103
|
+
const deletedType = cells[input.cell_index].cell_type;
|
|
73104
|
+
cells.splice(input.cell_index, 1);
|
|
73105
|
+
notebook.cells = cells;
|
|
73106
|
+
writeFileSync10(notebookPath, JSON.stringify(notebook, null, 1), "utf-8");
|
|
73107
|
+
return { data: { success: true, message: `Deleted ${deletedType} cell at index ${input.cell_index} (notebook now has ${cells.length} cells)` } };
|
|
73108
|
+
}
|
|
73109
|
+
case "move_cell": {
|
|
73110
|
+
if (input.cell_index == null) return { data: { success: false, error: "move_cell requires cell_index" } };
|
|
73111
|
+
if (input.target_index == null) return { data: { success: false, error: "move_cell requires target_index" } };
|
|
73112
|
+
if (input.cell_index < 0 || input.cell_index >= totalCells) {
|
|
73113
|
+
return { data: { success: false, error: `cell_index ${input.cell_index} out of range (0-${totalCells - 1})` } };
|
|
73114
|
+
}
|
|
73115
|
+
if (input.target_index < 0 || input.target_index >= totalCells) {
|
|
73116
|
+
return { data: { success: false, error: `target_index ${input.target_index} out of range (0-${totalCells - 1})` } };
|
|
73117
|
+
}
|
|
73118
|
+
if (input.cell_index === input.target_index) {
|
|
73119
|
+
return { data: { success: true, message: `Cell ${input.cell_index} is already at target position` } };
|
|
73120
|
+
}
|
|
73121
|
+
const [movedCell] = cells.splice(input.cell_index, 1);
|
|
73122
|
+
cells.splice(input.target_index, 0, movedCell);
|
|
73123
|
+
notebook.cells = cells;
|
|
73124
|
+
writeFileSync10(notebookPath, JSON.stringify(notebook, null, 1), "utf-8");
|
|
73125
|
+
return { data: { success: true, message: `Moved cell from index ${input.cell_index} to index ${input.target_index}` } };
|
|
73126
|
+
}
|
|
73127
|
+
case "change_cell_type": {
|
|
73128
|
+
if (input.cell_index == null) return { data: { success: false, error: "change_cell_type requires cell_index" } };
|
|
73129
|
+
if (!input.cell_type) return { data: { success: false, error: "change_cell_type requires cell_type" } };
|
|
73130
|
+
if (input.cell_index < 0 || input.cell_index >= totalCells) {
|
|
73131
|
+
return { data: { success: false, error: `cell_index ${input.cell_index} out of range (0-${totalCells - 1})` } };
|
|
73132
|
+
}
|
|
73133
|
+
const cell = cells[input.cell_index];
|
|
73134
|
+
const oldType = cell.cell_type;
|
|
73135
|
+
if (oldType === input.cell_type) {
|
|
73136
|
+
return { data: { success: true, message: `Cell ${input.cell_index} is already type ${input.cell_type}` } };
|
|
73137
|
+
}
|
|
73138
|
+
cell.cell_type = input.cell_type;
|
|
73139
|
+
if (input.cell_type === "code") {
|
|
73140
|
+
if (!("execution_count" in cell)) cell.execution_count = null;
|
|
73141
|
+
if (!("outputs" in cell)) cell.outputs = [];
|
|
73142
|
+
}
|
|
73143
|
+
if (oldType === "code" && input.cell_type !== "code") {
|
|
73144
|
+
delete cell.execution_count;
|
|
73145
|
+
delete cell.outputs;
|
|
73146
|
+
}
|
|
73147
|
+
writeFileSync10(notebookPath, JSON.stringify(notebook, null, 1), "utf-8");
|
|
73148
|
+
return { data: { success: true, message: `Changed cell ${input.cell_index} from ${oldType} to ${input.cell_type}` } };
|
|
73149
|
+
}
|
|
73150
|
+
default:
|
|
73151
|
+
return { data: { success: false, error: `Unknown command: ${input.command}` } };
|
|
71947
73152
|
}
|
|
71948
|
-
return { data: { success: false, error: "Cell index out of range" } };
|
|
71949
73153
|
} catch (e) {
|
|
71950
73154
|
return { data: { success: false, error: String(e) } };
|
|
71951
73155
|
}
|
|
71952
73156
|
},
|
|
71953
73157
|
mapResult(result, id) {
|
|
71954
|
-
return {
|
|
73158
|
+
return {
|
|
73159
|
+
type: "tool_result",
|
|
73160
|
+
tool_use_id: id,
|
|
73161
|
+
content: result.success ? result.message : `Error: ${result.error}`,
|
|
73162
|
+
...result.success ? {} : { is_error: true }
|
|
73163
|
+
};
|
|
71955
73164
|
}
|
|
71956
73165
|
});
|
|
71957
73166
|
configTool = simpleTool({
|
|
@@ -78249,9 +79458,9 @@ var init_protocol = __esm({
|
|
|
78249
79458
|
});
|
|
78250
79459
|
this.setRequestHandler(ListTasksRequestSchema, async (request, extra) => {
|
|
78251
79460
|
try {
|
|
78252
|
-
const { tasks, nextCursor } = await this._taskStore.listTasks(request.params?.cursor, extra.sessionId);
|
|
79461
|
+
const { tasks: tasks2, nextCursor } = await this._taskStore.listTasks(request.params?.cursor, extra.sessionId);
|
|
78253
79462
|
return {
|
|
78254
|
-
tasks,
|
|
79463
|
+
tasks: tasks2,
|
|
78255
79464
|
nextCursor,
|
|
78256
79465
|
_meta: {}
|
|
78257
79466
|
};
|
|
@@ -88942,6 +90151,13 @@ async function connectMcpServers(configs, batchSize = DEFAULT_BATCH_SIZE) {
|
|
|
88942
90151
|
}
|
|
88943
90152
|
return results;
|
|
88944
90153
|
}
|
|
90154
|
+
function getServerClient(name) {
|
|
90155
|
+
const server = connectedServers.get(name);
|
|
90156
|
+
return server?.client ?? null;
|
|
90157
|
+
}
|
|
90158
|
+
function getConnectedServerNames() {
|
|
90159
|
+
return [...connectedServers.keys()];
|
|
90160
|
+
}
|
|
88945
90161
|
function wrapMcpTool(serverName, mcpTool, client) {
|
|
88946
90162
|
const toolName = `mcp__${serverName}__${mcpTool.name}`;
|
|
88947
90163
|
return {
|
|
@@ -89027,6 +90243,239 @@ var init_client4 = __esm({
|
|
|
89027
90243
|
}
|
|
89028
90244
|
});
|
|
89029
90245
|
|
|
90246
|
+
// src/tools/builtin/mcp-resources.ts
|
|
90247
|
+
var ListMcpResourcesInputSchema, ListMcpResourcesOutputSchema, listMcpResourcesTool, LIST_MCP_RESOURCES_PROMPT, ReadMcpResourceInputSchema, ReadMcpResourceOutputSchema, readMcpResourceTool, READ_MCP_RESOURCE_PROMPT;
|
|
90248
|
+
var init_mcp_resources = __esm({
|
|
90249
|
+
"src/tools/builtin/mcp-resources.ts"() {
|
|
90250
|
+
"use strict";
|
|
90251
|
+
init_zod();
|
|
90252
|
+
init_constants();
|
|
90253
|
+
init_client4();
|
|
90254
|
+
ListMcpResourcesInputSchema = external_exports.strictObject({});
|
|
90255
|
+
ListMcpResourcesOutputSchema = external_exports.object({
|
|
90256
|
+
resources: external_exports.array(external_exports.object({
|
|
90257
|
+
server: external_exports.string(),
|
|
90258
|
+
uri: external_exports.string(),
|
|
90259
|
+
name: external_exports.string(),
|
|
90260
|
+
description: external_exports.string().optional(),
|
|
90261
|
+
mimeType: external_exports.string().optional()
|
|
90262
|
+
})),
|
|
90263
|
+
totalCount: external_exports.number()
|
|
90264
|
+
});
|
|
90265
|
+
listMcpResourcesTool = {
|
|
90266
|
+
name: LIST_MCP_RESOURCES_TOOL,
|
|
90267
|
+
searchHint: "list MCP server resources",
|
|
90268
|
+
maxResultSizeChars: DEFAULT_MAX_RESULT_SIZE_CHARS,
|
|
90269
|
+
shouldDefer: true,
|
|
90270
|
+
async description() {
|
|
90271
|
+
return "List all resources available from connected MCP servers.";
|
|
90272
|
+
},
|
|
90273
|
+
async prompt() {
|
|
90274
|
+
return LIST_MCP_RESOURCES_PROMPT;
|
|
90275
|
+
},
|
|
90276
|
+
get inputSchema() {
|
|
90277
|
+
return ListMcpResourcesInputSchema;
|
|
90278
|
+
},
|
|
90279
|
+
get outputSchema() {
|
|
90280
|
+
return ListMcpResourcesOutputSchema;
|
|
90281
|
+
},
|
|
90282
|
+
userFacingName() {
|
|
90283
|
+
return "List MCP Resources";
|
|
90284
|
+
},
|
|
90285
|
+
isEnabled() {
|
|
90286
|
+
return true;
|
|
90287
|
+
},
|
|
90288
|
+
isConcurrencySafe() {
|
|
90289
|
+
return true;
|
|
90290
|
+
},
|
|
90291
|
+
isReadOnly() {
|
|
90292
|
+
return true;
|
|
90293
|
+
},
|
|
90294
|
+
toAutoClassifierInput() {
|
|
90295
|
+
return "list mcp resources";
|
|
90296
|
+
},
|
|
90297
|
+
async validateInput() {
|
|
90298
|
+
return { result: true };
|
|
90299
|
+
},
|
|
90300
|
+
async checkPermissions() {
|
|
90301
|
+
return { behavior: "allow" };
|
|
90302
|
+
},
|
|
90303
|
+
async call(_input, _context) {
|
|
90304
|
+
const serverNames = getConnectedServerNames();
|
|
90305
|
+
const resources = [];
|
|
90306
|
+
for (const serverName of serverNames) {
|
|
90307
|
+
const client = getServerClient(serverName);
|
|
90308
|
+
if (!client) continue;
|
|
90309
|
+
try {
|
|
90310
|
+
const result = await client.listResources();
|
|
90311
|
+
if (result.resources && Array.isArray(result.resources)) {
|
|
90312
|
+
for (const res of result.resources) {
|
|
90313
|
+
resources.push({
|
|
90314
|
+
server: serverName,
|
|
90315
|
+
uri: res.uri,
|
|
90316
|
+
name: res.name,
|
|
90317
|
+
description: res.description,
|
|
90318
|
+
mimeType: res.mimeType
|
|
90319
|
+
});
|
|
90320
|
+
}
|
|
90321
|
+
}
|
|
90322
|
+
} catch {
|
|
90323
|
+
}
|
|
90324
|
+
}
|
|
90325
|
+
return {
|
|
90326
|
+
data: {
|
|
90327
|
+
resources,
|
|
90328
|
+
totalCount: resources.length
|
|
90329
|
+
}
|
|
90330
|
+
};
|
|
90331
|
+
},
|
|
90332
|
+
mapToolResultToToolResultBlockParam(result, toolUseId) {
|
|
90333
|
+
if (result.resources.length === 0) {
|
|
90334
|
+
return {
|
|
90335
|
+
type: "tool_result",
|
|
90336
|
+
tool_use_id: toolUseId,
|
|
90337
|
+
content: "No resources found from any connected MCP server."
|
|
90338
|
+
};
|
|
90339
|
+
}
|
|
90340
|
+
const lines = result.resources.map((r) => {
|
|
90341
|
+
let line = `[${r.server}] ${r.uri} \u2014 ${r.name}`;
|
|
90342
|
+
if (r.description) line += ` (${r.description})`;
|
|
90343
|
+
if (r.mimeType) line += ` [${r.mimeType}]`;
|
|
90344
|
+
return line;
|
|
90345
|
+
});
|
|
90346
|
+
return {
|
|
90347
|
+
type: "tool_result",
|
|
90348
|
+
tool_use_id: toolUseId,
|
|
90349
|
+
content: `Found ${result.totalCount} resource(s):
|
|
90350
|
+
|
|
90351
|
+
${lines.join("\n")}`
|
|
90352
|
+
};
|
|
90353
|
+
}
|
|
90354
|
+
};
|
|
90355
|
+
LIST_MCP_RESOURCES_PROMPT = `List all resources available from connected MCP servers.
|
|
90356
|
+
- Returns resources with server name, URI, name, description, and MIME type
|
|
90357
|
+
- No input required \u2014 queries all connected servers
|
|
90358
|
+
- Use ReadMcpResourceTool to read a specific resource by server name and URI`;
|
|
90359
|
+
ReadMcpResourceInputSchema = external_exports.strictObject({
|
|
90360
|
+
server_name: external_exports.string().describe("The name of the MCP server that owns the resource"),
|
|
90361
|
+
uri: external_exports.string().describe("The URI of the resource to read")
|
|
90362
|
+
});
|
|
90363
|
+
ReadMcpResourceOutputSchema = external_exports.object({
|
|
90364
|
+
contents: external_exports.array(external_exports.object({
|
|
90365
|
+
uri: external_exports.string(),
|
|
90366
|
+
mimeType: external_exports.string().optional(),
|
|
90367
|
+
text: external_exports.string().optional(),
|
|
90368
|
+
blob: external_exports.string().optional()
|
|
90369
|
+
}))
|
|
90370
|
+
});
|
|
90371
|
+
readMcpResourceTool = {
|
|
90372
|
+
name: READ_MCP_RESOURCE_TOOL,
|
|
90373
|
+
searchHint: "read MCP server resource by URI",
|
|
90374
|
+
maxResultSizeChars: DEFAULT_MAX_RESULT_SIZE_CHARS,
|
|
90375
|
+
shouldDefer: true,
|
|
90376
|
+
async description(input) {
|
|
90377
|
+
return input?.uri ? `Read MCP resource: ${input.uri}` : "Read a resource from a connected MCP server.";
|
|
90378
|
+
},
|
|
90379
|
+
async prompt() {
|
|
90380
|
+
return READ_MCP_RESOURCE_PROMPT;
|
|
90381
|
+
},
|
|
90382
|
+
get inputSchema() {
|
|
90383
|
+
return ReadMcpResourceInputSchema;
|
|
90384
|
+
},
|
|
90385
|
+
get outputSchema() {
|
|
90386
|
+
return ReadMcpResourceOutputSchema;
|
|
90387
|
+
},
|
|
90388
|
+
userFacingName() {
|
|
90389
|
+
return "Read MCP Resource";
|
|
90390
|
+
},
|
|
90391
|
+
isEnabled() {
|
|
90392
|
+
return true;
|
|
90393
|
+
},
|
|
90394
|
+
isConcurrencySafe() {
|
|
90395
|
+
return true;
|
|
90396
|
+
},
|
|
90397
|
+
isReadOnly() {
|
|
90398
|
+
return true;
|
|
90399
|
+
},
|
|
90400
|
+
toAutoClassifierInput(input) {
|
|
90401
|
+
return `${input.server_name} ${input.uri}`;
|
|
90402
|
+
},
|
|
90403
|
+
async validateInput(input) {
|
|
90404
|
+
if (!input.server_name?.trim()) {
|
|
90405
|
+
return { result: false, message: "server_name is required", errorCode: 1 };
|
|
90406
|
+
}
|
|
90407
|
+
if (!input.uri?.trim()) {
|
|
90408
|
+
return { result: false, message: "uri is required", errorCode: 2 };
|
|
90409
|
+
}
|
|
90410
|
+
return { result: true };
|
|
90411
|
+
},
|
|
90412
|
+
async checkPermissions() {
|
|
90413
|
+
return { behavior: "allow" };
|
|
90414
|
+
},
|
|
90415
|
+
async call(input, _context) {
|
|
90416
|
+
const client = getServerClient(input.server_name);
|
|
90417
|
+
if (!client) {
|
|
90418
|
+
return {
|
|
90419
|
+
data: {
|
|
90420
|
+
contents: [{
|
|
90421
|
+
uri: input.uri,
|
|
90422
|
+
text: `Error: MCP server "${input.server_name}" is not connected. Use ListMcpResourcesTool to see available servers.`
|
|
90423
|
+
}]
|
|
90424
|
+
}
|
|
90425
|
+
};
|
|
90426
|
+
}
|
|
90427
|
+
try {
|
|
90428
|
+
const result = await client.readResource({ uri: input.uri });
|
|
90429
|
+
const contents = (result.contents ?? []).map((c) => ({
|
|
90430
|
+
uri: c.uri ?? input.uri,
|
|
90431
|
+
mimeType: c.mimeType,
|
|
90432
|
+
text: c.text,
|
|
90433
|
+
blob: c.blob
|
|
90434
|
+
}));
|
|
90435
|
+
return { data: { contents } };
|
|
90436
|
+
} catch (error2) {
|
|
90437
|
+
return {
|
|
90438
|
+
data: {
|
|
90439
|
+
contents: [{
|
|
90440
|
+
uri: input.uri,
|
|
90441
|
+
text: `Error reading resource: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
90442
|
+
}]
|
|
90443
|
+
}
|
|
90444
|
+
};
|
|
90445
|
+
}
|
|
90446
|
+
},
|
|
90447
|
+
mapToolResultToToolResultBlockParam(result, toolUseId) {
|
|
90448
|
+
if (result.contents.length === 0) {
|
|
90449
|
+
return {
|
|
90450
|
+
type: "tool_result",
|
|
90451
|
+
tool_use_id: toolUseId,
|
|
90452
|
+
content: "Resource returned no content."
|
|
90453
|
+
};
|
|
90454
|
+
}
|
|
90455
|
+
const parts = [];
|
|
90456
|
+
for (const c of result.contents) {
|
|
90457
|
+
if (c.text) {
|
|
90458
|
+
parts.push(c.text);
|
|
90459
|
+
} else if (c.blob) {
|
|
90460
|
+
parts.push(`[base64 blob, ${c.blob.length} chars]${c.mimeType ? ` (${c.mimeType})` : ""}`);
|
|
90461
|
+
} else {
|
|
90462
|
+
parts.push(`[empty content for ${c.uri}]`);
|
|
90463
|
+
}
|
|
90464
|
+
}
|
|
90465
|
+
return {
|
|
90466
|
+
type: "tool_result",
|
|
90467
|
+
tool_use_id: toolUseId,
|
|
90468
|
+
content: parts.join("\n\n")
|
|
90469
|
+
};
|
|
90470
|
+
}
|
|
90471
|
+
};
|
|
90472
|
+
READ_MCP_RESOURCE_PROMPT = `Read a resource from a connected MCP server.
|
|
90473
|
+
- Requires server_name (the MCP server name) and uri (the resource URI)
|
|
90474
|
+
- Use ListMcpResourcesTool first to discover available resources
|
|
90475
|
+
- Returns text content or base64-encoded binary data`;
|
|
90476
|
+
}
|
|
90477
|
+
});
|
|
90478
|
+
|
|
89030
90479
|
// src/mcp/handlers.ts
|
|
89031
90480
|
function mcpToolsToHandlers() {
|
|
89032
90481
|
const mcpTools2 = getMcpTools();
|
|
@@ -89115,51 +90564,61 @@ var init_init = __esm({
|
|
|
89115
90564
|
});
|
|
89116
90565
|
|
|
89117
90566
|
// src/core/team.ts
|
|
89118
|
-
import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, existsSync as existsSync14, mkdirSync as mkdirSync7 } from "fs";
|
|
89119
|
-
import { join as join8 } from "path";
|
|
89120
90567
|
function createTeam(name, description) {
|
|
89121
|
-
const
|
|
90568
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
90569
|
+
dbRun(
|
|
90570
|
+
`INSERT OR IGNORE INTO teams (name, description, task_list_id, created_at) VALUES (?, ?, ?, ?)`,
|
|
90571
|
+
[name, description ?? null, name, now]
|
|
90572
|
+
);
|
|
90573
|
+
return {
|
|
89122
90574
|
name,
|
|
89123
90575
|
description,
|
|
89124
|
-
createdAt:
|
|
90576
|
+
createdAt: now,
|
|
89125
90577
|
members: [],
|
|
89126
90578
|
taskListId: name
|
|
89127
90579
|
};
|
|
89128
|
-
const teamsDir = getTeamsDir();
|
|
89129
|
-
writeFileSync8(join8(teamsDir, `${name}.json`), JSON.stringify(team, null, 2), "utf-8");
|
|
89130
|
-
const taskDir = join8(getTasksDir(), name);
|
|
89131
|
-
if (!existsSync14(taskDir)) mkdirSync7(taskDir, { recursive: true });
|
|
89132
|
-
return team;
|
|
89133
90580
|
}
|
|
89134
90581
|
function getTeam(name) {
|
|
89135
|
-
const
|
|
89136
|
-
if (!
|
|
89137
|
-
|
|
89138
|
-
|
|
89139
|
-
|
|
89140
|
-
|
|
89141
|
-
|
|
90582
|
+
const row = dbGet(`SELECT * FROM teams WHERE name = ?`, [name]);
|
|
90583
|
+
if (!row) return null;
|
|
90584
|
+
const members = dbAll(
|
|
90585
|
+
`SELECT * FROM team_members WHERE team_name = ?`,
|
|
90586
|
+
[name]
|
|
90587
|
+
);
|
|
90588
|
+
return {
|
|
90589
|
+
name: row.name,
|
|
90590
|
+
description: row.description ?? void 0,
|
|
90591
|
+
createdAt: row.created_at ?? "",
|
|
90592
|
+
taskListId: row.task_list_id ?? row.name,
|
|
90593
|
+
members: members.map((m) => ({
|
|
90594
|
+
name: m.agent_name,
|
|
90595
|
+
agentId: m.agent_name,
|
|
90596
|
+
role: m.role ?? void 0,
|
|
90597
|
+
status: m.status ?? "idle",
|
|
90598
|
+
currentTask: m.current_task ?? void 0
|
|
90599
|
+
}))
|
|
90600
|
+
};
|
|
89142
90601
|
}
|
|
89143
90602
|
function addTeamMember(teamName, member) {
|
|
89144
|
-
|
|
89145
|
-
|
|
89146
|
-
|
|
89147
|
-
|
|
89148
|
-
|
|
90603
|
+
dbRun(
|
|
90604
|
+
`DELETE FROM team_members WHERE team_name = ? AND agent_name = ?`,
|
|
90605
|
+
[teamName, member.name]
|
|
90606
|
+
);
|
|
90607
|
+
dbRun(
|
|
90608
|
+
`INSERT INTO team_members (team_name, agent_name, role, status, current_task) VALUES (?, ?, ?, ?, ?)`,
|
|
90609
|
+
[teamName, member.name, member.role ?? null, member.status, member.currentTask ?? null]
|
|
90610
|
+
);
|
|
89149
90611
|
}
|
|
89150
90612
|
function updateMemberStatus(teamName, memberName, status) {
|
|
89151
|
-
|
|
89152
|
-
|
|
89153
|
-
|
|
89154
|
-
|
|
89155
|
-
member.status = status;
|
|
89156
|
-
writeFileSync8(join8(getTeamsDir(), `${teamName}.json`), JSON.stringify(team, null, 2), "utf-8");
|
|
89157
|
-
}
|
|
90613
|
+
dbRun(
|
|
90614
|
+
`UPDATE team_members SET status = ? WHERE team_name = ? AND agent_name = ?`,
|
|
90615
|
+
[status, teamName, memberName]
|
|
90616
|
+
);
|
|
89158
90617
|
}
|
|
89159
90618
|
var init_team = __esm({
|
|
89160
90619
|
"src/core/team.ts"() {
|
|
89161
90620
|
"use strict";
|
|
89162
|
-
|
|
90621
|
+
init_db();
|
|
89163
90622
|
}
|
|
89164
90623
|
});
|
|
89165
90624
|
|
|
@@ -90163,6 +91622,7 @@ __export(app_exports, {
|
|
|
90163
91622
|
launchInkApp: () => launchInkApp,
|
|
90164
91623
|
runHeadless: () => runHeadless
|
|
90165
91624
|
});
|
|
91625
|
+
import { execSync as execSync4 } from "child_process";
|
|
90166
91626
|
function useSpinner(active) {
|
|
90167
91627
|
const [i, setI] = (0, import_react22.useState)(0);
|
|
90168
91628
|
(0, import_react22.useEffect)(() => {
|
|
@@ -90185,6 +91645,8 @@ function createToolHandlers(mcpHandlers) {
|
|
|
90185
91645
|
taskGetTool,
|
|
90186
91646
|
taskListTool,
|
|
90187
91647
|
taskUpdateTool,
|
|
91648
|
+
taskOutputTool,
|
|
91649
|
+
taskStopTool,
|
|
90188
91650
|
askUserQuestionTool,
|
|
90189
91651
|
webSearchTool,
|
|
90190
91652
|
webFetchTool,
|
|
@@ -90199,49 +91661,75 @@ function createToolHandlers(mcpHandlers) {
|
|
|
90199
91661
|
exitWorktreeTool,
|
|
90200
91662
|
notebookEditTool,
|
|
90201
91663
|
configTool,
|
|
90202
|
-
sendMessageTool
|
|
91664
|
+
sendMessageTool,
|
|
91665
|
+
listMcpResourcesTool,
|
|
91666
|
+
readMcpResourceTool,
|
|
91667
|
+
skillTool
|
|
90203
91668
|
];
|
|
90204
|
-
const permCtx = createDefaultPermissionContext();
|
|
91669
|
+
const permCtx = createDefaultPermissionContext(getSettings());
|
|
90205
91670
|
const appState = { toolPermissionContext: permCtx, verbose: false };
|
|
90206
|
-
const
|
|
90207
|
-
|
|
90208
|
-
|
|
90209
|
-
|
|
90210
|
-
|
|
90211
|
-
|
|
90212
|
-
|
|
90213
|
-
|
|
90214
|
-
|
|
90215
|
-
|
|
90216
|
-
|
|
90217
|
-
|
|
90218
|
-
|
|
90219
|
-
|
|
90220
|
-
options: { mainLoopModel: "sonnet", thinkingConfig: { type: "disabled" }, isNonInteractiveSession: false, tools: [], agentDefinitions: { activeAgents: [] } }
|
|
90221
|
-
};
|
|
90222
|
-
const result = await tool.call(input, toolCtx);
|
|
90223
|
-
const block2 = tool.mapToolResultToToolResultBlockParam(result.data, ctx.toolUseId ?? "");
|
|
90224
|
-
const dur = performance.now() - t0;
|
|
91671
|
+
const immediate = [];
|
|
91672
|
+
const all = [];
|
|
91673
|
+
const deferredInfo = [];
|
|
91674
|
+
const deferredSchemas = /* @__PURE__ */ new Map();
|
|
91675
|
+
for (const tool of tools) {
|
|
91676
|
+
const handler = {
|
|
91677
|
+
name: tool.name,
|
|
91678
|
+
description: TOOL_DESCRIPTIONS[tool.name] ?? `Tool: ${tool.name}`,
|
|
91679
|
+
inputSchema: TOOL_JSON_SCHEMAS[tool.name] ?? { type: "object", properties: {} },
|
|
91680
|
+
isReadOnly: tool.isReadOnly(),
|
|
91681
|
+
isConcurrencySafe: tool.isConcurrencySafe(),
|
|
91682
|
+
call: async (input, ctx) => {
|
|
91683
|
+
const summary = toolSummary(tool.name, input);
|
|
91684
|
+
const t0 = performance.now();
|
|
90225
91685
|
try {
|
|
90226
|
-
|
|
90227
|
-
|
|
90228
|
-
|
|
90229
|
-
|
|
90230
|
-
|
|
90231
|
-
|
|
90232
|
-
|
|
90233
|
-
|
|
90234
|
-
|
|
90235
|
-
|
|
91686
|
+
const toolCtx = {
|
|
91687
|
+
abortController: new AbortController(),
|
|
91688
|
+
getAppState: () => appState,
|
|
91689
|
+
setAppState: (fn) => Object.assign(appState, fn(appState)),
|
|
91690
|
+
options: { mainLoopModel: "sonnet", thinkingConfig: { type: "disabled" }, isNonInteractiveSession: false, tools: [], agentDefinitions: { activeAgents: [] } }
|
|
91691
|
+
};
|
|
91692
|
+
const result = await tool.call(input, toolCtx);
|
|
91693
|
+
const block2 = tool.mapToolResultToToolResultBlockParam(result.data, ctx.toolUseId ?? "");
|
|
91694
|
+
const dur = performance.now() - t0;
|
|
91695
|
+
try {
|
|
91696
|
+
dbRun("INSERT INTO audit_log (tool_name, input_summary, result_summary, duration_ms, was_allowed) VALUES (?, ?, ?, ?, 1)", [tool.name, summary, block2.content.slice(0, 200), dur]);
|
|
91697
|
+
} catch {
|
|
91698
|
+
}
|
|
91699
|
+
return block2.is_error ? { data: block2.content, error: block2.content, isError: true } : { data: block2.content };
|
|
91700
|
+
} catch (err) {
|
|
91701
|
+
const dur = performance.now() - t0;
|
|
91702
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
91703
|
+
try {
|
|
91704
|
+
dbRun("INSERT INTO audit_log (tool_name, input_summary, result_summary, duration_ms, was_allowed) VALUES (?, ?, ?, ?, 1)", [tool.name, summary, errMsg.slice(0, 200), dur]);
|
|
91705
|
+
} catch {
|
|
91706
|
+
}
|
|
91707
|
+
return { error: errMsg, isError: true };
|
|
90236
91708
|
}
|
|
90237
|
-
return { error: errMsg, isError: true };
|
|
90238
91709
|
}
|
|
91710
|
+
};
|
|
91711
|
+
all.push(handler);
|
|
91712
|
+
if (tool.shouldDefer) {
|
|
91713
|
+
deferredInfo.push({
|
|
91714
|
+
name: tool.name,
|
|
91715
|
+
description: TOOL_DESCRIPTIONS[tool.name] ?? tool.searchHint
|
|
91716
|
+
});
|
|
91717
|
+
deferredSchemas.set(tool.name, {
|
|
91718
|
+
name: tool.name,
|
|
91719
|
+
description: TOOL_DESCRIPTIONS[tool.name] ?? tool.searchHint,
|
|
91720
|
+
inputSchema: TOOL_JSON_SCHEMAS[tool.name] ?? { type: "object", properties: {} }
|
|
91721
|
+
});
|
|
91722
|
+
} else {
|
|
91723
|
+
immediate.push(handler);
|
|
90239
91724
|
}
|
|
90240
|
-
}
|
|
91725
|
+
}
|
|
90241
91726
|
if (mcpHandlers && mcpHandlers.length > 0) {
|
|
90242
|
-
|
|
91727
|
+
for (const h of mcpHandlers) {
|
|
91728
|
+
immediate.push(h);
|
|
91729
|
+
all.push(h);
|
|
91730
|
+
}
|
|
90243
91731
|
}
|
|
90244
|
-
return
|
|
91732
|
+
return { immediate, all, deferredInfo, deferredSchemas };
|
|
90245
91733
|
}
|
|
90246
91734
|
function shortPath(p) {
|
|
90247
91735
|
if (!p) return "";
|
|
@@ -90304,11 +91792,21 @@ function toolSummary(name, input) {
|
|
|
90304
91792
|
case "ExitWorktree":
|
|
90305
91793
|
return String(input.action ?? "");
|
|
90306
91794
|
case "NotebookEdit":
|
|
90307
|
-
return shortPath(String(input.notebook_path ?? ""));
|
|
91795
|
+
return `${input.command ?? ""} ${shortPath(String(input.notebook_path ?? ""))}`.trim();
|
|
90308
91796
|
case "Config":
|
|
90309
91797
|
return String(input.setting ?? "");
|
|
90310
91798
|
case "SendMessage":
|
|
90311
91799
|
return `to:${input.to ?? ""}`;
|
|
91800
|
+
case "TaskOutput":
|
|
91801
|
+
return String(input.task_id ?? "");
|
|
91802
|
+
case "TaskStop":
|
|
91803
|
+
return String(input.task_id ?? "");
|
|
91804
|
+
case "ListMcpResourcesTool":
|
|
91805
|
+
return "";
|
|
91806
|
+
case "ReadMcpResourceTool":
|
|
91807
|
+
return `${input.server_name ?? ""}:${input.uri ?? ""}`.slice(0, 60);
|
|
91808
|
+
case "Skill":
|
|
91809
|
+
return String(input.skill ?? "").slice(0, 50);
|
|
90312
91810
|
default:
|
|
90313
91811
|
return "";
|
|
90314
91812
|
}
|
|
@@ -90317,6 +91815,83 @@ function SpinnerDot() {
|
|
|
90317
91815
|
const f = useSpinner(true);
|
|
90318
91816
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "cyan", children: f });
|
|
90319
91817
|
}
|
|
91818
|
+
function BackgroundTaskItem({ task }) {
|
|
91819
|
+
const spinner = useSpinner(task.status === "running");
|
|
91820
|
+
const icon = task.status === "running" ? spinner : task.status === "completed" ? "\u2713" : "\u2717";
|
|
91821
|
+
const color = task.status === "running" ? "yellow" : task.status === "completed" ? "green" : "red";
|
|
91822
|
+
const now = Date.now();
|
|
91823
|
+
const durationMs = task.endTime ? task.endTime - task.startTime : now - task.startTime;
|
|
91824
|
+
const durSec = Math.round(durationMs / 1e3);
|
|
91825
|
+
const durStr = durSec < 60 ? `${durSec}s` : `${Math.floor(durSec / 60)}m ${durSec % 60}s`;
|
|
91826
|
+
const desc = task.description.length > 40 ? task.description.slice(0, 37) + "..." : task.description;
|
|
91827
|
+
let detail = `${task.status === "running" ? "running" : task.status}`;
|
|
91828
|
+
detail += ` \xB7 ${durStr}`;
|
|
91829
|
+
if (task.exitCode !== void 0 && task.exitCode !== null && task.status !== "running") {
|
|
91830
|
+
detail += ` \xB7 exit ${task.exitCode}`;
|
|
91831
|
+
}
|
|
91832
|
+
if (task.progress?.tokenCount) {
|
|
91833
|
+
detail += ` \xB7 ${fmtTok(task.progress.tokenCount)} tokens`;
|
|
91834
|
+
}
|
|
91835
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { children: [
|
|
91836
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { color, children: [
|
|
91837
|
+
icon,
|
|
91838
|
+
" "
|
|
91839
|
+
] }),
|
|
91840
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { bold: true, children: task.id }),
|
|
91841
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { children: [
|
|
91842
|
+
": ",
|
|
91843
|
+
desc,
|
|
91844
|
+
" "
|
|
91845
|
+
] }),
|
|
91846
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { dimColor: true, children: [
|
|
91847
|
+
"(",
|
|
91848
|
+
detail,
|
|
91849
|
+
")"
|
|
91850
|
+
] })
|
|
91851
|
+
] });
|
|
91852
|
+
}
|
|
91853
|
+
function BackgroundTaskList({ tasks: tasks2 }) {
|
|
91854
|
+
if (tasks2.length === 0) return null;
|
|
91855
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexDirection: "column", children: tasks2.map((t) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BackgroundTaskItem, { task: t }, t.id)) });
|
|
91856
|
+
}
|
|
91857
|
+
function useCustomStatusLine(config2, context) {
|
|
91858
|
+
const [output, setOutput] = (0, import_react22.useState)(null);
|
|
91859
|
+
const lastRunRef = (0, import_react22.useRef)(0);
|
|
91860
|
+
(0, import_react22.useEffect)(() => {
|
|
91861
|
+
if (!config2 || config2.type !== "command") {
|
|
91862
|
+
setOutput(null);
|
|
91863
|
+
return;
|
|
91864
|
+
}
|
|
91865
|
+
const runCommand = () => {
|
|
91866
|
+
try {
|
|
91867
|
+
const stdinData = JSON.stringify({
|
|
91868
|
+
model: context.model,
|
|
91869
|
+
cost: context.cost,
|
|
91870
|
+
tokens: context.tokens,
|
|
91871
|
+
cwd: process.cwd(),
|
|
91872
|
+
version: VERSION
|
|
91873
|
+
});
|
|
91874
|
+
const result = execSync4(config2.command, {
|
|
91875
|
+
timeout: 3e3,
|
|
91876
|
+
input: stdinData,
|
|
91877
|
+
encoding: "utf-8",
|
|
91878
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
91879
|
+
});
|
|
91880
|
+
const trimmed = result.trim();
|
|
91881
|
+
if (trimmed) {
|
|
91882
|
+
setOutput(config2.padding ? trimmed.padEnd(config2.padding) : trimmed);
|
|
91883
|
+
}
|
|
91884
|
+
} catch {
|
|
91885
|
+
setOutput(null);
|
|
91886
|
+
}
|
|
91887
|
+
lastRunRef.current = Date.now();
|
|
91888
|
+
};
|
|
91889
|
+
runCommand();
|
|
91890
|
+
const interval = setInterval(runCommand, 2e3);
|
|
91891
|
+
return () => clearInterval(interval);
|
|
91892
|
+
}, [config2?.command, config2?.padding, context.model, context.cost, context.tokens]);
|
|
91893
|
+
return output;
|
|
91894
|
+
}
|
|
90320
91895
|
function ToolItem({ tool }) {
|
|
90321
91896
|
const f = useSpinner(tool.status === "running");
|
|
90322
91897
|
const icon = tool.status === "running" ? f : "\u25CF";
|
|
@@ -90427,19 +92002,24 @@ function MessageView({ msg }) {
|
|
|
90427
92002
|
] }) })
|
|
90428
92003
|
] });
|
|
90429
92004
|
}
|
|
90430
|
-
function StatusBar({ model, mode, cost, tokens, agentName, teamName, classification }) {
|
|
92005
|
+
function StatusBar({ model, mode, cost, tokens, agentName, teamName, classification, bgTaskCount, customStatusLine }) {
|
|
92006
|
+
if (customStatusLine) {
|
|
92007
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { dimColor: true, children: customStatusLine }) });
|
|
92008
|
+
}
|
|
90431
92009
|
const teamLabel = agentName && teamName ? ` \xB7 ${agentName}@${teamName}` : "";
|
|
90432
92010
|
const intentLabel = classification && classification.intent !== "general" ? ` \xB7 [${classification.intent}]` : "";
|
|
92011
|
+
const bgLabel = bgTaskCount && bgTaskCount > 0 ? ` \xB7 ${bgTaskCount} background task${bgTaskCount > 1 ? "s" : ""}` : "";
|
|
90433
92012
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { dimColor: true, children: [
|
|
90434
92013
|
model,
|
|
90435
|
-
"
|
|
92014
|
+
" \\u00B7 ",
|
|
90436
92015
|
mode,
|
|
90437
|
-
"
|
|
92016
|
+
" \\u00B7 $",
|
|
90438
92017
|
cost.toFixed(4),
|
|
90439
|
-
"
|
|
92018
|
+
" \\u00B7 ",
|
|
90440
92019
|
fmtTok(tokens),
|
|
90441
92020
|
teamLabel,
|
|
90442
|
-
intentLabel
|
|
92021
|
+
intentLabel,
|
|
92022
|
+
bgLabel
|
|
90443
92023
|
] }) });
|
|
90444
92024
|
}
|
|
90445
92025
|
function App2({ model, mode, dangerouslySkipPermissions, initialPrompt, resumedSession, mcpToolHandlers, agentId, agentName, teamName }) {
|
|
@@ -90464,7 +92044,21 @@ function App2({ model, mode, dangerouslySkipPermissions, initialPrompt, resumedS
|
|
|
90464
92044
|
const _rows = stdout?.rows ?? 24;
|
|
90465
92045
|
const [slashSelected, setSlashSelected] = (0, import_react22.useState)(0);
|
|
90466
92046
|
const [lastClassification, setLastClassification] = (0, import_react22.useState)(null);
|
|
92047
|
+
const [bgTasks, setBgTasks] = (0, import_react22.useState)([]);
|
|
90467
92048
|
const appSettings = getSettings();
|
|
92049
|
+
const statusLineConfig = appSettings.statusLine;
|
|
92050
|
+
const customStatusLine = useCustomStatusLine(statusLineConfig, { model, cost, tokens });
|
|
92051
|
+
(0, import_react22.useEffect)(() => {
|
|
92052
|
+
const poll = () => {
|
|
92053
|
+
const running = getRunningTasks();
|
|
92054
|
+
const recent = getRecentlyCompletedTasks(5e3);
|
|
92055
|
+
const all = [...running, ...recent];
|
|
92056
|
+
setBgTasks(all);
|
|
92057
|
+
};
|
|
92058
|
+
poll();
|
|
92059
|
+
const interval = setInterval(poll, 1e3);
|
|
92060
|
+
return () => clearInterval(interval);
|
|
92061
|
+
}, []);
|
|
90468
92062
|
const thinkingConfig = (() => {
|
|
90469
92063
|
if (appSettings.thinking?.enabled) {
|
|
90470
92064
|
return appSettings.thinking.budgetTokens ? { type: "enabled", budget_tokens: appSettings.thinking.budgetTokens } : { type: "enabled" };
|
|
@@ -90581,6 +92175,42 @@ function App2({ model, mode, dangerouslySkipPermissions, initialPrompt, resumedS
|
|
|
90581
92175
|
]);
|
|
90582
92176
|
return;
|
|
90583
92177
|
}
|
|
92178
|
+
if (r.action === "compact") {
|
|
92179
|
+
if (history.length === 0) {
|
|
92180
|
+
setMsgs((p) => [...p, { id: `s${Date.now()}`, role: "system", content: "Nothing to compact \u2014 conversation is empty.", timestamp: Date.now() }]);
|
|
92181
|
+
return;
|
|
92182
|
+
}
|
|
92183
|
+
setMsgs((p) => [...p, { id: `s${Date.now()}`, role: "system", content: "Compacting conversation...", timestamp: Date.now() }]);
|
|
92184
|
+
try {
|
|
92185
|
+
const client = getApiClient();
|
|
92186
|
+
const customInstructions = r.data;
|
|
92187
|
+
const summaryPrompt = customInstructions ? `Summarize the conversation so far in 2-3 concise sentences, focusing on: ${customInstructions}. Include key decisions, files changed, and current state.` : "Summarize the conversation so far in 2-3 concise sentences. Include key decisions, files changed, and current state of the work.";
|
|
92188
|
+
const summaryResponse = await client.createMessage({
|
|
92189
|
+
model,
|
|
92190
|
+
messages: [
|
|
92191
|
+
...history,
|
|
92192
|
+
{ role: "user", content: summaryPrompt }
|
|
92193
|
+
],
|
|
92194
|
+
maxTokens: 1024
|
|
92195
|
+
});
|
|
92196
|
+
const summaryText = summaryResponse.content.filter((b) => b.type === "text").map((b) => b.text).join("\n").trim() || "Conversation compacted.";
|
|
92197
|
+
const summarySystemMsg = {
|
|
92198
|
+
id: `compact${Date.now()}`,
|
|
92199
|
+
role: "system",
|
|
92200
|
+
content: `[Compacted conversation summary]
|
|
92201
|
+
${summaryText}`,
|
|
92202
|
+
timestamp: Date.now()
|
|
92203
|
+
};
|
|
92204
|
+
setMsgs([summarySystemMsg]);
|
|
92205
|
+
setHistory([
|
|
92206
|
+
{ role: "user", content: "Here is a summary of our conversation so far:\n" + summaryText },
|
|
92207
|
+
{ role: "assistant", content: "Understood. I have the context from our previous conversation. How can I help you continue?" }
|
|
92208
|
+
]);
|
|
92209
|
+
} catch (e) {
|
|
92210
|
+
setMsgs((p) => [...p, { id: `e${Date.now()}`, role: "system", content: `Failed to compact: ${e instanceof Error ? e.message : String(e)}`, timestamp: Date.now() }]);
|
|
92211
|
+
}
|
|
92212
|
+
return;
|
|
92213
|
+
}
|
|
90584
92214
|
if (r.output) setMsgs((p) => [...p, { id: `s${Date.now()}`, role: "system", content: r.output, timestamp: Date.now() }]);
|
|
90585
92215
|
if (r.action === "exit") exit();
|
|
90586
92216
|
if (r.action === "clear") {
|
|
@@ -90610,48 +92240,22 @@ function App2({ model, mode, dangerouslySkipPermissions, initialPrompt, resumedS
|
|
|
90610
92240
|
}
|
|
90611
92241
|
const t0 = performance.now();
|
|
90612
92242
|
try {
|
|
90613
|
-
const
|
|
90614
|
-
const permCtx = createDefaultPermissionContext();
|
|
92243
|
+
const toolSplit = createToolHandlers(mcpToolHandlers);
|
|
92244
|
+
const permCtx = createDefaultPermissionContext(getSettings());
|
|
90615
92245
|
const toolStartTimes = /* @__PURE__ */ new Map();
|
|
92246
|
+
setDeferredToolSchemas([...toolSplit.deferredSchemas.values()]);
|
|
90616
92247
|
const classification = classifyPrompt(text);
|
|
90617
92248
|
setLastClassification(classification);
|
|
90618
|
-
const
|
|
90619
|
-
|
|
90620
|
-
"Read",
|
|
90621
|
-
"Edit",
|
|
90622
|
-
"Write",
|
|
90623
|
-
"Glob",
|
|
90624
|
-
"Grep",
|
|
90625
|
-
"Agent",
|
|
90626
|
-
"TaskCreate",
|
|
90627
|
-
"TaskGet",
|
|
90628
|
-
"TaskList",
|
|
90629
|
-
"TaskUpdate",
|
|
90630
|
-
"AskUserQuestion",
|
|
90631
|
-
"WebSearch",
|
|
90632
|
-
"WebFetch",
|
|
90633
|
-
"LSP",
|
|
90634
|
-
"EnterPlanMode",
|
|
90635
|
-
"ExitPlanMode",
|
|
90636
|
-
"ToolSearch",
|
|
90637
|
-
"CronCreate",
|
|
90638
|
-
"CronDelete",
|
|
90639
|
-
"CronList",
|
|
90640
|
-
"EnterWorktree",
|
|
90641
|
-
"ExitWorktree",
|
|
90642
|
-
"NotebookEdit",
|
|
90643
|
-
"Config",
|
|
90644
|
-
"SendMessage"
|
|
90645
|
-
]);
|
|
90646
|
-
const toolHandlers = filterToolsByClassification(allToolHandlers, classification, builtinToolNames);
|
|
92249
|
+
const allBuiltinToolNames = new Set(toolSplit.all.map((h) => h.name));
|
|
92250
|
+
const toolHandlers = filterToolsByClassification(toolSplit.all, classification, allBuiltinToolNames);
|
|
90647
92251
|
try {
|
|
90648
92252
|
dbRun(
|
|
90649
92253
|
"INSERT INTO audit_log (tool_name, input_summary, result_summary, duration_ms, was_allowed) VALUES (?, ?, ?, ?, 1)",
|
|
90650
|
-
["__classifier", text.slice(0, 200), `${classification.intent}: ${classification.reason} (${toolHandlers.length}/${
|
|
92254
|
+
["__classifier", text.slice(0, 200), `${classification.intent}: ${classification.reason} (${toolHandlers.length}/${toolSplit.all.length} tools, ${toolSplit.deferredInfo.length} deferred)`, 0]
|
|
90651
92255
|
);
|
|
90652
92256
|
} catch {
|
|
90653
92257
|
}
|
|
90654
|
-
const
|
|
92258
|
+
const immediateBuiltinTools = [
|
|
90655
92259
|
bashTool,
|
|
90656
92260
|
readTool,
|
|
90657
92261
|
editTool,
|
|
@@ -90659,28 +92263,11 @@ function App2({ model, mode, dangerouslySkipPermissions, initialPrompt, resumedS
|
|
|
90659
92263
|
globTool,
|
|
90660
92264
|
grepTool,
|
|
90661
92265
|
agentTool,
|
|
90662
|
-
taskCreateTool,
|
|
90663
|
-
taskGetTool,
|
|
90664
|
-
taskListTool,
|
|
90665
|
-
taskUpdateTool,
|
|
90666
|
-
askUserQuestionTool,
|
|
90667
|
-
webSearchTool,
|
|
90668
|
-
webFetchTool,
|
|
90669
|
-
lspTool,
|
|
90670
|
-
enterPlanModeTool,
|
|
90671
|
-
exitPlanModeTool,
|
|
90672
92266
|
toolSearchTool,
|
|
90673
|
-
|
|
90674
|
-
|
|
90675
|
-
cronListTool,
|
|
90676
|
-
enterWorktreeTool,
|
|
90677
|
-
exitWorktreeTool,
|
|
90678
|
-
notebookEditTool,
|
|
90679
|
-
configTool,
|
|
90680
|
-
sendMessageTool
|
|
90681
|
-
];
|
|
92267
|
+
skillTool
|
|
92268
|
+
].filter((t) => !t.shouldDefer);
|
|
90682
92269
|
const toolPrompts = await Promise.all(
|
|
90683
|
-
|
|
92270
|
+
immediateBuiltinTools.map(async (t) => ({ name: t.name, prompt: await t.prompt() }))
|
|
90684
92271
|
);
|
|
90685
92272
|
const turnAbort = new AbortController();
|
|
90686
92273
|
abortRef.current = turnAbort;
|
|
@@ -90693,7 +92280,8 @@ function App2({ model, mode, dangerouslySkipPermissions, initialPrompt, resumedS
|
|
|
90693
92280
|
projectDir: process.cwd(),
|
|
90694
92281
|
model,
|
|
90695
92282
|
permissionMode: mode,
|
|
90696
|
-
tools: toolPrompts
|
|
92283
|
+
tools: toolPrompts,
|
|
92284
|
+
deferredTools: toolSplit.deferredInfo
|
|
90697
92285
|
}),
|
|
90698
92286
|
tools: toolHandlers,
|
|
90699
92287
|
model,
|
|
@@ -90709,7 +92297,7 @@ function App2({ model, mode, dangerouslySkipPermissions, initialPrompt, resumedS
|
|
|
90709
92297
|
}
|
|
90710
92298
|
} catch {
|
|
90711
92299
|
}
|
|
90712
|
-
if (dangerouslySkipPermissions) {
|
|
92300
|
+
if (dangerouslySkipPermissions || permCtx.mode === "bypassPermissions") {
|
|
90713
92301
|
return { behavior: "allow" };
|
|
90714
92302
|
}
|
|
90715
92303
|
const ruleResult = checkToolPermission(toolName, toolInput, permCtx);
|
|
@@ -90956,6 +92544,7 @@ function App2({ model, mode, dangerouslySkipPermissions, initialPrompt, resumedS
|
|
|
90956
92544
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { dimColor: true, children: "]lways" })
|
|
90957
92545
|
] })
|
|
90958
92546
|
] }),
|
|
92547
|
+
bgTasks.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BackgroundTaskList, { tasks: bgTasks }),
|
|
90959
92548
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
90960
92549
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { dimColor: true, children: sep }),
|
|
90961
92550
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { children: [
|
|
@@ -90987,7 +92576,7 @@ function App2({ model, mode, dangerouslySkipPermissions, initialPrompt, resumedS
|
|
|
90987
92576
|
] })
|
|
90988
92577
|
] }, cmd.name)) }),
|
|
90989
92578
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { dimColor: true, children: sep }),
|
|
90990
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBar, { model, mode, cost, tokens, agentName: agentName ?? agentId, teamName, classification: lastClassification })
|
|
92579
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBar, { model, mode, cost, tokens, agentName: agentName ?? agentId, teamName, classification: lastClassification, bgTaskCount: bgTasks.filter((t) => t.status === "running").length, customStatusLine })
|
|
90991
92580
|
] })
|
|
90992
92581
|
] })
|
|
90993
92582
|
] });
|
|
@@ -91110,6 +92699,7 @@ var init_app = __esm({
|
|
|
91110
92699
|
init_agent_loop();
|
|
91111
92700
|
init_permissions();
|
|
91112
92701
|
init_db();
|
|
92702
|
+
init_background_tasks();
|
|
91113
92703
|
init_session();
|
|
91114
92704
|
init_system_prompt();
|
|
91115
92705
|
init_bash();
|
|
@@ -91120,17 +92710,21 @@ var init_app = __esm({
|
|
|
91120
92710
|
init_grep();
|
|
91121
92711
|
init_agent();
|
|
91122
92712
|
init_tasks();
|
|
92713
|
+
init_task_output();
|
|
91123
92714
|
init_ask_user();
|
|
91124
92715
|
init_web_search();
|
|
91125
92716
|
init_web_fetch();
|
|
91126
92717
|
init_lsp();
|
|
91127
92718
|
init_plan_mode();
|
|
91128
92719
|
init_misc();
|
|
92720
|
+
init_mcp_resources();
|
|
91129
92721
|
init_registry();
|
|
91130
92722
|
init_init();
|
|
91131
92723
|
init_client4();
|
|
91132
92724
|
init_team();
|
|
91133
92725
|
init_classifier();
|
|
92726
|
+
init_skill();
|
|
92727
|
+
init_registry2();
|
|
91134
92728
|
import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
|
|
91135
92729
|
CONN = "\u23BF";
|
|
91136
92730
|
PROMPT = "\u276F";
|
|
@@ -91366,10 +92960,13 @@ var init_app = __esm({
|
|
|
91366
92960
|
type: "object",
|
|
91367
92961
|
properties: {
|
|
91368
92962
|
notebook_path: { type: "string", description: "Path to the .ipynb file" },
|
|
91369
|
-
|
|
91370
|
-
|
|
92963
|
+
command: { type: "string", enum: ["insert_cell", "replace_cell", "delete_cell", "move_cell", "change_cell_type"], description: "Operation to perform on the notebook" },
|
|
92964
|
+
cell_index: { type: "number", description: "Cell index to operate on (0-based). For insert_cell, position to insert at (omit to append)." },
|
|
92965
|
+
cell_type: { type: "string", enum: ["code", "markdown", "raw"], description: "Cell type \u2014 required for insert_cell and change_cell_type" },
|
|
92966
|
+
new_source: { type: "string", description: "New cell content \u2014 required for insert_cell and replace_cell" },
|
|
92967
|
+
target_index: { type: "number", description: "Destination index for move_cell" }
|
|
91371
92968
|
},
|
|
91372
|
-
required: ["notebook_path", "
|
|
92969
|
+
required: ["notebook_path", "command"]
|
|
91373
92970
|
},
|
|
91374
92971
|
Config: {
|
|
91375
92972
|
type: "object",
|
|
@@ -91386,6 +92983,40 @@ var init_app = __esm({
|
|
|
91386
92983
|
message: { type: "string", description: "Message content" }
|
|
91387
92984
|
},
|
|
91388
92985
|
required: ["to", "message"]
|
|
92986
|
+
},
|
|
92987
|
+
TaskOutput: {
|
|
92988
|
+
type: "object",
|
|
92989
|
+
properties: {
|
|
92990
|
+
task_id: { type: "string", description: "The ID of the background task to check (e.g. 'bg-1', 'agent-2')" }
|
|
92991
|
+
},
|
|
92992
|
+
required: ["task_id"]
|
|
92993
|
+
},
|
|
92994
|
+
TaskStop: {
|
|
92995
|
+
type: "object",
|
|
92996
|
+
properties: {
|
|
92997
|
+
task_id: { type: "string", description: "The ID of the background task to stop (e.g. 'bg-1', 'agent-2')" }
|
|
92998
|
+
},
|
|
92999
|
+
required: ["task_id"]
|
|
93000
|
+
},
|
|
93001
|
+
ListMcpResourcesTool: {
|
|
93002
|
+
type: "object",
|
|
93003
|
+
properties: {}
|
|
93004
|
+
},
|
|
93005
|
+
ReadMcpResourceTool: {
|
|
93006
|
+
type: "object",
|
|
93007
|
+
properties: {
|
|
93008
|
+
server_name: { type: "string", description: "The name of the MCP server that owns the resource" },
|
|
93009
|
+
uri: { type: "string", description: "The URI of the resource to read" }
|
|
93010
|
+
},
|
|
93011
|
+
required: ["server_name", "uri"]
|
|
93012
|
+
},
|
|
93013
|
+
Skill: {
|
|
93014
|
+
type: "object",
|
|
93015
|
+
properties: {
|
|
93016
|
+
skill: { type: "string", description: "The skill name to invoke (e.g. 'commit', 'review-pr')" },
|
|
93017
|
+
args: { type: "string", description: "Optional arguments to pass to the skill prompt" }
|
|
93018
|
+
},
|
|
93019
|
+
required: ["skill"]
|
|
91389
93020
|
}
|
|
91390
93021
|
};
|
|
91391
93022
|
TOOL_DESCRIPTIONS = {
|
|
@@ -91412,9 +93043,14 @@ var init_app = __esm({
|
|
|
91412
93043
|
CronList: "List all active scheduled cron jobs.",
|
|
91413
93044
|
EnterWorktree: "Create an isolated git worktree and switch into it.",
|
|
91414
93045
|
ExitWorktree: "Exit a worktree session, keeping or removing the worktree.",
|
|
91415
|
-
NotebookEdit: "Edit
|
|
93046
|
+
NotebookEdit: "Edit Jupyter notebook cells \u2014 insert, replace, delete, move cells, or change cell type. Preserves all metadata and outputs.",
|
|
91416
93047
|
Config: "Get or set a configuration setting.",
|
|
91417
|
-
SendMessage: "Send a direct message to another agent or to the user."
|
|
93048
|
+
SendMessage: "Send a direct message to another agent or to the user.",
|
|
93049
|
+
TaskOutput: "Check the status and output of a background task (bash or agent).",
|
|
93050
|
+
TaskStop: "Stop a running background task by its ID.",
|
|
93051
|
+
ListMcpResourcesTool: "List all resources available from connected MCP servers.",
|
|
93052
|
+
ReadMcpResourceTool: "Read a resource from a connected MCP server by server name and URI.",
|
|
93053
|
+
Skill: "Execute a skill within the main conversation. Skills are user-defined prompts in .coders/skills/ or .claude/skills/ directories."
|
|
91418
93054
|
};
|
|
91419
93055
|
}
|
|
91420
93056
|
});
|
|
@@ -92233,16 +93869,16 @@ __export(marketplace_exports, {
|
|
|
92233
93869
|
removeMarketplace: () => removeMarketplace,
|
|
92234
93870
|
uninstallPlugin: () => uninstallPlugin
|
|
92235
93871
|
});
|
|
92236
|
-
import { readFileSync as
|
|
92237
|
-
import { join as
|
|
92238
|
-
import { execSync as
|
|
93872
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, existsSync as existsSync17, mkdirSync as mkdirSync8, cpSync, rmSync } from "fs";
|
|
93873
|
+
import { join as join11, resolve as resolve7 } from "path";
|
|
93874
|
+
import { execSync as execSync5 } from "child_process";
|
|
92239
93875
|
import { tmpdir } from "os";
|
|
92240
93876
|
import { randomBytes } from "crypto";
|
|
92241
93877
|
function getMarketplaces() {
|
|
92242
93878
|
const path = getMarketplacesConfigPath();
|
|
92243
|
-
if (!
|
|
93879
|
+
if (!existsSync17(path)) return [];
|
|
92244
93880
|
try {
|
|
92245
|
-
return JSON.parse(
|
|
93881
|
+
return JSON.parse(readFileSync14(path, "utf-8"));
|
|
92246
93882
|
} catch {
|
|
92247
93883
|
return [];
|
|
92248
93884
|
}
|
|
@@ -92262,8 +93898,8 @@ function removeMarketplace(name) {
|
|
|
92262
93898
|
}
|
|
92263
93899
|
function saveMarketplaces(marketplaces) {
|
|
92264
93900
|
const path = getMarketplacesConfigPath();
|
|
92265
|
-
const dir =
|
|
92266
|
-
if (!
|
|
93901
|
+
const dir = join11(path, "..");
|
|
93902
|
+
if (!existsSync17(dir)) mkdirSync8(dir, { recursive: true });
|
|
92267
93903
|
writeFileSync9(path, JSON.stringify(marketplaces, null, 2) + "\n", "utf-8");
|
|
92268
93904
|
}
|
|
92269
93905
|
async function installFromMarketplace(pluginName, marketplaceName) {
|
|
@@ -92287,7 +93923,7 @@ async function installPluginFromMarketplace(name, marketplace) {
|
|
|
92287
93923
|
return installFromGit(gitUrl, pluginsDir);
|
|
92288
93924
|
}
|
|
92289
93925
|
case "directory": {
|
|
92290
|
-
const sourcePath =
|
|
93926
|
+
const sourcePath = join11(marketplace.source, name);
|
|
92291
93927
|
return installFromDirectory(sourcePath, pluginsDir);
|
|
92292
93928
|
}
|
|
92293
93929
|
case "url":
|
|
@@ -92306,10 +93942,10 @@ function installFromSource(source, pluginsDir) {
|
|
|
92306
93942
|
}
|
|
92307
93943
|
function installFromGit(url2, pluginsDir) {
|
|
92308
93944
|
const dir = pluginsDir ?? getPluginsDir();
|
|
92309
|
-
const tempDir =
|
|
93945
|
+
const tempDir = join11(tmpdir(), `coders-plugin-${randomBytes(8).toString("hex")}`);
|
|
92310
93946
|
try {
|
|
92311
93947
|
try {
|
|
92312
|
-
|
|
93948
|
+
execSync5(`git clone --depth 1 ${escapeShellArg(url2)} ${escapeShellArg(tempDir)}`, {
|
|
92313
93949
|
encoding: "utf-8",
|
|
92314
93950
|
stdio: "pipe",
|
|
92315
93951
|
timeout: 6e4
|
|
@@ -92320,21 +93956,21 @@ function installFromGit(url2, pluginsDir) {
|
|
|
92320
93956
|
error: `Failed to clone "${url2}": ${err instanceof Error ? err.message : String(err)}`
|
|
92321
93957
|
};
|
|
92322
93958
|
}
|
|
92323
|
-
const manifestPath =
|
|
92324
|
-
if (!
|
|
93959
|
+
const manifestPath = join11(tempDir, "manifest.json");
|
|
93960
|
+
if (!existsSync17(manifestPath)) {
|
|
92325
93961
|
return { success: false, error: `No manifest.json found in cloned repository "${url2}"` };
|
|
92326
93962
|
}
|
|
92327
93963
|
const validated = validateManifest(manifestPath);
|
|
92328
93964
|
if (!validated.success) return validated;
|
|
92329
93965
|
const pluginName = validated.pluginName;
|
|
92330
|
-
const targetDir =
|
|
92331
|
-
if (
|
|
93966
|
+
const targetDir = join11(dir, pluginName);
|
|
93967
|
+
if (existsSync17(targetDir)) {
|
|
92332
93968
|
return { success: false, error: `Plugin "${pluginName}" is already installed` };
|
|
92333
93969
|
}
|
|
92334
93970
|
mkdirSync8(targetDir, { recursive: true });
|
|
92335
93971
|
cpSync(tempDir, targetDir, {
|
|
92336
93972
|
recursive: true,
|
|
92337
|
-
filter: (src) => !src.includes(
|
|
93973
|
+
filter: (src) => !src.includes(join11(tempDir, ".git"))
|
|
92338
93974
|
});
|
|
92339
93975
|
return {
|
|
92340
93976
|
success: true,
|
|
@@ -92352,18 +93988,18 @@ function installFromGit(url2, pluginsDir) {
|
|
|
92352
93988
|
function installFromDirectory(sourcePath, pluginsDir) {
|
|
92353
93989
|
const dir = pluginsDir ?? getPluginsDir();
|
|
92354
93990
|
const resolvedSource = resolve7(sourcePath);
|
|
92355
|
-
if (!
|
|
93991
|
+
if (!existsSync17(resolvedSource)) {
|
|
92356
93992
|
return { success: false, error: `Source directory does not exist: "${resolvedSource}"` };
|
|
92357
93993
|
}
|
|
92358
|
-
const manifestPath =
|
|
92359
|
-
if (!
|
|
93994
|
+
const manifestPath = join11(resolvedSource, "manifest.json");
|
|
93995
|
+
if (!existsSync17(manifestPath)) {
|
|
92360
93996
|
return { success: false, error: `No manifest.json found in "${resolvedSource}"` };
|
|
92361
93997
|
}
|
|
92362
93998
|
const validated = validateManifest(manifestPath);
|
|
92363
93999
|
if (!validated.success) return validated;
|
|
92364
94000
|
const pluginName = validated.pluginName;
|
|
92365
|
-
const targetDir =
|
|
92366
|
-
if (
|
|
94001
|
+
const targetDir = join11(dir, pluginName);
|
|
94002
|
+
if (existsSync17(targetDir)) {
|
|
92367
94003
|
return { success: false, error: `Plugin "${pluginName}" is already installed` };
|
|
92368
94004
|
}
|
|
92369
94005
|
mkdirSync8(targetDir, { recursive: true });
|
|
@@ -92377,8 +94013,8 @@ function installFromDirectory(sourcePath, pluginsDir) {
|
|
|
92377
94013
|
}
|
|
92378
94014
|
function uninstallPlugin(name, pluginsDir) {
|
|
92379
94015
|
const dir = pluginsDir ?? getPluginsDir();
|
|
92380
|
-
const targetDir =
|
|
92381
|
-
if (!
|
|
94016
|
+
const targetDir = join11(dir, name);
|
|
94017
|
+
if (!existsSync17(targetDir)) return false;
|
|
92382
94018
|
rmSync(targetDir, { recursive: true, force: true });
|
|
92383
94019
|
return true;
|
|
92384
94020
|
}
|
|
@@ -92387,7 +94023,7 @@ function isGitUrl(source) {
|
|
|
92387
94023
|
}
|
|
92388
94024
|
function validateManifest(manifestPath) {
|
|
92389
94025
|
try {
|
|
92390
|
-
const raw = JSON.parse(
|
|
94026
|
+
const raw = JSON.parse(readFileSync14(manifestPath, "utf-8"));
|
|
92391
94027
|
const result = PluginManifestSchema.safeParse(raw);
|
|
92392
94028
|
if (!result.success) {
|
|
92393
94029
|
const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
@@ -92421,8 +94057,8 @@ var main_exports = {};
|
|
|
92421
94057
|
__export(main_exports, {
|
|
92422
94058
|
main: () => main
|
|
92423
94059
|
});
|
|
92424
|
-
import { execSync as
|
|
92425
|
-
import { existsSync as
|
|
94060
|
+
import { execSync as execSync6 } from "child_process";
|
|
94061
|
+
import { existsSync as existsSync18 } from "fs";
|
|
92426
94062
|
function helpConfig() {
|
|
92427
94063
|
return {
|
|
92428
94064
|
sortSubcommands: true,
|
|
@@ -92856,15 +94492,15 @@ ${installed.length} plugin(s) installed`);
|
|
|
92856
94492
|
}
|
|
92857
94493
|
});
|
|
92858
94494
|
plugin.command("install <plugin>").alias("i").description("Install a plugin from a marketplace or local path").option("-s, --scope <scope>", "Installation scope", "user").option("-m, --marketplace <name>", "Marketplace to install from").action(async (source, options2) => {
|
|
92859
|
-
const { resolve: resolve8, join:
|
|
94495
|
+
const { resolve: resolve8, join: join12 } = await import("path");
|
|
92860
94496
|
const { existsSync: pathExists } = await import("fs");
|
|
92861
94497
|
const resolvedPath = resolve8(source);
|
|
92862
|
-
const isLocalDir = pathExists(resolvedPath) && pathExists(
|
|
94498
|
+
const isLocalDir = pathExists(resolvedPath) && pathExists(join12(resolvedPath, "manifest.json"));
|
|
92863
94499
|
if (isLocalDir) {
|
|
92864
94500
|
try {
|
|
92865
|
-
const { readFileSync:
|
|
94501
|
+
const { readFileSync: readFileSync15, cpSync: cpSync2, mkdirSync: mkdirSync9 } = await import("fs");
|
|
92866
94502
|
const { PluginManifestSchema: PluginManifestSchema2 } = await Promise.resolve().then(() => (init_manifest(), manifest_exports));
|
|
92867
|
-
const manifestRaw = JSON.parse(
|
|
94503
|
+
const manifestRaw = JSON.parse(readFileSync15(join12(resolvedPath, "manifest.json"), "utf-8"));
|
|
92868
94504
|
const result = PluginManifestSchema2.safeParse(manifestRaw);
|
|
92869
94505
|
if (!result.success) {
|
|
92870
94506
|
console.error("Error: Invalid plugin manifest:");
|
|
@@ -92875,7 +94511,7 @@ ${installed.length} plugin(s) installed`);
|
|
|
92875
94511
|
}
|
|
92876
94512
|
const pluginName = result.data.name;
|
|
92877
94513
|
const pluginsDir = getPluginsDir();
|
|
92878
|
-
const targetDir =
|
|
94514
|
+
const targetDir = join12(pluginsDir, pluginName);
|
|
92879
94515
|
if (pathExists(targetDir)) {
|
|
92880
94516
|
console.error(`Error: Plugin "${pluginName}" is already installed.`);
|
|
92881
94517
|
console.error("Uninstall it first: coders plugin uninstall " + pluginName);
|
|
@@ -92922,13 +94558,13 @@ ${installed.length} plugin(s) installed`);
|
|
|
92922
94558
|
});
|
|
92923
94559
|
plugin.command("validate <path>").description("Validate a plugin manifest").option("--json", "Output validation result as JSON").action(async (manifestPath, options2) => {
|
|
92924
94560
|
try {
|
|
92925
|
-
const { existsSync: pathExists, readFileSync:
|
|
92926
|
-
const { resolve: resolve8, join:
|
|
94561
|
+
const { existsSync: pathExists, readFileSync: readFileSync15 } = await import("fs");
|
|
94562
|
+
const { resolve: resolve8, join: join12 } = await import("path");
|
|
92927
94563
|
const { PluginManifestSchema: PluginManifestSchema2 } = await Promise.resolve().then(() => (init_manifest(), manifest_exports));
|
|
92928
94564
|
const resolvedPath = resolve8(manifestPath);
|
|
92929
94565
|
let filePath;
|
|
92930
|
-
if (pathExists(
|
|
92931
|
-
filePath =
|
|
94566
|
+
if (pathExists(join12(resolvedPath, "manifest.json"))) {
|
|
94567
|
+
filePath = join12(resolvedPath, "manifest.json");
|
|
92932
94568
|
} else if (pathExists(resolvedPath)) {
|
|
92933
94569
|
filePath = resolvedPath;
|
|
92934
94570
|
} else {
|
|
@@ -92938,7 +94574,7 @@ ${installed.length} plugin(s) installed`);
|
|
|
92938
94574
|
}
|
|
92939
94575
|
let raw;
|
|
92940
94576
|
try {
|
|
92941
|
-
raw = JSON.parse(
|
|
94577
|
+
raw = JSON.parse(readFileSync15(filePath, "utf-8"));
|
|
92942
94578
|
} catch {
|
|
92943
94579
|
console.error(`Error: Could not parse JSON from ${filePath}`);
|
|
92944
94580
|
process.exit(1);
|
|
@@ -93035,8 +94671,8 @@ ${installed.length} plugin(s) installed`);
|
|
|
93035
94671
|
try {
|
|
93036
94672
|
const userSettingsPath = getUserSettingsPath();
|
|
93037
94673
|
const projectSettingsPath = getProjectSettingsPath(process.cwd());
|
|
93038
|
-
const userExists =
|
|
93039
|
-
const projectExists =
|
|
94674
|
+
const userExists = existsSync18(userSettingsPath);
|
|
94675
|
+
const projectExists = existsSync18(projectSettingsPath);
|
|
93040
94676
|
const parts = [];
|
|
93041
94677
|
if (userExists) parts.push("user");
|
|
93042
94678
|
if (projectExists) parts.push("project");
|
|
@@ -93067,7 +94703,7 @@ ${installed.length} plugin(s) installed`);
|
|
|
93067
94703
|
issues++;
|
|
93068
94704
|
}
|
|
93069
94705
|
try {
|
|
93070
|
-
const gitVersion =
|
|
94706
|
+
const gitVersion = execSync6("git --version", { encoding: "utf-8", timeout: 5e3 }).trim();
|
|
93071
94707
|
console.log(` ${ok} Git: ${gitVersion.replace("git version ", "")}`);
|
|
93072
94708
|
} catch {
|
|
93073
94709
|
console.log(` ${fail} Git: not found in PATH`);
|
|
@@ -93075,7 +94711,7 @@ ${installed.length} plugin(s) installed`);
|
|
|
93075
94711
|
}
|
|
93076
94712
|
try {
|
|
93077
94713
|
const pluginsDir = getPluginsDir();
|
|
93078
|
-
const dirExists =
|
|
94714
|
+
const dirExists = existsSync18(pluginsDir);
|
|
93079
94715
|
if (dirExists) {
|
|
93080
94716
|
const discovered = discoverPlugins();
|
|
93081
94717
|
if (discovered.length > 0) {
|
|
@@ -93094,7 +94730,7 @@ ${installed.length} plugin(s) installed`);
|
|
|
93094
94730
|
issues++;
|
|
93095
94731
|
}
|
|
93096
94732
|
try {
|
|
93097
|
-
const rgVersion =
|
|
94733
|
+
const rgVersion = execSync6("rg --version", { encoding: "utf-8", timeout: 5e3 }).split("\n")[0].trim();
|
|
93098
94734
|
console.log(` ${ok} Ripgrep: ${rgVersion.replace("ripgrep ", "")}`);
|
|
93099
94735
|
} catch {
|
|
93100
94736
|
console.log(` ${fail} Ripgrep: not found in PATH (needed for Grep tool)`);
|
|
@@ -93113,7 +94749,7 @@ ${installed.length} plugin(s) installed`);
|
|
|
93113
94749
|
console.log("Checking for updates...\n");
|
|
93114
94750
|
let latestVersion;
|
|
93115
94751
|
try {
|
|
93116
|
-
latestVersion =
|
|
94752
|
+
latestVersion = execSync6(`npm view ${PACKAGE_NAME} version`, {
|
|
93117
94753
|
encoding: "utf-8",
|
|
93118
94754
|
timeout: 15e3,
|
|
93119
94755
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -93157,7 +94793,7 @@ ${installed.length} plugin(s) installed`);
|
|
|
93157
94793
|
}
|
|
93158
94794
|
let installCmd;
|
|
93159
94795
|
try {
|
|
93160
|
-
|
|
94796
|
+
execSync6("bun --version", { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] });
|
|
93161
94797
|
installCmd = `bun install -g ${PACKAGE_NAME}@latest`;
|
|
93162
94798
|
} catch {
|
|
93163
94799
|
installCmd = `npm install -g ${PACKAGE_NAME}@latest`;
|
|
@@ -93165,7 +94801,7 @@ ${installed.length} plugin(s) installed`);
|
|
|
93165
94801
|
console.log(`Running: ${installCmd}
|
|
93166
94802
|
`);
|
|
93167
94803
|
try {
|
|
93168
|
-
|
|
94804
|
+
execSync6(installCmd, { encoding: "utf-8", timeout: 12e4, stdio: "inherit" });
|
|
93169
94805
|
console.log(`
|
|
93170
94806
|
Successfully updated to v${latestVersion}.`);
|
|
93171
94807
|
} catch (err) {
|
|
@@ -93433,7 +95069,7 @@ var VERSION, BUILD_TIME, PACKAGE_NAME, ISSUES_URL, startupTimestamps, originalCw
|
|
|
93433
95069
|
var init_index = __esm({
|
|
93434
95070
|
"src/cli/index.ts"() {
|
|
93435
95071
|
VERSION = "0.1.2";
|
|
93436
|
-
BUILD_TIME = "2026-03-
|
|
95072
|
+
BUILD_TIME = "2026-03-21T05:56:28.429Z";
|
|
93437
95073
|
PACKAGE_NAME = "@hasna/coders";
|
|
93438
95074
|
ISSUES_URL = "https://github.com/hasnaxyz/open-coders/issues";
|
|
93439
95075
|
startupTimestamps = {};
|