@kernelonpanic/kitcode 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +213 -94
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -62,8 +62,7 @@ var themeSchema = z.object({
|
|
|
62
62
|
var langSchema = z.enum(["en", "ru"]);
|
|
63
63
|
var budgetSchema = z.object({
|
|
64
64
|
maxTokensPerTurn: z.number().int().min(0).max(1e7).default(1e7),
|
|
65
|
-
maxCostUsdPerTurn: z.number().nonnegative().max(1e3).default(0)
|
|
66
|
-
maxSubagentsPerTurn: z.number().int().min(0).max(16).default(3)
|
|
65
|
+
maxCostUsdPerTurn: z.number().nonnegative().max(1e3).default(0)
|
|
67
66
|
});
|
|
68
67
|
var diagnosticsSchema = z.object({
|
|
69
68
|
autoRun: z.boolean().default(true),
|
|
@@ -79,8 +78,7 @@ var configSchema = z.object({
|
|
|
79
78
|
maxTokens: z.number().int().positive().max(2e5).default(64e3),
|
|
80
79
|
budget: budgetSchema.default({
|
|
81
80
|
maxTokensPerTurn: 1e7,
|
|
82
|
-
maxCostUsdPerTurn: 0
|
|
83
|
-
maxSubagentsPerTurn: 3
|
|
81
|
+
maxCostUsdPerTurn: 0
|
|
84
82
|
}),
|
|
85
83
|
diagnostics: diagnosticsSchema.default({ autoRun: true, commands: [] }),
|
|
86
84
|
providers: z.record(providerIdSchema, providerConfigSchema).default({}),
|
|
@@ -1814,8 +1812,23 @@ var MAX_PAUSE_RESUMES = 5;
|
|
|
1814
1812
|
var MAX_RETRIES2 = 3;
|
|
1815
1813
|
var INITIAL_BACKOFF_MS = 1e3;
|
|
1816
1814
|
var MAX_TURN_STEPS = 64;
|
|
1817
|
-
|
|
1815
|
+
function createExecutionLane() {
|
|
1816
|
+
let tail2 = Promise.resolve();
|
|
1817
|
+
return {
|
|
1818
|
+
run(operation) {
|
|
1819
|
+
const result = tail2.then(operation);
|
|
1820
|
+
tail2 = result.then(() => void 0, () => void 0);
|
|
1821
|
+
return result;
|
|
1822
|
+
}
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1818
1825
|
async function runTurn(cfg, history, hooks, signal) {
|
|
1826
|
+
const permissionLane = cfg.permissionLane ?? createExecutionLane();
|
|
1827
|
+
const originalHooks = hooks;
|
|
1828
|
+
hooks = {
|
|
1829
|
+
...hooks,
|
|
1830
|
+
requestPermission: (request) => permissionLane.run(async () => signal.aborted ? "deny" : originalHooks.requestPermission(request))
|
|
1831
|
+
};
|
|
1819
1832
|
let messages = [...history];
|
|
1820
1833
|
let pauses = 0;
|
|
1821
1834
|
let steps = 0;
|
|
@@ -1833,40 +1846,35 @@ async function runTurn(cfg, history, hooks, signal) {
|
|
|
1833
1846
|
hooks.onEvent({ type: "turn_end", stopReason: "max_tokens" });
|
|
1834
1847
|
return messages;
|
|
1835
1848
|
}
|
|
1836
|
-
const
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1849
|
+
const request = async () => {
|
|
1850
|
+
if (signal.aborted) return { content: [], stopReason: "aborted" };
|
|
1851
|
+
const budgetDecision = cfg.budget?.beforeRequest({
|
|
1852
|
+
modelRef: cfg.modelRef,
|
|
1853
|
+
maxOutputTokens: cfg.maxTokens,
|
|
1854
|
+
estimatedInputTokens: estimateRequestTokens(cfg, messages)
|
|
1855
|
+
});
|
|
1856
|
+
if (budgetDecision && !budgetDecision.allowed) {
|
|
1857
|
+
hooks.onEvent({ type: "notice", level: "warn", text: budgetDecision.reason });
|
|
1858
|
+
hooks.onEvent({ type: "turn_end", stopReason: "max_tokens" });
|
|
1859
|
+
return null;
|
|
1860
|
+
}
|
|
1861
|
+
hooks.onEvent({ type: "turn_start" });
|
|
1862
|
+
return consumeStream(
|
|
1863
|
+
cfg,
|
|
1864
|
+
messages,
|
|
1865
|
+
hooks,
|
|
1866
|
+
signal,
|
|
1867
|
+
budgetDecision?.maxOutputTokens ?? cfg.maxTokens
|
|
1868
|
+
);
|
|
1869
|
+
};
|
|
1870
|
+
const outcome = await (cfg.modelRequestLane?.run(request) ?? request());
|
|
1871
|
+
if (!outcome) return messages;
|
|
1854
1872
|
messages.push({ role: "assistant", content: outcome.content });
|
|
1855
1873
|
if (outcome.stopReason === "aborted") {
|
|
1856
1874
|
hooks.onEvent({ type: "turn_end", stopReason: "aborted" });
|
|
1857
1875
|
return sanitizeHistory(messages);
|
|
1858
1876
|
}
|
|
1859
1877
|
if (outcome.stopReason === "tool_use") {
|
|
1860
|
-
const callCount = outcome.content.filter((block) => block.type === "tool_use").length;
|
|
1861
|
-
if (callCount > MAX_TOOL_CALLS_PER_STEP) {
|
|
1862
|
-
hooks.onEvent({
|
|
1863
|
-
type: "notice",
|
|
1864
|
-
level: "warn",
|
|
1865
|
-
text: `The model returned ${callCount} tool calls at once; the limit is ${MAX_TOOL_CALLS_PER_STEP}. None were run. Ask it to split the work into smaller batches.`
|
|
1866
|
-
});
|
|
1867
|
-
hooks.onEvent({ type: "turn_end", stopReason: "max_tokens" });
|
|
1868
|
-
return sanitizeHistory(messages);
|
|
1869
|
-
}
|
|
1870
1878
|
const results = await runToolCalls(cfg, outcome.content, hooks, signal);
|
|
1871
1879
|
if (results.length > 0) messages.push({ role: "user", content: results });
|
|
1872
1880
|
if (signal.aborted) {
|
|
@@ -2054,10 +2062,32 @@ function estimateRequestTokens(cfg, messages) {
|
|
|
2054
2062
|
async function runToolCalls(cfg, content, hooks, signal) {
|
|
2055
2063
|
const calls = content.filter((block) => block.type === "tool_use");
|
|
2056
2064
|
const results = [];
|
|
2057
|
-
|
|
2065
|
+
const run = (call) => {
|
|
2066
|
+
const operation = () => runOneCall(cfg, call, hooks, signal);
|
|
2067
|
+
return call.name !== "task" && cfg.executionLane ? cfg.executionLane.run(operation) : operation();
|
|
2068
|
+
};
|
|
2069
|
+
for (let index = 0; index < calls.length; ) {
|
|
2070
|
+
const call = calls[index];
|
|
2071
|
+
if (call.name !== "task") {
|
|
2072
|
+
results.push(await run(call));
|
|
2073
|
+
index += 1;
|
|
2074
|
+
continue;
|
|
2075
|
+
}
|
|
2076
|
+
const batch = [];
|
|
2077
|
+
while (calls[index]?.name === "task") {
|
|
2078
|
+
batch.push(run(calls[index]));
|
|
2079
|
+
index += 1;
|
|
2080
|
+
}
|
|
2081
|
+
const settled = await Promise.allSettled(batch);
|
|
2082
|
+
for (const result of settled) {
|
|
2083
|
+
if (result.status === "rejected") throw result.reason;
|
|
2084
|
+
results.push(result.value);
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2058
2087
|
return results;
|
|
2059
2088
|
}
|
|
2060
2089
|
async function runOneCall(cfg, call, hooks, signal) {
|
|
2090
|
+
if (signal.aborted) return toolError(call.id, "Interrupted by the user before this tool ran.");
|
|
2061
2091
|
const tool = cfg.tools.get(call.name);
|
|
2062
2092
|
if (!tool) {
|
|
2063
2093
|
return toolError(call.id, `Unknown tool "${call.name}". Use only the tools provided.`);
|
|
@@ -2076,26 +2106,31 @@ async function runOneCall(cfg, call, hooks, signal) {
|
|
|
2076
2106
|
}) !== "deny"
|
|
2077
2107
|
};
|
|
2078
2108
|
const requestedPermission = requestedPermissionFor(tool, call.input, ctx);
|
|
2079
|
-
const
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
if (gate === "ask") {
|
|
2087
|
-
const decision = await hooks.requestPermission({
|
|
2088
|
-
toolName: tool.name,
|
|
2089
|
-
summary: summary2,
|
|
2090
|
-
input: call.input,
|
|
2091
|
-
display: await previewCall(tool, call.input, ctx),
|
|
2092
|
-
allowAlways: canAlwaysApprove(tool)
|
|
2093
|
-
});
|
|
2094
|
-
if (decision === "deny") {
|
|
2095
|
-
return toolError(call.id, "The user declined this call. Do not retry it; ask how to proceed.");
|
|
2109
|
+
const permission = async () => {
|
|
2110
|
+
const gate = cfg.permissions.decide(tool, requestedPermission);
|
|
2111
|
+
if (gate === "deny") {
|
|
2112
|
+
return toolError(
|
|
2113
|
+
call.id,
|
|
2114
|
+
cfg.permissions.denyReason?.(tool, requestedPermission) ?? `Tool "${tool.name}" is disabled by the user's configuration. Do not retry it; find another way or ask.`
|
|
2115
|
+
);
|
|
2096
2116
|
}
|
|
2097
|
-
if (
|
|
2098
|
-
|
|
2117
|
+
if (gate === "ask") {
|
|
2118
|
+
const decision = await hooks.requestPermission({
|
|
2119
|
+
toolName: tool.name,
|
|
2120
|
+
summary: summary2,
|
|
2121
|
+
input: call.input,
|
|
2122
|
+
display: await previewCall(tool, call.input, ctx),
|
|
2123
|
+
allowAlways: canAlwaysApprove(tool)
|
|
2124
|
+
});
|
|
2125
|
+
if (decision === "deny") {
|
|
2126
|
+
return toolError(call.id, "The user declined this call. Do not retry it; ask how to proceed.");
|
|
2127
|
+
}
|
|
2128
|
+
if (decision === "always") cfg.permissions.grantForSession(tool.name);
|
|
2129
|
+
}
|
|
2130
|
+
return void 0;
|
|
2131
|
+
};
|
|
2132
|
+
const permissionResult = await permission();
|
|
2133
|
+
if (permissionResult) return permissionResult;
|
|
2099
2134
|
if (signal.aborted) {
|
|
2100
2135
|
return toolError(call.id, "Interrupted by the user before this tool ran.");
|
|
2101
2136
|
}
|
|
@@ -2191,6 +2226,7 @@ function createTurnBudget(limits, resolvePricing = pricingFor) {
|
|
|
2191
2226
|
costUsd
|
|
2192
2227
|
});
|
|
2193
2228
|
return {
|
|
2229
|
+
hasLimits: limits.maxTokensPerTurn > 0 || limits.maxCostUsdPerTurn > 0,
|
|
2194
2230
|
beforeRequest(request) {
|
|
2195
2231
|
const current = snapshot();
|
|
2196
2232
|
if (limits.maxTokensPerTurn > 0 && current.tokens >= limits.maxTokensPerTurn) {
|
|
@@ -3667,6 +3703,9 @@ var SUBAGENT_SYSTEM = [
|
|
|
3667
3703
|
'Your final message is the return value \u2014 it is the only thing the caller ever sees. End with the answer itself: the findings, the file paths, the conclusion. Never end with "I will now..." or a recap of the steps you took. Carry over every concrete detail the caller needs (paths, names, line numbers) and leave out the narration of how you found them.'
|
|
3668
3704
|
].join("\n");
|
|
3669
3705
|
function createSubagentRunner(makeConfig, tools) {
|
|
3706
|
+
const permissionLane = createExecutionLane();
|
|
3707
|
+
const executionLane = createExecutionLane();
|
|
3708
|
+
const modelRequestLane = createExecutionLane();
|
|
3670
3709
|
return {
|
|
3671
3710
|
async run(request) {
|
|
3672
3711
|
if (request.signal.aborted) return SUBAGENT_CANCELLED;
|
|
@@ -3674,6 +3713,9 @@ function createSubagentRunner(makeConfig, tools) {
|
|
|
3674
3713
|
const base = makeConfig(SUBAGENT_SYSTEM, tools);
|
|
3675
3714
|
const cfg = {
|
|
3676
3715
|
...base,
|
|
3716
|
+
permissionLane,
|
|
3717
|
+
executionLane,
|
|
3718
|
+
modelRequestLane: base.budget?.hasLimits ? modelRequestLane : void 0,
|
|
3677
3719
|
provider: {
|
|
3678
3720
|
id: base.provider.id,
|
|
3679
3721
|
kind: base.provider.kind,
|
|
@@ -3898,7 +3940,7 @@ function clip(value) {
|
|
|
3898
3940
|
// package.json
|
|
3899
3941
|
var package_default = {
|
|
3900
3942
|
name: "@kernelonpanic/kitcode",
|
|
3901
|
-
version: "1.3.
|
|
3943
|
+
version: "1.3.3",
|
|
3902
3944
|
description: "Terminal coding agent with a config you never have to write by hand",
|
|
3903
3945
|
type: "module",
|
|
3904
3946
|
license: "MIT",
|
|
@@ -3966,7 +4008,7 @@ var package_default = {
|
|
|
3966
4008
|
|
|
3967
4009
|
// src/version.ts
|
|
3968
4010
|
var KITCODE_VERSION = package_default.version;
|
|
3969
|
-
var KITCODE_COMMIT = true ? "
|
|
4011
|
+
var KITCODE_COMMIT = true ? "81f72aca6f23448aa2239b7bd9175da0f9e5862c" : "development";
|
|
3970
4012
|
|
|
3971
4013
|
// src/mcp/client.ts
|
|
3972
4014
|
var clientInfo = { name: "kitcode", version: KITCODE_VERSION };
|
|
@@ -6309,16 +6351,15 @@ function unknownSkill(name, available) {
|
|
|
6309
6351
|
// src/tools/task.ts
|
|
6310
6352
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
6311
6353
|
var MAX_PROGRESS_LINES = 10;
|
|
6312
|
-
var MAX_SUBAGENTS_PER_TURN = 3;
|
|
6313
6354
|
var DESCRIPTION = [
|
|
6314
6355
|
"Hand one self-contained sub-task to a subagent that works in its own fresh context and reports back a single summary.",
|
|
6315
6356
|
"Use it when the task is genuinely independent and its intermediate output would be long or noisy: a wide search across the repository, reading many files to answer one question, tracing where something is used.",
|
|
6316
6357
|
"Do not use it for work that is a couple of tool calls, and do not use it when you already have what you need \u2014 call the tools yourself instead.",
|
|
6317
6358
|
'The subagent shares this filesystem and working directory but has NO memory of this conversation and cannot ask you anything, so "prompt" must stand alone: the goal, the constraints, and exactly what to report back.',
|
|
6359
|
+
"For multiple independent tasks, issue consecutive task calls in the same response so they can run concurrently. Do not delegate overlapping file edits.",
|
|
6318
6360
|
"It runs to completion and you receive only its final message."
|
|
6319
6361
|
].join(" ");
|
|
6320
|
-
function createTaskTool(runner
|
|
6321
|
-
const spawnsPerTurn = /* @__PURE__ */ new WeakMap();
|
|
6362
|
+
function createTaskTool(runner) {
|
|
6322
6363
|
return {
|
|
6323
6364
|
name: TASK_TOOL_NAME,
|
|
6324
6365
|
description: DESCRIPTION,
|
|
@@ -6340,14 +6381,6 @@ function createTaskTool(runner, maxSubagents = MAX_SUBAGENTS_PER_TURN) {
|
|
|
6340
6381
|
if (instruction === "") {
|
|
6341
6382
|
return { content: "task needs a prompt: the full instruction for the subagent.", isError: true };
|
|
6342
6383
|
}
|
|
6343
|
-
const spawned = (spawnsPerTurn.get(ctx.signal) ?? 0) + 1;
|
|
6344
|
-
spawnsPerTurn.set(ctx.signal, spawned);
|
|
6345
|
-
if (spawned > maxSubagents) {
|
|
6346
|
-
return {
|
|
6347
|
-
content: `Already delegated ${maxSubagents} subagents while answering this message, which is the limit. Do the remaining work yourself with the tools you have.`,
|
|
6348
|
-
isError: true
|
|
6349
|
-
};
|
|
6350
|
-
}
|
|
6351
6384
|
const progress = [];
|
|
6352
6385
|
const subagentId = `sa${randomBytes3(4).toString("hex")}`;
|
|
6353
6386
|
const description = field(input, "description") || "subagent";
|
|
@@ -6675,7 +6708,7 @@ async function boot(options) {
|
|
|
6675
6708
|
}
|
|
6676
6709
|
};
|
|
6677
6710
|
tools.register([
|
|
6678
|
-
createTaskTool(wrappedRunner
|
|
6711
|
+
createTaskTool(wrappedRunner)
|
|
6679
6712
|
]);
|
|
6680
6713
|
let persistQueue = Promise.resolve();
|
|
6681
6714
|
let configQueue = Promise.resolve();
|
|
@@ -8632,6 +8665,18 @@ function appendInputHistory(history, value, limit = 100) {
|
|
|
8632
8665
|
// src/ui/components/PromptInput.tsx
|
|
8633
8666
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
8634
8667
|
var WINDOW2 = 6;
|
|
8668
|
+
var CAT_FRAME_MS = 500;
|
|
8669
|
+
var CAT_FRAMES = [
|
|
8670
|
+
"/\u1420\uFF61\uA788\uFF61\u141F\\ ~",
|
|
8671
|
+
"/\u1420\uFF61\uA788\uFF61\u141F\\ \u223F",
|
|
8672
|
+
"/\u1420\uFF61\uA788\uFF61\u141F\\ ~",
|
|
8673
|
+
"/\u1420\uFF61\uA788\uFF61\u141F\\ \u223E",
|
|
8674
|
+
"/\u1420\uFF61\uA788\uFF61\u141F\\ ~",
|
|
8675
|
+
"/\u1420\uFF61\uA788\uFF61\u141F\\ \u223F",
|
|
8676
|
+
"/\u1420-\uA788-\u141F\\ ~",
|
|
8677
|
+
"/\u1420\uFF61\uA788\uFF61\u141F\\ \u223E"
|
|
8678
|
+
];
|
|
8679
|
+
var MAX_INPUT_ROWS = 6;
|
|
8635
8680
|
var PromptInput = memo(function PromptInput2({
|
|
8636
8681
|
value,
|
|
8637
8682
|
onChange,
|
|
@@ -8646,8 +8691,19 @@ var PromptInput = memo(function PromptInput2({
|
|
|
8646
8691
|
onListFiles
|
|
8647
8692
|
}) {
|
|
8648
8693
|
const theme = useTheme();
|
|
8649
|
-
const { columns } = useTerminalSize();
|
|
8694
|
+
const { columns, rows } = useTerminalSize();
|
|
8695
|
+
const panelWidth = Math.max(2, columns - 1);
|
|
8696
|
+
const inputRows = Math.max(1, Math.min(MAX_INPUT_ROWS, rows - 16));
|
|
8650
8697
|
const strings = useStrings();
|
|
8698
|
+
const [catFrame, setCatFrame] = useState4(0);
|
|
8699
|
+
useEffect(() => {
|
|
8700
|
+
if (!disabled) return;
|
|
8701
|
+
const timer = setInterval(() => setCatFrame((frame) => (frame + 1) % CAT_FRAMES.length), CAT_FRAME_MS);
|
|
8702
|
+
return () => clearInterval(timer);
|
|
8703
|
+
}, [disabled]);
|
|
8704
|
+
const panelColor = disabled ? theme.warn : theme.accent;
|
|
8705
|
+
const fullTitle = disabled ? `KitCode ${CAT_FRAMES[catFrame]}` : "KitCode";
|
|
8706
|
+
const panelTitle = fullTitle.slice(0, Math.max(0, panelWidth - 5));
|
|
8651
8707
|
const safeValue = sanitizeTerminalText(value);
|
|
8652
8708
|
const [selectionCursor, setSelectionCursor] = useState4(0);
|
|
8653
8709
|
const [inputCursor, setInputCursor] = useState4(() => characters2(safeValue).length);
|
|
@@ -8810,31 +8866,64 @@ var PromptInput = memo(function PromptInput2({
|
|
|
8810
8866
|
const start = Math.max(0, Math.min(active2 - WINDOW2 + 2, suggestions.length - WINDOW2));
|
|
8811
8867
|
const visible = suggestions.slice(start, start + WINDOW2);
|
|
8812
8868
|
const fileStart = Math.max(0, Math.min(active2 - WINDOW2 + 2, files.length - WINDOW2));
|
|
8813
|
-
return /* @__PURE__ */ jsxs8(Box8, { width:
|
|
8814
|
-
/* @__PURE__ */ jsxs8(
|
|
8815
|
-
Box8,
|
|
8816
|
-
{
|
|
8817
|
-
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8869
|
+
return /* @__PURE__ */ jsxs8(Box8, { width: panelWidth, maxWidth: "100%", flexDirection: "column", marginTop: 1, flexShrink: 0, children: [
|
|
8870
|
+
/* @__PURE__ */ jsxs8(Box8, { width: "100%", flexShrink: 0, children: [
|
|
8871
|
+
/* @__PURE__ */ jsx8(Box8, { flexShrink: 0, children: /* @__PURE__ */ jsx8(Text8, { color: panelColor, children: "\u256D" }) }),
|
|
8872
|
+
/* @__PURE__ */ jsx8(Box8, { flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsxs8(Text8, { color: panelColor, wrap: "truncate-end", children: [
|
|
8873
|
+
"\u2500 ",
|
|
8874
|
+
panelTitle,
|
|
8875
|
+
" "
|
|
8876
|
+
] }) }),
|
|
8877
|
+
/* @__PURE__ */ jsx8(
|
|
8878
|
+
Box8,
|
|
8879
|
+
{
|
|
8880
|
+
flexGrow: 1,
|
|
8881
|
+
flexShrink: 1,
|
|
8882
|
+
minWidth: 0,
|
|
8883
|
+
height: 1,
|
|
8884
|
+
borderStyle: "single",
|
|
8885
|
+
borderColor: panelColor,
|
|
8886
|
+
borderTop: false,
|
|
8887
|
+
borderBottom: true,
|
|
8888
|
+
borderLeft: false,
|
|
8889
|
+
borderRight: false
|
|
8890
|
+
}
|
|
8891
|
+
),
|
|
8892
|
+
/* @__PURE__ */ jsx8(Box8, { flexShrink: 0, children: /* @__PURE__ */ jsx8(Text8, { color: panelColor, children: "\u256E" }) })
|
|
8893
|
+
] }),
|
|
8894
|
+
/* @__PURE__ */ jsxs8(Box8, { width: "100%", paddingX: 1, maxHeight: inputRows, overflowY: "hidden", children: [
|
|
8895
|
+
/* @__PURE__ */ jsx8(Text8, { color: panelColor, children: "\u203A " }),
|
|
8896
|
+
/* @__PURE__ */ jsx8(Box8, { flexGrow: 1, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx8(EditableText, { value: safeValue, cursor: inputCursor, placeholder: strings.placeholder }) }),
|
|
8897
|
+
pending && pending > 0 ? /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
|
|
8898
|
+
" \xB7 ",
|
|
8899
|
+
strings.queued(pending)
|
|
8900
|
+
] }) : null
|
|
8901
|
+
] }),
|
|
8832
8902
|
attachments.length > 0 && /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
|
|
8833
8903
|
" ",
|
|
8834
8904
|
"\u{1F4CE} ",
|
|
8835
8905
|
attachments.map(sanitizeTerminalText).join(" \xB7 ")
|
|
8836
8906
|
] }),
|
|
8837
|
-
|
|
8907
|
+
/* @__PURE__ */ jsxs8(Box8, { width: "100%", flexShrink: 0, children: [
|
|
8908
|
+
/* @__PURE__ */ jsx8(Box8, { flexShrink: 0, children: /* @__PURE__ */ jsx8(Text8, { color: panelColor, children: "\u2570" }) }),
|
|
8909
|
+
/* @__PURE__ */ jsx8(
|
|
8910
|
+
Box8,
|
|
8911
|
+
{
|
|
8912
|
+
flexGrow: 1,
|
|
8913
|
+
flexShrink: 1,
|
|
8914
|
+
minWidth: 0,
|
|
8915
|
+
height: 1,
|
|
8916
|
+
borderStyle: "single",
|
|
8917
|
+
borderColor: panelColor,
|
|
8918
|
+
borderTop: false,
|
|
8919
|
+
borderBottom: true,
|
|
8920
|
+
borderLeft: false,
|
|
8921
|
+
borderRight: false
|
|
8922
|
+
}
|
|
8923
|
+
),
|
|
8924
|
+
/* @__PURE__ */ jsx8(Box8, { flexShrink: 0, children: /* @__PURE__ */ jsx8(Text8, { color: panelColor, children: "\u256F" }) })
|
|
8925
|
+
] }),
|
|
8926
|
+
disabled && hint && /* @__PURE__ */ jsxs8(Text8, { color: theme.accent, children: [
|
|
8838
8927
|
" ",
|
|
8839
8928
|
sanitizeTerminalText(hint)
|
|
8840
8929
|
] }),
|
|
@@ -9153,9 +9242,9 @@ import { createContext as createContext3, Fragment as Fragment4, useContext as u
|
|
|
9153
9242
|
import stringWidth from "string-width";
|
|
9154
9243
|
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
9155
9244
|
var DimContext = createContext3(false);
|
|
9156
|
-
function Text10({ dimColor, ...props }) {
|
|
9245
|
+
function Text10({ dimColor, color, ...props }) {
|
|
9157
9246
|
const dim = useContext3(DimContext);
|
|
9158
|
-
return /* @__PURE__ */ jsx11(InkText, { ...props, dimColor: dimColor ?? dim });
|
|
9247
|
+
return /* @__PURE__ */ jsx11(InkText, { ...props, color: dim ? void 0 : color, dimColor: dimColor ?? dim });
|
|
9159
9248
|
}
|
|
9160
9249
|
function Markdown({ children, dim = false }) {
|
|
9161
9250
|
const blocks = useMemo3(() => extractBlocks(children), [children]);
|
|
@@ -9728,6 +9817,8 @@ var Transcript = memo2(function Transcript2({
|
|
|
9728
9817
|
}
|
|
9729
9818
|
const live = liveAt === -1 ? [] : bubbles.slice(liveAt);
|
|
9730
9819
|
const staticItems = [HEADER, ...stableRef.current];
|
|
9820
|
+
const agents = live.filter((bubble) => bubble.kind === "subagent");
|
|
9821
|
+
const groupedAgents = agents.length > 1;
|
|
9731
9822
|
return /* @__PURE__ */ jsxs11(
|
|
9732
9823
|
Box12,
|
|
9733
9824
|
{
|
|
@@ -9738,7 +9829,7 @@ var Transcript = memo2(function Transcript2({
|
|
|
9738
9829
|
overflowY: "hidden",
|
|
9739
9830
|
children: [
|
|
9740
9831
|
/* @__PURE__ */ jsx12(Static, { items: staticItems, children: (item) => item.kind === "header" ? /* @__PURE__ */ jsx12(Logo, { workspace }, "kitcode-header") : /* @__PURE__ */ jsx12(BubbleView, { bubble: item }, item.id) }),
|
|
9741
|
-
/* @__PURE__ */
|
|
9832
|
+
/* @__PURE__ */ jsxs11(
|
|
9742
9833
|
Box12,
|
|
9743
9834
|
{
|
|
9744
9835
|
flexDirection: "column",
|
|
@@ -9747,7 +9838,10 @@ var Transcript = memo2(function Transcript2({
|
|
|
9747
9838
|
maxHeight: maxLiveRows,
|
|
9748
9839
|
overflowY: "hidden",
|
|
9749
9840
|
justifyContent: "flex-end",
|
|
9750
|
-
children:
|
|
9841
|
+
children: [
|
|
9842
|
+
live.filter((bubble) => !groupedAgents || bubble.kind !== "subagent" && !(bubble.kind === "tool" && bubble.name === "task")).map((bubble) => /* @__PURE__ */ jsx12(BubbleView, { bubble, maxRows: maxLiveRows }, bubble.id)),
|
|
9843
|
+
groupedAgents && /* @__PURE__ */ jsx12(SubagentSummary, { agents })
|
|
9844
|
+
]
|
|
9751
9845
|
}
|
|
9752
9846
|
)
|
|
9753
9847
|
]
|
|
@@ -9884,6 +9978,30 @@ function previewLines(content) {
|
|
|
9884
9978
|
if (lines.length <= 6) return lines;
|
|
9885
9979
|
return [...lines.slice(0, 6), `\u2026 ${lines.length - 6} more lines`];
|
|
9886
9980
|
}
|
|
9981
|
+
var VISIBLE_SUBAGENTS = 3;
|
|
9982
|
+
function SubagentSummary({ agents }) {
|
|
9983
|
+
const theme = useTheme();
|
|
9984
|
+
const running = agents.filter((agent) => agent.state === "running");
|
|
9985
|
+
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", marginTop: 1, minWidth: 0, children: [
|
|
9986
|
+
/* @__PURE__ */ jsxs11(Text11, { color: theme.accent, wrap: "truncate-end", children: [
|
|
9987
|
+
"Subagents: ",
|
|
9988
|
+
running.length,
|
|
9989
|
+
" running \xB7 ",
|
|
9990
|
+
agents.length - running.length,
|
|
9991
|
+
" done"
|
|
9992
|
+
] }),
|
|
9993
|
+
running.slice(0, VISIBLE_SUBAGENTS).map((agent) => {
|
|
9994
|
+
const latest = agent.bubbles.at(-1);
|
|
9995
|
+
const progress = latest?.kind === "tool" ? latest.summary : latest?.kind === "assistant" ? sanitizeThinkingText(latest.text || latest.thinking, latest.streaming) : "waiting";
|
|
9996
|
+
return /* @__PURE__ */ jsxs11(Text11, { dimColor: true, wrap: "truncate-end", children: [
|
|
9997
|
+
agent.description,
|
|
9998
|
+
" \xB7 ",
|
|
9999
|
+
progress.replace(/\s+/g, " ").trim() || "waiting"
|
|
10000
|
+
] }, agent.id);
|
|
10001
|
+
}),
|
|
10002
|
+
/* @__PURE__ */ jsx12(Text11, { dimColor: true, children: "/subagents \xB7 all active tasks" })
|
|
10003
|
+
] });
|
|
10004
|
+
}
|
|
9887
10005
|
function SubagentView({ bubble, maxRows }) {
|
|
9888
10006
|
const theme = useTheme();
|
|
9889
10007
|
const { columns } = useTerminalSize();
|
|
@@ -10344,7 +10462,6 @@ function App({
|
|
|
10344
10462
|
const command = (firstSpace === -1 ? body : body.slice(0, firstSpace)).toLowerCase();
|
|
10345
10463
|
const rawRest = firstSpace === -1 ? "" : body.slice(firstSpace).trim();
|
|
10346
10464
|
const rest = rawRest ? rawRest.split(/\s+/) : [];
|
|
10347
|
-
setInput("");
|
|
10348
10465
|
switch (command) {
|
|
10349
10466
|
case "help":
|
|
10350
10467
|
notice(
|
|
@@ -11302,7 +11419,9 @@ Rename the file if you want a different name.`);
|
|
|
11302
11419
|
const text = raw.trim();
|
|
11303
11420
|
const submitSlash = () => {
|
|
11304
11421
|
if (!detachedInput) setInput("");
|
|
11305
|
-
|
|
11422
|
+
const command = text.slice(1).trim().split(/\s+/)[0]?.toLowerCase();
|
|
11423
|
+
const liveCommand = ["help", "usage", "subagents", "config", "exit", "quit"].includes(command ?? "");
|
|
11424
|
+
if (busyRef.current && !liveCommand || slashPendingRef.current > 0) {
|
|
11306
11425
|
queueRef.current = [...queueRef.current, { kind: "command", line: text }];
|
|
11307
11426
|
setPendingCount(queueRef.current.length);
|
|
11308
11427
|
return;
|