reasonix 0.4.24 → 0.4.26
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/{chunk-K6MR4SWS.js → chunk-2BYEKJHX.js} +119 -10
- package/dist/cli/chunk-2BYEKJHX.js.map +1 -0
- package/dist/cli/index.js +477 -31
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{prompt-VDN5U3YE.js → prompt-6DMLWG2H.js} +2 -2
- package/dist/index.d.ts +146 -2
- package/dist/index.js +523 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/chunk-K6MR4SWS.js.map +0 -1
- /package/dist/cli/{prompt-VDN5U3YE.js.map → prompt-6DMLWG2H.js.map} +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
memoryEnabled,
|
|
8
8
|
readProjectMemory,
|
|
9
9
|
sanitizeMemoryName
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2BYEKJHX.js";
|
|
11
11
|
|
|
12
12
|
// src/cli/index.ts
|
|
13
13
|
import { Command } from "commander";
|
|
@@ -1893,6 +1893,10 @@ var CacheFirstLoop = class {
|
|
|
1893
1893
|
usage = resp.usage;
|
|
1894
1894
|
}
|
|
1895
1895
|
} catch (err) {
|
|
1896
|
+
if (signal.aborted) {
|
|
1897
|
+
yield { turn: this._turn, role: "done", content: "" };
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1896
1900
|
yield {
|
|
1897
1901
|
turn: this._turn,
|
|
1898
1902
|
role: "error",
|
|
@@ -2212,6 +2216,74 @@ import { promises as fs } from "fs";
|
|
|
2212
2216
|
import * as pathMod from "path";
|
|
2213
2217
|
var DEFAULT_MAX_READ_BYTES = 2 * 1024 * 1024;
|
|
2214
2218
|
var DEFAULT_MAX_LIST_BYTES = 256 * 1024;
|
|
2219
|
+
var SKIP_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
2220
|
+
"node_modules",
|
|
2221
|
+
".git",
|
|
2222
|
+
".hg",
|
|
2223
|
+
".svn",
|
|
2224
|
+
"dist",
|
|
2225
|
+
"build",
|
|
2226
|
+
"out",
|
|
2227
|
+
".next",
|
|
2228
|
+
".nuxt",
|
|
2229
|
+
"target",
|
|
2230
|
+
// Rust / Java
|
|
2231
|
+
".venv",
|
|
2232
|
+
"venv",
|
|
2233
|
+
"__pycache__",
|
|
2234
|
+
".pytest_cache",
|
|
2235
|
+
".mypy_cache",
|
|
2236
|
+
".cache",
|
|
2237
|
+
"coverage"
|
|
2238
|
+
]);
|
|
2239
|
+
var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
2240
|
+
".png",
|
|
2241
|
+
".jpg",
|
|
2242
|
+
".jpeg",
|
|
2243
|
+
".gif",
|
|
2244
|
+
".bmp",
|
|
2245
|
+
".ico",
|
|
2246
|
+
".webp",
|
|
2247
|
+
".tiff",
|
|
2248
|
+
".pdf",
|
|
2249
|
+
".zip",
|
|
2250
|
+
".tar",
|
|
2251
|
+
".gz",
|
|
2252
|
+
".bz2",
|
|
2253
|
+
".xz",
|
|
2254
|
+
".7z",
|
|
2255
|
+
".rar",
|
|
2256
|
+
".exe",
|
|
2257
|
+
".dll",
|
|
2258
|
+
".so",
|
|
2259
|
+
".dylib",
|
|
2260
|
+
".bin",
|
|
2261
|
+
".class",
|
|
2262
|
+
".jar",
|
|
2263
|
+
".war",
|
|
2264
|
+
".o",
|
|
2265
|
+
".obj",
|
|
2266
|
+
".lib",
|
|
2267
|
+
".a",
|
|
2268
|
+
".woff",
|
|
2269
|
+
".woff2",
|
|
2270
|
+
".ttf",
|
|
2271
|
+
".otf",
|
|
2272
|
+
".eot",
|
|
2273
|
+
".mp3",
|
|
2274
|
+
".mp4",
|
|
2275
|
+
".mov",
|
|
2276
|
+
".avi",
|
|
2277
|
+
".webm",
|
|
2278
|
+
".wasm",
|
|
2279
|
+
".pyc",
|
|
2280
|
+
".pyo"
|
|
2281
|
+
]);
|
|
2282
|
+
function isLikelyBinaryByName(name) {
|
|
2283
|
+
const dot = name.lastIndexOf(".");
|
|
2284
|
+
if (dot < 0) return false;
|
|
2285
|
+
return BINARY_EXTENSIONS.has(name.slice(dot).toLowerCase());
|
|
2286
|
+
}
|
|
2215
2287
|
function registerFilesystemTools(registry, opts) {
|
|
2216
2288
|
const rootDir = pathMod.resolve(opts.rootDir);
|
|
2217
2289
|
const allowWriting = opts.allowWriting !== false;
|
|
@@ -2221,7 +2293,12 @@ function registerFilesystemTools(registry, opts) {
|
|
|
2221
2293
|
if (typeof raw !== "string" || raw.length === 0) {
|
|
2222
2294
|
throw new Error("path must be a non-empty string");
|
|
2223
2295
|
}
|
|
2224
|
-
|
|
2296
|
+
let normalized = raw;
|
|
2297
|
+
while (normalized.startsWith("/") || normalized.startsWith("\\")) {
|
|
2298
|
+
normalized = normalized.slice(1);
|
|
2299
|
+
}
|
|
2300
|
+
if (normalized.length === 0) normalized = ".";
|
|
2301
|
+
const resolved = pathMod.resolve(rootDir, normalized);
|
|
2225
2302
|
const normRoot = pathMod.resolve(rootDir);
|
|
2226
2303
|
const rel = pathMod.relative(normRoot, resolved);
|
|
2227
2304
|
if (rel.startsWith("..") || pathMod.isAbsolute(rel)) {
|
|
@@ -2387,6 +2464,114 @@ function registerFilesystemTools(registry, opts) {
|
|
|
2387
2464
|
return matches.length === 0 ? "(no matches)" : matches.join("\n");
|
|
2388
2465
|
}
|
|
2389
2466
|
});
|
|
2467
|
+
registry.register({
|
|
2468
|
+
name: "search_content",
|
|
2469
|
+
description: "Recursively grep file CONTENTS for a substring or regex. This is the right tool for 'find all places that call X', 'where is Y referenced', 'what files contain Z'. Different from search_files (which matches FILE NAMES). Returns one match per line in 'path:line: text' format. Skips dependency / VCS / build directories (node_modules, .git, dist, build, .next, target, .venv) and binary files by default.",
|
|
2470
|
+
readOnly: true,
|
|
2471
|
+
parameters: {
|
|
2472
|
+
type: "object",
|
|
2473
|
+
properties: {
|
|
2474
|
+
pattern: {
|
|
2475
|
+
type: "string",
|
|
2476
|
+
description: "Substring (or regex) to search file contents for."
|
|
2477
|
+
},
|
|
2478
|
+
path: {
|
|
2479
|
+
type: "string",
|
|
2480
|
+
description: "Directory to start the search at (default: sandbox root)."
|
|
2481
|
+
},
|
|
2482
|
+
glob: {
|
|
2483
|
+
type: "string",
|
|
2484
|
+
description: "Optional file-name suffix or substring filter. Examples: '.ts' (only TypeScript), 'test' (any file with 'test' in the name). Reduces noise when you know the file shape."
|
|
2485
|
+
},
|
|
2486
|
+
case_sensitive: {
|
|
2487
|
+
type: "boolean",
|
|
2488
|
+
description: "When true, match case exactly. Default false (case-insensitive)."
|
|
2489
|
+
},
|
|
2490
|
+
include_deps: {
|
|
2491
|
+
type: "boolean",
|
|
2492
|
+
description: "When true, also search inside node_modules / .git / dist / build / etc. Off by default \u2014 most exploration questions are about the user's own code."
|
|
2493
|
+
}
|
|
2494
|
+
},
|
|
2495
|
+
required: ["pattern"]
|
|
2496
|
+
},
|
|
2497
|
+
fn: async (args) => {
|
|
2498
|
+
const startAbs = safePath(args.path ?? ".");
|
|
2499
|
+
const caseSensitive = args.case_sensitive === true;
|
|
2500
|
+
const includeDeps = args.include_deps === true;
|
|
2501
|
+
const nameFilter = typeof args.glob === "string" ? args.glob.toLowerCase() : null;
|
|
2502
|
+
let re = null;
|
|
2503
|
+
try {
|
|
2504
|
+
re = new RegExp(args.pattern, caseSensitive ? "" : "i");
|
|
2505
|
+
} catch {
|
|
2506
|
+
re = null;
|
|
2507
|
+
}
|
|
2508
|
+
const needle = caseSensitive ? args.pattern : args.pattern.toLowerCase();
|
|
2509
|
+
const matches = [];
|
|
2510
|
+
let totalBytes = 0;
|
|
2511
|
+
let scanned = 0;
|
|
2512
|
+
let truncated = false;
|
|
2513
|
+
const walk2 = async (dir) => {
|
|
2514
|
+
if (truncated) return;
|
|
2515
|
+
let entries;
|
|
2516
|
+
try {
|
|
2517
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
2518
|
+
} catch {
|
|
2519
|
+
return;
|
|
2520
|
+
}
|
|
2521
|
+
for (const e of entries) {
|
|
2522
|
+
if (truncated) return;
|
|
2523
|
+
if (e.isDirectory()) {
|
|
2524
|
+
if (!includeDeps && SKIP_DIR_NAMES.has(e.name)) continue;
|
|
2525
|
+
await walk2(pathMod.join(dir, e.name));
|
|
2526
|
+
continue;
|
|
2527
|
+
}
|
|
2528
|
+
if (!e.isFile()) continue;
|
|
2529
|
+
if (nameFilter && !e.name.toLowerCase().includes(nameFilter)) continue;
|
|
2530
|
+
if (isLikelyBinaryByName(e.name)) continue;
|
|
2531
|
+
const full = pathMod.join(dir, e.name);
|
|
2532
|
+
let stat;
|
|
2533
|
+
try {
|
|
2534
|
+
stat = await fs.stat(full);
|
|
2535
|
+
} catch {
|
|
2536
|
+
continue;
|
|
2537
|
+
}
|
|
2538
|
+
if (stat.size > 2 * 1024 * 1024) continue;
|
|
2539
|
+
let raw;
|
|
2540
|
+
try {
|
|
2541
|
+
raw = await fs.readFile(full);
|
|
2542
|
+
} catch {
|
|
2543
|
+
continue;
|
|
2544
|
+
}
|
|
2545
|
+
const firstNul = raw.indexOf(0);
|
|
2546
|
+
if (firstNul !== -1 && firstNul < 8 * 1024) continue;
|
|
2547
|
+
const text = raw.toString("utf8");
|
|
2548
|
+
const rel = pathMod.relative(rootDir, full);
|
|
2549
|
+
const lines = text.split(/\r?\n/);
|
|
2550
|
+
for (let li = 0; li < lines.length; li++) {
|
|
2551
|
+
const line = lines[li];
|
|
2552
|
+
const lineForCheck = caseSensitive ? line : line.toLowerCase();
|
|
2553
|
+
const hit = re ? re.test(line) : lineForCheck.includes(needle);
|
|
2554
|
+
if (!hit) continue;
|
|
2555
|
+
const display = line.length > 200 ? `${line.slice(0, 200)}\u2026` : line;
|
|
2556
|
+
const out = `${rel}:${li + 1}: ${display}`;
|
|
2557
|
+
if (totalBytes + out.length + 1 > maxListBytes) {
|
|
2558
|
+
matches.push(`[\u2026 truncated at ${maxListBytes} bytes \u2014 refine pattern or path \u2026]`);
|
|
2559
|
+
truncated = true;
|
|
2560
|
+
return;
|
|
2561
|
+
}
|
|
2562
|
+
matches.push(out);
|
|
2563
|
+
totalBytes += out.length + 1;
|
|
2564
|
+
}
|
|
2565
|
+
scanned++;
|
|
2566
|
+
}
|
|
2567
|
+
};
|
|
2568
|
+
await walk2(startAbs);
|
|
2569
|
+
if (matches.length === 0) {
|
|
2570
|
+
return scanned === 0 ? "(no files scanned \u2014 path empty or all files filtered out)" : `(no matches across ${scanned} file${scanned === 1 ? "" : "s"})`;
|
|
2571
|
+
}
|
|
2572
|
+
return matches.join("\n");
|
|
2573
|
+
}
|
|
2574
|
+
});
|
|
2390
2575
|
registry.register({
|
|
2391
2576
|
name: "get_file_info",
|
|
2392
2577
|
description: "Stat a path under the sandbox root. Returns type (file|directory|symlink), size in bytes, mtime in ISO-8601.",
|
|
@@ -2713,6 +2898,127 @@ function registerPlanTool(registry, opts = {}) {
|
|
|
2713
2898
|
return registry;
|
|
2714
2899
|
}
|
|
2715
2900
|
|
|
2901
|
+
// src/tools/subagent.ts
|
|
2902
|
+
var DEFAULT_MAX_RESULT_CHARS2 = 8e3;
|
|
2903
|
+
var DEFAULT_MAX_ITERS = 16;
|
|
2904
|
+
var DEFAULT_SUBAGENT_MODEL = "deepseek-chat";
|
|
2905
|
+
var SUBAGENT_TOOL_NAME = "spawn_subagent";
|
|
2906
|
+
var NEVER_INHERITED_TOOLS = /* @__PURE__ */ new Set([SUBAGENT_TOOL_NAME, "submit_plan"]);
|
|
2907
|
+
async function spawnSubagent(opts) {
|
|
2908
|
+
const model = opts.model ?? DEFAULT_SUBAGENT_MODEL;
|
|
2909
|
+
const maxToolIters = opts.maxToolIters ?? DEFAULT_MAX_ITERS;
|
|
2910
|
+
const maxResultChars = opts.maxResultChars ?? DEFAULT_MAX_RESULT_CHARS2;
|
|
2911
|
+
const sink = opts.sink;
|
|
2912
|
+
const startedAt = Date.now();
|
|
2913
|
+
const taskPreview = opts.task.length > 30 ? `${opts.task.slice(0, 30)}\u2026` : opts.task;
|
|
2914
|
+
sink?.current?.({
|
|
2915
|
+
kind: "start",
|
|
2916
|
+
task: taskPreview,
|
|
2917
|
+
iter: 0,
|
|
2918
|
+
elapsedMs: 0
|
|
2919
|
+
});
|
|
2920
|
+
const childTools = forkRegistryExcluding(opts.parentRegistry, NEVER_INHERITED_TOOLS);
|
|
2921
|
+
const childPrefix = new ImmutablePrefix({
|
|
2922
|
+
system: opts.system,
|
|
2923
|
+
toolSpecs: childTools.specs()
|
|
2924
|
+
});
|
|
2925
|
+
const childLoop = new CacheFirstLoop({
|
|
2926
|
+
client: opts.client,
|
|
2927
|
+
prefix: childPrefix,
|
|
2928
|
+
tools: childTools,
|
|
2929
|
+
model,
|
|
2930
|
+
maxToolIters,
|
|
2931
|
+
hooks: [],
|
|
2932
|
+
stream: false
|
|
2933
|
+
});
|
|
2934
|
+
const onParentAbort = () => childLoop.abort();
|
|
2935
|
+
opts.parentSignal?.addEventListener("abort", onParentAbort, { once: true });
|
|
2936
|
+
let final = "";
|
|
2937
|
+
let errorMessage;
|
|
2938
|
+
let toolIter = 0;
|
|
2939
|
+
try {
|
|
2940
|
+
for await (const ev of childLoop.step(opts.task)) {
|
|
2941
|
+
if (ev.role === "tool") {
|
|
2942
|
+
toolIter++;
|
|
2943
|
+
sink?.current?.({
|
|
2944
|
+
kind: "progress",
|
|
2945
|
+
task: taskPreview,
|
|
2946
|
+
iter: toolIter,
|
|
2947
|
+
elapsedMs: Date.now() - startedAt
|
|
2948
|
+
});
|
|
2949
|
+
}
|
|
2950
|
+
if (ev.role === "assistant_final") {
|
|
2951
|
+
final = ev.content ?? "";
|
|
2952
|
+
}
|
|
2953
|
+
if (ev.role === "error") {
|
|
2954
|
+
errorMessage = ev.error ?? "subagent error";
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
} catch (err) {
|
|
2958
|
+
errorMessage = err.message;
|
|
2959
|
+
} finally {
|
|
2960
|
+
opts.parentSignal?.removeEventListener("abort", onParentAbort);
|
|
2961
|
+
}
|
|
2962
|
+
if (!errorMessage && !final) {
|
|
2963
|
+
errorMessage = opts.parentSignal?.aborted ? "subagent aborted before producing an answer" : "subagent ended without producing an answer";
|
|
2964
|
+
}
|
|
2965
|
+
const elapsedMs = Date.now() - startedAt;
|
|
2966
|
+
const turns = childLoop.stats.turns.length;
|
|
2967
|
+
const costUsd2 = childLoop.stats.totalCost;
|
|
2968
|
+
const truncated = final.length > maxResultChars ? `${final.slice(0, maxResultChars)}
|
|
2969
|
+
|
|
2970
|
+
[\u2026truncated ${final.length - maxResultChars} chars; ask the subagent for a tighter summary if you need more.]` : final;
|
|
2971
|
+
sink?.current?.({
|
|
2972
|
+
kind: "end",
|
|
2973
|
+
task: taskPreview,
|
|
2974
|
+
iter: toolIter,
|
|
2975
|
+
elapsedMs,
|
|
2976
|
+
summary: errorMessage ? void 0 : truncated.slice(0, 120),
|
|
2977
|
+
error: errorMessage,
|
|
2978
|
+
turns
|
|
2979
|
+
});
|
|
2980
|
+
return {
|
|
2981
|
+
success: !errorMessage,
|
|
2982
|
+
output: errorMessage ? "" : truncated,
|
|
2983
|
+
error: errorMessage,
|
|
2984
|
+
turns,
|
|
2985
|
+
toolIters: toolIter,
|
|
2986
|
+
elapsedMs,
|
|
2987
|
+
costUsd: costUsd2
|
|
2988
|
+
};
|
|
2989
|
+
}
|
|
2990
|
+
function formatSubagentResult(r) {
|
|
2991
|
+
if (!r.success) {
|
|
2992
|
+
return JSON.stringify({
|
|
2993
|
+
success: false,
|
|
2994
|
+
error: r.error ?? "unknown subagent error",
|
|
2995
|
+
turns: r.turns,
|
|
2996
|
+
tool_iters: r.toolIters,
|
|
2997
|
+
elapsed_ms: r.elapsedMs
|
|
2998
|
+
});
|
|
2999
|
+
}
|
|
3000
|
+
return JSON.stringify({
|
|
3001
|
+
success: true,
|
|
3002
|
+
output: r.output,
|
|
3003
|
+
turns: r.turns,
|
|
3004
|
+
tool_iters: r.toolIters,
|
|
3005
|
+
elapsed_ms: r.elapsedMs,
|
|
3006
|
+
cost_usd: r.costUsd
|
|
3007
|
+
});
|
|
3008
|
+
}
|
|
3009
|
+
function forkRegistryExcluding(parent, exclude) {
|
|
3010
|
+
const child = new ToolRegistry();
|
|
3011
|
+
for (const spec of parent.specs()) {
|
|
3012
|
+
const name = spec.function.name;
|
|
3013
|
+
if (exclude.has(name)) continue;
|
|
3014
|
+
const def = parent.get(name);
|
|
3015
|
+
if (!def) continue;
|
|
3016
|
+
child.register(def);
|
|
3017
|
+
}
|
|
3018
|
+
if (parent.planMode) child.setPlanMode(true);
|
|
3019
|
+
return child;
|
|
3020
|
+
}
|
|
3021
|
+
|
|
2716
3022
|
// src/tools/shell.ts
|
|
2717
3023
|
import { spawn as spawn2 } from "child_process";
|
|
2718
3024
|
import { existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
@@ -2910,7 +3216,7 @@ function prepareSpawn(argv, opts = {}) {
|
|
|
2910
3216
|
const cmdline = [resolved, ...tail].map(quoteForCmdExe).join(" ");
|
|
2911
3217
|
return {
|
|
2912
3218
|
bin: "cmd.exe",
|
|
2913
|
-
args: ["/d", "/s", "/c", cmdline],
|
|
3219
|
+
args: ["/d", "/s", "/c", withUtf8Codepage(cmdline)],
|
|
2914
3220
|
// windowsVerbatimArguments prevents Node from re-quoting the /c
|
|
2915
3221
|
// payload — we've already composed an exact cmd.exe command
|
|
2916
3222
|
// line. Without this Node wraps our already-quoted string in
|
|
@@ -2922,12 +3228,36 @@ function prepareSpawn(argv, opts = {}) {
|
|
|
2922
3228
|
const cmdline = [head, ...tail].map(quoteForCmdExe).join(" ");
|
|
2923
3229
|
return {
|
|
2924
3230
|
bin: "cmd.exe",
|
|
2925
|
-
args: ["/d", "/s", "/c", cmdline],
|
|
3231
|
+
args: ["/d", "/s", "/c", withUtf8Codepage(cmdline)],
|
|
2926
3232
|
spawnOverrides: { windowsVerbatimArguments: true }
|
|
2927
3233
|
};
|
|
2928
3234
|
}
|
|
3235
|
+
if (isPowerShellExe(resolved)) {
|
|
3236
|
+
const patched = injectPowerShellUtf8(tail);
|
|
3237
|
+
if (patched) {
|
|
3238
|
+
return { bin: resolved, args: patched, spawnOverrides: {} };
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
2929
3241
|
return { bin: resolved, args: [...tail], spawnOverrides: {} };
|
|
2930
3242
|
}
|
|
3243
|
+
function isPowerShellExe(resolved) {
|
|
3244
|
+
return /(?:^|[\\/])(?:powershell|pwsh)(?:\.exe)?$/i.test(resolved);
|
|
3245
|
+
}
|
|
3246
|
+
function injectPowerShellUtf8(args) {
|
|
3247
|
+
const prelude = "[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;$OutputEncoding=[System.Text.Encoding]::UTF8;";
|
|
3248
|
+
for (let i = 0; i < args.length; i++) {
|
|
3249
|
+
const a = args[i] ?? "";
|
|
3250
|
+
if (/^-(?:Command|c)$/i.test(a) && i + 1 < args.length) {
|
|
3251
|
+
const out = [...args];
|
|
3252
|
+
out[i + 1] = `${prelude}${args[i + 1] ?? ""}`;
|
|
3253
|
+
return out;
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
return null;
|
|
3257
|
+
}
|
|
3258
|
+
function withUtf8Codepage(cmdline) {
|
|
3259
|
+
return `chcp 65001 >nul & ${cmdline}`;
|
|
3260
|
+
}
|
|
2931
3261
|
function isBareWindowsName(s) {
|
|
2932
3262
|
if (!s) return false;
|
|
2933
3263
|
if (s.includes("/") || s.includes("\\")) return false;
|
|
@@ -4713,23 +5043,32 @@ import { existsSync as existsSync8, statSync as statSync4 } from "fs";
|
|
|
4713
5043
|
import { render } from "ink";
|
|
4714
5044
|
import React15, { useState as useState7 } from "react";
|
|
4715
5045
|
|
|
5046
|
+
// src/cli/ui/App.tsx
|
|
5047
|
+
import { Box as Box11, Static, Text as Text11, useApp, useInput as useInput4 } from "ink";
|
|
5048
|
+
import React12, { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState5 } from "react";
|
|
5049
|
+
|
|
4716
5050
|
// src/tools/skills.ts
|
|
4717
5051
|
function registerSkillTools(registry, opts = {}) {
|
|
4718
|
-
const store = new SkillStore({
|
|
5052
|
+
const store = new SkillStore({
|
|
5053
|
+
homeDir: opts.homeDir,
|
|
5054
|
+
projectRoot: opts.projectRoot,
|
|
5055
|
+
disableBuiltins: opts.disableBuiltins
|
|
5056
|
+
});
|
|
5057
|
+
const subagentRunner = opts.subagentRunner;
|
|
4719
5058
|
registry.register({
|
|
4720
5059
|
name: "run_skill",
|
|
4721
|
-
description: "
|
|
5060
|
+
description: "Invoke a playbook from the Skills index pinned in the system prompt. Each entry is a self-contained instruction block. Skills marked with \u{1F9EC} in the index spawn an isolated subagent \u2014 only the final distilled answer comes back, the model's tool calls + reasoning during the run never enter your context. Plain skills are inlined: the body becomes a tool result you read and follow. For \u{1F9EC} subagent skills, supply 'arguments' describing the concrete task \u2014 they'll be the only context the subagent has.",
|
|
4722
5061
|
readOnly: true,
|
|
4723
5062
|
parameters: {
|
|
4724
5063
|
type: "object",
|
|
4725
5064
|
properties: {
|
|
4726
5065
|
name: {
|
|
4727
5066
|
type: "string",
|
|
4728
|
-
description: "Skill identifier as it appears in the pinned Skills index (e.g. 'review', 'security-review'). Case-sensitive."
|
|
5067
|
+
description: "Skill identifier as it appears in the pinned Skills index (e.g. 'explore', 'review', 'security-review'). Case-sensitive."
|
|
4729
5068
|
},
|
|
4730
5069
|
arguments: {
|
|
4731
5070
|
type: "string",
|
|
4732
|
-
description: "
|
|
5071
|
+
description: "Free-form arguments the skill should act on. For inline skills: appended to the body as an 'Arguments:' line; the skill's own instructions decide how to consume them. For \u{1F9EC} subagent skills: REQUIRED \u2014 becomes the entire task description the subagent receives, since it has no other context."
|
|
4733
5072
|
}
|
|
4734
5073
|
},
|
|
4735
5074
|
required: ["name"]
|
|
@@ -4748,6 +5087,19 @@ function registerSkillTools(registry, opts = {}) {
|
|
|
4748
5087
|
});
|
|
4749
5088
|
}
|
|
4750
5089
|
const rawArgs = typeof args.arguments === "string" ? args.arguments.trim() : "";
|
|
5090
|
+
if (skill.runAs === "subagent") {
|
|
5091
|
+
if (!subagentRunner) {
|
|
5092
|
+
return JSON.stringify({
|
|
5093
|
+
error: `run_skill: skill ${JSON.stringify(name)} is marked runAs=subagent but no subagent runner is configured for this session. Skill authors who need isolation should run inside reasonix code (or a library setup that passes subagentRunner to registerSkillTools).`
|
|
5094
|
+
});
|
|
5095
|
+
}
|
|
5096
|
+
if (!rawArgs) {
|
|
5097
|
+
return JSON.stringify({
|
|
5098
|
+
error: `run_skill: skill ${JSON.stringify(name)} is a subagent and requires 'arguments' \u2014 the subagent has no other context, so describe the concrete task in the arguments field.`
|
|
5099
|
+
});
|
|
5100
|
+
}
|
|
5101
|
+
return subagentRunner(skill, rawArgs);
|
|
5102
|
+
}
|
|
4751
5103
|
const header2 = [
|
|
4752
5104
|
`# Skill: ${skill.name}`,
|
|
4753
5105
|
skill.description ? `> ${skill.description}` : "",
|
|
@@ -4764,10 +5116,6 @@ ${skill.body}${argsBlock}`;
|
|
|
4764
5116
|
return registry;
|
|
4765
5117
|
}
|
|
4766
5118
|
|
|
4767
|
-
// src/cli/ui/App.tsx
|
|
4768
|
-
import { Box as Box11, Static, Text as Text11, useApp, useInput as useInput4 } from "ink";
|
|
4769
|
-
import React12, { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState5 } from "react";
|
|
4770
|
-
|
|
4771
5119
|
// src/cli/ui/EventLog.tsx
|
|
4772
5120
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
4773
5121
|
import React4 from "react";
|
|
@@ -4840,7 +5188,7 @@ function stripMath(s) {
|
|
|
4840
5188
|
).replace(/\\sqrt\s*\{([^{}]+)\}/g, (_m, g) => `\u221A(${g.trim()})`).replace(/\\boxed\s*\{([^{}]+)\}/g, (_m, g) => `\u3010${g.trim()}\u3011`).replace(/\\text\s*\{([^{}]+)\}/g, (_m, g) => g.trim()).replace(/\\overline\s*\{([^{}]+)\}/g, (_m, g) => `${g.trim()}\u0304`).replace(/\\hat\s*\{([^{}]+)\}/g, (_m, g) => `${g.trim()}\u0302`).replace(/\\vec\s*\{([^{}]+)\}/g, (_m, g) => `\u2192${g.trim()}`).replace(/\\cdot/g, "\xB7").replace(/\\times/g, "\xD7").replace(/\\div/g, "\xF7").replace(/\\pm/g, "\xB1").replace(/\\mp/g, "\u2213").replace(/\\leq/g, "\u2264").replace(/\\geq/g, "\u2265").replace(/\\neq/g, "\u2260").replace(/\\approx/g, "\u2248").replace(/\\in\b/g, "\u2208").replace(/\\notin\b/g, "\u2209").replace(/\\infty/g, "\u221E").replace(/\\sum\b/g, "\u03A3").replace(/\\prod\b/g, "\u03A0").replace(/\\int\b/g, "\u222B").replace(/\\alpha/g, "\u03B1").replace(/\\beta/g, "\u03B2").replace(/\\gamma/g, "\u03B3").replace(/\\delta/g, "\u03B4").replace(/\\theta/g, "\u03B8").replace(/\\lambda/g, "\u03BB").replace(/\\mu/g, "\u03BC").replace(/\\pi/g, "\u03C0").replace(/\\sigma/g, "\u03C3").replace(/\\phi/g, "\u03C6").replace(/\\omega/g, "\u03C9").replace(/\\implies\b/g, "\u21D2").replace(/\\iff\b/g, "\u21D4").replace(/\\to\b/g, "\u2192").replace(/\\rightarrow/g, "\u2192").replace(/\\Rightarrow/g, "\u21D2").replace(/\\leftarrow/g, "\u2190").replace(/\\Leftarrow/g, "\u21D0").replace(/\\ldots/g, "\u2026").replace(/\\cdots/g, "\u22EF").replace(/\\quad/g, " ").replace(/\\qquad/g, " ").replace(/\\,/g, " ").replace(/\\;/g, " ").replace(/\\!/g, "").replace(/\\\\/g, "\n").replace(/\^\{([\w+-]+)\}/g, (_m, g) => toSuperscript(g)).replace(/\^([0-9+\-n])/g, (_m, g) => toSuperscript(g)).replace(/_\{([\w+-]+)\}/g, (_m, g) => toSubscript(g)).replace(/_([0-9+\-])/g, (_m, g) => toSubscript(g)).replace(/\\[a-zA-Z]+\s*\{([^{}]+)\}\s*\{([^{}]+)\}/g, "($1)/($2)").replace(/\\[a-zA-Z]+\s*\{([^{}]+)\}/g, "$1").replace(/\\[a-zA-Z]+/g, "").replace(/[ \t]{2,}/g, " ");
|
|
4841
5189
|
}
|
|
4842
5190
|
var INLINE_RE = /(\*\*([^*\n]+?)\*\*|```([^\n]+?)```|`([^`\n]+?)`|(?<![*\w])\*([^*\n]+?)\*(?!\w))/g;
|
|
4843
|
-
function InlineMd({ text }) {
|
|
5191
|
+
function InlineMd({ text, padTo }) {
|
|
4844
5192
|
const parts = [];
|
|
4845
5193
|
let last = 0;
|
|
4846
5194
|
let idx = 0;
|
|
@@ -4872,8 +5220,20 @@ function InlineMd({ text }) {
|
|
|
4872
5220
|
if (last < text.length) {
|
|
4873
5221
|
parts.push(/* @__PURE__ */ React2.createElement(Text2, { key: `t${idx++}` }, text.slice(last)));
|
|
4874
5222
|
}
|
|
5223
|
+
if (padTo !== void 0) {
|
|
5224
|
+
const seen = visibleWidth(text);
|
|
5225
|
+
if (seen < padTo) {
|
|
5226
|
+
parts.push(/* @__PURE__ */ React2.createElement(Text2, { key: `pad${idx++}` }, " ".repeat(padTo - seen)));
|
|
5227
|
+
}
|
|
5228
|
+
}
|
|
4875
5229
|
return /* @__PURE__ */ React2.createElement(Text2, null, parts);
|
|
4876
5230
|
}
|
|
5231
|
+
function stripInlineMarkup(s) {
|
|
5232
|
+
return s.replace(/\*\*([^*\n]+?)\*\*/g, "$1").replace(/```([^\n]+?)```/g, (_m, c) => c.replace(/^(\w+)\s+/, "")).replace(/`([^`\n]+?)`/g, "$1").replace(/(?<![*\w])\*([^*\n]+?)\*(?!\w)/g, "$1");
|
|
5233
|
+
}
|
|
5234
|
+
function visibleWidth(s) {
|
|
5235
|
+
return displayWidth(stripInlineMarkup(s));
|
|
5236
|
+
}
|
|
4877
5237
|
function parseBlocks(raw) {
|
|
4878
5238
|
const lines = raw.split(/\r?\n/);
|
|
4879
5239
|
const out = [];
|
|
@@ -4980,17 +5340,47 @@ function parseBlocks(raw) {
|
|
|
4980
5340
|
out.push({ kind: "heading", level: hm[1].length, text: hm[2].trim() });
|
|
4981
5341
|
continue;
|
|
4982
5342
|
}
|
|
4983
|
-
if (line
|
|
5343
|
+
if (/^\s*┌─+┐\s*$/.test(line)) {
|
|
5344
|
+
let j = i + 1;
|
|
5345
|
+
const bodyLines = [];
|
|
5346
|
+
while (j < lines.length && !/^\s*└─+┘\s*$/.test(lines[j])) {
|
|
5347
|
+
const inner = lines[j];
|
|
5348
|
+
const m = inner.match(/^\s*│\s?(.*?)\s?│\s*$/);
|
|
5349
|
+
bodyLines.push(m ? m[1] ?? "" : inner);
|
|
5350
|
+
j++;
|
|
5351
|
+
}
|
|
5352
|
+
if (j < lines.length) {
|
|
5353
|
+
flushPara();
|
|
5354
|
+
flushList();
|
|
5355
|
+
out.push({ kind: "code", lang: "", text: bodyLines.join("\n") });
|
|
5356
|
+
i = j;
|
|
5357
|
+
continue;
|
|
5358
|
+
}
|
|
5359
|
+
}
|
|
5360
|
+
if (line.includes("|") || line.includes("\u2502")) {
|
|
4984
5361
|
const next = (lines[i + 1] ?? "").trim();
|
|
4985
|
-
|
|
5362
|
+
const isGfmSep = /^\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)+\|?\s*$/.test(next);
|
|
5363
|
+
const isBoxSep = /^[│─┼┬┴┌┐└┘├┤\s]+$/.test(next) && /─{2,}/.test(next);
|
|
5364
|
+
if (isGfmSep || isBoxSep) {
|
|
4986
5365
|
flushPara();
|
|
4987
5366
|
flushList();
|
|
4988
5367
|
const header2 = splitTableRow(line);
|
|
5368
|
+
const colCount = header2.length;
|
|
4989
5369
|
const rows = [];
|
|
4990
5370
|
let j = i + 2;
|
|
4991
5371
|
while (j < lines.length) {
|
|
4992
5372
|
const r = lines[j].replace(/\s+$/g, "");
|
|
4993
|
-
if (r.trim() === ""
|
|
5373
|
+
if (r.trim() === "") break;
|
|
5374
|
+
if (!r.includes("|") && !r.includes("\u2502")) {
|
|
5375
|
+
const prev = rows[rows.length - 1];
|
|
5376
|
+
if (prev && prev.length === colCount) {
|
|
5377
|
+
const lastIdx = prev.length - 1;
|
|
5378
|
+
prev[lastIdx] = `${prev[lastIdx] ?? ""} ${r.trim()}`;
|
|
5379
|
+
j++;
|
|
5380
|
+
continue;
|
|
5381
|
+
}
|
|
5382
|
+
break;
|
|
5383
|
+
}
|
|
4994
5384
|
rows.push(splitTableRow(r));
|
|
4995
5385
|
j++;
|
|
4996
5386
|
}
|
|
@@ -5049,7 +5439,7 @@ function BlockView({ block }) {
|
|
|
5049
5439
|
}
|
|
5050
5440
|
function splitTableRow(line) {
|
|
5051
5441
|
const SENTINEL = "\0";
|
|
5052
|
-
const masked = line.replace(/\\\|/g, SENTINEL);
|
|
5442
|
+
const masked = line.replace(/\\\|/g, SENTINEL).replace(/│/g, "|");
|
|
5053
5443
|
const trimmed = masked.trim().replace(/^\||\|$/g, "");
|
|
5054
5444
|
return trimmed.split("|").map((c) => c.trim().replace(new RegExp(SENTINEL, "g"), "|"));
|
|
5055
5445
|
}
|
|
@@ -5057,24 +5447,19 @@ function TableBlockRow({ block }) {
|
|
|
5057
5447
|
const colCount = Math.max(block.header.length, ...block.rows.map((r) => r.length));
|
|
5058
5448
|
const widths = [];
|
|
5059
5449
|
for (let c = 0; c < colCount; c++) {
|
|
5060
|
-
const cellLengths = [
|
|
5061
|
-
for (const r of block.rows) cellLengths.push(
|
|
5450
|
+
const cellLengths = [visibleWidth(block.header[c] ?? "")];
|
|
5451
|
+
for (const r of block.rows) cellLengths.push(visibleWidth(r[c] ?? ""));
|
|
5062
5452
|
widths.push(Math.min(40, Math.max(3, ...cellLengths)));
|
|
5063
5453
|
}
|
|
5064
|
-
const pad3 = (s, w) => {
|
|
5065
|
-
const dw = displayWidth(s);
|
|
5066
|
-
if (dw >= w) return s;
|
|
5067
|
-
return s + " ".repeat(w - dw);
|
|
5068
|
-
};
|
|
5069
5454
|
const separator = widths.map((w) => "\u2500".repeat(w)).join("\u2500\u253C\u2500");
|
|
5070
5455
|
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Box2, null, block.header.map((cell, ci) => (
|
|
5071
5456
|
// biome-ignore lint/suspicious/noArrayIndexKey: table columns never reorder — derived from a static header array
|
|
5072
|
-
/* @__PURE__ */ React2.createElement(Text2, { key: `h-${ci}`, bold: true, color: "cyan" },
|
|
5457
|
+
/* @__PURE__ */ React2.createElement(Text2, { key: `h-${ci}`, bold: true, color: "cyan" }, /* @__PURE__ */ React2.createElement(InlineMd, { text: cell, padTo: widths[ci] ?? 3 }), ci < colCount - 1 ? " \u2502 " : "")
|
|
5073
5458
|
))), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, separator), block.rows.map((row2, ri) => (
|
|
5074
5459
|
// biome-ignore lint/suspicious/noArrayIndexKey: table rows render in source order and don't reorder
|
|
5075
5460
|
/* @__PURE__ */ React2.createElement(Box2, { key: `r-${ri}` }, Array.from({ length: colCount }).map((_, ci) => (
|
|
5076
5461
|
// biome-ignore lint/suspicious/noArrayIndexKey: same — column axis is fixed by the table shape
|
|
5077
|
-
/* @__PURE__ */ React2.createElement(Text2, { key: `c-${ri}-${ci}` },
|
|
5462
|
+
/* @__PURE__ */ React2.createElement(Text2, { key: `c-${ri}-${ci}` }, /* @__PURE__ */ React2.createElement(InlineMd, { text: row2[ci] ?? "", padTo: widths[ci] ?? 3 }), ci < colCount - 1 ? " \u2502 " : "")
|
|
5078
5463
|
)))
|
|
5079
5464
|
)));
|
|
5080
5465
|
}
|
|
@@ -6710,6 +7095,7 @@ function App({
|
|
|
6710
7095
|
const abortedThisTurn = useRef2(false);
|
|
6711
7096
|
const [ongoingTool, setOngoingTool] = useState5(null);
|
|
6712
7097
|
const [toolProgress, setToolProgress] = useState5(null);
|
|
7098
|
+
const [subagentActivity, setSubagentActivity] = useState5(null);
|
|
6713
7099
|
const [statusLine, setStatusLine] = useState5(null);
|
|
6714
7100
|
const [balance, setBalance] = useState5(null);
|
|
6715
7101
|
const [latestVersion, setLatestVersion] = useState5(null);
|
|
@@ -6766,9 +7152,30 @@ function App({
|
|
|
6766
7152
|
});
|
|
6767
7153
|
}, [slashMatches]);
|
|
6768
7154
|
const loopRef = useRef2(null);
|
|
7155
|
+
const subagentSinkRef = useRef2({ current: null });
|
|
6769
7156
|
const loop = useMemo(() => {
|
|
6770
7157
|
if (loopRef.current) return loopRef.current;
|
|
6771
7158
|
const client = new DeepSeekClient();
|
|
7159
|
+
if (tools && !tools.has("run_skill")) {
|
|
7160
|
+
registerSkillTools(tools, {
|
|
7161
|
+
projectRoot: codeMode?.rootDir,
|
|
7162
|
+
subagentRunner: async (skill, task) => {
|
|
7163
|
+
const result = await spawnSubagent({
|
|
7164
|
+
client,
|
|
7165
|
+
parentRegistry: tools,
|
|
7166
|
+
// Skill body is the subagent's persona/playbook; the user-
|
|
7167
|
+
// supplied task is what to actually do inside it.
|
|
7168
|
+
system: skill.body,
|
|
7169
|
+
task,
|
|
7170
|
+
// Per-skill model override (frontmatter `model: ...`),
|
|
7171
|
+
// else falls through to spawnSubagent's default.
|
|
7172
|
+
model: skill.model,
|
|
7173
|
+
sink: subagentSinkRef.current
|
|
7174
|
+
});
|
|
7175
|
+
return formatSubagentResult(result);
|
|
7176
|
+
}
|
|
7177
|
+
});
|
|
7178
|
+
}
|
|
6772
7179
|
const prefix = new ImmutablePrefix({
|
|
6773
7180
|
system,
|
|
6774
7181
|
toolSpecs: tools?.specs()
|
|
@@ -6786,7 +7193,7 @@ function App({
|
|
|
6786
7193
|
});
|
|
6787
7194
|
loopRef.current = l;
|
|
6788
7195
|
return l;
|
|
6789
|
-
}, [model, system, harvest2, branch, session, tools]);
|
|
7196
|
+
}, [model, system, harvest2, branch, session, tools, codeMode]);
|
|
6790
7197
|
useEffect2(() => {
|
|
6791
7198
|
loop.hooks = hookList;
|
|
6792
7199
|
}, [loop, hookList]);
|
|
@@ -6826,6 +7233,40 @@ function App({
|
|
|
6826
7233
|
if (progressSink.current) progressSink.current = null;
|
|
6827
7234
|
};
|
|
6828
7235
|
}, [progressSink]);
|
|
7236
|
+
useEffect2(() => {
|
|
7237
|
+
subagentSinkRef.current.current = (ev) => {
|
|
7238
|
+
if (ev.kind === "start") {
|
|
7239
|
+
setSubagentActivity({
|
|
7240
|
+
task: ev.task,
|
|
7241
|
+
iter: ev.iter ?? 0,
|
|
7242
|
+
elapsedMs: ev.elapsedMs ?? 0
|
|
7243
|
+
});
|
|
7244
|
+
return;
|
|
7245
|
+
}
|
|
7246
|
+
if (ev.kind === "progress") {
|
|
7247
|
+
setSubagentActivity({
|
|
7248
|
+
task: ev.task,
|
|
7249
|
+
iter: ev.iter ?? 0,
|
|
7250
|
+
elapsedMs: ev.elapsedMs ?? 0
|
|
7251
|
+
});
|
|
7252
|
+
return;
|
|
7253
|
+
}
|
|
7254
|
+
setSubagentActivity(null);
|
|
7255
|
+
const seconds = ((ev.elapsedMs ?? 0) / 1e3).toFixed(1);
|
|
7256
|
+
const summary2 = ev.error ? `\u{1F9EC} subagent "${ev.task}" failed after ${seconds}s \xB7 ${ev.iter ?? 0} tool call(s) \u2014 ${ev.error}` : `\u{1F9EC} subagent "${ev.task}" done in ${seconds}s \xB7 ${ev.iter ?? 0} tool call(s) \xB7 ${ev.turns ?? 0} turn(s)`;
|
|
7257
|
+
setHistorical((prev) => [
|
|
7258
|
+
...prev,
|
|
7259
|
+
{
|
|
7260
|
+
id: `subagent-end-${Date.now()}`,
|
|
7261
|
+
role: "info",
|
|
7262
|
+
text: summary2
|
|
7263
|
+
}
|
|
7264
|
+
]);
|
|
7265
|
+
};
|
|
7266
|
+
return () => {
|
|
7267
|
+
subagentSinkRef.current.current = null;
|
|
7268
|
+
};
|
|
7269
|
+
}, []);
|
|
6829
7270
|
const sessionBannerShown = useRef2(false);
|
|
6830
7271
|
useEffect2(() => {
|
|
6831
7272
|
if (sessionBannerShown.current) return;
|
|
@@ -7436,7 +7877,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
|
|
|
7436
7877
|
balance,
|
|
7437
7878
|
updateAvailable
|
|
7438
7879
|
}
|
|
7439
|
-
), /* @__PURE__ */ React12.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React12.createElement(EventRow, { key: item.id, event: item })), !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && streaming ? /* @__PURE__ */ React12.createElement(Box11, { marginY: 1 }, /* @__PURE__ */ React12.createElement(EventRow, { event: streaming })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && ongoingTool ? /* @__PURE__ */ React12.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !ongoingTool && statusLine ? /* @__PURE__ */ React12.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React12.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React12.createElement(
|
|
7880
|
+
), /* @__PURE__ */ React12.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React12.createElement(EventRow, { key: item.id, event: item })), !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && streaming ? /* @__PURE__ */ React12.createElement(Box11, { marginY: 1 }, /* @__PURE__ */ React12.createElement(EventRow, { event: streaming })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && ongoingTool ? /* @__PURE__ */ React12.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && subagentActivity ? /* @__PURE__ */ React12.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !ongoingTool && statusLine ? /* @__PURE__ */ React12.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React12.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React12.createElement(
|
|
7440
7881
|
PlanRefineInput,
|
|
7441
7882
|
{
|
|
7442
7883
|
mode: stagedInput.mode,
|
|
@@ -7466,6 +7907,13 @@ function StatusRow({ text }) {
|
|
|
7466
7907
|
const elapsed = useElapsedSeconds();
|
|
7467
7908
|
return /* @__PURE__ */ React12.createElement(Box11, { marginY: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React12.createElement(Text11, { color: "magenta" }, ` ${text}`), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, ` ${elapsed}s`));
|
|
7468
7909
|
}
|
|
7910
|
+
function SubagentRow({
|
|
7911
|
+
activity
|
|
7912
|
+
}) {
|
|
7913
|
+
const tick = useTick();
|
|
7914
|
+
const seconds = (activity.elapsedMs / 1e3).toFixed(1);
|
|
7915
|
+
return /* @__PURE__ */ React12.createElement(Box11, { paddingLeft: 2 }, /* @__PURE__ */ React12.createElement(Text11, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React12.createElement(Text11, { color: "magenta" }, ` \u{1F9EC} subagent: ${activity.task}`), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, ` \xB7 iter ${activity.iter} \xB7 ${seconds}s`));
|
|
7916
|
+
}
|
|
7469
7917
|
function OngoingToolRow({
|
|
7470
7918
|
tool,
|
|
7471
7919
|
progress
|
|
@@ -7784,7 +8232,6 @@ async function chatCommand(opts) {
|
|
|
7784
8232
|
if (!opts.seedTools) {
|
|
7785
8233
|
if (!tools) tools = new ToolRegistry();
|
|
7786
8234
|
registerMemoryTools(tools, {});
|
|
7787
|
-
registerSkillTools(tools);
|
|
7788
8235
|
}
|
|
7789
8236
|
let sessionPreview;
|
|
7790
8237
|
if (opts.session && !opts.forceResume && !opts.forceNew) {
|
|
@@ -7824,7 +8271,7 @@ async function chatCommand(opts) {
|
|
|
7824
8271
|
// src/cli/commands/code.tsx
|
|
7825
8272
|
import { basename, resolve as resolve5 } from "path";
|
|
7826
8273
|
async function codeCommand(opts = {}) {
|
|
7827
|
-
const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-
|
|
8274
|
+
const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-6DMLWG2H.js");
|
|
7828
8275
|
const rootDir = resolve5(opts.dir ?? process.cwd());
|
|
7829
8276
|
const session = opts.noSession ? void 0 : `code-${sanitizeName(basename(rootDir))}`;
|
|
7830
8277
|
const tools = new ToolRegistry();
|
|
@@ -7840,7 +8287,6 @@ async function codeCommand(opts = {}) {
|
|
|
7840
8287
|
});
|
|
7841
8288
|
registerPlanTool(tools);
|
|
7842
8289
|
registerMemoryTools(tools, { projectRoot: rootDir });
|
|
7843
|
-
registerSkillTools(tools, { projectRoot: rootDir });
|
|
7844
8290
|
process.stderr.write(
|
|
7845
8291
|
`\u25B8 reasonix code: rooted at ${rootDir}, session "${session ?? "(ephemeral)"}" \xB7 ${tools.size} native tool(s)
|
|
7846
8292
|
`
|