@hasna/assistants 1.1.25 → 1.1.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/index.js +668 -196
- package/dist/index.js.map +19 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21563,9 +21563,10 @@ class NativeHookRegistry {
|
|
|
21563
21563
|
config = {};
|
|
21564
21564
|
register(hook) {
|
|
21565
21565
|
const eventHooks = this.hooks.get(hook.event) || [];
|
|
21566
|
-
eventHooks.
|
|
21567
|
-
|
|
21568
|
-
|
|
21566
|
+
const deduped = eventHooks.filter((existing) => existing.id !== hook.id);
|
|
21567
|
+
deduped.push(hook);
|
|
21568
|
+
deduped.sort((a, b) => a.priority - b.priority);
|
|
21569
|
+
this.hooks.set(hook.event, deduped);
|
|
21569
21570
|
}
|
|
21570
21571
|
getHooks(event) {
|
|
21571
21572
|
return this.hooks.get(event) || [];
|
|
@@ -72917,16 +72918,28 @@ class BudgetTracker {
|
|
|
72917
72918
|
case "assistant":
|
|
72918
72919
|
if (idOrAssistant) {
|
|
72919
72920
|
this.assistantUsages.set(idOrAssistant, newUsage);
|
|
72921
|
+
} else {
|
|
72922
|
+
this.assistantUsages.clear();
|
|
72920
72923
|
}
|
|
72921
72924
|
break;
|
|
72922
72925
|
case "swarm":
|
|
72923
72926
|
this.swarmUsage = newUsage;
|
|
72924
72927
|
break;
|
|
72925
72928
|
case "project":
|
|
72926
|
-
|
|
72927
|
-
|
|
72928
|
-
this.
|
|
72929
|
-
|
|
72929
|
+
if (idOrAssistant) {
|
|
72930
|
+
this.projectUsages.set(idOrAssistant, newUsage);
|
|
72931
|
+
this.saveProjectState(idOrAssistant, newUsage);
|
|
72932
|
+
break;
|
|
72933
|
+
}
|
|
72934
|
+
if (this.activeProjectId) {
|
|
72935
|
+
this.projectUsages.set(this.activeProjectId, newUsage);
|
|
72936
|
+
this.saveProjectState(this.activeProjectId, newUsage);
|
|
72937
|
+
break;
|
|
72938
|
+
}
|
|
72939
|
+
for (const projectId of this.projectUsages.keys()) {
|
|
72940
|
+
const resetProjectUsage = createEmptyUsage();
|
|
72941
|
+
this.projectUsages.set(projectId, resetProjectUsage);
|
|
72942
|
+
this.saveProjectState(projectId, resetProjectUsage);
|
|
72930
72943
|
}
|
|
72931
72944
|
break;
|
|
72932
72945
|
}
|
|
@@ -72936,6 +72949,9 @@ class BudgetTracker {
|
|
|
72936
72949
|
this.sessionUsage = createEmptyUsage();
|
|
72937
72950
|
this.assistantUsages.clear();
|
|
72938
72951
|
this.swarmUsage = createEmptyUsage();
|
|
72952
|
+
for (const projectId of this.projectUsages.keys()) {
|
|
72953
|
+
this.saveProjectState(projectId, createEmptyUsage());
|
|
72954
|
+
}
|
|
72939
72955
|
this.projectUsages.clear();
|
|
72940
72956
|
this.saveState();
|
|
72941
72957
|
}
|
|
@@ -73034,6 +73050,22 @@ var init_tracker = __esm(() => {
|
|
|
73034
73050
|
});
|
|
73035
73051
|
|
|
73036
73052
|
// packages/core/src/budget/tools.ts
|
|
73053
|
+
function normalizeScope2(value) {
|
|
73054
|
+
return String(value ?? "").trim().toLowerCase();
|
|
73055
|
+
}
|
|
73056
|
+
function isBudgetToolScope(value) {
|
|
73057
|
+
return BUDGET_TOOL_SCOPES.includes(value);
|
|
73058
|
+
}
|
|
73059
|
+
function isBudgetResetScope(value) {
|
|
73060
|
+
return value === "all" || isBudgetToolScope(value);
|
|
73061
|
+
}
|
|
73062
|
+
function parseLimitValue(value) {
|
|
73063
|
+
const numeric = Number(value);
|
|
73064
|
+
if (!Number.isFinite(numeric) || numeric < 0) {
|
|
73065
|
+
return null;
|
|
73066
|
+
}
|
|
73067
|
+
return numeric === 0 ? undefined : numeric;
|
|
73068
|
+
}
|
|
73037
73069
|
function createBudgetToolExecutors(getBudgetTracker) {
|
|
73038
73070
|
return {
|
|
73039
73071
|
budget_status: async (input) => {
|
|
@@ -73041,7 +73073,11 @@ function createBudgetToolExecutors(getBudgetTracker) {
|
|
|
73041
73073
|
if (!tracker) {
|
|
73042
73074
|
return "Budget tracking is not enabled.";
|
|
73043
73075
|
}
|
|
73044
|
-
const
|
|
73076
|
+
const scopeInput = normalizeScope2(input.scope || "session");
|
|
73077
|
+
if (!isBudgetToolScope(scopeInput)) {
|
|
73078
|
+
return `Invalid scope: ${scopeInput || "(empty)"}. Use "session", "swarm", or "project".`;
|
|
73079
|
+
}
|
|
73080
|
+
const scope = scopeInput;
|
|
73045
73081
|
const status = tracker.checkBudget(scope);
|
|
73046
73082
|
const lines = [];
|
|
73047
73083
|
lines.push(`## Budget Status (${scope})`);
|
|
@@ -73096,53 +73132,51 @@ function createBudgetToolExecutors(getBudgetTracker) {
|
|
|
73096
73132
|
if (!tracker) {
|
|
73097
73133
|
return "Budget tracking is not enabled.";
|
|
73098
73134
|
}
|
|
73099
|
-
const
|
|
73100
|
-
|
|
73101
|
-
|
|
73102
|
-
switch (scope) {
|
|
73103
|
-
case "session":
|
|
73104
|
-
limitsKey = "sessionLimits";
|
|
73105
|
-
break;
|
|
73106
|
-
case "swarm":
|
|
73107
|
-
limitsKey = "swarmLimits";
|
|
73108
|
-
break;
|
|
73109
|
-
case "project":
|
|
73110
|
-
limitsKey = "projectLimits";
|
|
73111
|
-
break;
|
|
73112
|
-
default:
|
|
73113
|
-
return `Invalid scope: ${scope}. Use "session", "swarm", or "project".`;
|
|
73135
|
+
const scopeInput = normalizeScope2(input.scope || "session");
|
|
73136
|
+
if (!isBudgetToolScope(scopeInput)) {
|
|
73137
|
+
return `Invalid scope: ${scopeInput || "(empty)"}. Use "session", "swarm", or "project".`;
|
|
73114
73138
|
}
|
|
73139
|
+
const scope = scopeInput;
|
|
73140
|
+
const config = tracker.getConfig();
|
|
73115
73141
|
const updates = {};
|
|
73116
|
-
|
|
73117
|
-
|
|
73118
|
-
|
|
73119
|
-
|
|
73120
|
-
|
|
73121
|
-
|
|
73122
|
-
|
|
73123
|
-
|
|
73124
|
-
|
|
73125
|
-
|
|
73126
|
-
|
|
73127
|
-
updates
|
|
73128
|
-
|
|
73142
|
+
const providedFields = [];
|
|
73143
|
+
const invalidFields = [];
|
|
73144
|
+
for (const field of LIMIT_FIELDS) {
|
|
73145
|
+
if (input[field] === undefined)
|
|
73146
|
+
continue;
|
|
73147
|
+
providedFields.push(field);
|
|
73148
|
+
const parsed = parseLimitValue(input[field]);
|
|
73149
|
+
if (parsed === null) {
|
|
73150
|
+
invalidFields.push(field);
|
|
73151
|
+
continue;
|
|
73152
|
+
}
|
|
73153
|
+
updates[field] = parsed;
|
|
73154
|
+
}
|
|
73155
|
+
if (providedFields.length === 0) {
|
|
73129
73156
|
return "No limits specified. Provide at least one limit to update.";
|
|
73130
73157
|
}
|
|
73158
|
+
if (invalidFields.length > 0) {
|
|
73159
|
+
return `Invalid limit values for: ${invalidFields.join(", ")}. Values must be numbers >= 0 (0 = unlimited).`;
|
|
73160
|
+
}
|
|
73131
73161
|
tracker.updateConfig({
|
|
73132
|
-
[
|
|
73133
|
-
...config[
|
|
73162
|
+
[scope]: {
|
|
73163
|
+
...config[scope] || {},
|
|
73134
73164
|
...updates
|
|
73135
73165
|
}
|
|
73136
73166
|
});
|
|
73167
|
+
const applied = Object.fromEntries(providedFields.map((field) => [field, updates[field] ?? "unlimited"]));
|
|
73137
73168
|
return `Budget limits updated for ${scope} scope:
|
|
73138
|
-
${JSON.stringify(
|
|
73169
|
+
${JSON.stringify(applied, null, 2)}`;
|
|
73139
73170
|
},
|
|
73140
73171
|
budget_reset: async (input) => {
|
|
73141
73172
|
const tracker = getBudgetTracker();
|
|
73142
73173
|
if (!tracker) {
|
|
73143
73174
|
return "Budget tracking is not enabled.";
|
|
73144
73175
|
}
|
|
73145
|
-
const scope =
|
|
73176
|
+
const scope = normalizeScope2(input.scope || "session");
|
|
73177
|
+
if (!isBudgetResetScope(scope)) {
|
|
73178
|
+
return `Invalid scope: ${scope || "(empty)"}. Use "session", "swarm", "project", or "all".`;
|
|
73179
|
+
}
|
|
73146
73180
|
if (scope === "all") {
|
|
73147
73181
|
tracker.resetAll();
|
|
73148
73182
|
return "All budget counters have been reset.";
|
|
@@ -73158,8 +73192,17 @@ function registerBudgetTools(registry, getBudgetTracker) {
|
|
|
73158
73192
|
registry.register(tool, executors[tool.name]);
|
|
73159
73193
|
}
|
|
73160
73194
|
}
|
|
73161
|
-
var budgetStatusTool, budgetGetTool, budgetSetTool, budgetResetTool, budgetTools;
|
|
73195
|
+
var BUDGET_TOOL_SCOPES, LIMIT_FIELDS, budgetStatusTool, budgetGetTool, budgetSetTool, budgetResetTool, budgetTools;
|
|
73162
73196
|
var init_tools4 = __esm(() => {
|
|
73197
|
+
BUDGET_TOOL_SCOPES = ["session", "swarm", "project"];
|
|
73198
|
+
LIMIT_FIELDS = [
|
|
73199
|
+
"maxInputTokens",
|
|
73200
|
+
"maxOutputTokens",
|
|
73201
|
+
"maxTotalTokens",
|
|
73202
|
+
"maxLlmCalls",
|
|
73203
|
+
"maxToolCalls",
|
|
73204
|
+
"maxDurationMs"
|
|
73205
|
+
];
|
|
73163
73206
|
budgetStatusTool = {
|
|
73164
73207
|
name: "budget_status",
|
|
73165
73208
|
description: "Get current budget status showing usage vs limits for the specified scope (session, swarm, or project).",
|
|
@@ -73231,8 +73274,8 @@ var init_tools4 = __esm(() => {
|
|
|
73231
73274
|
properties: {
|
|
73232
73275
|
scope: {
|
|
73233
73276
|
type: "string",
|
|
73234
|
-
description: 'Budget scope to reset: "session", "swarm", or "all"',
|
|
73235
|
-
enum: ["session", "swarm", "all"]
|
|
73277
|
+
description: 'Budget scope to reset: "session", "swarm", "project", or "all"',
|
|
73278
|
+
enum: ["session", "swarm", "project", "all"]
|
|
73236
73279
|
}
|
|
73237
73280
|
},
|
|
73238
73281
|
required: ["scope"]
|
|
@@ -78300,6 +78343,7 @@ class BuiltinCommands {
|
|
|
78300
78343
|
registerAll(loader) {
|
|
78301
78344
|
loader.register(this.helpCommand(loader));
|
|
78302
78345
|
loader.register(this.aboutCommand());
|
|
78346
|
+
loader.register(this.docsCommand());
|
|
78303
78347
|
loader.register(this.clearCommand());
|
|
78304
78348
|
loader.register(this.newCommand());
|
|
78305
78349
|
loader.register(this.sessionCommand());
|
|
@@ -78347,6 +78391,8 @@ class BuiltinCommands {
|
|
|
78347
78391
|
loader.register(this.tasksCommand());
|
|
78348
78392
|
loader.register(this.setupCommand());
|
|
78349
78393
|
loader.register(this.exitCommand());
|
|
78394
|
+
loader.register(this.diffCommand());
|
|
78395
|
+
loader.register(this.undoCommand());
|
|
78350
78396
|
}
|
|
78351
78397
|
aboutCommand() {
|
|
78352
78398
|
return {
|
|
@@ -78369,6 +78415,62 @@ class BuiltinCommands {
|
|
|
78369
78415
|
|
|
78370
78416
|
`;
|
|
78371
78417
|
message += `assistants is a terminal-first AI environment for connecting tools, running tasks, and collaborating with agents.
|
|
78418
|
+
`;
|
|
78419
|
+
context.emit("text", message);
|
|
78420
|
+
context.emit("done");
|
|
78421
|
+
return { handled: true };
|
|
78422
|
+
}
|
|
78423
|
+
};
|
|
78424
|
+
}
|
|
78425
|
+
docsCommand() {
|
|
78426
|
+
return {
|
|
78427
|
+
name: "docs",
|
|
78428
|
+
description: "Open docs panel in terminal or print full usage guide",
|
|
78429
|
+
builtin: true,
|
|
78430
|
+
selfHandled: true,
|
|
78431
|
+
content: "",
|
|
78432
|
+
handler: async (_args, context) => {
|
|
78433
|
+
let message = `
|
|
78434
|
+
**assistants Documentation**
|
|
78435
|
+
|
|
78436
|
+
`;
|
|
78437
|
+
message += "In the terminal app, `/docs` opens an interactive documentation panel with keyboard navigation.\n\n";
|
|
78438
|
+
message += `**Quick Start**
|
|
78439
|
+
`;
|
|
78440
|
+
message += " 1. Run `/init` in a project.\n";
|
|
78441
|
+
message += " 2. Run `/onboarding` to select provider, model, and API key setup.\n";
|
|
78442
|
+
message += " 3. Start work with `/new` and inspect status via `/status`, `/tokens`, and `/cost`.\n\n";
|
|
78443
|
+
message += `**Core Workflow**
|
|
78444
|
+
`;
|
|
78445
|
+
message += ` - Sessions keep history, tool calls, context, and model state.
|
|
78446
|
+
`;
|
|
78447
|
+
message += " - `/sessions` switches sessions.\n";
|
|
78448
|
+
message += " - `/compact` summarizes long context.\n";
|
|
78449
|
+
message += " - `/resume` recovers interrupted work.\n\n";
|
|
78450
|
+
message += `**Configuration and Models**
|
|
78451
|
+
`;
|
|
78452
|
+
message += " - `/model` opens interactive model selection.\n";
|
|
78453
|
+
message += " - `/config` manages user/project/local config.\n";
|
|
78454
|
+
message += " - `/memory`, `/context`, `/hooks`, and `/guardrails` control behavior and safety.\n\n";
|
|
78455
|
+
message += `**Workspaces and Projects**
|
|
78456
|
+
`;
|
|
78457
|
+
message += " - `/workspace` switches isolated workspace state.\n";
|
|
78458
|
+
message += " - `/projects` and `/plans` manage project scope and plan execution.\n\n";
|
|
78459
|
+
message += `**Resources and Operations**
|
|
78460
|
+
`;
|
|
78461
|
+
message += " - `/wallet`, `/secrets`, and `/budgets` manage cards, secrets, and limits.\n";
|
|
78462
|
+
message += " - `/tasks`, `/schedules`, `/jobs`, `/orders`, `/heartbeat`, and `/logs` manage operations.\n\n";
|
|
78463
|
+
message += `**Collaboration**
|
|
78464
|
+
`;
|
|
78465
|
+
message += " - `/assistants`, `/identity`, `/messages`, `/channels`, `/people`, `/telephony`.\n\n";
|
|
78466
|
+
message += `**Voice**
|
|
78467
|
+
`;
|
|
78468
|
+
message += " - `/voice`, `/listen`, `/talk`, `/say`.\n\n";
|
|
78469
|
+
message += `**Storage**
|
|
78470
|
+
`;
|
|
78471
|
+
message += " - Project data: `.assistants/`\n";
|
|
78472
|
+
message += " - User/global data: `~/.assistants/`\n";
|
|
78473
|
+
message += ` - Workspace switching isolates sessions, assistants, settings, and resource state.
|
|
78372
78474
|
`;
|
|
78373
78475
|
context.emit("text", message);
|
|
78374
78476
|
context.emit("done");
|
|
@@ -86888,6 +86990,140 @@ ${repoUrl}/issues/new
|
|
|
86888
86990
|
}
|
|
86889
86991
|
};
|
|
86890
86992
|
}
|
|
86993
|
+
diffCommand() {
|
|
86994
|
+
return {
|
|
86995
|
+
name: "diff",
|
|
86996
|
+
description: "Show git diff of current changes (supports --staged, <file>)",
|
|
86997
|
+
builtin: true,
|
|
86998
|
+
selfHandled: true,
|
|
86999
|
+
content: "",
|
|
87000
|
+
handler: async (args, context) => {
|
|
87001
|
+
const { exec } = await import("child_process");
|
|
87002
|
+
const { promisify } = await import("util");
|
|
87003
|
+
const execAsync = promisify(exec);
|
|
87004
|
+
const parts = splitArgs(args);
|
|
87005
|
+
try {
|
|
87006
|
+
let diffCmd = "git diff";
|
|
87007
|
+
let statCmd = "git diff --stat";
|
|
87008
|
+
if (parts.includes("--staged") || parts.includes("--cached")) {
|
|
87009
|
+
diffCmd += " --staged";
|
|
87010
|
+
statCmd += " --staged";
|
|
87011
|
+
const fileArgs = parts.filter((p) => p !== "--staged" && p !== "--cached");
|
|
87012
|
+
if (fileArgs.length > 0) {
|
|
87013
|
+
const files = fileArgs.map((f) => `'${f.replace(/'/g, "'\\''")}'`).join(" ");
|
|
87014
|
+
diffCmd += ` -- ${files}`;
|
|
87015
|
+
statCmd += ` -- ${files}`;
|
|
87016
|
+
}
|
|
87017
|
+
} else if (parts.length > 0) {
|
|
87018
|
+
const files = parts.map((f) => `'${f.replace(/'/g, "'\\''")}'`).join(" ");
|
|
87019
|
+
diffCmd += ` -- ${files}`;
|
|
87020
|
+
statCmd += ` -- ${files}`;
|
|
87021
|
+
}
|
|
87022
|
+
const opts = { cwd: context.cwd, maxBuffer: 1048576 };
|
|
87023
|
+
const [statResult, diffResult] = await Promise.all([
|
|
87024
|
+
execAsync(statCmd, opts).catch(() => ({ stdout: "" })),
|
|
87025
|
+
execAsync(diffCmd, opts).catch(() => ({ stdout: "" }))
|
|
87026
|
+
]);
|
|
87027
|
+
const statOutput = (statResult.stdout || "").trim();
|
|
87028
|
+
const diffOutput = (diffResult.stdout || "").trim();
|
|
87029
|
+
if (!statOutput && !diffOutput) {
|
|
87030
|
+
context.emit("text", `
|
|
87031
|
+
No changes detected.
|
|
87032
|
+
`);
|
|
87033
|
+
context.emit("done");
|
|
87034
|
+
return { handled: true };
|
|
87035
|
+
}
|
|
87036
|
+
let message = `
|
|
87037
|
+
**Git Diff**
|
|
87038
|
+
|
|
87039
|
+
`;
|
|
87040
|
+
if (statOutput) {
|
|
87041
|
+
message += "**Summary:**\n```\n" + statOutput + "\n```\n\n";
|
|
87042
|
+
}
|
|
87043
|
+
if (diffOutput) {
|
|
87044
|
+
message += "**Changes:**\n```diff\n" + diffOutput + "\n```\n";
|
|
87045
|
+
}
|
|
87046
|
+
context.emit("text", message);
|
|
87047
|
+
} catch {
|
|
87048
|
+
context.emit("text", `
|
|
87049
|
+
Not a git repository or git not available.
|
|
87050
|
+
`);
|
|
87051
|
+
}
|
|
87052
|
+
context.emit("done");
|
|
87053
|
+
return { handled: true };
|
|
87054
|
+
}
|
|
87055
|
+
};
|
|
87056
|
+
}
|
|
87057
|
+
undoCommand() {
|
|
87058
|
+
return {
|
|
87059
|
+
name: "undo",
|
|
87060
|
+
description: "Revert uncommitted changes (file, all, or show preview)",
|
|
87061
|
+
builtin: true,
|
|
87062
|
+
selfHandled: true,
|
|
87063
|
+
content: "",
|
|
87064
|
+
handler: async (args, context) => {
|
|
87065
|
+
const { exec } = await import("child_process");
|
|
87066
|
+
const { promisify } = await import("util");
|
|
87067
|
+
const execAsync = promisify(exec);
|
|
87068
|
+
const parts = splitArgs(args);
|
|
87069
|
+
const opts = { cwd: context.cwd };
|
|
87070
|
+
try {
|
|
87071
|
+
if (parts.length === 0) {
|
|
87072
|
+
const { stdout: stdout2 } = await execAsync("git diff --stat", opts);
|
|
87073
|
+
const statOutput = stdout2.trim();
|
|
87074
|
+
if (!statOutput) {
|
|
87075
|
+
context.emit("text", `
|
|
87076
|
+
No uncommitted changes to undo.
|
|
87077
|
+
`);
|
|
87078
|
+
context.emit("done");
|
|
87079
|
+
return { handled: true };
|
|
87080
|
+
}
|
|
87081
|
+
let message = "\n**Uncommitted Changes:**\n```\n" + statOutput + "\n```\n\n";
|
|
87082
|
+
message += "Use `/undo <file>` to revert a specific file\n";
|
|
87083
|
+
message += "Use `/undo all` to revert all changes\n";
|
|
87084
|
+
context.emit("text", message);
|
|
87085
|
+
context.emit("done");
|
|
87086
|
+
return { handled: true };
|
|
87087
|
+
}
|
|
87088
|
+
if (parts[0] === "all") {
|
|
87089
|
+
const { stdout: stdout2 } = await execAsync("git diff --stat", opts);
|
|
87090
|
+
const statOutput = stdout2.trim();
|
|
87091
|
+
if (!statOutput) {
|
|
87092
|
+
context.emit("text", `
|
|
87093
|
+
No uncommitted changes to undo.
|
|
87094
|
+
`);
|
|
87095
|
+
context.emit("done");
|
|
87096
|
+
return { handled: true };
|
|
87097
|
+
}
|
|
87098
|
+
await execAsync("git checkout -- .", opts);
|
|
87099
|
+
context.emit("text", "\n**Reverted all uncommitted changes:**\n```\n" + statOutput + "\n```\n");
|
|
87100
|
+
context.emit("done");
|
|
87101
|
+
return { handled: true };
|
|
87102
|
+
}
|
|
87103
|
+
const escaped = parts.map((f) => `'${f.replace(/'/g, "'\\''")}'`).join(" ");
|
|
87104
|
+
const { stdout } = await execAsync(`git diff --stat -- ${escaped}`, opts);
|
|
87105
|
+
const checkOutput = stdout.trim();
|
|
87106
|
+
if (!checkOutput) {
|
|
87107
|
+
context.emit("text", `
|
|
87108
|
+
No changes found for: ${parts.join(" ")}
|
|
87109
|
+
`);
|
|
87110
|
+
context.emit("done");
|
|
87111
|
+
return { handled: true };
|
|
87112
|
+
}
|
|
87113
|
+
await execAsync(`git checkout -- ${escaped}`, opts);
|
|
87114
|
+
context.emit("text", `
|
|
87115
|
+
**Reverted:** ${parts.join(" ")}
|
|
87116
|
+
`);
|
|
87117
|
+
} catch {
|
|
87118
|
+
context.emit("text", `
|
|
87119
|
+
Not a git repository or git not available.
|
|
87120
|
+
`);
|
|
87121
|
+
}
|
|
87122
|
+
context.emit("done");
|
|
87123
|
+
return { handled: true };
|
|
87124
|
+
}
|
|
87125
|
+
};
|
|
87126
|
+
}
|
|
86891
87127
|
async resolveProject(context, target) {
|
|
86892
87128
|
const byId = await readProject(context.cwd, target);
|
|
86893
87129
|
if (byId)
|
|
@@ -86918,7 +87154,7 @@ ${repoUrl}/issues/new
|
|
|
86918
87154
|
context.setProjectContext(projectContext);
|
|
86919
87155
|
}
|
|
86920
87156
|
}
|
|
86921
|
-
var VERSION2 = "1.1.
|
|
87157
|
+
var VERSION2 = "1.1.26";
|
|
86922
87158
|
var init_builtin = __esm(async () => {
|
|
86923
87159
|
init_src2();
|
|
86924
87160
|
init_store();
|
|
@@ -92083,14 +92319,22 @@ var init_conventions = __esm(() => {
|
|
|
92083
92319
|
});
|
|
92084
92320
|
|
|
92085
92321
|
// packages/core/src/heartbeat/auto-schedule-hook.ts
|
|
92086
|
-
|
|
92087
|
-
const
|
|
92322
|
+
function resolveHeartbeatConfig(input, context) {
|
|
92323
|
+
const inputHeartbeat = input.heartbeat;
|
|
92324
|
+
if (inputHeartbeat && typeof inputHeartbeat === "object") {
|
|
92325
|
+
return inputHeartbeat;
|
|
92326
|
+
}
|
|
92327
|
+
return context.config?.heartbeat;
|
|
92328
|
+
}
|
|
92329
|
+
async function autoScheduleHeartbeatHandler(input, context) {
|
|
92330
|
+
const heartbeatCfg = resolveHeartbeatConfig(input, context);
|
|
92088
92331
|
if (!heartbeatCfg?.autonomous)
|
|
92089
92332
|
return null;
|
|
92090
92333
|
const scheduleId = heartbeatScheduleId(context.sessionId);
|
|
92091
92334
|
try {
|
|
92092
92335
|
const existing = await getSchedule(context.cwd, scheduleId);
|
|
92093
|
-
|
|
92336
|
+
const hasValidNextRunAt = Number.isFinite(existing?.nextRunAt);
|
|
92337
|
+
if (existing && existing.status === "active" && hasValidNextRunAt) {
|
|
92094
92338
|
return null;
|
|
92095
92339
|
}
|
|
92096
92340
|
const maxSleep = heartbeatCfg.maxSleepMs ?? DEFAULT_MAX_SLEEP_MS;
|
|
@@ -92135,11 +92379,13 @@ var init_auto_schedule_hook = __esm(async () => {
|
|
|
92135
92379
|
async function ensureWatchdogSchedule(cwd, sessionId, intervalMs = DEFAULT_WATCHDOG_INTERVAL_MS) {
|
|
92136
92380
|
const scheduleId = watchdogScheduleId(sessionId);
|
|
92137
92381
|
const existing = await getSchedule(cwd, scheduleId);
|
|
92138
|
-
|
|
92382
|
+
const existingHasValidNextRunAt = Number.isFinite(existing?.nextRunAt);
|
|
92383
|
+
if (existing && existing.status === "active" && existingHasValidNextRunAt) {
|
|
92139
92384
|
return;
|
|
92140
92385
|
}
|
|
92141
92386
|
const legacy = await getSchedule(cwd, WATCHDOG_SCHEDULE_ID);
|
|
92142
|
-
|
|
92387
|
+
const legacyHasValidNextRunAt = Number.isFinite(legacy?.nextRunAt);
|
|
92388
|
+
if (legacy && legacy.status === "active" && legacy.sessionId === sessionId && legacyHasValidNextRunAt) {
|
|
92143
92389
|
return;
|
|
92144
92390
|
}
|
|
92145
92391
|
const intervalSeconds = Math.max(60, Math.round(intervalMs / 1000));
|
|
@@ -92170,24 +92416,33 @@ var init_watchdog = __esm(async () => {
|
|
|
92170
92416
|
|
|
92171
92417
|
// packages/core/src/heartbeat/install-skills.ts
|
|
92172
92418
|
import { join as join30 } from "path";
|
|
92173
|
-
async function
|
|
92174
|
-
const { mkdir: mkdir10, writeFile: writeFile8,
|
|
92419
|
+
async function writeSkillIfNeeded(dir, skillName, content) {
|
|
92420
|
+
const { mkdir: mkdir10, writeFile: writeFile8, readFile: readFile11 } = await import("fs/promises");
|
|
92175
92421
|
const skillDir = join30(dir, `skill-${skillName}`);
|
|
92176
92422
|
const skillFile = join30(skillDir, "SKILL.md");
|
|
92177
|
-
try {
|
|
92178
|
-
await access(skillFile);
|
|
92179
|
-
return false;
|
|
92180
|
-
} catch {}
|
|
92181
92423
|
await mkdir10(skillDir, { recursive: true });
|
|
92182
|
-
|
|
92183
|
-
|
|
92424
|
+
try {
|
|
92425
|
+
const existing = await readFile11(skillFile, "utf-8");
|
|
92426
|
+
if (existing === content) {
|
|
92427
|
+
return false;
|
|
92428
|
+
}
|
|
92429
|
+
const hasLegacyPatterns = LEGACY_SKILL_PATTERNS.some((pattern) => pattern.test(existing));
|
|
92430
|
+
if (!hasLegacyPatterns) {
|
|
92431
|
+
return false;
|
|
92432
|
+
}
|
|
92433
|
+
await writeFile8(skillFile, content, "utf-8");
|
|
92434
|
+
return true;
|
|
92435
|
+
} catch {
|
|
92436
|
+
await writeFile8(skillFile, content, "utf-8");
|
|
92437
|
+
return true;
|
|
92438
|
+
}
|
|
92184
92439
|
}
|
|
92185
92440
|
async function installHeartbeatSkills() {
|
|
92186
92441
|
const sharedSkillsDir = join30(getConfigDir(), "shared", "skills");
|
|
92187
92442
|
const installed = [];
|
|
92188
92443
|
const results = await Promise.all([
|
|
92189
|
-
|
|
92190
|
-
|
|
92444
|
+
writeSkillIfNeeded(sharedSkillsDir, "main-loop", MAIN_LOOP_SKILL),
|
|
92445
|
+
writeSkillIfNeeded(sharedSkillsDir, "watchdog", WATCHDOG_SKILL)
|
|
92191
92446
|
]);
|
|
92192
92447
|
if (results[0])
|
|
92193
92448
|
installed.push("main-loop");
|
|
@@ -92216,8 +92471,8 @@ You are running as an autonomous heartbeat turn. This is a scheduled wakeup \u20
|
|
|
92216
92471
|
- \`memory_save agent.state.lastActions "..."\` with a brief summary of what you did this turn.
|
|
92217
92472
|
- \`memory_save agent.state.pending "..."\` with any items still pending.
|
|
92218
92473
|
7. **Schedule next heartbeat** \u2014 choose when you should wake up next based on urgency:
|
|
92219
|
-
- Delete the old heartbeat schedule: \`
|
|
92220
|
-
- Create a new schedule: \`
|
|
92474
|
+
- Delete the old heartbeat schedule: call \`schedule\` with \`{ action: "delete", id: "heartbeat-{SESSION_ID}" }\`
|
|
92475
|
+
- Create a new schedule: call \`schedule\` with \`action: "create"\`, \`actionType: "message"\`, \`message: "/main-loop"\`, and either \`at\` (one-shot) or \`cron\` + \`startImmediately: true\` (recurring).
|
|
92221
92476
|
- Save your reasoning: \`memory_save agent.heartbeat.intention "..."\`
|
|
92222
92477
|
8. **Record timestamp** \u2014 \`memory_save agent.heartbeat.last\` with the current ISO timestamp.
|
|
92223
92478
|
|
|
@@ -92237,7 +92492,7 @@ You are running as an autonomous heartbeat turn. This is a scheduled wakeup \u20
|
|
|
92237
92492
|
name: watchdog
|
|
92238
92493
|
description: Safety-net watchdog \u2014 checks if the heartbeat is healthy and forces a wakeup if overdue.
|
|
92239
92494
|
user-invocable: false
|
|
92240
|
-
allowed-tools: memory_recall, memory_save,
|
|
92495
|
+
allowed-tools: memory_recall, memory_save, schedule
|
|
92241
92496
|
---
|
|
92242
92497
|
|
|
92243
92498
|
## Watchdog Check
|
|
@@ -92249,14 +92504,20 @@ You are the watchdog. Your only job is to verify the heartbeat is running and fo
|
|
|
92249
92504
|
1. Read \`memory_recall agent.heartbeat.last\` to get the last heartbeat timestamp.
|
|
92250
92505
|
2. Read \`memory_recall agent.heartbeat.next\` to get the expected next heartbeat time.
|
|
92251
92506
|
3. If the last heartbeat is more than **double** the expected interval overdue:
|
|
92252
|
-
- Call \`
|
|
92507
|
+
- Call \`schedule\` with \`{ action: "list" }\` to check if a heartbeat schedule exists.
|
|
92253
92508
|
- If no active heartbeat schedule exists, create one that fires immediately:
|
|
92254
|
-
\`
|
|
92509
|
+
call \`schedule\` with \`action: "create"\`, \`actionType: "message"\`, \`message: "/main-loop"\`, and \`cron: "* * * * *"\` + \`startImmediately: true\`.
|
|
92255
92510
|
- Save \`memory_save agent.heartbeat.intention "Watchdog forced wakeup \u2014 heartbeat was overdue."\`
|
|
92256
92511
|
4. If the heartbeat is healthy, do nothing.
|
|
92257
|
-
|
|
92512
|
+
`, LEGACY_SKILL_PATTERNS;
|
|
92258
92513
|
var init_install_skills = __esm(async () => {
|
|
92259
92514
|
await init_config();
|
|
92515
|
+
LEGACY_SKILL_PATTERNS = [
|
|
92516
|
+
/`schedule_create`/,
|
|
92517
|
+
/`schedule_delete`/,
|
|
92518
|
+
/`schedules_list`/,
|
|
92519
|
+
/allowed-tools:\s*.*schedule_create/i
|
|
92520
|
+
];
|
|
92260
92521
|
});
|
|
92261
92522
|
|
|
92262
92523
|
// packages/core/src/heartbeat/index.ts
|
|
@@ -186336,15 +186597,6 @@ var init_loop = __esm(async () => {
|
|
|
186336
186597
|
if (heartbeatCfg?.autonomous) {
|
|
186337
186598
|
nativeHookRegistry.register(createAutoScheduleHeartbeatHook());
|
|
186338
186599
|
installHeartbeatSkills().catch(() => {});
|
|
186339
|
-
nativeHookRegistry.setConfig({
|
|
186340
|
-
...nativeHookRegistry.getConfig(),
|
|
186341
|
-
heartbeat: {
|
|
186342
|
-
autonomous: heartbeatCfg.autonomous,
|
|
186343
|
-
maxSleepMs: heartbeatCfg.maxSleepMs,
|
|
186344
|
-
watchdogEnabled: heartbeatCfg.watchdogEnabled,
|
|
186345
|
-
watchdogIntervalMs: heartbeatCfg.watchdogIntervalMs
|
|
186346
|
-
}
|
|
186347
|
-
});
|
|
186348
186600
|
if (heartbeatCfg.watchdogEnabled) {
|
|
186349
186601
|
ensureWatchdogSchedule(this.cwd, this.sessionId, heartbeatCfg.watchdogIntervalMs).catch(() => {});
|
|
186350
186602
|
}
|
|
@@ -186380,8 +186632,8 @@ You are running in **autonomous mode**. You manage your own wakeup schedule.
|
|
|
186380
186632
|
- \`memory_save agent.state.pending "items waiting for follow-up"\`
|
|
186381
186633
|
- \`memory_save agent.state.lastActions "what you just did"\`
|
|
186382
186634
|
2. **Schedule your next heartbeat**:
|
|
186383
|
-
- Delete old: \`
|
|
186384
|
-
- Create new: \`
|
|
186635
|
+
- Delete old: call \`schedule\` with \`{ action: "delete", id: "heartbeat-${this.sessionId}" }\`
|
|
186636
|
+
- Create new: call \`schedule\` with \`action: "create"\`, \`actionType: "message"\`, \`message: "/main-loop"\`, and either \`at\` (one-shot) or \`cron\` + \`startImmediately: true\` (recurring)
|
|
186385
186637
|
3. **Save goals** when they change: \`memory_save agent.goals "..."\`
|
|
186386
186638
|
|
|
186387
186639
|
### Timing guidelines
|
|
@@ -186635,9 +186887,9 @@ You are running in **autonomous mode**. You manage your own wakeup schedule.
|
|
|
186635
186887
|
turn++;
|
|
186636
186888
|
this.cumulativeTurns++;
|
|
186637
186889
|
if (this.paused) {
|
|
186638
|
-
this.onBudgetWarning?.("Budget exceeded - agent paused. Use /
|
|
186890
|
+
this.onBudgetWarning?.("Budget exceeded - agent paused. Use /budgets resume to continue.");
|
|
186639
186891
|
this.emit({ type: "text", content: `
|
|
186640
|
-
[Agent paused - budget exceeded. Use /
|
|
186892
|
+
[Agent paused - budget exceeded. Use /budgets resume to continue.]
|
|
186641
186893
|
` });
|
|
186642
186894
|
await new Promise((resolve5) => {
|
|
186643
186895
|
this.pauseResolve = resolve5;
|
|
@@ -186714,11 +186966,7 @@ You are running in **autonomous mode**. You manage your own wakeup schedule.
|
|
|
186714
186966
|
});
|
|
186715
186967
|
} catch {}
|
|
186716
186968
|
try {
|
|
186717
|
-
await nativeHookRegistry.execute("Stop", {
|
|
186718
|
-
session_id: this.sessionId,
|
|
186719
|
-
hook_event_name: "Stop",
|
|
186720
|
-
cwd: this.cwd
|
|
186721
|
-
}, {
|
|
186969
|
+
await nativeHookRegistry.execute("Stop", this.buildNativeStopHookInput(), {
|
|
186722
186970
|
sessionId: this.sessionId,
|
|
186723
186971
|
cwd: this.cwd,
|
|
186724
186972
|
messages: this.context.getMessages()
|
|
@@ -186840,11 +187088,7 @@ You are running in **autonomous mode**. You manage your own wakeup schedule.
|
|
|
186840
187088
|
if (!scopeContext) {
|
|
186841
187089
|
return null;
|
|
186842
187090
|
}
|
|
186843
|
-
const result = await nativeHookRegistry.execute("Stop", {
|
|
186844
|
-
session_id: this.sessionId,
|
|
186845
|
-
hook_event_name: "Stop",
|
|
186846
|
-
cwd: this.cwd
|
|
186847
|
-
}, {
|
|
187091
|
+
const result = await nativeHookRegistry.execute("Stop", this.buildNativeStopHookInput(), {
|
|
186848
187092
|
sessionId: this.sessionId,
|
|
186849
187093
|
cwd: this.cwd,
|
|
186850
187094
|
messages: this.context.getMessages(),
|
|
@@ -186859,6 +187103,20 @@ You are running in **autonomous mode**. You manage your own wakeup schedule.
|
|
|
186859
187103
|
systemMessage: result.systemMessage
|
|
186860
187104
|
};
|
|
186861
187105
|
}
|
|
187106
|
+
buildNativeStopHookInput() {
|
|
187107
|
+
const heartbeatCfg = this.config?.heartbeat;
|
|
187108
|
+
return {
|
|
187109
|
+
session_id: this.sessionId,
|
|
187110
|
+
hook_event_name: "Stop",
|
|
187111
|
+
cwd: this.cwd,
|
|
187112
|
+
heartbeat: heartbeatCfg ? {
|
|
187113
|
+
autonomous: heartbeatCfg.autonomous,
|
|
187114
|
+
maxSleepMs: heartbeatCfg.maxSleepMs,
|
|
187115
|
+
watchdogEnabled: heartbeatCfg.watchdogEnabled,
|
|
187116
|
+
watchdogIntervalMs: heartbeatCfg.watchdogIntervalMs
|
|
187117
|
+
} : undefined
|
|
187118
|
+
};
|
|
187119
|
+
}
|
|
186862
187120
|
async firePostToolUseFailure(toolCall, resultContent) {
|
|
186863
187121
|
await this.hookExecutor.execute(this.hookLoader.getHooks("PostToolUseFailure"), {
|
|
186864
187122
|
session_id: this.sessionId,
|
|
@@ -187323,9 +187581,32 @@ You are running in **autonomous mode**. You manage your own wakeup schedule.
|
|
|
187323
187581
|
setBudgetEnabled: (enabled) => {
|
|
187324
187582
|
if (this.budgetTracker) {
|
|
187325
187583
|
this.budgetTracker.setEnabled(enabled);
|
|
187326
|
-
|
|
187327
|
-
|
|
187328
|
-
|
|
187584
|
+
this.budgetConfig = this.budgetTracker.getConfig();
|
|
187585
|
+
return;
|
|
187586
|
+
}
|
|
187587
|
+
if (!enabled) {
|
|
187588
|
+
if (this.budgetConfig) {
|
|
187589
|
+
this.budgetConfig = {
|
|
187590
|
+
...this.budgetConfig,
|
|
187591
|
+
enabled: false
|
|
187592
|
+
};
|
|
187593
|
+
}
|
|
187594
|
+
return;
|
|
187595
|
+
}
|
|
187596
|
+
const seed = this.budgetConfig || DEFAULT_BUDGET_CONFIG;
|
|
187597
|
+
this.budgetConfig = {
|
|
187598
|
+
...DEFAULT_BUDGET_CONFIG,
|
|
187599
|
+
...seed,
|
|
187600
|
+
session: { ...DEFAULT_BUDGET_CONFIG.session || {}, ...seed.session || {} },
|
|
187601
|
+
assistant: { ...DEFAULT_BUDGET_CONFIG.assistant || {}, ...seed.assistant || {} },
|
|
187602
|
+
swarm: { ...DEFAULT_BUDGET_CONFIG.swarm || {}, ...seed.swarm || {} },
|
|
187603
|
+
project: { ...DEFAULT_BUDGET_CONFIG.project || {}, ...seed.project || {} },
|
|
187604
|
+
enabled: true
|
|
187605
|
+
};
|
|
187606
|
+
this.budgetTracker = new BudgetTracker(this.sessionId, this.budgetConfig);
|
|
187607
|
+
this.budgetTracker.setEnabled(true);
|
|
187608
|
+
if (this.activeProjectId) {
|
|
187609
|
+
this.budgetTracker.setActiveProject(this.activeProjectId);
|
|
187329
187610
|
}
|
|
187330
187611
|
},
|
|
187331
187612
|
resetBudget: (scope) => {
|
|
@@ -187751,7 +188032,7 @@ You are running in **autonomous mode**. You manage your own wakeup schedule.
|
|
|
187751
188032
|
this.onBudgetWarning?.("Budget exceeded - stopping assistant");
|
|
187752
188033
|
this.stop();
|
|
187753
188034
|
} else if (onExceeded === "pause") {
|
|
187754
|
-
this.onBudgetWarning?.("Budget exceeded - pausing (requires /
|
|
188035
|
+
this.onBudgetWarning?.("Budget exceeded - pausing (requires /budgets resume to continue)");
|
|
187755
188036
|
this.paused = true;
|
|
187756
188037
|
}
|
|
187757
188038
|
}
|
|
@@ -210481,6 +210762,12 @@ function useSafeInput(handler, options = {}) {
|
|
|
210481
210762
|
` : "\x1B\r";
|
|
210482
210763
|
}
|
|
210483
210764
|
const key2 = { ...inkKey };
|
|
210765
|
+
if ((input2 === "m" || input2 === "j") && key2.ctrl && !key2.return) {
|
|
210766
|
+
input2 = input2 === "j" ? `
|
|
210767
|
+
` : "\r";
|
|
210768
|
+
key2.return = true;
|
|
210769
|
+
key2.ctrl = false;
|
|
210770
|
+
}
|
|
210484
210771
|
const isReturnInput = input2 === "\r" || input2 === `
|
|
210485
210772
|
` || input2 === `\r
|
|
210486
210773
|
` || input2 === `
|
|
@@ -210610,6 +210897,8 @@ var COMMANDS = [
|
|
|
210610
210897
|
{ name: "/secrets", description: "manage assistant secrets" },
|
|
210611
210898
|
{ name: "/jobs", description: "manage background jobs" },
|
|
210612
210899
|
{ name: "/docs", description: "interactive app documentation" },
|
|
210900
|
+
{ name: "/diff", description: "show git diff of changes" },
|
|
210901
|
+
{ name: "/undo", description: "revert uncommitted changes" },
|
|
210613
210902
|
{ name: "/rest", description: "enter rest mode" },
|
|
210614
210903
|
{ name: "/logs", description: "view security event logs" },
|
|
210615
210904
|
{ name: "/verification", description: "scope verification status" },
|
|
@@ -210644,6 +210933,7 @@ function isLargePaste(text, thresholds = DEFAULT_PASTE_THRESHOLDS) {
|
|
|
210644
210933
|
}
|
|
210645
210934
|
var Input = import_react28.default.forwardRef(function Input2({
|
|
210646
210935
|
onSubmit,
|
|
210936
|
+
onStopProcessing,
|
|
210647
210937
|
isProcessing,
|
|
210648
210938
|
queueLength = 0,
|
|
210649
210939
|
commands: commands9,
|
|
@@ -210657,7 +210947,8 @@ var Input = import_react28.default.forwardRef(function Input2({
|
|
|
210657
210947
|
pasteConfig,
|
|
210658
210948
|
isRecording = false,
|
|
210659
210949
|
recordingStatus,
|
|
210660
|
-
onStopRecording
|
|
210950
|
+
onStopRecording,
|
|
210951
|
+
onFileSearch
|
|
210661
210952
|
}, ref) {
|
|
210662
210953
|
const pasteEnabled = pasteConfig?.enabled !== false;
|
|
210663
210954
|
const pasteThresholds = pasteConfig?.thresholds ?? DEFAULT_PASTE_THRESHOLDS;
|
|
@@ -210712,8 +211003,14 @@ var Input = import_react28.default.forwardRef(function Input2({
|
|
|
210712
211003
|
if (value.startsWith("/") && !value.includes(" ")) {
|
|
210713
211004
|
return "command";
|
|
210714
211005
|
}
|
|
211006
|
+
if (onFileSearch) {
|
|
211007
|
+
const atMatch = value.match(/(?:^|.*\s)@([^\s]*)$/);
|
|
211008
|
+
if (atMatch) {
|
|
211009
|
+
return "file";
|
|
211010
|
+
}
|
|
211011
|
+
}
|
|
210715
211012
|
return null;
|
|
210716
|
-
}, [value, isAskingUser]);
|
|
211013
|
+
}, [value, isAskingUser, onFileSearch]);
|
|
210717
211014
|
const filteredCommands = import_react28.useMemo(() => {
|
|
210718
211015
|
if (autocompleteMode !== "command")
|
|
210719
211016
|
return [];
|
|
@@ -210726,7 +211023,18 @@ var Input = import_react28.default.forwardRef(function Input2({
|
|
|
210726
211023
|
const search = value.slice(1).toLowerCase();
|
|
210727
211024
|
return skills.filter((skill) => skill.name.toLowerCase().startsWith(search));
|
|
210728
211025
|
}, [value, autocompleteMode, skills]);
|
|
210729
|
-
const
|
|
211026
|
+
const fileSearchQuery = import_react28.useMemo(() => {
|
|
211027
|
+
if (autocompleteMode !== "file")
|
|
211028
|
+
return "";
|
|
211029
|
+
const atMatch = value.match(/(?:^|.*\s)@([^\s]*)$/);
|
|
211030
|
+
return atMatch ? atMatch[1] : "";
|
|
211031
|
+
}, [value, autocompleteMode]);
|
|
211032
|
+
const filteredFiles = import_react28.useMemo(() => {
|
|
211033
|
+
if (autocompleteMode !== "file" || !onFileSearch)
|
|
211034
|
+
return [];
|
|
211035
|
+
return onFileSearch(fileSearchQuery);
|
|
211036
|
+
}, [autocompleteMode, fileSearchQuery, onFileSearch]);
|
|
211037
|
+
const autocompleteItems = autocompleteMode === "skill" ? filteredSkills : autocompleteMode === "file" ? filteredFiles.map((f6) => ({ name: f6 })) : filteredCommands;
|
|
210730
211038
|
import_react28.useEffect(() => {
|
|
210731
211039
|
if (autocompleteItems.length === 0) {
|
|
210732
211040
|
setSelectedIndex(0);
|
|
@@ -210907,6 +211215,10 @@ var Input = import_react28.default.forwardRef(function Input2({
|
|
|
210907
211215
|
return;
|
|
210908
211216
|
}
|
|
210909
211217
|
if (key.escape && !isAskingUser) {
|
|
211218
|
+
if (isProcessing && onStopProcessing) {
|
|
211219
|
+
onStopProcessing();
|
|
211220
|
+
return;
|
|
211221
|
+
}
|
|
210910
211222
|
if (largePaste) {
|
|
210911
211223
|
setLargePaste(null);
|
|
210912
211224
|
setShowPastePreview(false);
|
|
@@ -210932,8 +211244,15 @@ var Input = import_react28.default.forwardRef(function Input2({
|
|
|
210932
211244
|
if (key.tab) {
|
|
210933
211245
|
if (autocompleteItems.length > 0) {
|
|
210934
211246
|
const selected = autocompleteItems[selectedIndex] || autocompleteItems[0];
|
|
210935
|
-
|
|
210936
|
-
|
|
211247
|
+
if (autocompleteMode === "file") {
|
|
211248
|
+
const atMatch = value.match(/^(.*(?:^|\s))@[^\s]*$/);
|
|
211249
|
+
const prefix2 = atMatch ? atMatch[1] : "";
|
|
211250
|
+
const nextValue = prefix2 + selected.name + " ";
|
|
211251
|
+
setValueAndCursor(nextValue);
|
|
211252
|
+
} else {
|
|
211253
|
+
const nextValue = autocompleteMode === "skill" ? `$${selected.name} ` : `${selected.name} `;
|
|
211254
|
+
setValueAndCursor(nextValue);
|
|
211255
|
+
}
|
|
210937
211256
|
return;
|
|
210938
211257
|
}
|
|
210939
211258
|
if (isProcessing && value.trim()) {
|
|
@@ -211013,12 +211332,6 @@ var Input = import_react28.default.forwardRef(function Input2({
|
|
|
211013
211332
|
deleteForward();
|
|
211014
211333
|
return;
|
|
211015
211334
|
}
|
|
211016
|
-
if (input === "\x1B\r" || input === `\x1B
|
|
211017
|
-
`) {
|
|
211018
|
-
insertText(`
|
|
211019
|
-
`);
|
|
211020
|
-
return;
|
|
211021
|
-
}
|
|
211022
211335
|
if (key.return) {
|
|
211023
211336
|
if (isRecording && onStopRecording) {
|
|
211024
211337
|
onStopRecording();
|
|
@@ -211029,7 +211342,8 @@ var Input = import_react28.default.forwardRef(function Input2({
|
|
|
211029
211342
|
setValueAndCursor("");
|
|
211030
211343
|
return;
|
|
211031
211344
|
}
|
|
211032
|
-
if (key.meta && value.trim()
|
|
211345
|
+
if (key.meta && value.trim() && input !== "\x1B\r" && input !== `\x1B
|
|
211346
|
+
`) {
|
|
211033
211347
|
onSubmit(value, "queue");
|
|
211034
211348
|
setValueAndCursor("");
|
|
211035
211349
|
return;
|
|
@@ -211068,6 +211382,8 @@ var Input = import_react28.default.forwardRef(function Input2({
|
|
|
211068
211382
|
};
|
|
211069
211383
|
const visibleSkills = getVisibleItems(filteredSkills);
|
|
211070
211384
|
const visibleCommands = getVisibleItems(filteredCommands);
|
|
211385
|
+
const fileItems = import_react28.useMemo(() => filteredFiles.map((f6) => ({ name: f6 })), [filteredFiles]);
|
|
211386
|
+
const visibleFiles = getVisibleItems(fileItems);
|
|
211071
211387
|
const layout = buildLayout(value, cursor, textWidth);
|
|
211072
211388
|
const lines = layout.displayLines;
|
|
211073
211389
|
const lineCount = value.split(`
|
|
@@ -211340,6 +211656,41 @@ var Input = import_react28.default.forwardRef(function Input2({
|
|
|
211340
211656
|
]
|
|
211341
211657
|
}, undefined, true, undefined, this)
|
|
211342
211658
|
]
|
|
211659
|
+
}, undefined, true, undefined, this),
|
|
211660
|
+
autocompleteMode === "file" && filteredFiles.length > 0 && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
211661
|
+
flexDirection: "column",
|
|
211662
|
+
marginTop: 1,
|
|
211663
|
+
marginLeft: 2,
|
|
211664
|
+
children: [
|
|
211665
|
+
visibleFiles.startIndex > 0 && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text3, {
|
|
211666
|
+
dimColor: true,
|
|
211667
|
+
children: [
|
|
211668
|
+
" \u2191 ",
|
|
211669
|
+
visibleFiles.startIndex,
|
|
211670
|
+
" more above"
|
|
211671
|
+
]
|
|
211672
|
+
}, undefined, true, undefined, this),
|
|
211673
|
+
visibleFiles.items.map((file, i5) => {
|
|
211674
|
+
const actualIndex = visibleFiles.startIndex + i5;
|
|
211675
|
+
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
211676
|
+
children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text3, {
|
|
211677
|
+
color: actualIndex === selectedIndex ? "cyan" : "#5fb3a1",
|
|
211678
|
+
children: [
|
|
211679
|
+
actualIndex === selectedIndex ? "\u25B8 " : " ",
|
|
211680
|
+
file.name
|
|
211681
|
+
]
|
|
211682
|
+
}, undefined, true, undefined, this)
|
|
211683
|
+
}, file.name, false, undefined, this);
|
|
211684
|
+
}),
|
|
211685
|
+
visibleFiles.startIndex + maxVisible < filteredFiles.length && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text3, {
|
|
211686
|
+
dimColor: true,
|
|
211687
|
+
children: [
|
|
211688
|
+
" \u2193 ",
|
|
211689
|
+
filteredFiles.length - visibleFiles.startIndex - maxVisible,
|
|
211690
|
+
" more below"
|
|
211691
|
+
]
|
|
211692
|
+
}, undefined, true, undefined, this)
|
|
211693
|
+
]
|
|
211343
211694
|
}, undefined, true, undefined, this)
|
|
211344
211695
|
]
|
|
211345
211696
|
}, undefined, true, undefined, this);
|
|
@@ -213778,7 +214129,8 @@ function Status({
|
|
|
213778
214129
|
backgroundProcessingCount = 0,
|
|
213779
214130
|
processingStartTime,
|
|
213780
214131
|
verboseTools = false,
|
|
213781
|
-
recentTools = []
|
|
214132
|
+
recentTools = [],
|
|
214133
|
+
gitBranch
|
|
213782
214134
|
}) {
|
|
213783
214135
|
const [elapsed, setElapsed] = import_react30.useState(0);
|
|
213784
214136
|
const [heartbeatCountdown, setHeartbeatCountdown] = import_react30.useState("");
|
|
@@ -213879,7 +214231,8 @@ function Status({
|
|
|
213879
214231
|
dimColor: true,
|
|
213880
214232
|
children: [
|
|
213881
214233
|
"/help",
|
|
213882
|
-
sessionCount && sessionCount > 1 ? " \xB7 Ctrl+]" : ""
|
|
214234
|
+
sessionCount && sessionCount > 1 ? " \xB7 Ctrl+]" : "",
|
|
214235
|
+
gitBranch ? ` \xB7 \u2387 ${gitBranch}` : ""
|
|
213883
214236
|
]
|
|
213884
214237
|
}, undefined, true, undefined, this),
|
|
213885
214238
|
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
@@ -214851,6 +215204,7 @@ function ConnectorsPanel({
|
|
|
214851
215204
|
const [loadedConnectors, setLoadedConnectors] = import_react36.useState(new Map);
|
|
214852
215205
|
const [autoRefreshEntries, setAutoRefreshEntries] = import_react36.useState(new Map);
|
|
214853
215206
|
const [autoRefreshError, setAutoRefreshError] = import_react36.useState(null);
|
|
215207
|
+
const pendingAuthChecksRef = import_react36.useRef(new Set);
|
|
214854
215208
|
const filteredConnectors = import_react36.useMemo(() => {
|
|
214855
215209
|
if (!searchQuery.trim()) {
|
|
214856
215210
|
return connectors;
|
|
@@ -214874,24 +215228,6 @@ function ConnectorsPanel({
|
|
|
214874
215228
|
}
|
|
214875
215229
|
}
|
|
214876
215230
|
}, [initialConnector, filteredConnectors]);
|
|
214877
|
-
import_react36.useEffect(() => {
|
|
214878
|
-
const loadStatuses = async () => {
|
|
214879
|
-
const results = await Promise.all(connectors.map(async (connector) => {
|
|
214880
|
-
try {
|
|
214881
|
-
const status = await onCheckAuth(connector);
|
|
214882
|
-
return { name: connector.name, status };
|
|
214883
|
-
} catch {
|
|
214884
|
-
return { name: connector.name, status: { authenticated: false, error: "Failed to check" } };
|
|
214885
|
-
}
|
|
214886
|
-
}));
|
|
214887
|
-
const statusMap = new Map;
|
|
214888
|
-
for (const { name: name2, status } of results) {
|
|
214889
|
-
statusMap.set(name2, status);
|
|
214890
|
-
}
|
|
214891
|
-
setAuthStatuses(statusMap);
|
|
214892
|
-
};
|
|
214893
|
-
loadStatuses();
|
|
214894
|
-
}, [connectors, onCheckAuth]);
|
|
214895
215231
|
const loadAutoRefreshEntries = import_react36.useCallback(async () => {
|
|
214896
215232
|
try {
|
|
214897
215233
|
const manager = ConnectorAutoRefreshManager.getInstance();
|
|
@@ -214991,6 +215327,10 @@ function ConnectorsPanel({
|
|
|
214991
215327
|
}, [mode, loadCommandHelp]);
|
|
214992
215328
|
useSafeInput((input, key) => {
|
|
214993
215329
|
if (isSearching) {
|
|
215330
|
+
if (input === "q" || input === "Q") {
|
|
215331
|
+
onClose();
|
|
215332
|
+
return;
|
|
215333
|
+
}
|
|
214994
215334
|
if (key.escape) {
|
|
214995
215335
|
if (searchQuery) {
|
|
214996
215336
|
setSearchQuery("");
|
|
@@ -215049,7 +215389,7 @@ function ConnectorsPanel({
|
|
|
215049
215389
|
if (key.upArrow) {
|
|
215050
215390
|
if (mode === "list" && filteredConnectors.length > 0) {
|
|
215051
215391
|
setConnectorIndex((prev) => prev === 0 ? filteredConnectors.length - 1 : prev - 1);
|
|
215052
|
-
} else if (mode === "detail") {
|
|
215392
|
+
} else if (mode === "detail" && currentCommands.length > 0) {
|
|
215053
215393
|
setCommandIndex((prev) => prev === 0 ? currentCommands.length - 1 : prev - 1);
|
|
215054
215394
|
}
|
|
215055
215395
|
return;
|
|
@@ -215057,7 +215397,7 @@ function ConnectorsPanel({
|
|
|
215057
215397
|
if (key.downArrow) {
|
|
215058
215398
|
if (mode === "list" && filteredConnectors.length > 0) {
|
|
215059
215399
|
setConnectorIndex((prev) => prev === filteredConnectors.length - 1 ? 0 : prev + 1);
|
|
215060
|
-
} else if (mode === "detail") {
|
|
215400
|
+
} else if (mode === "detail" && currentCommands.length > 0) {
|
|
215061
215401
|
setCommandIndex((prev) => prev === currentCommands.length - 1 ? 0 : prev + 1);
|
|
215062
215402
|
}
|
|
215063
215403
|
return;
|
|
@@ -215071,10 +215411,6 @@ function ConnectorsPanel({
|
|
|
215071
215411
|
}
|
|
215072
215412
|
return;
|
|
215073
215413
|
}
|
|
215074
|
-
if (mode === "list" && input && /^[a-zA-Z]$/.test(input)) {
|
|
215075
|
-
setIsSearching(true);
|
|
215076
|
-
setSearchQuery(input);
|
|
215077
|
-
}
|
|
215078
215414
|
});
|
|
215079
215415
|
const getStatusIcon = (status) => {
|
|
215080
215416
|
if (!status)
|
|
@@ -215088,6 +215424,45 @@ function ConnectorsPanel({
|
|
|
215088
215424
|
const connectorRange = import_react36.useMemo(() => getVisibleRange(safeConnectorIndex, filteredConnectors.length), [safeConnectorIndex, filteredConnectors.length]);
|
|
215089
215425
|
const commandRange = import_react36.useMemo(() => getVisibleRange(commandIndex, currentCommands.length), [commandIndex, currentCommands.length]);
|
|
215090
215426
|
const visibleConnectors = filteredConnectors.slice(connectorRange.start, connectorRange.end);
|
|
215427
|
+
import_react36.useEffect(() => {
|
|
215428
|
+
const targets = mode === "list" ? visibleConnectors : currentConnector ? [currentConnector] : [];
|
|
215429
|
+
if (targets.length === 0) {
|
|
215430
|
+
return;
|
|
215431
|
+
}
|
|
215432
|
+
let cancelled = false;
|
|
215433
|
+
const loadStatuses = async () => {
|
|
215434
|
+
for (const connector of targets) {
|
|
215435
|
+
const name2 = connector.name;
|
|
215436
|
+
if (authStatuses.has(name2) || pendingAuthChecksRef.current.has(name2)) {
|
|
215437
|
+
continue;
|
|
215438
|
+
}
|
|
215439
|
+
pendingAuthChecksRef.current.add(name2);
|
|
215440
|
+
try {
|
|
215441
|
+
let status;
|
|
215442
|
+
try {
|
|
215443
|
+
status = await onCheckAuth(connector);
|
|
215444
|
+
} catch {
|
|
215445
|
+
status = { authenticated: false, error: "Failed to check" };
|
|
215446
|
+
}
|
|
215447
|
+
if (cancelled)
|
|
215448
|
+
continue;
|
|
215449
|
+
setAuthStatuses((prev) => {
|
|
215450
|
+
if (prev.has(name2))
|
|
215451
|
+
return prev;
|
|
215452
|
+
const next = new Map(prev);
|
|
215453
|
+
next.set(name2, status);
|
|
215454
|
+
return next;
|
|
215455
|
+
});
|
|
215456
|
+
} finally {
|
|
215457
|
+
pendingAuthChecksRef.current.delete(name2);
|
|
215458
|
+
}
|
|
215459
|
+
}
|
|
215460
|
+
};
|
|
215461
|
+
loadStatuses();
|
|
215462
|
+
return () => {
|
|
215463
|
+
cancelled = true;
|
|
215464
|
+
};
|
|
215465
|
+
}, [authStatuses, currentConnector, mode, onCheckAuth, visibleConnectors]);
|
|
215091
215466
|
if (connectors.length === 0) {
|
|
215092
215467
|
return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
|
|
215093
215468
|
flexDirection: "column",
|
|
@@ -226654,16 +227029,16 @@ function JobsPanel({ manager, onClose }) {
|
|
|
226654
227029
|
if (!job || isWorking)
|
|
226655
227030
|
return;
|
|
226656
227031
|
if (!isActiveStatus(job.status)) {
|
|
226657
|
-
setStatusMessage(`Job ${job.id} is ${job.status}. Only pending/running jobs can be
|
|
227032
|
+
setStatusMessage(`Job ${job.id} is ${job.status}. Only pending/running jobs can be killed.`);
|
|
226658
227033
|
return;
|
|
226659
227034
|
}
|
|
226660
227035
|
setIsWorking(true);
|
|
226661
227036
|
try {
|
|
226662
227037
|
const cancelled = await manager.cancelJob(job.id);
|
|
226663
227038
|
if (cancelled) {
|
|
226664
|
-
setStatusMessage(`
|
|
227039
|
+
setStatusMessage(`Killed ${job.id}.`);
|
|
226665
227040
|
} else {
|
|
226666
|
-
setStatusMessage(`Could not
|
|
227041
|
+
setStatusMessage(`Could not kill ${job.id}.`);
|
|
226667
227042
|
}
|
|
226668
227043
|
await refreshJobs(false);
|
|
226669
227044
|
} catch (err) {
|
|
@@ -226672,6 +227047,38 @@ function JobsPanel({ manager, onClose }) {
|
|
|
226672
227047
|
setIsWorking(false);
|
|
226673
227048
|
}
|
|
226674
227049
|
}, [isWorking, manager, refreshJobs]);
|
|
227050
|
+
const killAllActiveJobs = import_react50.useCallback(async () => {
|
|
227051
|
+
if (isWorking)
|
|
227052
|
+
return;
|
|
227053
|
+
const activeJobs = jobs2.filter((job) => isActiveStatus(job.status));
|
|
227054
|
+
if (activeJobs.length === 0) {
|
|
227055
|
+
setStatusMessage("No active jobs to kill.");
|
|
227056
|
+
return;
|
|
227057
|
+
}
|
|
227058
|
+
setIsWorking(true);
|
|
227059
|
+
try {
|
|
227060
|
+
let killed = 0;
|
|
227061
|
+
for (const job of activeJobs) {
|
|
227062
|
+
try {
|
|
227063
|
+
const cancelled = await manager.cancelJob(job.id);
|
|
227064
|
+
if (cancelled)
|
|
227065
|
+
killed += 1;
|
|
227066
|
+
} catch {}
|
|
227067
|
+
}
|
|
227068
|
+
if (killed === 0) {
|
|
227069
|
+
setStatusMessage("Could not kill any active jobs.");
|
|
227070
|
+
} else if (killed === activeJobs.length) {
|
|
227071
|
+
setStatusMessage(`Killed ${killed} active job${killed === 1 ? "" : "s"}.`);
|
|
227072
|
+
} else {
|
|
227073
|
+
setStatusMessage(`Killed ${killed}/${activeJobs.length} active jobs.`);
|
|
227074
|
+
}
|
|
227075
|
+
await refreshJobs(false);
|
|
227076
|
+
} catch (err) {
|
|
227077
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
227078
|
+
} finally {
|
|
227079
|
+
setIsWorking(false);
|
|
227080
|
+
}
|
|
227081
|
+
}, [isWorking, jobs2, manager, refreshJobs]);
|
|
226675
227082
|
const openDetail = import_react50.useCallback(() => {
|
|
226676
227083
|
const selected = filteredJobs[selectedIndex];
|
|
226677
227084
|
if (!selected)
|
|
@@ -226694,7 +227101,11 @@ function JobsPanel({ manager, onClose }) {
|
|
|
226694
227101
|
refreshJobs(true);
|
|
226695
227102
|
return;
|
|
226696
227103
|
}
|
|
226697
|
-
if (input === "
|
|
227104
|
+
if (input === "K") {
|
|
227105
|
+
killAllActiveJobs();
|
|
227106
|
+
return;
|
|
227107
|
+
}
|
|
227108
|
+
if (input === "x" || input === "c" || input === "d") {
|
|
226698
227109
|
cancelJob(detailJob);
|
|
226699
227110
|
}
|
|
226700
227111
|
return;
|
|
@@ -226748,7 +227159,11 @@ function JobsPanel({ manager, onClose }) {
|
|
|
226748
227159
|
refreshJobs(true);
|
|
226749
227160
|
return;
|
|
226750
227161
|
}
|
|
226751
|
-
if (input === "
|
|
227162
|
+
if (input === "K") {
|
|
227163
|
+
killAllActiveJobs();
|
|
227164
|
+
return;
|
|
227165
|
+
}
|
|
227166
|
+
if (input === "x" || input === "c" || input === "d") {
|
|
226752
227167
|
cancelJob(filteredJobs[selectedIndex] || null);
|
|
226753
227168
|
}
|
|
226754
227169
|
});
|
|
@@ -226786,7 +227201,9 @@ function JobsPanel({ manager, onClose }) {
|
|
|
226786
227201
|
children: [
|
|
226787
227202
|
"(",
|
|
226788
227203
|
jobs2.length,
|
|
226789
|
-
" total
|
|
227204
|
+
" total, ",
|
|
227205
|
+
jobs2.filter((job) => isActiveStatus(job.status)).length,
|
|
227206
|
+
" active)"
|
|
226790
227207
|
]
|
|
226791
227208
|
}, undefined, true, undefined, this)
|
|
226792
227209
|
]
|
|
@@ -226907,7 +227324,7 @@ function JobsPanel({ manager, onClose }) {
|
|
|
226907
227324
|
marginTop: 1,
|
|
226908
227325
|
children: /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Text3, {
|
|
226909
227326
|
color: "gray",
|
|
226910
|
-
children: "x/c
|
|
227327
|
+
children: "d/x/c kill selected K kill all active r refresh esc back q close"
|
|
226911
227328
|
}, undefined, false, undefined, this)
|
|
226912
227329
|
}, undefined, false, undefined, this)
|
|
226913
227330
|
]
|
|
@@ -227027,7 +227444,7 @@ function JobsPanel({ manager, onClose }) {
|
|
|
227027
227444
|
marginTop: 1,
|
|
227028
227445
|
children: /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Text3, {
|
|
227029
227446
|
color: "gray",
|
|
227030
|
-
children: "j/k or arrows move enter view x/c
|
|
227447
|
+
children: "j/k or arrows move enter view d/x/c kill selected K kill all active r refresh 1/2/3 filter q close"
|
|
227031
227448
|
}, undefined, false, undefined, this)
|
|
227032
227449
|
}, undefined, false, undefined, this)
|
|
227033
227450
|
]
|
|
@@ -227116,7 +227533,7 @@ var DOCS_SECTIONS = [
|
|
|
227116
227533
|
content: [
|
|
227117
227534
|
"Use /tasks for queued local tasks with priority and pause/resume controls.",
|
|
227118
227535
|
"Use /schedules for recurring command execution with next-run visibility.",
|
|
227119
|
-
"Use /jobs for background connector/tool jobs.
|
|
227536
|
+
"Use /jobs for background connector/tool jobs. Kill jobs directly in the panel.",
|
|
227120
227537
|
"Use /orders for interactive order/store workflows (tabs, table navigation, detail views).",
|
|
227121
227538
|
"Use /logs for security events and /heartbeat for recurring assistant runs."
|
|
227122
227539
|
]
|
|
@@ -236360,7 +236777,7 @@ function SecretsPanel({
|
|
|
236360
236777
|
setIsProcessing(false);
|
|
236361
236778
|
}
|
|
236362
236779
|
};
|
|
236363
|
-
const
|
|
236780
|
+
const normalizeScope3 = (rawScope) => {
|
|
236364
236781
|
const scope = rawScope.trim().toLowerCase();
|
|
236365
236782
|
if (!scope)
|
|
236366
236783
|
return "assistant";
|
|
@@ -236369,7 +236786,7 @@ function SecretsPanel({
|
|
|
236369
236786
|
return null;
|
|
236370
236787
|
};
|
|
236371
236788
|
const normalizeAddInput = (form) => {
|
|
236372
|
-
const scope =
|
|
236789
|
+
const scope = normalizeScope3(String(form.scope));
|
|
236373
236790
|
if (!scope) {
|
|
236374
236791
|
return null;
|
|
236375
236792
|
}
|
|
@@ -236390,7 +236807,7 @@ function SecretsPanel({
|
|
|
236390
236807
|
return;
|
|
236391
236808
|
}
|
|
236392
236809
|
if (currentAddField.key === "scope") {
|
|
236393
|
-
const normalizedScope =
|
|
236810
|
+
const normalizedScope = normalizeScope3(currentValue);
|
|
236394
236811
|
if (!normalizedScope) {
|
|
236395
236812
|
setStatusMessage('Scope must be "assistant" or "global".');
|
|
236396
236813
|
return;
|
|
@@ -238870,6 +239287,18 @@ function ResumePanel({
|
|
|
238870
239287
|
}, undefined, true, undefined, this);
|
|
238871
239288
|
}
|
|
238872
239289
|
|
|
239290
|
+
// packages/terminal/src/components/queueUtils.ts
|
|
239291
|
+
function takeNextQueuedMessage(queue, sessionId) {
|
|
239292
|
+
const next = queue.find((msg) => msg.sessionId === sessionId);
|
|
239293
|
+
if (!next) {
|
|
239294
|
+
return { next: null, remaining: queue };
|
|
239295
|
+
}
|
|
239296
|
+
return {
|
|
239297
|
+
next,
|
|
239298
|
+
remaining: queue.filter((msg) => msg.id !== next.id)
|
|
239299
|
+
};
|
|
239300
|
+
}
|
|
239301
|
+
|
|
238873
239302
|
// packages/terminal/src/output/sanitize.ts
|
|
238874
239303
|
var CLEAR_SCREEN_SEQUENCE = "\x1B[2J\x1B[3J\x1B[H";
|
|
238875
239304
|
var CLEAR_SCREEN_TOKEN = "__ASSISTANTS_CLEAR_SCREEN__";
|
|
@@ -239256,6 +239685,7 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
239256
239685
|
const [heartbeatState, setHeartbeatState] = import_react72.useState();
|
|
239257
239686
|
const [identityInfo, setIdentityInfo] = import_react72.useState();
|
|
239258
239687
|
const [verboseTools, setVerboseTools] = import_react72.useState(false);
|
|
239688
|
+
const [gitBranch, setGitBranch] = import_react72.useState();
|
|
239259
239689
|
const [askUserState, setAskUserState] = import_react72.useState(null);
|
|
239260
239690
|
const [processingStartTime, setProcessingStartTime] = import_react72.useState();
|
|
239261
239691
|
const [currentTurnTokens, setCurrentTurnTokens] = import_react72.useState(0);
|
|
@@ -239269,6 +239699,42 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
239269
239699
|
const pttRecorderRef = import_react72.useRef(null);
|
|
239270
239700
|
const [skills, setSkills] = import_react72.useState([]);
|
|
239271
239701
|
const [commands9, setCommands] = import_react72.useState([]);
|
|
239702
|
+
const fileListCacheRef = import_react72.useRef({ files: [], timestamp: 0 });
|
|
239703
|
+
const searchFiles = import_react72.useCallback((query) => {
|
|
239704
|
+
const cache7 = fileListCacheRef.current;
|
|
239705
|
+
const now2 = Date.now();
|
|
239706
|
+
if (now2 - cache7.timestamp > 30000 || cache7.files.length === 0) {
|
|
239707
|
+
try {
|
|
239708
|
+
const { execSync } = __require("child_process");
|
|
239709
|
+
let output;
|
|
239710
|
+
try {
|
|
239711
|
+
output = execSync("git ls-files --cached --others --exclude-standard 2>/dev/null", {
|
|
239712
|
+
cwd: cwd2,
|
|
239713
|
+
encoding: "utf-8",
|
|
239714
|
+
maxBuffer: 1024 * 1024,
|
|
239715
|
+
timeout: 3000
|
|
239716
|
+
});
|
|
239717
|
+
} catch {
|
|
239718
|
+
output = execSync('find . -type f -not -path "*/node_modules/*" -not -path "*/.git/*" -maxdepth 5 2>/dev/null | head -1000', {
|
|
239719
|
+
cwd: cwd2,
|
|
239720
|
+
encoding: "utf-8",
|
|
239721
|
+
maxBuffer: 1024 * 1024,
|
|
239722
|
+
timeout: 3000
|
|
239723
|
+
});
|
|
239724
|
+
}
|
|
239725
|
+
cache7.files = output.trim().split(`
|
|
239726
|
+
`).filter(Boolean).slice(0, 2000);
|
|
239727
|
+
cache7.timestamp = now2;
|
|
239728
|
+
} catch {
|
|
239729
|
+
return [];
|
|
239730
|
+
}
|
|
239731
|
+
}
|
|
239732
|
+
if (!query)
|
|
239733
|
+
return cache7.files.slice(0, 20);
|
|
239734
|
+
const lower = query.toLowerCase();
|
|
239735
|
+
const matches = cache7.files.filter((f6) => f6.toLowerCase().includes(lower));
|
|
239736
|
+
return matches.slice(0, 20);
|
|
239737
|
+
}, [cwd2]);
|
|
239272
239738
|
const lastCtrlCRef = import_react72.useRef(0);
|
|
239273
239739
|
const [showExitHint, setShowExitHint] = import_react72.useState(false);
|
|
239274
239740
|
const responseRef = import_react72.useRef("");
|
|
@@ -239277,6 +239743,8 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
239277
239743
|
const activityLogRef = import_react72.useRef([]);
|
|
239278
239744
|
const skipNextDoneRef = import_react72.useRef(false);
|
|
239279
239745
|
const isProcessingRef = import_react72.useRef(isProcessing);
|
|
239746
|
+
const currentToolCallRef = import_react72.useRef(currentToolCall);
|
|
239747
|
+
const hasPendingToolsRef = import_react72.useRef(false);
|
|
239280
239748
|
const inputRef = import_react72.useRef(null);
|
|
239281
239749
|
const isListeningRef = import_react72.useRef(isListening);
|
|
239282
239750
|
const listenLoopRef = import_react72.useRef({
|
|
@@ -239357,6 +239825,9 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
239357
239825
|
import_react72.useEffect(() => {
|
|
239358
239826
|
isProcessingRef.current = isProcessing;
|
|
239359
239827
|
}, [isProcessing]);
|
|
239828
|
+
import_react72.useEffect(() => {
|
|
239829
|
+
currentToolCallRef.current = currentToolCall;
|
|
239830
|
+
}, [currentToolCall]);
|
|
239360
239831
|
import_react72.useEffect(() => {
|
|
239361
239832
|
isListeningRef.current = isListening;
|
|
239362
239833
|
}, [isListening]);
|
|
@@ -239370,6 +239841,14 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
239370
239841
|
processingStartTimeRef.current = now2;
|
|
239371
239842
|
}
|
|
239372
239843
|
}, [isProcessing, processingStartTime]);
|
|
239844
|
+
import_react72.useEffect(() => {
|
|
239845
|
+
const { exec: exec3 } = __require("child_process");
|
|
239846
|
+
exec3("git branch --show-current 2>/dev/null", { cwd: cwd2 }, (err, stdout2) => {
|
|
239847
|
+
if (!err && stdout2?.trim()) {
|
|
239848
|
+
setGitBranch(stdout2.trim());
|
|
239849
|
+
}
|
|
239850
|
+
});
|
|
239851
|
+
}, [cwd2]);
|
|
239373
239852
|
const buildFullResponse = import_react72.useCallback(() => {
|
|
239374
239853
|
const parts = activityLogRef.current.filter((entry) => entry.type === "text" && entry.content).map((entry) => entry.content);
|
|
239375
239854
|
if (responseRef.current.trim()) {
|
|
@@ -240048,7 +240527,7 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
240048
240527
|
const pendingIndex = pendingSendsRef.current.findIndex((entry) => entry.sessionId === active.id);
|
|
240049
240528
|
if (pendingIndex !== -1) {
|
|
240050
240529
|
const [started] = pendingSendsRef.current.splice(pendingIndex, 1);
|
|
240051
|
-
if (started
|
|
240530
|
+
if (started) {
|
|
240052
240531
|
setInlinePending((prev) => prev.filter((msg) => msg.id !== started.id));
|
|
240053
240532
|
}
|
|
240054
240533
|
}
|
|
@@ -240702,17 +241181,10 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
240702
241181
|
const activeSession2 = registryRef.current.getActiveSession();
|
|
240703
241182
|
if (!activeSession2 || !activeSessionId)
|
|
240704
241183
|
return;
|
|
240705
|
-
|
|
240706
|
-
setMessageQueue((prev) => {
|
|
240707
|
-
const idx = prev.findIndex((msg) => msg.sessionId === activeSessionId);
|
|
240708
|
-
if (idx === -1) {
|
|
240709
|
-
return prev;
|
|
240710
|
-
}
|
|
240711
|
-
nextMessage = prev[idx];
|
|
240712
|
-
return [...prev.slice(0, idx), ...prev.slice(idx + 1)];
|
|
240713
|
-
});
|
|
241184
|
+
const { next: nextMessage, remaining } = takeNextQueuedMessage(messageQueue, activeSessionId);
|
|
240714
241185
|
if (!nextMessage)
|
|
240715
241186
|
return;
|
|
241187
|
+
setMessageQueue(remaining);
|
|
240716
241188
|
const userMessage = {
|
|
240717
241189
|
id: nextMessage.id,
|
|
240718
241190
|
role: "user",
|
|
@@ -240741,7 +241213,6 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
240741
241213
|
setIsProcessing(true);
|
|
240742
241214
|
isProcessingRef.current = true;
|
|
240743
241215
|
registryRef.current.setProcessing(activeSession2.id, true);
|
|
240744
|
-
pendingSendsRef.current.push({ id: nextMessage.id, sessionId: activeSessionId, mode: "queued" });
|
|
240745
241216
|
try {
|
|
240746
241217
|
await activeSession2.client.send(nextMessage.content);
|
|
240747
241218
|
} catch (err) {
|
|
@@ -240750,8 +241221,9 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
240750
241221
|
setIsProcessing(false);
|
|
240751
241222
|
isProcessingRef.current = false;
|
|
240752
241223
|
registryRef.current.setProcessing(activeSession2.id, false);
|
|
241224
|
+
setQueueFlushTrigger((prev) => prev + 1);
|
|
240753
241225
|
}
|
|
240754
|
-
}, [activeSessionId, clearPendingSend]);
|
|
241226
|
+
}, [activeSessionId, clearPendingSend, messageQueue]);
|
|
240755
241227
|
const activeQueue = activeSessionId ? messageQueue.filter((msg) => msg.sessionId === activeSessionId) : [];
|
|
240756
241228
|
const activeInline = activeSessionId ? inlinePending.filter((msg) => msg.sessionId === activeSessionId) : [];
|
|
240757
241229
|
const queuedMessageIds = import_react72.useMemo(() => new Set(activeQueue.filter((msg) => msg.mode === "queued").map((msg) => msg.id)), [activeQueue]);
|
|
@@ -240811,6 +241283,9 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
240811
241283
|
}
|
|
240812
241284
|
return false;
|
|
240813
241285
|
}, [activityLog]);
|
|
241286
|
+
import_react72.useEffect(() => {
|
|
241287
|
+
hasPendingToolsRef.current = hasPendingTools;
|
|
241288
|
+
}, [hasPendingTools]);
|
|
240814
241289
|
const isBusy = isProcessing || hasPendingTools;
|
|
240815
241290
|
const listenHints = import_react72.useMemo(() => {
|
|
240816
241291
|
if (!isListening)
|
|
@@ -240890,6 +241365,26 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
240890
241365
|
setError(err instanceof Error ? err.message : "Failed to create session");
|
|
240891
241366
|
}
|
|
240892
241367
|
}, [cwd2, createAndActivateSession]);
|
|
241368
|
+
const stopActiveProcessing = import_react72.useCallback((status = "stopped") => {
|
|
241369
|
+
const active = registryRef.current.getActiveSession();
|
|
241370
|
+
if (!active)
|
|
241371
|
+
return false;
|
|
241372
|
+
const sessionProcessing = active.isProcessing;
|
|
241373
|
+
const shouldStopNow = isProcessingRef.current || hasPendingToolsRef.current || sessionProcessing || Boolean(currentToolCallRef.current);
|
|
241374
|
+
if (!shouldStopNow)
|
|
241375
|
+
return false;
|
|
241376
|
+
active.client.stop();
|
|
241377
|
+
const finalized = finalizeResponse2(status);
|
|
241378
|
+
if (finalized) {
|
|
241379
|
+
skipNextDoneRef.current = true;
|
|
241380
|
+
}
|
|
241381
|
+
resetTurnState();
|
|
241382
|
+
registryRef.current.setProcessing(active.id, false);
|
|
241383
|
+
setIsProcessing(false);
|
|
241384
|
+
isProcessingRef.current = false;
|
|
241385
|
+
setQueueFlushTrigger((prev) => prev + 1);
|
|
241386
|
+
return true;
|
|
241387
|
+
}, [finalizeResponse2, resetTurnState]);
|
|
240893
241388
|
useSafeInput((input, key) => {
|
|
240894
241389
|
if (isListeningRef.current && key.ctrl && input === "l") {
|
|
240895
241390
|
stopListening();
|
|
@@ -240910,18 +241405,7 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
240910
241405
|
if (hasAsk) {
|
|
240911
241406
|
cancelAskUser("Cancelled by user", activeSessionId);
|
|
240912
241407
|
}
|
|
240913
|
-
|
|
240914
|
-
if ((isProcessing || hasPendingTools || sessionProcessing || currentToolCall) && activeSession) {
|
|
240915
|
-
activeSession.client.stop();
|
|
240916
|
-
const finalized = finalizeResponse2("stopped");
|
|
240917
|
-
if (finalized) {
|
|
240918
|
-
skipNextDoneRef.current = true;
|
|
240919
|
-
}
|
|
240920
|
-
resetTurnState();
|
|
240921
|
-
registryRef.current.setProcessing(activeSession.id, false);
|
|
240922
|
-
setIsProcessing(false);
|
|
240923
|
-
isProcessingRef.current = false;
|
|
240924
|
-
setQueueFlushTrigger((prev) => prev + 1);
|
|
241408
|
+
if (stopActiveProcessing("stopped")) {
|
|
240925
241409
|
lastCtrlCRef.current = 0;
|
|
240926
241410
|
setShowExitHint(false);
|
|
240927
241411
|
return;
|
|
@@ -240950,18 +241434,8 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
240950
241434
|
if (activeSessionId && askUserStateRef.current.has(activeSessionId)) {
|
|
240951
241435
|
cancelAskUser("Cancelled by user", activeSessionId);
|
|
240952
241436
|
}
|
|
240953
|
-
|
|
240954
|
-
|
|
240955
|
-
activeSession.client.stop();
|
|
240956
|
-
const finalized = finalizeResponse2("stopped");
|
|
240957
|
-
if (finalized) {
|
|
240958
|
-
skipNextDoneRef.current = true;
|
|
240959
|
-
}
|
|
240960
|
-
resetTurnState();
|
|
240961
|
-
registryRef.current.setProcessing(activeSession.id, false);
|
|
240962
|
-
setIsProcessing(false);
|
|
240963
|
-
isProcessingRef.current = false;
|
|
240964
|
-
setQueueFlushTrigger((prev) => prev + 1);
|
|
241437
|
+
if (stopActiveProcessing("stopped")) {
|
|
241438
|
+
return;
|
|
240965
241439
|
}
|
|
240966
241440
|
}
|
|
240967
241441
|
if (key.ctrl && input === "a") {
|
|
@@ -240972,7 +241446,7 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
240972
241446
|
openBudgetsPanel();
|
|
240973
241447
|
return;
|
|
240974
241448
|
}
|
|
240975
|
-
if (key.ctrl && input === "m") {
|
|
241449
|
+
if (key.ctrl && input === "m" && !key.return) {
|
|
240976
241450
|
const messagesManager = registry2.getActiveSession()?.client.getMessagesManager?.();
|
|
240977
241451
|
if (messagesManager) {
|
|
240978
241452
|
messagesManager.list({ limit: 50 }).then((msgs) => {
|
|
@@ -241455,7 +241929,7 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
241455
241929
|
timestamp: now()
|
|
241456
241930
|
}
|
|
241457
241931
|
]);
|
|
241458
|
-
pendingSendsRef.current.push({ id: inlineId, sessionId: activeSessionId
|
|
241932
|
+
pendingSendsRef.current.push({ id: inlineId, sessionId: activeSessionId });
|
|
241459
241933
|
try {
|
|
241460
241934
|
await activeSession.client.send(trimmedInput);
|
|
241461
241935
|
} catch (err) {
|
|
@@ -241464,17 +241938,8 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
241464
241938
|
}
|
|
241465
241939
|
return;
|
|
241466
241940
|
}
|
|
241467
|
-
if (mode === "interrupt" &&
|
|
241468
|
-
|
|
241469
|
-
const finalized = finalizeResponse2("interrupted");
|
|
241470
|
-
if (finalized) {
|
|
241471
|
-
skipNextDoneRef.current = true;
|
|
241472
|
-
}
|
|
241473
|
-
resetTurnState();
|
|
241474
|
-
setIsProcessing(false);
|
|
241475
|
-
isProcessingRef.current = false;
|
|
241476
|
-
registry2.setProcessing(activeSession.id, false);
|
|
241477
|
-
setQueueFlushTrigger((prev) => prev + 1);
|
|
241941
|
+
if (mode === "interrupt" && isBusy) {
|
|
241942
|
+
stopActiveProcessing("interrupted");
|
|
241478
241943
|
await new Promise((r6) => setTimeout(r6, 100));
|
|
241479
241944
|
}
|
|
241480
241945
|
const userMessage = {
|
|
@@ -241516,6 +241981,7 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
241516
241981
|
}, [
|
|
241517
241982
|
activeSession,
|
|
241518
241983
|
isProcessing,
|
|
241984
|
+
isBusy,
|
|
241519
241985
|
registry2,
|
|
241520
241986
|
sessions,
|
|
241521
241987
|
handleNewSession,
|
|
@@ -241527,7 +241993,8 @@ function App2({ cwd: cwd2, version: version3 }) {
|
|
|
241527
241993
|
submitAskAnswer,
|
|
241528
241994
|
clearPendingSend,
|
|
241529
241995
|
startListening,
|
|
241530
|
-
stopListening
|
|
241996
|
+
stopListening,
|
|
241997
|
+
stopActiveProcessing
|
|
241531
241998
|
]);
|
|
241532
241999
|
import_react72.useEffect(() => {
|
|
241533
242000
|
sendListenMessageRef.current = (text) => {
|
|
@@ -243292,6 +243759,9 @@ ${msg.body || msg.preview}`);
|
|
|
243292
243759
|
/* @__PURE__ */ jsx_dev_runtime48.jsxDEV(Input, {
|
|
243293
243760
|
ref: inputRef,
|
|
243294
243761
|
onSubmit: handleSubmit,
|
|
243762
|
+
onStopProcessing: () => {
|
|
243763
|
+
stopActiveProcessing("stopped");
|
|
243764
|
+
},
|
|
243295
243765
|
isProcessing: isBusy,
|
|
243296
243766
|
queueLength: activeQueue.length + inlineCount,
|
|
243297
243767
|
commands: commands9,
|
|
@@ -243303,7 +243773,8 @@ ${msg.body || msg.preview}`);
|
|
|
243303
243773
|
assistantName: identityInfo?.assistant?.name || undefined,
|
|
243304
243774
|
isRecording: pttRecording,
|
|
243305
243775
|
recordingStatus: pttStatus,
|
|
243306
|
-
onStopRecording: togglePushToTalk
|
|
243776
|
+
onStopRecording: togglePushToTalk,
|
|
243777
|
+
onFileSearch: searchFiles
|
|
243307
243778
|
}, undefined, false, undefined, this),
|
|
243308
243779
|
/* @__PURE__ */ jsx_dev_runtime48.jsxDEV(Status, {
|
|
243309
243780
|
isProcessing: isBusy,
|
|
@@ -243318,7 +243789,8 @@ ${msg.body || msg.preview}`);
|
|
|
243318
243789
|
sessionCount,
|
|
243319
243790
|
backgroundProcessingCount,
|
|
243320
243791
|
processingStartTime,
|
|
243321
|
-
verboseTools
|
|
243792
|
+
verboseTools,
|
|
243793
|
+
gitBranch
|
|
243322
243794
|
}, undefined, false, undefined, this)
|
|
243323
243795
|
]
|
|
243324
243796
|
}, undefined, true, undefined, this);
|
|
@@ -243766,7 +244238,7 @@ Interactive Mode:
|
|
|
243766
244238
|
// packages/terminal/src/index.tsx
|
|
243767
244239
|
var jsx_dev_runtime49 = __toESM(require_jsx_dev_runtime(), 1);
|
|
243768
244240
|
setRuntime(bunRuntime);
|
|
243769
|
-
var VERSION4 = "1.1.
|
|
244241
|
+
var VERSION4 = "1.1.26";
|
|
243770
244242
|
var SYNC_START = "\x1B[?2026h";
|
|
243771
244243
|
var SYNC_END = "\x1B[?2026l";
|
|
243772
244244
|
function enableSynchronizedOutput() {
|
|
@@ -243906,4 +244378,4 @@ export {
|
|
|
243906
244378
|
main
|
|
243907
244379
|
};
|
|
243908
244380
|
|
|
243909
|
-
//# debugId=
|
|
244381
|
+
//# debugId=6204ABF8948FEE3864756E2164756E21
|