@robota-sdk/agent-sdk 3.0.0-beta.34 → 3.0.0-beta.35

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.
@@ -686,7 +686,7 @@ function resolveSubagentLogDir(parentSessionId, baseLogsDir) {
686
686
 
687
687
  // src/index.ts
688
688
  import { Session as Session3 } from "@robota-sdk/agent-sessions";
689
- import { FileSessionLogger as FileSessionLogger2, SilentSessionLogger } from "@robota-sdk/agent-sessions";
689
+ import { FileSessionLogger as FileSessionLogger3, SilentSessionLogger } from "@robota-sdk/agent-sessions";
690
690
  import { SessionStore } from "@robota-sdk/agent-sessions";
691
691
 
692
692
  // src/config/config-loader.ts
@@ -1908,6 +1908,715 @@ var MarketplaceClient = class {
1908
1908
  }
1909
1909
  };
1910
1910
 
1911
+ // src/commands/command-registry.ts
1912
+ var CommandRegistry = class {
1913
+ sources = [];
1914
+ addSource(source) {
1915
+ this.sources.push(source);
1916
+ }
1917
+ /** Get all commands, optionally filtered by prefix */
1918
+ getCommands(filter) {
1919
+ const all = [];
1920
+ for (const source of this.sources) {
1921
+ all.push(...source.getCommands());
1922
+ }
1923
+ if (!filter) return all;
1924
+ const lower = filter.toLowerCase();
1925
+ return all.filter((cmd) => cmd.name.toLowerCase().startsWith(lower));
1926
+ }
1927
+ /** Resolve a short name to its fully qualified plugin:name form */
1928
+ resolveQualifiedName(shortName) {
1929
+ const matches = this.getCommands().filter(
1930
+ (c) => c.source === "plugin" && c.name.includes(":") && c.name.endsWith(`:${shortName}`)
1931
+ );
1932
+ if (matches.length !== 1) return null;
1933
+ return matches[0].name;
1934
+ }
1935
+ /** Get subcommands for a specific command */
1936
+ getSubcommands(commandName) {
1937
+ const lower = commandName.toLowerCase();
1938
+ for (const source of this.sources) {
1939
+ for (const cmd of source.getCommands()) {
1940
+ if (cmd.name.toLowerCase() === lower && cmd.subcommands) {
1941
+ return cmd.subcommands;
1942
+ }
1943
+ }
1944
+ }
1945
+ return [];
1946
+ }
1947
+ };
1948
+
1949
+ // src/commands/builtin-source.ts
1950
+ import { CLAUDE_MODELS, formatTokenCount } from "@robota-sdk/agent-core";
1951
+ function buildModelSubcommands() {
1952
+ const seen = /* @__PURE__ */ new Set();
1953
+ const commands = [];
1954
+ for (const model of Object.values(CLAUDE_MODELS)) {
1955
+ if (seen.has(model.name)) continue;
1956
+ seen.add(model.name);
1957
+ commands.push({
1958
+ name: model.id,
1959
+ description: `${model.name} (${formatTokenCount(model.contextWindow).toUpperCase()})`,
1960
+ source: "builtin"
1961
+ });
1962
+ }
1963
+ return commands;
1964
+ }
1965
+ function createBuiltinCommands() {
1966
+ return [
1967
+ { name: "help", description: "Show available commands", source: "builtin" },
1968
+ { name: "clear", description: "Clear conversation history", source: "builtin" },
1969
+ {
1970
+ name: "mode",
1971
+ description: "Permission mode",
1972
+ source: "builtin",
1973
+ subcommands: [
1974
+ { name: "plan", description: "Plan only, no execution", source: "builtin" },
1975
+ { name: "default", description: "Ask before risky actions", source: "builtin" },
1976
+ { name: "acceptEdits", description: "Auto-approve file edits", source: "builtin" },
1977
+ { name: "bypassPermissions", description: "Skip all permission checks", source: "builtin" }
1978
+ ]
1979
+ },
1980
+ {
1981
+ name: "model",
1982
+ description: "Select AI model",
1983
+ source: "builtin",
1984
+ subcommands: buildModelSubcommands()
1985
+ },
1986
+ {
1987
+ name: "language",
1988
+ description: "Set response language",
1989
+ source: "builtin",
1990
+ subcommands: [
1991
+ { name: "ko", description: "Korean", source: "builtin" },
1992
+ { name: "en", description: "English", source: "builtin" },
1993
+ { name: "ja", description: "Japanese", source: "builtin" },
1994
+ { name: "zh", description: "Chinese", source: "builtin" }
1995
+ ]
1996
+ },
1997
+ { name: "compact", description: "Compress context window", source: "builtin" },
1998
+ { name: "cost", description: "Show session info", source: "builtin" },
1999
+ { name: "context", description: "Context window info", source: "builtin" },
2000
+ { name: "permissions", description: "Permission rules", source: "builtin" },
2001
+ { name: "plugin", description: "Manage plugins", source: "builtin" },
2002
+ { name: "reload-plugins", description: "Reload all plugin resources", source: "builtin" },
2003
+ { name: "reset", description: "Delete settings and exit", source: "builtin" },
2004
+ { name: "exit", description: "Exit CLI", source: "builtin" }
2005
+ ];
2006
+ }
2007
+ var BuiltinCommandSource = class {
2008
+ name = "builtin";
2009
+ commands;
2010
+ constructor() {
2011
+ this.commands = createBuiltinCommands();
2012
+ }
2013
+ getCommands() {
2014
+ return this.commands;
2015
+ }
2016
+ };
2017
+
2018
+ // src/commands/skill-source.ts
2019
+ import { readdirSync as readdirSync3, readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
2020
+ import { join as join10, basename as basename2 } from "path";
2021
+ import { homedir as homedir3 } from "os";
2022
+ var BOOLEAN_KEYS = /* @__PURE__ */ new Set(["disable-model-invocation", "user-invocable"]);
2023
+ var LIST_KEYS2 = /* @__PURE__ */ new Set(["allowed-tools"]);
2024
+ function kebabToCamel(key) {
2025
+ return key.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
2026
+ }
2027
+ function parseFrontmatter2(content) {
2028
+ const lines = content.split("\n");
2029
+ if (lines[0]?.trim() !== "---") return null;
2030
+ const result = {};
2031
+ for (let i = 1; i < lines.length; i++) {
2032
+ const line = lines[i];
2033
+ if (line.trim() === "---") break;
2034
+ const match = line.match(/^([a-z][a-z0-9-]*):\s*(.+)/);
2035
+ if (!match) continue;
2036
+ const key = match[1];
2037
+ const rawValue = match[2].trim();
2038
+ const camelKey = kebabToCamel(key);
2039
+ if (BOOLEAN_KEYS.has(key)) {
2040
+ result[camelKey] = rawValue === "true";
2041
+ } else if (LIST_KEYS2.has(key)) {
2042
+ result[camelKey] = rawValue.split(",").map((s) => s.trim());
2043
+ } else {
2044
+ result[camelKey] = rawValue;
2045
+ }
2046
+ }
2047
+ return Object.keys(result).length > 0 ? result : null;
2048
+ }
2049
+ function buildCommand(frontmatter, content, fallbackName) {
2050
+ const cmd = {
2051
+ name: frontmatter?.name ?? fallbackName,
2052
+ description: frontmatter?.description ?? `Skill: ${fallbackName}`,
2053
+ source: "skill",
2054
+ skillContent: content
2055
+ };
2056
+ if (frontmatter?.argumentHint !== void 0) cmd.argumentHint = frontmatter.argumentHint;
2057
+ if (frontmatter?.disableModelInvocation !== void 0)
2058
+ cmd.disableModelInvocation = frontmatter.disableModelInvocation;
2059
+ if (frontmatter?.userInvocable !== void 0) cmd.userInvocable = frontmatter.userInvocable;
2060
+ if (frontmatter?.allowedTools !== void 0) cmd.allowedTools = frontmatter.allowedTools;
2061
+ if (frontmatter?.model !== void 0) cmd.model = frontmatter.model;
2062
+ if (frontmatter?.effort !== void 0) cmd.effort = frontmatter.effort;
2063
+ if (frontmatter?.context !== void 0) cmd.context = frontmatter.context;
2064
+ if (frontmatter?.agent !== void 0) cmd.agent = frontmatter.agent;
2065
+ return cmd;
2066
+ }
2067
+ function scanSkillsDir(skillsDir) {
2068
+ if (!existsSync9(skillsDir)) return [];
2069
+ const commands = [];
2070
+ const entries = readdirSync3(skillsDir, { withFileTypes: true });
2071
+ for (const entry of entries) {
2072
+ if (!entry.isDirectory()) continue;
2073
+ const skillFile = join10(skillsDir, entry.name, "SKILL.md");
2074
+ if (!existsSync9(skillFile)) continue;
2075
+ const content = readFileSync9(skillFile, "utf-8");
2076
+ const frontmatter = parseFrontmatter2(content);
2077
+ commands.push(buildCommand(frontmatter, content, entry.name));
2078
+ }
2079
+ return commands;
2080
+ }
2081
+ function scanCommandsDir(commandsDir) {
2082
+ if (!existsSync9(commandsDir)) return [];
2083
+ const commands = [];
2084
+ const entries = readdirSync3(commandsDir, { withFileTypes: true });
2085
+ for (const entry of entries) {
2086
+ if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
2087
+ const filePath = join10(commandsDir, entry.name);
2088
+ const content = readFileSync9(filePath, "utf-8");
2089
+ const frontmatter = parseFrontmatter2(content);
2090
+ const fallbackName = basename2(entry.name, ".md");
2091
+ commands.push(buildCommand(frontmatter, content, fallbackName));
2092
+ }
2093
+ return commands;
2094
+ }
2095
+ var SkillCommandSource = class {
2096
+ name = "skill";
2097
+ cwd;
2098
+ home;
2099
+ cachedCommands = null;
2100
+ constructor(cwd, home) {
2101
+ this.cwd = cwd;
2102
+ this.home = home ?? homedir3();
2103
+ }
2104
+ getCommands() {
2105
+ if (this.cachedCommands) return this.cachedCommands;
2106
+ const sources = [
2107
+ scanSkillsDir(join10(this.cwd, ".claude", "skills")),
2108
+ scanCommandsDir(join10(this.cwd, ".claude", "commands")),
2109
+ scanSkillsDir(join10(this.home, ".robota", "skills")),
2110
+ scanSkillsDir(join10(this.cwd, ".agents", "skills"))
2111
+ ];
2112
+ const seen = /* @__PURE__ */ new Set();
2113
+ const merged = [];
2114
+ for (const commands of sources) {
2115
+ for (const cmd of commands) {
2116
+ if (!seen.has(cmd.name)) {
2117
+ seen.add(cmd.name);
2118
+ merged.push(cmd);
2119
+ }
2120
+ }
2121
+ }
2122
+ this.cachedCommands = merged;
2123
+ return this.cachedCommands;
2124
+ }
2125
+ getModelInvocableSkills() {
2126
+ return this.getCommands().filter((cmd) => cmd.disableModelInvocation !== true);
2127
+ }
2128
+ getUserInvocableSkills() {
2129
+ return this.getCommands().filter((cmd) => cmd.userInvocable !== false);
2130
+ }
2131
+ };
2132
+
2133
+ // src/commands/system-command.ts
2134
+ var VALID_MODES = ["plan", "default", "acceptEdits", "bypassPermissions"];
2135
+ function createSystemCommands() {
2136
+ return [
2137
+ {
2138
+ name: "help",
2139
+ description: "Show available commands",
2140
+ execute: (_session, _args) => ({
2141
+ message: [
2142
+ "Available commands:",
2143
+ " help \u2014 Show this help",
2144
+ " clear \u2014 Clear conversation",
2145
+ " compact [instr] \u2014 Compact context (optional focus instructions)",
2146
+ " mode [m] \u2014 Show/change permission mode",
2147
+ " model <id> \u2014 Change AI model",
2148
+ " language <code> \u2014 Set response language (ko, en, ja, zh)",
2149
+ " cost \u2014 Show session info",
2150
+ " context \u2014 Context window info",
2151
+ " permissions \u2014 Permission rules",
2152
+ " reset \u2014 Delete settings and exit"
2153
+ ].join("\n"),
2154
+ success: true
2155
+ })
2156
+ },
2157
+ {
2158
+ name: "clear",
2159
+ description: "Clear conversation history",
2160
+ execute: (session, _args) => {
2161
+ const underlying = session.getSession();
2162
+ underlying.clearHistory();
2163
+ return { message: "Conversation cleared.", success: true };
2164
+ }
2165
+ },
2166
+ {
2167
+ name: "compact",
2168
+ description: "Compress context window",
2169
+ execute: async (session, args) => {
2170
+ const underlying = session.getSession();
2171
+ const instructions = args.trim() || void 0;
2172
+ const before = underlying.getContextState().usedPercentage;
2173
+ await underlying.compact(instructions);
2174
+ const after = underlying.getContextState().usedPercentage;
2175
+ return {
2176
+ message: `Context compacted: ${Math.round(before)}% -> ${Math.round(after)}%`,
2177
+ success: true,
2178
+ data: { before, after }
2179
+ };
2180
+ }
2181
+ },
2182
+ {
2183
+ name: "mode",
2184
+ description: "Show/change permission mode",
2185
+ execute: (session, args) => {
2186
+ const underlying = session.getSession();
2187
+ const arg = args.trim().split(/\s+/)[0];
2188
+ if (!arg) {
2189
+ return {
2190
+ message: `Current mode: ${underlying.getPermissionMode()}`,
2191
+ success: true,
2192
+ data: { mode: underlying.getPermissionMode() }
2193
+ };
2194
+ }
2195
+ if (VALID_MODES.includes(arg)) {
2196
+ underlying.setPermissionMode(arg);
2197
+ return {
2198
+ message: `Permission mode set to: ${arg}`,
2199
+ success: true,
2200
+ data: { mode: arg }
2201
+ };
2202
+ }
2203
+ return {
2204
+ message: `Invalid mode. Valid: ${VALID_MODES.join(" | ")}`,
2205
+ success: false
2206
+ };
2207
+ }
2208
+ },
2209
+ {
2210
+ name: "model",
2211
+ description: "Change AI model",
2212
+ execute: (_session, args) => {
2213
+ const modelId = args.trim().split(/\s+/)[0];
2214
+ if (!modelId) {
2215
+ return { message: "Usage: model <model-id>", success: false };
2216
+ }
2217
+ return {
2218
+ message: `Model change requested: ${modelId}`,
2219
+ success: true,
2220
+ data: { modelId }
2221
+ };
2222
+ }
2223
+ },
2224
+ {
2225
+ name: "language",
2226
+ description: "Set response language",
2227
+ execute: (_session, args) => {
2228
+ const lang = args.trim().split(/\s+/)[0];
2229
+ if (!lang) {
2230
+ return { message: "Usage: language <code> (e.g., ko, en, ja, zh)", success: false };
2231
+ }
2232
+ return {
2233
+ message: `Language set to "${lang}".`,
2234
+ success: true,
2235
+ data: { language: lang }
2236
+ };
2237
+ }
2238
+ },
2239
+ {
2240
+ name: "cost",
2241
+ description: "Show session info",
2242
+ execute: (session, _args) => {
2243
+ const underlying = session.getSession();
2244
+ const sessionId = underlying.getSessionId();
2245
+ const messageCount = underlying.getMessageCount();
2246
+ return {
2247
+ message: `Session: ${sessionId}
2248
+ Messages: ${messageCount}`,
2249
+ success: true,
2250
+ data: { sessionId, messageCount }
2251
+ };
2252
+ }
2253
+ },
2254
+ {
2255
+ name: "context",
2256
+ description: "Context window info",
2257
+ execute: (session, _args) => {
2258
+ const ctx = session.getContextState();
2259
+ return {
2260
+ message: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`,
2261
+ success: true,
2262
+ data: {
2263
+ usedTokens: ctx.usedTokens,
2264
+ maxTokens: ctx.maxTokens,
2265
+ percentage: ctx.usedPercentage
2266
+ }
2267
+ };
2268
+ }
2269
+ },
2270
+ {
2271
+ name: "permissions",
2272
+ description: "Show permission rules",
2273
+ execute: (session, _args) => {
2274
+ const underlying = session.getSession();
2275
+ const mode = underlying.getPermissionMode();
2276
+ const sessionAllowed = underlying.getSessionAllowedTools();
2277
+ const lines = [`Permission mode: ${mode}`];
2278
+ if (sessionAllowed.length > 0) {
2279
+ lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
2280
+ } else {
2281
+ lines.push("No session-approved tools.");
2282
+ }
2283
+ return {
2284
+ message: lines.join("\n"),
2285
+ success: true,
2286
+ data: { mode, sessionAllowed }
2287
+ };
2288
+ }
2289
+ },
2290
+ {
2291
+ name: "reset",
2292
+ description: "Delete settings",
2293
+ execute: (_session, _args) => {
2294
+ return {
2295
+ message: "Reset requested.",
2296
+ success: true,
2297
+ data: { resetRequested: true }
2298
+ };
2299
+ }
2300
+ }
2301
+ ];
2302
+ }
2303
+ var SystemCommandExecutor = class {
2304
+ commands;
2305
+ constructor(commands) {
2306
+ this.commands = /* @__PURE__ */ new Map();
2307
+ for (const cmd of commands ?? createSystemCommands()) {
2308
+ this.commands.set(cmd.name, cmd);
2309
+ }
2310
+ }
2311
+ /** Register an additional command. */
2312
+ register(command) {
2313
+ this.commands.set(command.name, command);
2314
+ }
2315
+ /** Execute a command by name. Returns null if command not found. */
2316
+ async execute(name, session, args) {
2317
+ const cmd = this.commands.get(name);
2318
+ if (!cmd) return null;
2319
+ return await cmd.execute(session, args);
2320
+ }
2321
+ /** List all registered commands. */
2322
+ listCommands() {
2323
+ return [...this.commands.values()];
2324
+ }
2325
+ /** Check if a command exists. */
2326
+ hasCommand(name) {
2327
+ return this.commands.has(name);
2328
+ }
2329
+ };
2330
+
2331
+ // src/interactive/interactive-session.ts
2332
+ import { FileSessionLogger as FileSessionLogger2 } from "@robota-sdk/agent-sessions";
2333
+ import {
2334
+ createUserMessage,
2335
+ createAssistantMessage,
2336
+ createSystemMessage,
2337
+ createToolMessage
2338
+ } from "@robota-sdk/agent-core";
2339
+ import { randomUUID } from "crypto";
2340
+ var TOOL_ARG_DISPLAY_MAX = 80;
2341
+ var TAIL_KEEP = 30;
2342
+ var MAX_COMPLETED_TOOLS = 50;
2343
+ var STREAMING_FLUSH_INTERVAL_MS = 16;
2344
+ var InteractiveSession = class {
2345
+ session;
2346
+ listeners = /* @__PURE__ */ new Map();
2347
+ // Streaming state
2348
+ streamingText = "";
2349
+ flushTimer = null;
2350
+ // Tool state
2351
+ activeTools = [];
2352
+ // Execution state
2353
+ executing = false;
2354
+ pendingPrompt = null;
2355
+ // Display messages (what clients render — not the raw session history)
2356
+ messages = [];
2357
+ constructor(options) {
2358
+ if (options.session) {
2359
+ this.session = options.session;
2360
+ } else {
2361
+ const cwd = options.cwd ?? process.cwd();
2362
+ const paths = projectPaths(cwd);
2363
+ this.session = createSession({
2364
+ config: options.config,
2365
+ context: options.context,
2366
+ projectInfo: options.projectInfo,
2367
+ sessionStore: options.sessionStore,
2368
+ permissionMode: options.permissionMode,
2369
+ maxTurns: options.maxTurns,
2370
+ terminal: NOOP_TERMINAL,
2371
+ sessionLogger: new FileSessionLogger2(paths.logs),
2372
+ permissionHandler: options.permissionHandler,
2373
+ onTextDelta: (delta) => this.handleTextDelta(delta),
2374
+ onToolExecution: (event) => this.handleToolExecution(event)
2375
+ });
2376
+ }
2377
+ }
2378
+ // ── Event system ──────────────────────────────────────────────
2379
+ on(event, handler) {
2380
+ if (!this.listeners.has(event)) {
2381
+ this.listeners.set(event, /* @__PURE__ */ new Set());
2382
+ }
2383
+ this.listeners.get(event).add(handler);
2384
+ }
2385
+ off(event, handler) {
2386
+ this.listeners.get(event)?.delete(handler);
2387
+ }
2388
+ emit(event, ...args) {
2389
+ const handlers = this.listeners.get(event);
2390
+ if (handlers) {
2391
+ for (const handler of handlers) {
2392
+ handler(...args);
2393
+ }
2394
+ }
2395
+ }
2396
+ // ── Public API ────────────────────────────────────────────────
2397
+ /** Submit a prompt. Queues if already executing (max 1 queued). */
2398
+ async submit(input) {
2399
+ if (this.executing) {
2400
+ this.pendingPrompt = input;
2401
+ return;
2402
+ }
2403
+ await this.executePrompt(input);
2404
+ }
2405
+ /** Abort current execution and clear queue. */
2406
+ abort() {
2407
+ this.pendingPrompt = null;
2408
+ this.session.abort();
2409
+ }
2410
+ /** Cancel queued prompt without aborting current execution. */
2411
+ cancelQueue() {
2412
+ this.pendingPrompt = null;
2413
+ }
2414
+ isExecuting() {
2415
+ return this.executing;
2416
+ }
2417
+ getPendingPrompt() {
2418
+ return this.pendingPrompt;
2419
+ }
2420
+ getMessages() {
2421
+ return this.messages;
2422
+ }
2423
+ getStreamingText() {
2424
+ return this.streamingText;
2425
+ }
2426
+ getActiveTools() {
2427
+ return this.activeTools;
2428
+ }
2429
+ getContextState() {
2430
+ return this.session.getContextState();
2431
+ }
2432
+ getSession() {
2433
+ return this.session;
2434
+ }
2435
+ // ── Execution ─────────────────────────────────────────────────
2436
+ async executePrompt(input) {
2437
+ this.executing = true;
2438
+ this.clearStreaming();
2439
+ this.emit("thinking", true);
2440
+ this.messages.push(createUserMessage(input));
2441
+ const historyBefore = this.session.getHistory().length;
2442
+ try {
2443
+ const response = await this.session.run(input);
2444
+ this.flushStreaming();
2445
+ this.clearStreaming();
2446
+ const result = this.buildResult(response || "(empty response)", historyBefore);
2447
+ this.messages.push(createAssistantMessage(result.response));
2448
+ this.emit("complete", result);
2449
+ this.emit("context_update", this.getContextState());
2450
+ } catch (err) {
2451
+ this.flushStreaming();
2452
+ this.clearStreaming();
2453
+ if (isAbortError(err)) {
2454
+ const result = this.buildInterruptedResult(historyBefore);
2455
+ if (result.response) {
2456
+ this.messages.push(createAssistantMessage(result.response));
2457
+ }
2458
+ this.messages.push(createSystemMessage("Interrupted by user."));
2459
+ this.emit("interrupted", result);
2460
+ } else {
2461
+ const errMsg = err instanceof Error ? err.message : String(err);
2462
+ this.messages.push(createSystemMessage(`Error: ${errMsg}`));
2463
+ this.emit("error", err instanceof Error ? err : new Error(errMsg));
2464
+ }
2465
+ } finally {
2466
+ this.executing = false;
2467
+ this.emit("thinking", false);
2468
+ if (this.pendingPrompt) {
2469
+ const queued = this.pendingPrompt;
2470
+ this.pendingPrompt = null;
2471
+ setTimeout(() => this.executePrompt(queued), 0);
2472
+ }
2473
+ }
2474
+ }
2475
+ // ── Streaming callbacks ───────────────────────────────────────
2476
+ handleTextDelta(delta) {
2477
+ this.streamingText += delta;
2478
+ this.emit("text_delta", delta);
2479
+ if (!this.flushTimer) {
2480
+ this.flushTimer = setTimeout(() => {
2481
+ this.flushTimer = null;
2482
+ }, STREAMING_FLUSH_INTERVAL_MS);
2483
+ }
2484
+ }
2485
+ handleToolExecution(event) {
2486
+ if (event.type === "start") {
2487
+ const firstArg = extractFirstArg(event.toolArgs);
2488
+ const state = {
2489
+ toolName: event.toolName,
2490
+ firstArg,
2491
+ isRunning: true
2492
+ };
2493
+ this.activeTools.push(state);
2494
+ this.emit("tool_start", state);
2495
+ } else {
2496
+ const result = event.denied ? "denied" : event.success === false ? "error" : "success";
2497
+ const idx = this.activeTools.findIndex((t) => t.toolName === event.toolName && t.isRunning);
2498
+ if (idx !== -1) {
2499
+ const finished = {
2500
+ ...this.activeTools[idx],
2501
+ isRunning: false,
2502
+ result
2503
+ };
2504
+ this.activeTools[idx] = finished;
2505
+ this.trimCompletedTools();
2506
+ this.emit("tool_end", finished);
2507
+ }
2508
+ }
2509
+ }
2510
+ // ── Helpers ───────────────────────────────────────────────────
2511
+ clearStreaming() {
2512
+ this.streamingText = "";
2513
+ this.activeTools = [];
2514
+ if (this.flushTimer) {
2515
+ clearTimeout(this.flushTimer);
2516
+ this.flushTimer = null;
2517
+ }
2518
+ }
2519
+ flushStreaming() {
2520
+ if (this.flushTimer) {
2521
+ clearTimeout(this.flushTimer);
2522
+ this.flushTimer = null;
2523
+ }
2524
+ }
2525
+ buildResult(response, historyBefore) {
2526
+ const toolSummaries = this.extractToolSummaries(historyBefore);
2527
+ if (toolSummaries.length > 0) {
2528
+ this.messages.push(
2529
+ createToolMessage(JSON.stringify(toolSummaries), {
2530
+ toolCallId: randomUUID(),
2531
+ name: `${toolSummaries.length} tools`
2532
+ })
2533
+ );
2534
+ }
2535
+ return {
2536
+ response,
2537
+ messages: this.messages,
2538
+ toolSummaries,
2539
+ contextState: this.getContextState()
2540
+ };
2541
+ }
2542
+ buildInterruptedResult(historyBefore) {
2543
+ const history = this.session.getHistory();
2544
+ const toolSummaries = this.extractToolSummaries(historyBefore);
2545
+ if (toolSummaries.length > 0) {
2546
+ this.messages.push(
2547
+ createToolMessage(JSON.stringify(toolSummaries), {
2548
+ toolCallId: randomUUID(),
2549
+ name: `${toolSummaries.length} tools`
2550
+ })
2551
+ );
2552
+ }
2553
+ const parts = [];
2554
+ for (let i = historyBefore; i < history.length; i++) {
2555
+ const msg = history[i];
2556
+ if (msg?.role === "assistant" && msg.content) {
2557
+ parts.push(msg.content);
2558
+ }
2559
+ }
2560
+ return {
2561
+ response: parts.join("\n\n"),
2562
+ messages: this.messages,
2563
+ toolSummaries,
2564
+ contextState: this.getContextState()
2565
+ };
2566
+ }
2567
+ extractToolSummaries(historyBefore) {
2568
+ const history = this.session.getHistory();
2569
+ const summaries = [];
2570
+ for (let i = historyBefore; i < history.length; i++) {
2571
+ const msg = history[i];
2572
+ if (msg?.role === "assistant" && msg.toolCalls) {
2573
+ for (const tc of msg.toolCalls) {
2574
+ summaries.push({ name: tc.function.name, args: tc.function.arguments });
2575
+ }
2576
+ }
2577
+ }
2578
+ return summaries;
2579
+ }
2580
+ trimCompletedTools() {
2581
+ const completed = this.activeTools.filter((t) => !t.isRunning);
2582
+ if (completed.length > MAX_COMPLETED_TOOLS) {
2583
+ const excess = completed.length - MAX_COMPLETED_TOOLS;
2584
+ let removed = 0;
2585
+ this.activeTools = this.activeTools.filter((t) => {
2586
+ if (!t.isRunning && removed < excess) {
2587
+ removed++;
2588
+ return false;
2589
+ }
2590
+ return true;
2591
+ });
2592
+ }
2593
+ }
2594
+ };
2595
+ function isAbortError(err) {
2596
+ return err instanceof DOMException && err.name === "AbortError" || err instanceof Error && (err.message.includes("aborted") || err.message.includes("abort"));
2597
+ }
2598
+ function extractFirstArg(toolArgs) {
2599
+ if (!toolArgs) return "";
2600
+ const firstVal = Object.values(toolArgs)[0];
2601
+ const raw = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal ?? "");
2602
+ return raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_DISPLAY_MAX - TAIL_KEEP - 3) + "..." + raw.slice(-TAIL_KEEP) : raw;
2603
+ }
2604
+ var NOOP_TERMINAL = {
2605
+ write: () => {
2606
+ },
2607
+ writeLine: () => {
2608
+ },
2609
+ writeMarkdown: () => {
2610
+ },
2611
+ writeError: () => {
2612
+ },
2613
+ prompt: () => Promise.resolve(""),
2614
+ select: () => Promise.resolve(0),
2615
+ spinner: () => ({ stop: () => {
2616
+ }, update: () => {
2617
+ } })
2618
+ };
2619
+
1911
2620
  // src/index.ts
1912
2621
  import { bashTool as bashTool2 } from "@robota-sdk/agent-tools";
1913
2622
  import { readTool as readTool2 } from "@robota-sdk/agent-tools";
@@ -1918,16 +2627,21 @@ import { grepTool as grepTool2 } from "@robota-sdk/agent-tools";
1918
2627
  export {
1919
2628
  AgentExecutor,
1920
2629
  BUILT_IN_AGENTS,
2630
+ BuiltinCommandSource,
1921
2631
  BundlePluginInstaller,
1922
2632
  BundlePluginLoader,
2633
+ CommandRegistry,
1923
2634
  DEFAULT_TOOL_DESCRIPTIONS,
1924
- FileSessionLogger2 as FileSessionLogger,
2635
+ FileSessionLogger3 as FileSessionLogger,
2636
+ InteractiveSession,
1925
2637
  MarketplaceClient,
1926
2638
  PluginSettingsStore,
1927
2639
  PromptExecutor,
1928
2640
  Session3 as Session,
1929
2641
  SessionStore,
1930
2642
  SilentSessionLogger,
2643
+ SkillCommandSource,
2644
+ SystemCommandExecutor,
1931
2645
  TRUST_TO_MODE,
1932
2646
  assembleSubagentPrompt,
1933
2647
  bashTool2 as bashTool,
@@ -1938,6 +2652,7 @@ export {
1938
2652
  createSession,
1939
2653
  createSubagentLogger,
1940
2654
  createSubagentSession,
2655
+ createSystemCommands,
1941
2656
  detectProject,
1942
2657
  editTool2 as editTool,
1943
2658
  evaluatePermission,
@@ -1948,6 +2663,7 @@ export {
1948
2663
  grepTool2 as grepTool,
1949
2664
  loadConfig,
1950
2665
  loadContext,
2666
+ parseFrontmatter2 as parseFrontmatter,
1951
2667
  projectPaths,
1952
2668
  promptForApproval,
1953
2669
  query,