@hasna/assistants 0.6.18 → 0.6.20
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 +1594 -543
- package/dist/index.js.map +20 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25630,7 +25630,7 @@ var __classPrivateFieldSet = function(receiver, state, value, kind2, f) {
|
|
|
25630
25630
|
}
|
|
25631
25631
|
}, startsWithSchemeRegexp, isAbsoluteURL = (url) => {
|
|
25632
25632
|
return startsWithSchemeRegexp.test(url);
|
|
25633
|
-
}, sleep2 = (ms) => new Promise((
|
|
25633
|
+
}, sleep2 = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)), validatePositiveInteger = (name, n) => {
|
|
25634
25634
|
if (typeof n !== "number" || !Number.isInteger(n)) {
|
|
25635
25635
|
throw new AnthropicError(`${name} must be an integer`);
|
|
25636
25636
|
}
|
|
@@ -25696,8 +25696,8 @@ var init_core = __esm(() => {
|
|
|
25696
25696
|
init_uploads();
|
|
25697
25697
|
APIPromise = class APIPromise extends Promise {
|
|
25698
25698
|
constructor(responsePromise, parseResponse = defaultParseResponse) {
|
|
25699
|
-
super((
|
|
25700
|
-
|
|
25699
|
+
super((resolve5) => {
|
|
25700
|
+
resolve5(null);
|
|
25701
25701
|
});
|
|
25702
25702
|
this.responsePromise = responsePromise;
|
|
25703
25703
|
this.parseResponse = parseResponse;
|
|
@@ -26295,12 +26295,12 @@ var init_PromptCachingBetaMessageStream = __esm(() => {
|
|
|
26295
26295
|
}
|
|
26296
26296
|
return this._emit("error", new AnthropicError(String(error)));
|
|
26297
26297
|
});
|
|
26298
|
-
__classPrivateFieldSet2(this, _PromptCachingBetaMessageStream_connectedPromise, new Promise((
|
|
26299
|
-
__classPrivateFieldSet2(this, _PromptCachingBetaMessageStream_resolveConnectedPromise,
|
|
26298
|
+
__classPrivateFieldSet2(this, _PromptCachingBetaMessageStream_connectedPromise, new Promise((resolve5, reject) => {
|
|
26299
|
+
__classPrivateFieldSet2(this, _PromptCachingBetaMessageStream_resolveConnectedPromise, resolve5, "f");
|
|
26300
26300
|
__classPrivateFieldSet2(this, _PromptCachingBetaMessageStream_rejectConnectedPromise, reject, "f");
|
|
26301
26301
|
}), "f");
|
|
26302
|
-
__classPrivateFieldSet2(this, _PromptCachingBetaMessageStream_endPromise, new Promise((
|
|
26303
|
-
__classPrivateFieldSet2(this, _PromptCachingBetaMessageStream_resolveEndPromise,
|
|
26302
|
+
__classPrivateFieldSet2(this, _PromptCachingBetaMessageStream_endPromise, new Promise((resolve5, reject) => {
|
|
26303
|
+
__classPrivateFieldSet2(this, _PromptCachingBetaMessageStream_resolveEndPromise, resolve5, "f");
|
|
26304
26304
|
__classPrivateFieldSet2(this, _PromptCachingBetaMessageStream_rejectEndPromise, reject, "f");
|
|
26305
26305
|
}), "f");
|
|
26306
26306
|
__classPrivateFieldGet2(this, _PromptCachingBetaMessageStream_connectedPromise, "f").catch(() => {});
|
|
@@ -26390,11 +26390,11 @@ var init_PromptCachingBetaMessageStream = __esm(() => {
|
|
|
26390
26390
|
return this;
|
|
26391
26391
|
}
|
|
26392
26392
|
emitted(event) {
|
|
26393
|
-
return new Promise((
|
|
26393
|
+
return new Promise((resolve5, reject) => {
|
|
26394
26394
|
__classPrivateFieldSet2(this, _PromptCachingBetaMessageStream_catchingPromiseCreated, true, "f");
|
|
26395
26395
|
if (event !== "error")
|
|
26396
26396
|
this.once("error", reject);
|
|
26397
|
-
this.once(event,
|
|
26397
|
+
this.once(event, resolve5);
|
|
26398
26398
|
});
|
|
26399
26399
|
}
|
|
26400
26400
|
async done() {
|
|
@@ -26612,7 +26612,7 @@ var init_PromptCachingBetaMessageStream = __esm(() => {
|
|
|
26612
26612
|
if (done) {
|
|
26613
26613
|
return { value: undefined, done: true };
|
|
26614
26614
|
}
|
|
26615
|
-
return new Promise((
|
|
26615
|
+
return new Promise((resolve5, reject) => readQueue.push({ resolve: resolve5, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: undefined, done: true });
|
|
26616
26616
|
}
|
|
26617
26617
|
const chunk = pushQueue.shift();
|
|
26618
26618
|
return { value: chunk, done: false };
|
|
@@ -26758,12 +26758,12 @@ var init_MessageStream = __esm(() => {
|
|
|
26758
26758
|
}
|
|
26759
26759
|
return this._emit("error", new AnthropicError(String(error)));
|
|
26760
26760
|
});
|
|
26761
|
-
__classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((
|
|
26762
|
-
__classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise,
|
|
26761
|
+
__classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve5, reject) => {
|
|
26762
|
+
__classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve5, "f");
|
|
26763
26763
|
__classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, "f");
|
|
26764
26764
|
}), "f");
|
|
26765
|
-
__classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((
|
|
26766
|
-
__classPrivateFieldSet3(this, _MessageStream_resolveEndPromise,
|
|
26765
|
+
__classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve5, reject) => {
|
|
26766
|
+
__classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve5, "f");
|
|
26767
26767
|
__classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, "f");
|
|
26768
26768
|
}), "f");
|
|
26769
26769
|
__classPrivateFieldGet3(this, _MessageStream_connectedPromise, "f").catch(() => {});
|
|
@@ -26853,11 +26853,11 @@ var init_MessageStream = __esm(() => {
|
|
|
26853
26853
|
return this;
|
|
26854
26854
|
}
|
|
26855
26855
|
emitted(event) {
|
|
26856
|
-
return new Promise((
|
|
26856
|
+
return new Promise((resolve5, reject) => {
|
|
26857
26857
|
__classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, "f");
|
|
26858
26858
|
if (event !== "error")
|
|
26859
26859
|
this.once("error", reject);
|
|
26860
|
-
this.once(event,
|
|
26860
|
+
this.once(event, resolve5);
|
|
26861
26861
|
});
|
|
26862
26862
|
}
|
|
26863
26863
|
async done() {
|
|
@@ -27075,7 +27075,7 @@ var init_MessageStream = __esm(() => {
|
|
|
27075
27075
|
if (done) {
|
|
27076
27076
|
return { value: undefined, done: true };
|
|
27077
27077
|
}
|
|
27078
|
-
return new Promise((
|
|
27078
|
+
return new Promise((resolve5, reject) => readQueue.push({ resolve: resolve5, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: undefined, done: true });
|
|
27079
27079
|
}
|
|
27080
27080
|
const chunk = pushQueue.shift();
|
|
27081
27081
|
return { value: chunk, done: false };
|
|
@@ -27292,11 +27292,11 @@ __export(exports_anthropic, {
|
|
|
27292
27292
|
});
|
|
27293
27293
|
import { readFileSync as readFileSync2, existsSync as existsSync7 } from "fs";
|
|
27294
27294
|
import { homedir as homedir8 } from "os";
|
|
27295
|
-
import { join as
|
|
27295
|
+
import { join as join12 } from "path";
|
|
27296
27296
|
function loadApiKeyFromSecrets() {
|
|
27297
27297
|
const envHome = process.env.HOME || process.env.USERPROFILE;
|
|
27298
27298
|
const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir8();
|
|
27299
|
-
const secretsPath =
|
|
27299
|
+
const secretsPath = join12(homeDir, ".secrets");
|
|
27300
27300
|
if (existsSync7(secretsPath)) {
|
|
27301
27301
|
try {
|
|
27302
27302
|
const content = readFileSync2(secretsPath, "utf-8");
|
|
@@ -35507,7 +35507,7 @@ var import_react20 = __toESM(require_react(), 1);
|
|
|
35507
35507
|
var import_react21 = __toESM(require_react(), 1);
|
|
35508
35508
|
// packages/core/src/agent/loop.ts
|
|
35509
35509
|
init_src();
|
|
35510
|
-
import { join as
|
|
35510
|
+
import { join as join19 } from "path";
|
|
35511
35511
|
|
|
35512
35512
|
// packages/core/src/agent/context.ts
|
|
35513
35513
|
init_src();
|
|
@@ -35567,6 +35567,13 @@ class AgentContext {
|
|
|
35567
35567
|
this.messages.push(message);
|
|
35568
35568
|
return message;
|
|
35569
35569
|
}
|
|
35570
|
+
removeSystemMessages(predicate) {
|
|
35571
|
+
this.messages = this.messages.filter((msg) => {
|
|
35572
|
+
if (msg.role !== "system")
|
|
35573
|
+
return true;
|
|
35574
|
+
return !predicate(msg.content);
|
|
35575
|
+
});
|
|
35576
|
+
}
|
|
35570
35577
|
getMessages() {
|
|
35571
35578
|
return [...this.messages];
|
|
35572
35579
|
}
|
|
@@ -36637,6 +36644,10 @@ function resolveTimeout(resolve) {
|
|
|
36637
36644
|
class ConnectorBridge {
|
|
36638
36645
|
connectors = new Map;
|
|
36639
36646
|
static cache = new Map;
|
|
36647
|
+
cwd;
|
|
36648
|
+
constructor(cwd2) {
|
|
36649
|
+
this.cwd = cwd2;
|
|
36650
|
+
}
|
|
36640
36651
|
getHomeDir() {
|
|
36641
36652
|
const envHome = process.env.HOME || process.env.USERPROFILE;
|
|
36642
36653
|
return envHome && envHome.trim().length > 0 ? envHome : homedir2();
|
|
@@ -36644,8 +36655,10 @@ class ConnectorBridge {
|
|
|
36644
36655
|
autoDiscoverConnectorNames() {
|
|
36645
36656
|
const connectorNames = new Set;
|
|
36646
36657
|
const pathDirs = (process.env.PATH || "").split(delimiter);
|
|
36658
|
+
const baseCwd = this.cwd || process.cwd();
|
|
36647
36659
|
const homeDir = this.getHomeDir();
|
|
36648
36660
|
const extraDirs = [
|
|
36661
|
+
join3(baseCwd, "node_modules", ".bin"),
|
|
36649
36662
|
join3(homeDir, ".bun", "bin"),
|
|
36650
36663
|
join3(homeDir, ".npm-global", "bin"),
|
|
36651
36664
|
"/usr/local/bin"
|
|
@@ -36888,17 +36901,20 @@ class ConnectorBridge {
|
|
|
36888
36901
|
}
|
|
36889
36902
|
const lowerCommand = command.toLowerCase();
|
|
36890
36903
|
const lowerArgs = args.map((arg) => arg.toLowerCase());
|
|
36891
|
-
const
|
|
36892
|
-
|
|
36904
|
+
const combined = [lowerCommand, ...lowerArgs].join(" ");
|
|
36905
|
+
const isAuthLogin = /\bauth\b/.test(combined) && /(login|authorize|authorization|oauth|signin|sign-in|connect)/.test(combined);
|
|
36906
|
+
const runInBackground = options.background === true;
|
|
36907
|
+
if (isAuthLogin || runInBackground) {
|
|
36893
36908
|
try {
|
|
36894
|
-
Bun.spawn(cmdParts, {
|
|
36909
|
+
const proc = Bun.spawn(cmdParts, {
|
|
36895
36910
|
cwd: cwd2,
|
|
36896
36911
|
stdin: "ignore",
|
|
36897
36912
|
stdout: "ignore",
|
|
36898
36913
|
stderr: "pipe"
|
|
36899
36914
|
});
|
|
36915
|
+
proc.unref?.();
|
|
36900
36916
|
} catch {}
|
|
36901
|
-
return "Auth login started in the background. Complete it in your browser, then run auth status to confirm.";
|
|
36917
|
+
return isAuthLogin ? "Auth login started in the background. Complete it in your browser, then run auth status to confirm." : "Command started in the background.";
|
|
36902
36918
|
}
|
|
36903
36919
|
try {
|
|
36904
36920
|
const proc = Bun.spawn(cmdParts, {
|
|
@@ -37036,6 +37052,38 @@ function stripQuotedSegments(input) {
|
|
|
37036
37052
|
}
|
|
37037
37053
|
return result;
|
|
37038
37054
|
}
|
|
37055
|
+
function normalizeNewlinesOutsideQuotes(input) {
|
|
37056
|
+
let result = "";
|
|
37057
|
+
let quote = null;
|
|
37058
|
+
let escaped = false;
|
|
37059
|
+
for (let i = 0;i < input.length; i += 1) {
|
|
37060
|
+
const char = input[i];
|
|
37061
|
+
if (quote) {
|
|
37062
|
+
result += char;
|
|
37063
|
+
if (quote === '"' && !escaped && char === "\\") {
|
|
37064
|
+
escaped = true;
|
|
37065
|
+
continue;
|
|
37066
|
+
}
|
|
37067
|
+
if (!escaped && char === quote) {
|
|
37068
|
+
quote = null;
|
|
37069
|
+
}
|
|
37070
|
+
escaped = false;
|
|
37071
|
+
continue;
|
|
37072
|
+
}
|
|
37073
|
+
if (char === '"' || char === "'") {
|
|
37074
|
+
quote = char;
|
|
37075
|
+
result += char;
|
|
37076
|
+
continue;
|
|
37077
|
+
}
|
|
37078
|
+
if (char === "\r" || char === `
|
|
37079
|
+
`) {
|
|
37080
|
+
result += " ";
|
|
37081
|
+
continue;
|
|
37082
|
+
}
|
|
37083
|
+
result += char;
|
|
37084
|
+
}
|
|
37085
|
+
return result;
|
|
37086
|
+
}
|
|
37039
37087
|
|
|
37040
37088
|
class BashTool {
|
|
37041
37089
|
static tool = {
|
|
@@ -37155,7 +37203,11 @@ class BashTool {
|
|
|
37155
37203
|
const command = input.command;
|
|
37156
37204
|
const cwd2 = input.cwd || process.cwd();
|
|
37157
37205
|
const timeout = input.timeout || 30000;
|
|
37158
|
-
const
|
|
37206
|
+
const baseCommand = command.replace(/\s*2>&1\s*/g, " ").trim();
|
|
37207
|
+
const baseTrimmed = baseCommand.toLowerCase();
|
|
37208
|
+
const allowConnectorNewlines = baseTrimmed.startsWith("connect-");
|
|
37209
|
+
const commandForExec = allowConnectorNewlines ? normalizeNewlinesOutsideQuotes(baseCommand).trim() : baseCommand;
|
|
37210
|
+
const commandForChecks = commandForExec;
|
|
37159
37211
|
const commandSansQuotes = stripQuotedSegments(commandForChecks);
|
|
37160
37212
|
const securityCheck = validateBashCommand(commandForChecks);
|
|
37161
37213
|
if (!securityCheck.valid) {
|
|
@@ -37229,7 +37281,7 @@ class BashTool {
|
|
|
37229
37281
|
});
|
|
37230
37282
|
}
|
|
37231
37283
|
try {
|
|
37232
|
-
const proc = Bun.spawn(["bash", "-c",
|
|
37284
|
+
const proc = Bun.spawn(["bash", "-c", commandForExec], {
|
|
37233
37285
|
cwd: cwd2,
|
|
37234
37286
|
stdout: "pipe",
|
|
37235
37287
|
stderr: "pipe"
|
|
@@ -37356,15 +37408,16 @@ async function isPathSafe(targetPath, operation, options = {}) {
|
|
|
37356
37408
|
|
|
37357
37409
|
// packages/core/src/tools/filesystem.ts
|
|
37358
37410
|
var currentSessionId = "default";
|
|
37359
|
-
function getScriptsFolder(cwd2) {
|
|
37411
|
+
function getScriptsFolder(cwd2, sessionId) {
|
|
37412
|
+
const resolvedSessionId = sessionId || currentSessionId;
|
|
37360
37413
|
const legacyDir = join4(cwd2, ".oldpal");
|
|
37361
37414
|
if (existsSync2(legacyDir)) {
|
|
37362
|
-
return join4(legacyDir, "scripts",
|
|
37415
|
+
return join4(legacyDir, "scripts", resolvedSessionId);
|
|
37363
37416
|
}
|
|
37364
|
-
return join4(getProjectConfigDir(cwd2), "scripts",
|
|
37417
|
+
return join4(getProjectConfigDir(cwd2), "scripts", resolvedSessionId);
|
|
37365
37418
|
}
|
|
37366
|
-
function isInScriptsFolder(path2, cwd2) {
|
|
37367
|
-
const scriptsFolder = resolve3(getScriptsFolder(cwd2));
|
|
37419
|
+
function isInScriptsFolder(path2, cwd2, sessionId) {
|
|
37420
|
+
const scriptsFolder = resolve3(getScriptsFolder(cwd2, sessionId));
|
|
37368
37421
|
const resolved = resolve3(path2);
|
|
37369
37422
|
if (resolved === scriptsFolder)
|
|
37370
37423
|
return true;
|
|
@@ -37520,7 +37573,7 @@ class FilesystemTools {
|
|
|
37520
37573
|
const filename = input.filename || input.path;
|
|
37521
37574
|
const content = input.content;
|
|
37522
37575
|
const baseCwd = input.cwd || process.cwd();
|
|
37523
|
-
const scriptsFolder = getScriptsFolder(baseCwd);
|
|
37576
|
+
const scriptsFolder = getScriptsFolder(baseCwd, input.sessionId);
|
|
37524
37577
|
if (!filename || !filename.trim()) {
|
|
37525
37578
|
throw new ToolExecutionError("Filename is required", {
|
|
37526
37579
|
toolName: "write",
|
|
@@ -37533,7 +37586,7 @@ class FilesystemTools {
|
|
|
37533
37586
|
}
|
|
37534
37587
|
const sanitizedFilename = filename.replace(/\.\.[/\\]/g, "").replace(/\.\./g, "").replace(/^[/\\]+/, "");
|
|
37535
37588
|
const path2 = join4(scriptsFolder, sanitizedFilename);
|
|
37536
|
-
if (!isInScriptsFolder(path2, baseCwd)) {
|
|
37589
|
+
if (!isInScriptsFolder(path2, baseCwd, input.sessionId)) {
|
|
37537
37590
|
throw new ToolExecutionError(`Cannot write outside scripts folder. Files are saved to ${scriptsFolder}`, {
|
|
37538
37591
|
toolName: "write",
|
|
37539
37592
|
toolInput: input,
|
|
@@ -38775,6 +38828,10 @@ class SchedulerTool {
|
|
|
38775
38828
|
type: "string",
|
|
38776
38829
|
description: "Optional description for this schedule"
|
|
38777
38830
|
},
|
|
38831
|
+
sessionId: {
|
|
38832
|
+
type: "string",
|
|
38833
|
+
description: "Session id to scope the schedule to"
|
|
38834
|
+
},
|
|
38778
38835
|
id: {
|
|
38779
38836
|
type: "string",
|
|
38780
38837
|
description: "Schedule id (for delete/pause/resume)"
|
|
@@ -38819,6 +38876,7 @@ class SchedulerTool {
|
|
|
38819
38876
|
createdAt: now2,
|
|
38820
38877
|
updatedAt: now2,
|
|
38821
38878
|
createdBy: "agent",
|
|
38879
|
+
sessionId: typeof input.sessionId === "string" ? input.sessionId : undefined,
|
|
38822
38880
|
command,
|
|
38823
38881
|
description: input.description,
|
|
38824
38882
|
status: "active",
|
|
@@ -39732,13 +39790,217 @@ ${stderr}`;
|
|
|
39732
39790
|
}
|
|
39733
39791
|
}
|
|
39734
39792
|
// packages/core/src/commands/builtin.ts
|
|
39735
|
-
import { join as
|
|
39793
|
+
import { join as join11 } from "path";
|
|
39736
39794
|
import { homedir as homedir7, platform as platform2, release, arch } from "os";
|
|
39737
39795
|
import { existsSync as existsSync6, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
39738
39796
|
init_src();
|
|
39739
|
-
|
|
39740
|
-
|
|
39741
|
-
|
|
39797
|
+
|
|
39798
|
+
// packages/core/src/projects/store.ts
|
|
39799
|
+
init_src();
|
|
39800
|
+
import { join as join10 } from "path";
|
|
39801
|
+
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile2, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
|
|
39802
|
+
function projectsDir(cwd2) {
|
|
39803
|
+
return join10(cwd2, ".oldpal", "projects");
|
|
39804
|
+
}
|
|
39805
|
+
function projectPath(cwd2, id) {
|
|
39806
|
+
return join10(projectsDir(cwd2), `${id}.json`);
|
|
39807
|
+
}
|
|
39808
|
+
async function ensureProjectsDir(cwd2) {
|
|
39809
|
+
await mkdir3(projectsDir(cwd2), { recursive: true });
|
|
39810
|
+
}
|
|
39811
|
+
function normalizeName(name) {
|
|
39812
|
+
return name.trim().toLowerCase();
|
|
39813
|
+
}
|
|
39814
|
+
async function listProjects(cwd2) {
|
|
39815
|
+
try {
|
|
39816
|
+
const dir = projectsDir(cwd2);
|
|
39817
|
+
const files = await readdir2(dir);
|
|
39818
|
+
const projects = [];
|
|
39819
|
+
for (const file of files) {
|
|
39820
|
+
if (!file.endsWith(".json"))
|
|
39821
|
+
continue;
|
|
39822
|
+
try {
|
|
39823
|
+
const raw = await readFile2(join10(dir, file), "utf-8");
|
|
39824
|
+
const parsed = JSON.parse(raw);
|
|
39825
|
+
if (parsed?.id && parsed?.name) {
|
|
39826
|
+
projects.push(parsed);
|
|
39827
|
+
}
|
|
39828
|
+
} catch {}
|
|
39829
|
+
}
|
|
39830
|
+
return projects.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
39831
|
+
} catch {
|
|
39832
|
+
return [];
|
|
39833
|
+
}
|
|
39834
|
+
}
|
|
39835
|
+
async function readProject(cwd2, id) {
|
|
39836
|
+
try {
|
|
39837
|
+
const raw = await readFile2(projectPath(cwd2, id), "utf-8");
|
|
39838
|
+
const project = JSON.parse(raw);
|
|
39839
|
+
if (!project?.id || !project?.name)
|
|
39840
|
+
return null;
|
|
39841
|
+
return project;
|
|
39842
|
+
} catch {
|
|
39843
|
+
return null;
|
|
39844
|
+
}
|
|
39845
|
+
}
|
|
39846
|
+
async function findProjectByName(cwd2, name) {
|
|
39847
|
+
const normalized = normalizeName(name);
|
|
39848
|
+
const projects = await listProjects(cwd2);
|
|
39849
|
+
return projects.find((project) => normalizeName(project.name) === normalized) || null;
|
|
39850
|
+
}
|
|
39851
|
+
async function saveProject(cwd2, project) {
|
|
39852
|
+
await ensureProjectsDir(cwd2);
|
|
39853
|
+
await writeFile2(projectPath(cwd2, project.id), JSON.stringify(project, null, 2), "utf-8");
|
|
39854
|
+
}
|
|
39855
|
+
async function deleteProject(cwd2, id) {
|
|
39856
|
+
try {
|
|
39857
|
+
await unlink2(projectPath(cwd2, id));
|
|
39858
|
+
return true;
|
|
39859
|
+
} catch {
|
|
39860
|
+
return false;
|
|
39861
|
+
}
|
|
39862
|
+
}
|
|
39863
|
+
async function createProject(cwd2, name, description) {
|
|
39864
|
+
const now2 = Date.now();
|
|
39865
|
+
const project = {
|
|
39866
|
+
id: generateId(),
|
|
39867
|
+
name: name.trim(),
|
|
39868
|
+
description: description?.trim() || undefined,
|
|
39869
|
+
createdAt: now2,
|
|
39870
|
+
updatedAt: now2,
|
|
39871
|
+
context: [],
|
|
39872
|
+
plans: []
|
|
39873
|
+
};
|
|
39874
|
+
await saveProject(cwd2, project);
|
|
39875
|
+
return project;
|
|
39876
|
+
}
|
|
39877
|
+
async function updateProject(cwd2, id, updater) {
|
|
39878
|
+
const project = await readProject(cwd2, id);
|
|
39879
|
+
if (!project)
|
|
39880
|
+
return null;
|
|
39881
|
+
const updated = updater(project);
|
|
39882
|
+
await saveProject(cwd2, updated);
|
|
39883
|
+
return updated;
|
|
39884
|
+
}
|
|
39885
|
+
async function ensureDefaultProject(cwd2) {
|
|
39886
|
+
const projects = await listProjects(cwd2);
|
|
39887
|
+
if (projects.length > 0)
|
|
39888
|
+
return projects[0];
|
|
39889
|
+
return createProject(cwd2, "default", "Default project for this folder");
|
|
39890
|
+
}
|
|
39891
|
+
function hasProjectNameConflict(projects, name) {
|
|
39892
|
+
const normalized = normalizeName(name);
|
|
39893
|
+
return projects.some((project) => normalizeName(project.name) === normalized);
|
|
39894
|
+
}
|
|
39895
|
+
|
|
39896
|
+
// packages/core/src/projects/context.ts
|
|
39897
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
39898
|
+
import { resolve as resolve4 } from "path";
|
|
39899
|
+
var DEFAULT_MAX_FILE_BYTES = 12000;
|
|
39900
|
+
function formatPlan(plan) {
|
|
39901
|
+
const lines = [];
|
|
39902
|
+
lines.push(`- ${plan.title} (${plan.steps.length} steps)`);
|
|
39903
|
+
for (const step of plan.steps) {
|
|
39904
|
+
lines.push(` - [${step.status}] ${step.text}`);
|
|
39905
|
+
}
|
|
39906
|
+
return lines.join(`
|
|
39907
|
+
`);
|
|
39908
|
+
}
|
|
39909
|
+
function normalizeEntryLabel(entry) {
|
|
39910
|
+
return entry.label ? entry.label.trim() : entry.value.trim();
|
|
39911
|
+
}
|
|
39912
|
+
async function renderFileEntry(entry, options) {
|
|
39913
|
+
const rawPath = entry.value.trim();
|
|
39914
|
+
const resolved = resolve4(options.cwd, rawPath);
|
|
39915
|
+
const validation = await validatePath(resolved, { allowedPaths: [options.cwd] });
|
|
39916
|
+
if (!validation.valid) {
|
|
39917
|
+
return `- File: ${rawPath} (unavailable: ${validation.error || "invalid path"})`;
|
|
39918
|
+
}
|
|
39919
|
+
let content = "";
|
|
39920
|
+
try {
|
|
39921
|
+
const data = await readFile3(validation.resolved, "utf-8");
|
|
39922
|
+
const limit = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
39923
|
+
if (data.length > limit) {
|
|
39924
|
+
content = `${data.slice(0, limit)}
|
|
39925
|
+
|
|
39926
|
+
... [truncated ${data.length - limit} chars]`;
|
|
39927
|
+
} else {
|
|
39928
|
+
content = data;
|
|
39929
|
+
}
|
|
39930
|
+
} catch (error) {
|
|
39931
|
+
return `- File: ${rawPath} (unavailable: ${error instanceof Error ? error.message : String(error)})`;
|
|
39932
|
+
}
|
|
39933
|
+
return `- File: ${rawPath}
|
|
39934
|
+
\`\`\`
|
|
39935
|
+
${content}
|
|
39936
|
+
\`\`\``;
|
|
39937
|
+
}
|
|
39938
|
+
function renderConnectorEntry(entry, connectors) {
|
|
39939
|
+
const name = entry.value.trim();
|
|
39940
|
+
const connector = connectors?.find((c) => c.name === name);
|
|
39941
|
+
if (!connector) {
|
|
39942
|
+
return `- Connector: ${name}`;
|
|
39943
|
+
}
|
|
39944
|
+
const lines = [];
|
|
39945
|
+
lines.push(`- Connector: ${connector.name}`);
|
|
39946
|
+
if (connector.description) {
|
|
39947
|
+
lines.push(` - ${connector.description}`);
|
|
39948
|
+
}
|
|
39949
|
+
if (connector.cli) {
|
|
39950
|
+
lines.push(` - CLI: ${connector.cli}`);
|
|
39951
|
+
}
|
|
39952
|
+
if (connector.commands && connector.commands.length > 0) {
|
|
39953
|
+
const subset = connector.commands.slice(0, 5);
|
|
39954
|
+
for (const cmd of subset) {
|
|
39955
|
+
lines.push(` - ${cmd.name}: ${cmd.description}`);
|
|
39956
|
+
}
|
|
39957
|
+
if (connector.commands.length > subset.length) {
|
|
39958
|
+
lines.push(` - ... ${connector.commands.length - subset.length} more commands`);
|
|
39959
|
+
}
|
|
39960
|
+
}
|
|
39961
|
+
return lines.join(`
|
|
39962
|
+
`);
|
|
39963
|
+
}
|
|
39964
|
+
function renderGenericEntry(entry) {
|
|
39965
|
+
const label = normalizeEntryLabel(entry);
|
|
39966
|
+
return `- ${entry.type}: ${label}`;
|
|
39967
|
+
}
|
|
39968
|
+
async function buildProjectContext(project, options) {
|
|
39969
|
+
const lines = [];
|
|
39970
|
+
lines.push(`## Project: ${project.name}`);
|
|
39971
|
+
if (project.description) {
|
|
39972
|
+
lines.push(`Description: ${project.description}`);
|
|
39973
|
+
}
|
|
39974
|
+
if (project.context.length > 0) {
|
|
39975
|
+
lines.push("");
|
|
39976
|
+
lines.push("### Project Context");
|
|
39977
|
+
for (const entry of project.context) {
|
|
39978
|
+
if (entry.type === "file") {
|
|
39979
|
+
lines.push(await renderFileEntry(entry, options));
|
|
39980
|
+
continue;
|
|
39981
|
+
}
|
|
39982
|
+
if (entry.type === "connector") {
|
|
39983
|
+
lines.push(renderConnectorEntry(entry, options.connectors));
|
|
39984
|
+
continue;
|
|
39985
|
+
}
|
|
39986
|
+
lines.push(renderGenericEntry(entry));
|
|
39987
|
+
}
|
|
39988
|
+
}
|
|
39989
|
+
if (project.plans.length > 0) {
|
|
39990
|
+
lines.push("");
|
|
39991
|
+
lines.push("### Plans");
|
|
39992
|
+
for (const plan of project.plans) {
|
|
39993
|
+
lines.push(formatPlan(plan));
|
|
39994
|
+
}
|
|
39995
|
+
}
|
|
39996
|
+
return lines.join(`
|
|
39997
|
+
`);
|
|
39998
|
+
}
|
|
39999
|
+
|
|
40000
|
+
// packages/core/src/commands/builtin.ts
|
|
40001
|
+
var VERSION = process.env.ASSISTANTS_VERSION || process.env.npm_package_version || process.env.OLDPAL_VERSION || "unknown";
|
|
40002
|
+
function resolveAuthTimeout(resolve5) {
|
|
40003
|
+
resolve5({ exitCode: 1, stdout: { toString: () => "{}" } });
|
|
39742
40004
|
}
|
|
39743
40005
|
function splitArgs(input) {
|
|
39744
40006
|
const args = [];
|
|
@@ -39787,6 +40049,8 @@ class BuiltinCommands {
|
|
|
39787
40049
|
loader.register(this.statusCommand());
|
|
39788
40050
|
loader.register(this.tokensCommand());
|
|
39789
40051
|
loader.register(this.contextCommand());
|
|
40052
|
+
loader.register(this.projectsCommand());
|
|
40053
|
+
loader.register(this.plansCommand());
|
|
39790
40054
|
loader.register(this.summarizeCommand());
|
|
39791
40055
|
loader.register(this.restCommand());
|
|
39792
40056
|
loader.register(this.voiceCommand());
|
|
@@ -40392,148 +40656,740 @@ Identities:
|
|
|
40392
40656
|
contextCommand() {
|
|
40393
40657
|
return {
|
|
40394
40658
|
name: "context",
|
|
40395
|
-
description: "
|
|
40659
|
+
description: "Manage injected project context (files, connectors, notes) or show status",
|
|
40396
40660
|
builtin: true,
|
|
40397
40661
|
selfHandled: true,
|
|
40398
40662
|
content: "",
|
|
40399
40663
|
handler: async (args, context) => {
|
|
40400
|
-
const
|
|
40401
|
-
|
|
40664
|
+
const parts = splitArgs(args);
|
|
40665
|
+
const sub = parts[0] || "status";
|
|
40666
|
+
if (sub === "help") {
|
|
40667
|
+
const usage = [
|
|
40668
|
+
"Usage:",
|
|
40669
|
+
" /context status",
|
|
40670
|
+
" /context list",
|
|
40671
|
+
" /context add file <path>",
|
|
40672
|
+
" /context add connector <name>",
|
|
40673
|
+
" /context add database <name>",
|
|
40674
|
+
" /context add note <text>",
|
|
40675
|
+
" /context add entity <text>",
|
|
40676
|
+
" /context remove <id>",
|
|
40677
|
+
" /context clear"
|
|
40678
|
+
].join(`
|
|
40679
|
+
`);
|
|
40402
40680
|
context.emit("text", `
|
|
40403
|
-
|
|
40681
|
+
${usage}
|
|
40404
40682
|
`);
|
|
40405
40683
|
context.emit("done");
|
|
40406
40684
|
return { handled: true };
|
|
40407
40685
|
}
|
|
40408
|
-
|
|
40409
|
-
|
|
40410
|
-
|
|
40686
|
+
if (sub === "status") {
|
|
40687
|
+
const info = context.getContextInfo?.();
|
|
40688
|
+
if (!info) {
|
|
40689
|
+
context.emit("text", `
|
|
40690
|
+
Context summarization is not available.
|
|
40691
|
+
`);
|
|
40692
|
+
context.emit("done");
|
|
40693
|
+
return { handled: true };
|
|
40694
|
+
}
|
|
40695
|
+
const { config, state } = info;
|
|
40696
|
+
const usedPercent = Math.round(state.totalTokens / config.maxContextTokens * 100);
|
|
40697
|
+
let message = `
|
|
40411
40698
|
**Context Status**
|
|
40412
40699
|
|
|
40413
40700
|
`;
|
|
40414
|
-
|
|
40701
|
+
message += `**Messages:** ${state.messageCount}
|
|
40415
40702
|
`;
|
|
40416
|
-
|
|
40703
|
+
message += `**Estimated Tokens:** ${state.totalTokens.toLocaleString()} / ${config.maxContextTokens.toLocaleString()} (${usedPercent}%)
|
|
40417
40704
|
`;
|
|
40418
|
-
|
|
40705
|
+
message += `**Summary Count:** ${state.summaryCount}
|
|
40419
40706
|
`;
|
|
40420
|
-
|
|
40707
|
+
message += `**Strategy:** ${config.summaryStrategy}
|
|
40421
40708
|
`;
|
|
40422
|
-
|
|
40709
|
+
message += `**Keep Recent Messages:** ${config.keepRecentMessages}
|
|
40423
40710
|
`;
|
|
40424
|
-
|
|
40425
|
-
|
|
40711
|
+
if (state.lastSummaryAt) {
|
|
40712
|
+
message += `**Last Summary:** ${state.lastSummaryAt}
|
|
40426
40713
|
`;
|
|
40427
|
-
|
|
40428
|
-
|
|
40714
|
+
if (state.lastSummaryTokensBefore && state.lastSummaryTokensAfter) {
|
|
40715
|
+
message += `**Last Summary Tokens:** ${state.lastSummaryTokensBefore.toLocaleString()} -> ${state.lastSummaryTokensAfter.toLocaleString()}
|
|
40429
40716
|
`;
|
|
40717
|
+
}
|
|
40430
40718
|
}
|
|
40431
|
-
|
|
40432
|
-
|
|
40433
|
-
|
|
40434
|
-
|
|
40435
|
-
message += `
|
|
40719
|
+
const barLength = 30;
|
|
40720
|
+
const filledLength = Math.round(usedPercent / 100 * barLength);
|
|
40721
|
+
const bar = "\u2588".repeat(filledLength) + "\u2591".repeat(barLength - filledLength);
|
|
40722
|
+
message += `
|
|
40436
40723
|
[${bar}] ${usedPercent}%
|
|
40437
40724
|
`;
|
|
40438
|
-
|
|
40439
|
-
context.emit("done");
|
|
40440
|
-
return { handled: true };
|
|
40441
|
-
}
|
|
40442
|
-
};
|
|
40443
|
-
}
|
|
40444
|
-
summarizeCommand() {
|
|
40445
|
-
return {
|
|
40446
|
-
name: "summarize",
|
|
40447
|
-
description: "Summarize and compress the current conversation",
|
|
40448
|
-
builtin: true,
|
|
40449
|
-
selfHandled: true,
|
|
40450
|
-
content: "",
|
|
40451
|
-
handler: async (args, context) => {
|
|
40452
|
-
if (!context.summarizeContext) {
|
|
40453
|
-
context.emit("text", `
|
|
40454
|
-
Context summarization is not available.
|
|
40455
|
-
`);
|
|
40725
|
+
context.emit("text", message);
|
|
40456
40726
|
context.emit("done");
|
|
40457
40727
|
return { handled: true };
|
|
40458
40728
|
}
|
|
40459
|
-
const
|
|
40460
|
-
if (!
|
|
40461
|
-
context.emit("text", `
|
|
40462
|
-
Nothing to summarize right now.
|
|
40729
|
+
const project = await this.ensureActiveProject(context, true);
|
|
40730
|
+
if (!project) {
|
|
40731
|
+
context.emit("text", `No project found. Use /projects new <name> first.
|
|
40463
40732
|
`);
|
|
40464
40733
|
context.emit("done");
|
|
40465
40734
|
return { handled: true };
|
|
40466
40735
|
}
|
|
40467
|
-
|
|
40468
|
-
|
|
40469
|
-
|
|
40470
|
-
|
|
40471
|
-
|
|
40472
|
-
|
|
40473
|
-
|
|
40736
|
+
if (sub === "list") {
|
|
40737
|
+
if (project.context.length === 0) {
|
|
40738
|
+
context.emit("text", `
|
|
40739
|
+
No context entries for project "${project.name}".
|
|
40740
|
+
`);
|
|
40741
|
+
context.emit("done");
|
|
40742
|
+
return { handled: true };
|
|
40743
|
+
}
|
|
40744
|
+
let output = `
|
|
40745
|
+
**Context Entries (${project.name})**
|
|
40474
40746
|
|
|
40475
40747
|
`;
|
|
40476
|
-
|
|
40477
|
-
|
|
40748
|
+
for (const entry of project.context) {
|
|
40749
|
+
const label = entry.label ? ` (${entry.label})` : "";
|
|
40750
|
+
output += `- ${entry.id} [${entry.type}] ${entry.value}${label}
|
|
40478
40751
|
`;
|
|
40752
|
+
}
|
|
40753
|
+
context.emit("text", output);
|
|
40754
|
+
context.emit("done");
|
|
40755
|
+
return { handled: true };
|
|
40479
40756
|
}
|
|
40480
|
-
|
|
40757
|
+
if (sub === "clear") {
|
|
40758
|
+
const updated = await updateProject(context.cwd, project.id, (current) => ({
|
|
40759
|
+
...current,
|
|
40760
|
+
context: [],
|
|
40761
|
+
updatedAt: Date.now()
|
|
40762
|
+
}));
|
|
40763
|
+
if (updated) {
|
|
40764
|
+
await this.applyProjectContext(context, updated);
|
|
40765
|
+
context.emit("text", `Cleared context entries for "${updated.name}".
|
|
40766
|
+
`);
|
|
40767
|
+
context.emit("done");
|
|
40768
|
+
return { handled: true };
|
|
40769
|
+
}
|
|
40770
|
+
}
|
|
40771
|
+
if (sub === "remove") {
|
|
40772
|
+
const id = parts[1];
|
|
40773
|
+
if (!id) {
|
|
40774
|
+
context.emit("text", `Usage: /context remove <id>
|
|
40775
|
+
`);
|
|
40776
|
+
context.emit("done");
|
|
40777
|
+
return { handled: true };
|
|
40778
|
+
}
|
|
40779
|
+
if (!project.context.some((entry) => entry.id === id)) {
|
|
40780
|
+
context.emit("text", `Context entry not found: ${id}
|
|
40781
|
+
`);
|
|
40782
|
+
context.emit("done");
|
|
40783
|
+
return { handled: true };
|
|
40784
|
+
}
|
|
40785
|
+
const updated = await updateProject(context.cwd, project.id, (current) => ({
|
|
40786
|
+
...current,
|
|
40787
|
+
context: current.context.filter((entry) => entry.id !== id),
|
|
40788
|
+
updatedAt: Date.now()
|
|
40789
|
+
}));
|
|
40790
|
+
if (updated) {
|
|
40791
|
+
await this.applyProjectContext(context, updated);
|
|
40792
|
+
context.emit("text", `Removed context entry ${id} from "${updated.name}".
|
|
40793
|
+
`);
|
|
40794
|
+
context.emit("done");
|
|
40795
|
+
return { handled: true };
|
|
40796
|
+
}
|
|
40797
|
+
}
|
|
40798
|
+
if (sub === "add") {
|
|
40799
|
+
const type = parts[1];
|
|
40800
|
+
const value = parts.slice(2).join(" ").trim();
|
|
40801
|
+
if (!type) {
|
|
40802
|
+
context.emit("text", `Usage: /context add <type> <value>
|
|
40803
|
+
`);
|
|
40804
|
+
context.emit("done");
|
|
40805
|
+
return { handled: true };
|
|
40806
|
+
}
|
|
40807
|
+
const allowedTypes = ["file", "connector", "database", "note", "entity"];
|
|
40808
|
+
const entryType = allowedTypes.includes(type) ? type : "note";
|
|
40809
|
+
const entryValue = entryType === "note" && !value ? parts.slice(1).join(" ").trim() : value;
|
|
40810
|
+
if (!entryValue) {
|
|
40811
|
+
context.emit("text", `Error: context value is required.
|
|
40812
|
+
`);
|
|
40813
|
+
context.emit("done");
|
|
40814
|
+
return { handled: true };
|
|
40815
|
+
}
|
|
40816
|
+
const entry = {
|
|
40817
|
+
id: generateId(),
|
|
40818
|
+
type: entryType,
|
|
40819
|
+
value: entryValue,
|
|
40820
|
+
addedAt: Date.now()
|
|
40821
|
+
};
|
|
40822
|
+
const updated = await updateProject(context.cwd, project.id, (current) => ({
|
|
40823
|
+
...current,
|
|
40824
|
+
context: [...current.context, entry],
|
|
40825
|
+
updatedAt: Date.now()
|
|
40826
|
+
}));
|
|
40827
|
+
if (updated) {
|
|
40828
|
+
await this.applyProjectContext(context, updated);
|
|
40829
|
+
context.emit("text", `Added ${entry.type} context to "${updated.name}".
|
|
40830
|
+
`);
|
|
40831
|
+
context.emit("done");
|
|
40832
|
+
return { handled: true };
|
|
40833
|
+
}
|
|
40834
|
+
}
|
|
40835
|
+
context.emit("text", `Unknown /context command. Use /context help.
|
|
40836
|
+
`);
|
|
40481
40837
|
context.emit("done");
|
|
40482
40838
|
return { handled: true };
|
|
40483
40839
|
}
|
|
40484
40840
|
};
|
|
40485
40841
|
}
|
|
40486
|
-
|
|
40842
|
+
projectsCommand() {
|
|
40487
40843
|
return {
|
|
40488
|
-
name: "
|
|
40489
|
-
description: "
|
|
40844
|
+
name: "projects",
|
|
40845
|
+
description: "Manage projects inside this folder",
|
|
40490
40846
|
builtin: true,
|
|
40491
40847
|
selfHandled: true,
|
|
40492
40848
|
content: "",
|
|
40493
40849
|
handler: async (args, context) => {
|
|
40494
|
-
|
|
40850
|
+
const parts = splitArgs(args);
|
|
40851
|
+
const sub = parts[0] || "list";
|
|
40852
|
+
if (sub === "help") {
|
|
40853
|
+
const usage = [
|
|
40854
|
+
"Usage:",
|
|
40855
|
+
" /projects list",
|
|
40856
|
+
" /projects new <name>",
|
|
40857
|
+
" /projects use <id|name>",
|
|
40858
|
+
" /projects show [id|name]",
|
|
40859
|
+
" /projects delete <id|name>",
|
|
40860
|
+
" /projects describe <id|name> <description>"
|
|
40861
|
+
].join(`
|
|
40862
|
+
`);
|
|
40495
40863
|
context.emit("text", `
|
|
40496
|
-
|
|
40864
|
+
${usage}
|
|
40497
40865
|
`);
|
|
40498
40866
|
context.emit("done");
|
|
40499
40867
|
return { handled: true };
|
|
40500
40868
|
}
|
|
40501
|
-
|
|
40502
|
-
|
|
40503
|
-
|
|
40504
|
-
|
|
40505
|
-
|
|
40506
|
-
const percent = Math.round(state.current / Math.max(1, state.max) * 100);
|
|
40507
|
-
context.emit("text", `
|
|
40508
|
-
Energy restored. Current level: ${percent}% (${state.current}/${state.max}).
|
|
40509
|
-
`);
|
|
40510
|
-
} else {
|
|
40511
|
-
context.emit("text", `
|
|
40512
|
-
Energy restored.
|
|
40869
|
+
if (sub === "list" || sub === "ls") {
|
|
40870
|
+
const projects = await listProjects(context.cwd);
|
|
40871
|
+
if (projects.length === 0) {
|
|
40872
|
+
context.emit("text", `
|
|
40873
|
+
No projects found. Use /projects new <name>.
|
|
40513
40874
|
`);
|
|
40514
|
-
|
|
40515
|
-
|
|
40516
|
-
|
|
40517
|
-
|
|
40518
|
-
|
|
40519
|
-
|
|
40520
|
-
skillsCommand(loader) {
|
|
40521
|
-
return {
|
|
40522
|
-
name: "skills",
|
|
40523
|
-
description: "List available skills",
|
|
40524
|
-
builtin: true,
|
|
40525
|
-
selfHandled: true,
|
|
40526
|
-
content: "",
|
|
40527
|
-
handler: async (args, context) => {
|
|
40528
|
-
let message = `
|
|
40529
|
-
**Available Skills**
|
|
40530
|
-
|
|
40531
|
-
`;
|
|
40532
|
-
message += `Skills are invoked with $skill-name [arguments] or /skill-name [arguments]
|
|
40875
|
+
context.emit("done");
|
|
40876
|
+
return { handled: true };
|
|
40877
|
+
}
|
|
40878
|
+
const activeId = context.getActiveProjectId?.();
|
|
40879
|
+
let output = `
|
|
40880
|
+
**Projects**
|
|
40533
40881
|
|
|
40534
40882
|
`;
|
|
40535
|
-
|
|
40536
|
-
|
|
40883
|
+
for (const project of projects) {
|
|
40884
|
+
const marker = project.id === activeId ? "*" : " ";
|
|
40885
|
+
output += `${marker} ${project.name} (${project.id})
|
|
40886
|
+
`;
|
|
40887
|
+
}
|
|
40888
|
+
context.emit("text", output);
|
|
40889
|
+
context.emit("done");
|
|
40890
|
+
return { handled: true };
|
|
40891
|
+
}
|
|
40892
|
+
if (sub === "new" || sub === "create") {
|
|
40893
|
+
const name = parts.slice(1).join(" ").trim();
|
|
40894
|
+
if (!name) {
|
|
40895
|
+
context.emit("text", `Usage: /projects new <name>
|
|
40896
|
+
`);
|
|
40897
|
+
context.emit("done");
|
|
40898
|
+
return { handled: true };
|
|
40899
|
+
}
|
|
40900
|
+
const existing = await listProjects(context.cwd);
|
|
40901
|
+
if (hasProjectNameConflict(existing, name)) {
|
|
40902
|
+
context.emit("text", `Project "${name}" already exists.
|
|
40903
|
+
`);
|
|
40904
|
+
context.emit("done");
|
|
40905
|
+
return { handled: true };
|
|
40906
|
+
}
|
|
40907
|
+
const project = await createProject(context.cwd, name);
|
|
40908
|
+
context.setActiveProjectId?.(project.id);
|
|
40909
|
+
await this.applyProjectContext(context, project);
|
|
40910
|
+
context.emit("text", `Created project "${project.name}" (${project.id}).
|
|
40911
|
+
`);
|
|
40912
|
+
context.emit("done");
|
|
40913
|
+
return { handled: true };
|
|
40914
|
+
}
|
|
40915
|
+
if (sub === "use" || sub === "switch") {
|
|
40916
|
+
const target = parts.slice(1).join(" ").trim();
|
|
40917
|
+
if (!target) {
|
|
40918
|
+
context.emit("text", `Usage: /projects use <id|name>
|
|
40919
|
+
`);
|
|
40920
|
+
context.emit("done");
|
|
40921
|
+
return { handled: true };
|
|
40922
|
+
}
|
|
40923
|
+
const project = await this.resolveProject(context, target);
|
|
40924
|
+
if (!project) {
|
|
40925
|
+
context.emit("text", `Project not found: ${target}
|
|
40926
|
+
`);
|
|
40927
|
+
context.emit("done");
|
|
40928
|
+
return { handled: true };
|
|
40929
|
+
}
|
|
40930
|
+
context.setActiveProjectId?.(project.id);
|
|
40931
|
+
await this.applyProjectContext(context, project);
|
|
40932
|
+
context.emit("text", `Switched to project "${project.name}".
|
|
40933
|
+
`);
|
|
40934
|
+
context.emit("done");
|
|
40935
|
+
return { handled: true };
|
|
40936
|
+
}
|
|
40937
|
+
if (sub === "show" || sub === "info") {
|
|
40938
|
+
const target = parts.slice(1).join(" ").trim();
|
|
40939
|
+
const project = target ? await this.resolveProject(context, target) : await this.ensureActiveProject(context, false);
|
|
40940
|
+
if (!project) {
|
|
40941
|
+
context.emit("text", `No project selected. Use /projects use <id|name>.
|
|
40942
|
+
`);
|
|
40943
|
+
context.emit("done");
|
|
40944
|
+
return { handled: true };
|
|
40945
|
+
}
|
|
40946
|
+
let output = `
|
|
40947
|
+
**Project: ${project.name}**
|
|
40948
|
+
|
|
40949
|
+
`;
|
|
40950
|
+
output += `ID: ${project.id}
|
|
40951
|
+
`;
|
|
40952
|
+
if (project.description) {
|
|
40953
|
+
output += `Description: ${project.description}
|
|
40954
|
+
`;
|
|
40955
|
+
}
|
|
40956
|
+
output += `Context entries: ${project.context.length}
|
|
40957
|
+
`;
|
|
40958
|
+
output += `Plans: ${project.plans.length}
|
|
40959
|
+
`;
|
|
40960
|
+
context.emit("text", output);
|
|
40961
|
+
context.emit("done");
|
|
40962
|
+
return { handled: true };
|
|
40963
|
+
}
|
|
40964
|
+
if (sub === "describe" || sub === "desc") {
|
|
40965
|
+
const target = parts[1];
|
|
40966
|
+
const description = parts.slice(2).join(" ").trim();
|
|
40967
|
+
if (!target || !description) {
|
|
40968
|
+
context.emit("text", `Usage: /projects describe <id|name> <description>
|
|
40969
|
+
`);
|
|
40970
|
+
context.emit("done");
|
|
40971
|
+
return { handled: true };
|
|
40972
|
+
}
|
|
40973
|
+
const project = await this.resolveProject(context, target);
|
|
40974
|
+
if (!project) {
|
|
40975
|
+
context.emit("text", `Project not found: ${target}
|
|
40976
|
+
`);
|
|
40977
|
+
context.emit("done");
|
|
40978
|
+
return { handled: true };
|
|
40979
|
+
}
|
|
40980
|
+
const updated = await updateProject(context.cwd, project.id, (current) => ({
|
|
40981
|
+
...current,
|
|
40982
|
+
description,
|
|
40983
|
+
updatedAt: Date.now()
|
|
40984
|
+
}));
|
|
40985
|
+
if (updated) {
|
|
40986
|
+
await this.applyProjectContext(context, updated);
|
|
40987
|
+
context.emit("text", `Updated project "${updated.name}".
|
|
40988
|
+
`);
|
|
40989
|
+
context.emit("done");
|
|
40990
|
+
return { handled: true };
|
|
40991
|
+
}
|
|
40992
|
+
}
|
|
40993
|
+
if (sub === "delete" || sub === "rm") {
|
|
40994
|
+
const target = parts.slice(1).join(" ").trim();
|
|
40995
|
+
if (!target) {
|
|
40996
|
+
context.emit("text", `Usage: /projects delete <id|name>
|
|
40997
|
+
`);
|
|
40998
|
+
context.emit("done");
|
|
40999
|
+
return { handled: true };
|
|
41000
|
+
}
|
|
41001
|
+
const project = await this.resolveProject(context, target);
|
|
41002
|
+
if (!project) {
|
|
41003
|
+
context.emit("text", `Project not found: ${target}
|
|
41004
|
+
`);
|
|
41005
|
+
context.emit("done");
|
|
41006
|
+
return { handled: true };
|
|
41007
|
+
}
|
|
41008
|
+
const ok = await deleteProject(context.cwd, project.id);
|
|
41009
|
+
if (ok) {
|
|
41010
|
+
if (context.getActiveProjectId?.() === project.id) {
|
|
41011
|
+
context.setActiveProjectId?.(null);
|
|
41012
|
+
context.setProjectContext?.(null);
|
|
41013
|
+
}
|
|
41014
|
+
context.emit("text", `Deleted project "${project.name}".
|
|
41015
|
+
`);
|
|
41016
|
+
context.emit("done");
|
|
41017
|
+
return { handled: true };
|
|
41018
|
+
}
|
|
41019
|
+
}
|
|
41020
|
+
context.emit("text", `Unknown /projects command. Use /projects help.
|
|
41021
|
+
`);
|
|
41022
|
+
context.emit("done");
|
|
41023
|
+
return { handled: true };
|
|
41024
|
+
}
|
|
41025
|
+
};
|
|
41026
|
+
}
|
|
41027
|
+
plansCommand() {
|
|
41028
|
+
return {
|
|
41029
|
+
name: "plans",
|
|
41030
|
+
description: "Manage plans linked to the active project",
|
|
41031
|
+
builtin: true,
|
|
41032
|
+
selfHandled: true,
|
|
41033
|
+
content: "",
|
|
41034
|
+
handler: async (args, context) => {
|
|
41035
|
+
const parts = splitArgs(args);
|
|
41036
|
+
const sub = parts[0] || "list";
|
|
41037
|
+
if (sub === "help") {
|
|
41038
|
+
const usage = [
|
|
41039
|
+
"Usage:",
|
|
41040
|
+
" /plans list",
|
|
41041
|
+
" /plans new <title>",
|
|
41042
|
+
" /plans show <planId>",
|
|
41043
|
+
" /plans add <planId> <step>",
|
|
41044
|
+
" /plans set <planId> <stepId> <todo|doing|done|blocked>",
|
|
41045
|
+
" /plans remove <planId> <stepId>",
|
|
41046
|
+
" /plans delete <planId>"
|
|
41047
|
+
].join(`
|
|
41048
|
+
`);
|
|
41049
|
+
context.emit("text", `
|
|
41050
|
+
${usage}
|
|
41051
|
+
`);
|
|
41052
|
+
context.emit("done");
|
|
41053
|
+
return { handled: true };
|
|
41054
|
+
}
|
|
41055
|
+
const project = await this.ensureActiveProject(context, true);
|
|
41056
|
+
if (!project) {
|
|
41057
|
+
context.emit("text", `No project found. Use /projects new <name> first.
|
|
41058
|
+
`);
|
|
41059
|
+
context.emit("done");
|
|
41060
|
+
return { handled: true };
|
|
41061
|
+
}
|
|
41062
|
+
if (sub === "list" || sub === "ls") {
|
|
41063
|
+
if (project.plans.length === 0) {
|
|
41064
|
+
context.emit("text", `
|
|
41065
|
+
No plans for project "${project.name}".
|
|
41066
|
+
`);
|
|
41067
|
+
context.emit("done");
|
|
41068
|
+
return { handled: true };
|
|
41069
|
+
}
|
|
41070
|
+
let output = `
|
|
41071
|
+
**Plans (${project.name})**
|
|
41072
|
+
|
|
41073
|
+
`;
|
|
41074
|
+
for (const plan of project.plans) {
|
|
41075
|
+
output += `- ${plan.id} ${plan.title} (${plan.steps.length} steps)
|
|
41076
|
+
`;
|
|
41077
|
+
}
|
|
41078
|
+
context.emit("text", output);
|
|
41079
|
+
context.emit("done");
|
|
41080
|
+
return { handled: true };
|
|
41081
|
+
}
|
|
41082
|
+
if (sub === "new" || sub === "create") {
|
|
41083
|
+
const title = parts.slice(1).join(" ").trim();
|
|
41084
|
+
if (!title) {
|
|
41085
|
+
context.emit("text", `Usage: /plans new <title>
|
|
41086
|
+
`);
|
|
41087
|
+
context.emit("done");
|
|
41088
|
+
return { handled: true };
|
|
41089
|
+
}
|
|
41090
|
+
const now2 = Date.now();
|
|
41091
|
+
const plan = {
|
|
41092
|
+
id: generateId(),
|
|
41093
|
+
title,
|
|
41094
|
+
createdAt: now2,
|
|
41095
|
+
updatedAt: now2,
|
|
41096
|
+
steps: []
|
|
41097
|
+
};
|
|
41098
|
+
const updated = await updateProject(context.cwd, project.id, (current) => ({
|
|
41099
|
+
...current,
|
|
41100
|
+
plans: [...current.plans, plan],
|
|
41101
|
+
updatedAt: now2
|
|
41102
|
+
}));
|
|
41103
|
+
if (updated) {
|
|
41104
|
+
await this.applyProjectContext(context, updated);
|
|
41105
|
+
context.emit("text", `Created plan "${plan.title}" (${plan.id}).
|
|
41106
|
+
`);
|
|
41107
|
+
context.emit("done");
|
|
41108
|
+
return { handled: true };
|
|
41109
|
+
}
|
|
41110
|
+
}
|
|
41111
|
+
if (sub === "show") {
|
|
41112
|
+
const id = parts[1];
|
|
41113
|
+
if (!id) {
|
|
41114
|
+
context.emit("text", `Usage: /plans show <planId>
|
|
41115
|
+
`);
|
|
41116
|
+
context.emit("done");
|
|
41117
|
+
return { handled: true };
|
|
41118
|
+
}
|
|
41119
|
+
const plan = project.plans.find((p) => p.id === id);
|
|
41120
|
+
if (!plan) {
|
|
41121
|
+
context.emit("text", `Plan not found: ${id}
|
|
41122
|
+
`);
|
|
41123
|
+
context.emit("done");
|
|
41124
|
+
return { handled: true };
|
|
41125
|
+
}
|
|
41126
|
+
let output = `
|
|
41127
|
+
**Plan: ${plan.title}**
|
|
41128
|
+
|
|
41129
|
+
`;
|
|
41130
|
+
output += `ID: ${plan.id}
|
|
41131
|
+
`;
|
|
41132
|
+
if (plan.steps.length === 0) {
|
|
41133
|
+
output += `No steps yet.
|
|
41134
|
+
`;
|
|
41135
|
+
} else {
|
|
41136
|
+
for (const step of plan.steps) {
|
|
41137
|
+
output += `- ${step.id} [${step.status}] ${step.text}
|
|
41138
|
+
`;
|
|
41139
|
+
}
|
|
41140
|
+
}
|
|
41141
|
+
context.emit("text", output);
|
|
41142
|
+
context.emit("done");
|
|
41143
|
+
return { handled: true };
|
|
41144
|
+
}
|
|
41145
|
+
if (sub === "add") {
|
|
41146
|
+
const planId = parts[1];
|
|
41147
|
+
const text = parts.slice(2).join(" ").trim();
|
|
41148
|
+
if (!planId || !text) {
|
|
41149
|
+
context.emit("text", `Usage: /plans add <planId> <step>
|
|
41150
|
+
`);
|
|
41151
|
+
context.emit("done");
|
|
41152
|
+
return { handled: true };
|
|
41153
|
+
}
|
|
41154
|
+
if (!project.plans.some((plan) => plan.id === planId)) {
|
|
41155
|
+
context.emit("text", `Plan not found: ${planId}
|
|
41156
|
+
`);
|
|
41157
|
+
context.emit("done");
|
|
41158
|
+
return { handled: true };
|
|
41159
|
+
}
|
|
41160
|
+
const now2 = Date.now();
|
|
41161
|
+
const step = {
|
|
41162
|
+
id: generateId(),
|
|
41163
|
+
text,
|
|
41164
|
+
status: "todo",
|
|
41165
|
+
createdAt: now2,
|
|
41166
|
+
updatedAt: now2
|
|
41167
|
+
};
|
|
41168
|
+
const updated = await updateProject(context.cwd, project.id, (current) => ({
|
|
41169
|
+
...current,
|
|
41170
|
+
plans: current.plans.map((plan) => plan.id === planId ? { ...plan, steps: [...plan.steps, step], updatedAt: now2 } : plan),
|
|
41171
|
+
updatedAt: now2
|
|
41172
|
+
}));
|
|
41173
|
+
if (updated) {
|
|
41174
|
+
await this.applyProjectContext(context, updated);
|
|
41175
|
+
context.emit("text", `Added step to plan ${planId}.
|
|
41176
|
+
`);
|
|
41177
|
+
context.emit("done");
|
|
41178
|
+
return { handled: true };
|
|
41179
|
+
}
|
|
41180
|
+
}
|
|
41181
|
+
if (sub === "set") {
|
|
41182
|
+
const planId = parts[1];
|
|
41183
|
+
const stepId = parts[2];
|
|
41184
|
+
const status = parts[3];
|
|
41185
|
+
if (!planId || !stepId || !status) {
|
|
41186
|
+
context.emit("text", `Usage: /plans set <planId> <stepId> <todo|doing|done|blocked>
|
|
41187
|
+
`);
|
|
41188
|
+
context.emit("done");
|
|
41189
|
+
return { handled: true };
|
|
41190
|
+
}
|
|
41191
|
+
const plan = project.plans.find((item) => item.id === planId);
|
|
41192
|
+
if (!plan) {
|
|
41193
|
+
context.emit("text", `Plan not found: ${planId}
|
|
41194
|
+
`);
|
|
41195
|
+
context.emit("done");
|
|
41196
|
+
return { handled: true };
|
|
41197
|
+
}
|
|
41198
|
+
if (!plan.steps.some((step) => step.id === stepId)) {
|
|
41199
|
+
context.emit("text", `Step not found: ${stepId}
|
|
41200
|
+
`);
|
|
41201
|
+
context.emit("done");
|
|
41202
|
+
return { handled: true };
|
|
41203
|
+
}
|
|
41204
|
+
const allowed = ["todo", "doing", "done", "blocked"];
|
|
41205
|
+
if (!allowed.includes(status)) {
|
|
41206
|
+
context.emit("text", `Invalid status. Use todo, doing, done, or blocked.
|
|
41207
|
+
`);
|
|
41208
|
+
context.emit("done");
|
|
41209
|
+
return { handled: true };
|
|
41210
|
+
}
|
|
41211
|
+
const now2 = Date.now();
|
|
41212
|
+
const updated = await updateProject(context.cwd, project.id, (current) => ({
|
|
41213
|
+
...current,
|
|
41214
|
+
plans: current.plans.map((plan2) => plan2.id === planId ? {
|
|
41215
|
+
...plan2,
|
|
41216
|
+
steps: plan2.steps.map((step) => step.id === stepId ? { ...step, status, updatedAt: now2 } : step),
|
|
41217
|
+
updatedAt: now2
|
|
41218
|
+
} : plan2),
|
|
41219
|
+
updatedAt: now2
|
|
41220
|
+
}));
|
|
41221
|
+
if (updated) {
|
|
41222
|
+
await this.applyProjectContext(context, updated);
|
|
41223
|
+
context.emit("text", `Updated step ${stepId} to ${status}.
|
|
41224
|
+
`);
|
|
41225
|
+
context.emit("done");
|
|
41226
|
+
return { handled: true };
|
|
41227
|
+
}
|
|
41228
|
+
}
|
|
41229
|
+
if (sub === "remove") {
|
|
41230
|
+
const planId = parts[1];
|
|
41231
|
+
const stepId = parts[2];
|
|
41232
|
+
if (!planId || !stepId) {
|
|
41233
|
+
context.emit("text", `Usage: /plans remove <planId> <stepId>
|
|
41234
|
+
`);
|
|
41235
|
+
context.emit("done");
|
|
41236
|
+
return { handled: true };
|
|
41237
|
+
}
|
|
41238
|
+
const plan = project.plans.find((item) => item.id === planId);
|
|
41239
|
+
if (!plan) {
|
|
41240
|
+
context.emit("text", `Plan not found: ${planId}
|
|
41241
|
+
`);
|
|
41242
|
+
context.emit("done");
|
|
41243
|
+
return { handled: true };
|
|
41244
|
+
}
|
|
41245
|
+
if (!plan.steps.some((step) => step.id === stepId)) {
|
|
41246
|
+
context.emit("text", `Step not found: ${stepId}
|
|
41247
|
+
`);
|
|
41248
|
+
context.emit("done");
|
|
41249
|
+
return { handled: true };
|
|
41250
|
+
}
|
|
41251
|
+
const now2 = Date.now();
|
|
41252
|
+
const updated = await updateProject(context.cwd, project.id, (current) => ({
|
|
41253
|
+
...current,
|
|
41254
|
+
plans: current.plans.map((plan2) => plan2.id === planId ? { ...plan2, steps: plan2.steps.filter((step) => step.id !== stepId), updatedAt: now2 } : plan2),
|
|
41255
|
+
updatedAt: now2
|
|
41256
|
+
}));
|
|
41257
|
+
if (updated) {
|
|
41258
|
+
await this.applyProjectContext(context, updated);
|
|
41259
|
+
context.emit("text", `Removed step ${stepId} from plan ${planId}.
|
|
41260
|
+
`);
|
|
41261
|
+
context.emit("done");
|
|
41262
|
+
return { handled: true };
|
|
41263
|
+
}
|
|
41264
|
+
}
|
|
41265
|
+
if (sub === "delete" || sub === "rm") {
|
|
41266
|
+
const planId = parts[1];
|
|
41267
|
+
if (!planId) {
|
|
41268
|
+
context.emit("text", `Usage: /plans delete <planId>
|
|
41269
|
+
`);
|
|
41270
|
+
context.emit("done");
|
|
41271
|
+
return { handled: true };
|
|
41272
|
+
}
|
|
41273
|
+
if (!project.plans.some((plan) => plan.id === planId)) {
|
|
41274
|
+
context.emit("text", `Plan not found: ${planId}
|
|
41275
|
+
`);
|
|
41276
|
+
context.emit("done");
|
|
41277
|
+
return { handled: true };
|
|
41278
|
+
}
|
|
41279
|
+
const now2 = Date.now();
|
|
41280
|
+
const updated = await updateProject(context.cwd, project.id, (current) => ({
|
|
41281
|
+
...current,
|
|
41282
|
+
plans: current.plans.filter((plan) => plan.id !== planId),
|
|
41283
|
+
updatedAt: now2
|
|
41284
|
+
}));
|
|
41285
|
+
if (updated) {
|
|
41286
|
+
await this.applyProjectContext(context, updated);
|
|
41287
|
+
context.emit("text", `Deleted plan ${planId}.
|
|
41288
|
+
`);
|
|
41289
|
+
context.emit("done");
|
|
41290
|
+
return { handled: true };
|
|
41291
|
+
}
|
|
41292
|
+
}
|
|
41293
|
+
context.emit("text", `Unknown /plans command. Use /plans help.
|
|
41294
|
+
`);
|
|
41295
|
+
context.emit("done");
|
|
41296
|
+
return { handled: true };
|
|
41297
|
+
}
|
|
41298
|
+
};
|
|
41299
|
+
}
|
|
41300
|
+
summarizeCommand() {
|
|
41301
|
+
return {
|
|
41302
|
+
name: "summarize",
|
|
41303
|
+
description: "Summarize and compress the current conversation",
|
|
41304
|
+
builtin: true,
|
|
41305
|
+
selfHandled: true,
|
|
41306
|
+
content: "",
|
|
41307
|
+
handler: async (args, context) => {
|
|
41308
|
+
if (!context.summarizeContext) {
|
|
41309
|
+
context.emit("text", `
|
|
41310
|
+
Context summarization is not available.
|
|
41311
|
+
`);
|
|
41312
|
+
context.emit("done");
|
|
41313
|
+
return { handled: true };
|
|
41314
|
+
}
|
|
41315
|
+
const result = await context.summarizeContext();
|
|
41316
|
+
if (!result.summarized) {
|
|
41317
|
+
context.emit("text", `
|
|
41318
|
+
Nothing to summarize right now.
|
|
41319
|
+
`);
|
|
41320
|
+
context.emit("done");
|
|
41321
|
+
return { handled: true };
|
|
41322
|
+
}
|
|
41323
|
+
let message = `
|
|
41324
|
+
**Context Summary Generated**
|
|
41325
|
+
|
|
41326
|
+
`;
|
|
41327
|
+
message += `Summarized ${result.summarizedCount} message(s).
|
|
41328
|
+
`;
|
|
41329
|
+
message += `Tokens: ${result.tokensBefore.toLocaleString()} -> ${result.tokensAfter.toLocaleString()}
|
|
41330
|
+
|
|
41331
|
+
`;
|
|
41332
|
+
if (result.summary) {
|
|
41333
|
+
message += `${result.summary}
|
|
41334
|
+
`;
|
|
41335
|
+
}
|
|
41336
|
+
context.emit("text", message);
|
|
41337
|
+
context.emit("done");
|
|
41338
|
+
return { handled: true };
|
|
41339
|
+
}
|
|
41340
|
+
};
|
|
41341
|
+
}
|
|
41342
|
+
restCommand() {
|
|
41343
|
+
return {
|
|
41344
|
+
name: "rest",
|
|
41345
|
+
description: "Recharge assistant energy",
|
|
41346
|
+
builtin: true,
|
|
41347
|
+
selfHandled: true,
|
|
41348
|
+
content: "",
|
|
41349
|
+
handler: async (args, context) => {
|
|
41350
|
+
if (!context.restEnergy) {
|
|
41351
|
+
context.emit("text", `
|
|
41352
|
+
Energy system is not available.
|
|
41353
|
+
`);
|
|
41354
|
+
context.emit("done");
|
|
41355
|
+
return { handled: true };
|
|
41356
|
+
}
|
|
41357
|
+
const parsed = parseInt(args.trim(), 10);
|
|
41358
|
+
const amount = Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
41359
|
+
context.restEnergy(amount);
|
|
41360
|
+
const state = context.getEnergyState?.();
|
|
41361
|
+
if (state) {
|
|
41362
|
+
const percent = Math.round(state.current / Math.max(1, state.max) * 100);
|
|
41363
|
+
context.emit("text", `
|
|
41364
|
+
Energy restored. Current level: ${percent}% (${state.current}/${state.max}).
|
|
41365
|
+
`);
|
|
41366
|
+
} else {
|
|
41367
|
+
context.emit("text", `
|
|
41368
|
+
Energy restored.
|
|
41369
|
+
`);
|
|
41370
|
+
}
|
|
41371
|
+
context.emit("done");
|
|
41372
|
+
return { handled: true };
|
|
41373
|
+
}
|
|
41374
|
+
};
|
|
41375
|
+
}
|
|
41376
|
+
skillsCommand(loader) {
|
|
41377
|
+
return {
|
|
41378
|
+
name: "skills",
|
|
41379
|
+
description: "List available skills",
|
|
41380
|
+
builtin: true,
|
|
41381
|
+
selfHandled: true,
|
|
41382
|
+
content: "",
|
|
41383
|
+
handler: async (args, context) => {
|
|
41384
|
+
let message = `
|
|
41385
|
+
**Available Skills**
|
|
41386
|
+
|
|
41387
|
+
`;
|
|
41388
|
+
message += `Skills are invoked with $skill-name [arguments] or /skill-name [arguments]
|
|
41389
|
+
|
|
41390
|
+
`;
|
|
41391
|
+
if (context.skills.length === 0) {
|
|
41392
|
+
message += `No skills loaded.
|
|
40537
41393
|
`;
|
|
40538
41394
|
message += `
|
|
40539
41395
|
Add skills to ~/.assistants/assistants-shared/skills/ or .assistants/skills/
|
|
@@ -40557,7 +41413,7 @@ ${context.skills.length} skill(s) available.
|
|
|
40557
41413
|
statusCommand() {
|
|
40558
41414
|
return {
|
|
40559
41415
|
name: "status",
|
|
40560
|
-
description: "Show current session status and token usage",
|
|
41416
|
+
description: "Show current session status, energy, identity, and token usage",
|
|
40561
41417
|
builtin: true,
|
|
40562
41418
|
selfHandled: true,
|
|
40563
41419
|
content: "",
|
|
@@ -40567,11 +41423,46 @@ ${context.skills.length} skill(s) available.
|
|
|
40567
41423
|
let message = `
|
|
40568
41424
|
**Session Status**
|
|
40569
41425
|
|
|
41426
|
+
`;
|
|
41427
|
+
message += `**Session ID:** ${context.sessionId}
|
|
40570
41428
|
`;
|
|
40571
41429
|
message += `**Working Directory:** ${context.cwd}
|
|
40572
41430
|
`;
|
|
40573
|
-
|
|
41431
|
+
const assistant = context.getAssistantManager?.()?.getActive();
|
|
41432
|
+
const identity = context.getIdentityManager?.()?.getActive();
|
|
41433
|
+
if (assistant) {
|
|
41434
|
+
message += `**Assistant:** ${assistant.name}`;
|
|
41435
|
+
if (identity) {
|
|
41436
|
+
message += ` \xB7 ${identity.name}`;
|
|
41437
|
+
}
|
|
41438
|
+
message += `
|
|
41439
|
+
`;
|
|
41440
|
+
}
|
|
41441
|
+
const energyState = context.getEnergyState?.();
|
|
41442
|
+
if (energyState) {
|
|
41443
|
+
const energyPercent = Math.round(energyState.current / Math.max(1, energyState.max) * 100);
|
|
41444
|
+
const energyBar = "\u2588".repeat(Math.round(energyPercent / 10)) + "\u2591".repeat(10 - Math.round(energyPercent / 10));
|
|
41445
|
+
const energyEmoji = energyPercent > 70 ? "\u26A1" : energyPercent > 30 ? "\uD83D\uDD0B" : "\uD83E\uDEAB";
|
|
41446
|
+
message += `**Energy:** ${energyEmoji} [${energyBar}] ${energyPercent}% (${energyState.current}/${energyState.max})
|
|
41447
|
+
`;
|
|
41448
|
+
}
|
|
41449
|
+
const voiceState = context.getVoiceState?.();
|
|
41450
|
+
if (voiceState?.enabled) {
|
|
41451
|
+
const voiceActivity = voiceState.isSpeaking ? "speaking" : voiceState.isListening ? "listening" : "idle";
|
|
41452
|
+
message += `**Voice:** ${voiceActivity}`;
|
|
41453
|
+
if (voiceState.sttProvider || voiceState.ttsProvider) {
|
|
41454
|
+
message += ` (STT: ${voiceState.sttProvider || "n/a"}, TTS: ${voiceState.ttsProvider || "n/a"})`;
|
|
41455
|
+
}
|
|
41456
|
+
message += `
|
|
41457
|
+
`;
|
|
41458
|
+
}
|
|
41459
|
+
if (context.getActiveProjectId) {
|
|
41460
|
+
const projectId = context.getActiveProjectId();
|
|
41461
|
+
if (projectId) {
|
|
41462
|
+
message += `**Active Project:** ${projectId}
|
|
40574
41463
|
`;
|
|
41464
|
+
}
|
|
41465
|
+
}
|
|
40575
41466
|
message += `**Messages:** ${context.messages.length}
|
|
40576
41467
|
`;
|
|
40577
41468
|
message += `**Available Tools:** ${context.tools.length}
|
|
@@ -40658,9 +41549,9 @@ Format the summary as a brief bullet-point list. This summary will replace the c
|
|
|
40658
41549
|
content: "",
|
|
40659
41550
|
handler: async (args, context) => {
|
|
40660
41551
|
const configPaths = [
|
|
40661
|
-
|
|
40662
|
-
|
|
40663
|
-
|
|
41552
|
+
join11(context.cwd, ".assistants", "config.json"),
|
|
41553
|
+
join11(context.cwd, ".assistants", "config.local.json"),
|
|
41554
|
+
join11(getConfigDir(), "config.json")
|
|
40664
41555
|
];
|
|
40665
41556
|
let message = `
|
|
40666
41557
|
**Configuration**
|
|
@@ -40678,9 +41569,9 @@ Format the summary as a brief bullet-point list. This summary will replace the c
|
|
|
40678
41569
|
message += `
|
|
40679
41570
|
**Commands Directories:**
|
|
40680
41571
|
`;
|
|
40681
|
-
message += ` - Project: ${
|
|
41572
|
+
message += ` - Project: ${join11(context.cwd, ".assistants", "commands")}
|
|
40682
41573
|
`;
|
|
40683
|
-
message += ` - Global: ${
|
|
41574
|
+
message += ` - Global: ${join11(homeDir, ".assistants", "commands")}
|
|
40684
41575
|
`;
|
|
40685
41576
|
context.emit("text", message);
|
|
40686
41577
|
context.emit("done");
|
|
@@ -40696,7 +41587,7 @@ Format the summary as a brief bullet-point list. This summary will replace the c
|
|
|
40696
41587
|
selfHandled: true,
|
|
40697
41588
|
content: "",
|
|
40698
41589
|
handler: async (args, context) => {
|
|
40699
|
-
const commandsDir =
|
|
41590
|
+
const commandsDir = join11(context.cwd, ".assistants", "commands");
|
|
40700
41591
|
mkdirSync2(commandsDir, { recursive: true });
|
|
40701
41592
|
const exampleCommand = `---
|
|
40702
41593
|
name: reflect
|
|
@@ -40712,7 +41603,7 @@ Please summarize the last interaction and suggest 2-3 next steps.
|
|
|
40712
41603
|
- Focus on clarity
|
|
40713
41604
|
- Ask a follow-up question if needed
|
|
40714
41605
|
`;
|
|
40715
|
-
const examplePath =
|
|
41606
|
+
const examplePath = join11(commandsDir, "reflect.md");
|
|
40716
41607
|
if (!existsSync6(examplePath)) {
|
|
40717
41608
|
writeFileSync3(examplePath, exampleCommand);
|
|
40718
41609
|
}
|
|
@@ -40862,6 +41753,7 @@ Keep it concise but comprehensive.`
|
|
|
40862
41753
|
createdAt: now2,
|
|
40863
41754
|
updatedAt: now2,
|
|
40864
41755
|
createdBy: "user",
|
|
41756
|
+
sessionId: context.sessionId,
|
|
40865
41757
|
command,
|
|
40866
41758
|
status: "active",
|
|
40867
41759
|
schedule: {
|
|
@@ -41032,8 +41924,8 @@ Connector "${connectorName}" not found.
|
|
|
41032
41924
|
`;
|
|
41033
41925
|
try {
|
|
41034
41926
|
let timeoutId = null;
|
|
41035
|
-
const timeoutPromise = new Promise((
|
|
41036
|
-
timeoutId = setTimeout(resolveAuthTimeout, 1000,
|
|
41927
|
+
const timeoutPromise = new Promise((resolve5) => {
|
|
41928
|
+
timeoutId = setTimeout(resolveAuthTimeout, 1000, resolve5);
|
|
41037
41929
|
});
|
|
41038
41930
|
const result = await Promise.race([
|
|
41039
41931
|
Bun.$`${connector.cli} auth status --format json`.quiet().nothrow(),
|
|
@@ -41095,8 +41987,8 @@ Connector "${connectorName}" not found.
|
|
|
41095
41987
|
let status = "\u25CB";
|
|
41096
41988
|
let timeoutId = null;
|
|
41097
41989
|
try {
|
|
41098
|
-
const timeoutPromise = new Promise((
|
|
41099
|
-
timeoutId = setTimeout(resolveAuthTimeout, 1000,
|
|
41990
|
+
const timeoutPromise = new Promise((resolve5) => {
|
|
41991
|
+
timeoutId = setTimeout(resolveAuthTimeout, 1000, resolve5);
|
|
41100
41992
|
});
|
|
41101
41993
|
const result = await Promise.race([
|
|
41102
41994
|
Bun.$`${connector.cli} auth status --format json`.quiet().nothrow(),
|
|
@@ -41371,6 +42263,35 @@ ${repoUrl}/issues/new
|
|
|
41371
42263
|
}
|
|
41372
42264
|
};
|
|
41373
42265
|
}
|
|
42266
|
+
async resolveProject(context, target) {
|
|
42267
|
+
const byId = await readProject(context.cwd, target);
|
|
42268
|
+
if (byId)
|
|
42269
|
+
return byId;
|
|
42270
|
+
return findProjectByName(context.cwd, target);
|
|
42271
|
+
}
|
|
42272
|
+
async ensureActiveProject(context, createIfMissing) {
|
|
42273
|
+
const activeId = context.getActiveProjectId?.();
|
|
42274
|
+
if (activeId) {
|
|
42275
|
+
const project2 = await readProject(context.cwd, activeId);
|
|
42276
|
+
if (project2)
|
|
42277
|
+
return project2;
|
|
42278
|
+
}
|
|
42279
|
+
if (!createIfMissing)
|
|
42280
|
+
return null;
|
|
42281
|
+
const project = await ensureDefaultProject(context.cwd);
|
|
42282
|
+
context.setActiveProjectId?.(project.id);
|
|
42283
|
+
await this.applyProjectContext(context, project);
|
|
42284
|
+
return project;
|
|
42285
|
+
}
|
|
42286
|
+
async applyProjectContext(context, project) {
|
|
42287
|
+
if (!context.setProjectContext)
|
|
42288
|
+
return;
|
|
42289
|
+
const projectContext = await buildProjectContext(project, {
|
|
42290
|
+
cwd: context.cwd,
|
|
42291
|
+
connectors: context.connectors
|
|
42292
|
+
});
|
|
42293
|
+
context.setProjectContext(projectContext);
|
|
42294
|
+
}
|
|
41374
42295
|
}
|
|
41375
42296
|
// packages/core/src/llm/client.ts
|
|
41376
42297
|
async function createLLMClient(config) {
|
|
@@ -41384,7 +42305,7 @@ async function createLLMClient(config) {
|
|
|
41384
42305
|
// packages/core/src/heartbeat/manager.ts
|
|
41385
42306
|
import { dirname as dirname5 } from "path";
|
|
41386
42307
|
import { mkdirSync as mkdirSync3 } from "fs";
|
|
41387
|
-
import { readFile as
|
|
42308
|
+
import { readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
41388
42309
|
|
|
41389
42310
|
class HeartbeatManager {
|
|
41390
42311
|
config;
|
|
@@ -41463,12 +42384,12 @@ class HeartbeatManager {
|
|
|
41463
42384
|
}
|
|
41464
42385
|
async persist(heartbeat) {
|
|
41465
42386
|
try {
|
|
41466
|
-
await
|
|
42387
|
+
await writeFile3(this.config.persistPath, JSON.stringify(heartbeat, null, 2));
|
|
41467
42388
|
} catch {}
|
|
41468
42389
|
}
|
|
41469
42390
|
static async checkStale(path2, thresholdMs) {
|
|
41470
42391
|
try {
|
|
41471
|
-
const content = await
|
|
42392
|
+
const content = await readFile4(path2, "utf-8");
|
|
41472
42393
|
const heartbeat = JSON.parse(content);
|
|
41473
42394
|
const age = Date.now() - new Date(heartbeat.timestamp).getTime();
|
|
41474
42395
|
return { isStale: age > thresholdMs, lastHeartbeat: heartbeat };
|
|
@@ -41480,7 +42401,7 @@ class HeartbeatManager {
|
|
|
41480
42401
|
// packages/core/src/heartbeat/persistence.ts
|
|
41481
42402
|
import { dirname as dirname6 } from "path";
|
|
41482
42403
|
import { mkdirSync as mkdirSync4 } from "fs";
|
|
41483
|
-
import { readFile as
|
|
42404
|
+
import { readFile as readFile5, writeFile as writeFile4, unlink as unlink3 } from "fs/promises";
|
|
41484
42405
|
|
|
41485
42406
|
class StatePersistence {
|
|
41486
42407
|
path;
|
|
@@ -41490,12 +42411,12 @@ class StatePersistence {
|
|
|
41490
42411
|
}
|
|
41491
42412
|
async save(state) {
|
|
41492
42413
|
try {
|
|
41493
|
-
await
|
|
42414
|
+
await writeFile4(this.path, JSON.stringify(state, null, 2));
|
|
41494
42415
|
} catch {}
|
|
41495
42416
|
}
|
|
41496
42417
|
async load() {
|
|
41497
42418
|
try {
|
|
41498
|
-
const content = await
|
|
42419
|
+
const content = await readFile5(this.path, "utf-8");
|
|
41499
42420
|
return JSON.parse(content);
|
|
41500
42421
|
} catch {
|
|
41501
42422
|
return null;
|
|
@@ -41503,7 +42424,7 @@ class StatePersistence {
|
|
|
41503
42424
|
}
|
|
41504
42425
|
async clear() {
|
|
41505
42426
|
try {
|
|
41506
|
-
await
|
|
42427
|
+
await unlink3(this.path);
|
|
41507
42428
|
} catch {}
|
|
41508
42429
|
}
|
|
41509
42430
|
}
|
|
@@ -41707,7 +42628,7 @@ class EnergyManager {
|
|
|
41707
42628
|
// packages/core/src/energy/storage.ts
|
|
41708
42629
|
import { dirname as dirname7 } from "path";
|
|
41709
42630
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
41710
|
-
import { readFile as
|
|
42631
|
+
import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
41711
42632
|
|
|
41712
42633
|
class EnergyStorage {
|
|
41713
42634
|
path;
|
|
@@ -41717,12 +42638,12 @@ class EnergyStorage {
|
|
|
41717
42638
|
}
|
|
41718
42639
|
async save(state) {
|
|
41719
42640
|
try {
|
|
41720
|
-
await
|
|
42641
|
+
await writeFile5(this.path, JSON.stringify(state, null, 2));
|
|
41721
42642
|
} catch {}
|
|
41722
42643
|
}
|
|
41723
42644
|
async load() {
|
|
41724
42645
|
try {
|
|
41725
|
-
const content = await
|
|
42646
|
+
const content = await readFile6(this.path, "utf-8");
|
|
41726
42647
|
return JSON.parse(content);
|
|
41727
42648
|
} catch {
|
|
41728
42649
|
return null;
|
|
@@ -41782,12 +42703,12 @@ function validateToolCalls(toolCalls, tools) {
|
|
|
41782
42703
|
// packages/core/src/voice/utils.ts
|
|
41783
42704
|
import { existsSync as existsSync8, readFileSync as readFileSync3 } from "fs";
|
|
41784
42705
|
import { homedir as homedir9 } from "os";
|
|
41785
|
-
import { join as
|
|
42706
|
+
import { join as join13 } from "path";
|
|
41786
42707
|
import { spawnSync } from "child_process";
|
|
41787
42708
|
function loadApiKeyFromSecrets2(key) {
|
|
41788
42709
|
const envHome = process.env.HOME || process.env.USERPROFILE;
|
|
41789
42710
|
const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir9();
|
|
41790
|
-
const secretsPath =
|
|
42711
|
+
const secretsPath = join13(homeDir, ".secrets");
|
|
41791
42712
|
if (!existsSync8(secretsPath))
|
|
41792
42713
|
return;
|
|
41793
42714
|
try {
|
|
@@ -41861,7 +42782,7 @@ class SystemSTT {
|
|
|
41861
42782
|
// packages/core/src/voice/tts.ts
|
|
41862
42783
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
41863
42784
|
import { tmpdir as tmpdir2 } from "os";
|
|
41864
|
-
import { join as
|
|
42785
|
+
import { join as join14 } from "path";
|
|
41865
42786
|
import { readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
41866
42787
|
class ElevenLabsTTS {
|
|
41867
42788
|
apiKey;
|
|
@@ -41965,7 +42886,7 @@ class SystemTTS {
|
|
|
41965
42886
|
if (!say) {
|
|
41966
42887
|
throw new Error('System TTS not available: missing "say" command.');
|
|
41967
42888
|
}
|
|
41968
|
-
const output =
|
|
42889
|
+
const output = join14(tmpdir2(), `assistants-tts-${Date.now()}.aiff`);
|
|
41969
42890
|
const args = [];
|
|
41970
42891
|
if (this.voiceId) {
|
|
41971
42892
|
args.push("-v", this.voiceId);
|
|
@@ -41987,7 +42908,7 @@ class SystemTTS {
|
|
|
41987
42908
|
}
|
|
41988
42909
|
const espeak = findExecutable("espeak") || findExecutable("espeak-ng");
|
|
41989
42910
|
if (espeak) {
|
|
41990
|
-
const output =
|
|
42911
|
+
const output = join14(tmpdir2(), `assistants-tts-${Date.now()}.wav`);
|
|
41991
42912
|
const args = ["-w", output];
|
|
41992
42913
|
if (this.voiceId) {
|
|
41993
42914
|
args.push("-v", this.voiceId);
|
|
@@ -42014,32 +42935,32 @@ class SystemTTS {
|
|
|
42014
42935
|
// packages/core/src/voice/player.ts
|
|
42015
42936
|
import { spawn } from "child_process";
|
|
42016
42937
|
import { tmpdir as tmpdir3 } from "os";
|
|
42017
|
-
import { join as
|
|
42018
|
-
import { unlink as
|
|
42938
|
+
import { join as join15 } from "path";
|
|
42939
|
+
import { unlink as unlink4, writeFileSync as writeFileSync4 } from "fs";
|
|
42019
42940
|
class AudioPlayer {
|
|
42020
42941
|
currentProcess = null;
|
|
42021
42942
|
playing = false;
|
|
42022
42943
|
async play(audio, options = {}) {
|
|
42023
42944
|
const format = options.format ?? "mp3";
|
|
42024
|
-
const tempFile =
|
|
42945
|
+
const tempFile = join15(tmpdir3(), `assistants-audio-${Date.now()}.${format}`);
|
|
42025
42946
|
writeFileSync4(tempFile, Buffer.from(audio));
|
|
42026
42947
|
const player = this.resolvePlayer(format);
|
|
42027
42948
|
if (!player) {
|
|
42028
42949
|
throw new Error("No supported audio player found. Install afplay, ffplay, mpg123, or aplay.");
|
|
42029
42950
|
}
|
|
42030
|
-
await new Promise((
|
|
42951
|
+
await new Promise((resolve5, reject) => {
|
|
42031
42952
|
this.playing = true;
|
|
42032
42953
|
this.currentProcess = spawn(player.command, [...player.args, tempFile], { stdio: "ignore" });
|
|
42033
42954
|
this.currentProcess.on("close", () => {
|
|
42034
42955
|
this.playing = false;
|
|
42035
42956
|
this.currentProcess = null;
|
|
42036
|
-
|
|
42037
|
-
|
|
42957
|
+
unlink4(tempFile, () => {});
|
|
42958
|
+
resolve5();
|
|
42038
42959
|
});
|
|
42039
42960
|
this.currentProcess.on("error", (error) => {
|
|
42040
42961
|
this.playing = false;
|
|
42041
42962
|
this.currentProcess = null;
|
|
42042
|
-
|
|
42963
|
+
unlink4(tempFile, () => {});
|
|
42043
42964
|
reject(error);
|
|
42044
42965
|
});
|
|
42045
42966
|
});
|
|
@@ -42089,8 +43010,8 @@ class AudioPlayer {
|
|
|
42089
43010
|
// packages/core/src/voice/recorder.ts
|
|
42090
43011
|
import { spawn as spawn2 } from "child_process";
|
|
42091
43012
|
import { tmpdir as tmpdir4 } from "os";
|
|
42092
|
-
import { join as
|
|
42093
|
-
import { readFileSync as readFileSync5, unlink as
|
|
43013
|
+
import { join as join16 } from "path";
|
|
43014
|
+
import { readFileSync as readFileSync5, unlink as unlink5 } from "fs";
|
|
42094
43015
|
class AudioRecorder {
|
|
42095
43016
|
currentProcess = null;
|
|
42096
43017
|
async record(options = {}) {
|
|
@@ -42100,17 +43021,17 @@ class AudioRecorder {
|
|
|
42100
43021
|
const duration = options.durationSeconds ?? 5;
|
|
42101
43022
|
const sampleRate = options.sampleRate ?? 16000;
|
|
42102
43023
|
const channels = options.channels ?? 1;
|
|
42103
|
-
const output =
|
|
43024
|
+
const output = join16(tmpdir4(), `assistants-record-${Date.now()}.wav`);
|
|
42104
43025
|
const recorder = this.resolveRecorder(sampleRate, channels, duration, output);
|
|
42105
43026
|
if (!recorder) {
|
|
42106
43027
|
throw new Error("No supported audio recorder found. Install sox or ffmpeg.");
|
|
42107
43028
|
}
|
|
42108
|
-
await new Promise((
|
|
43029
|
+
await new Promise((resolve5, reject) => {
|
|
42109
43030
|
this.currentProcess = spawn2(recorder.command, recorder.args, { stdio: "ignore" });
|
|
42110
43031
|
this.currentProcess.on("close", (code) => {
|
|
42111
43032
|
this.currentProcess = null;
|
|
42112
43033
|
if (code === 0) {
|
|
42113
|
-
|
|
43034
|
+
resolve5();
|
|
42114
43035
|
} else {
|
|
42115
43036
|
reject(new Error("Audio recording failed."));
|
|
42116
43037
|
}
|
|
@@ -42121,7 +43042,7 @@ class AudioRecorder {
|
|
|
42121
43042
|
});
|
|
42122
43043
|
});
|
|
42123
43044
|
const data = readFileSync5(output);
|
|
42124
|
-
|
|
43045
|
+
unlink5(output, () => {});
|
|
42125
43046
|
return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
42126
43047
|
}
|
|
42127
43048
|
stop() {
|
|
@@ -42293,14 +43214,14 @@ class VoiceManager {
|
|
|
42293
43214
|
// packages/core/src/identity/assistant-manager.ts
|
|
42294
43215
|
init_src();
|
|
42295
43216
|
import { existsSync as existsSync10 } from "fs";
|
|
42296
|
-
import { mkdir as
|
|
42297
|
-
import { join as
|
|
43217
|
+
import { mkdir as mkdir5, readFile as readFile8, writeFile as writeFile7, rm as rm2 } from "fs/promises";
|
|
43218
|
+
import { join as join18 } from "path";
|
|
42298
43219
|
|
|
42299
43220
|
// packages/core/src/identity/identity-manager.ts
|
|
42300
43221
|
init_src();
|
|
42301
43222
|
import { existsSync as existsSync9 } from "fs";
|
|
42302
|
-
import { mkdir as
|
|
42303
|
-
import { join as
|
|
43223
|
+
import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile6, rm } from "fs/promises";
|
|
43224
|
+
import { join as join17 } from "path";
|
|
42304
43225
|
var DEFAULT_PROFILE = {
|
|
42305
43226
|
displayName: "Assistant",
|
|
42306
43227
|
timezone: "UTC",
|
|
@@ -42330,22 +43251,22 @@ class IdentityManager {
|
|
|
42330
43251
|
this.basePath = basePath;
|
|
42331
43252
|
}
|
|
42332
43253
|
get identitiesRoot() {
|
|
42333
|
-
return
|
|
43254
|
+
return join17(this.basePath, "assistants", this.assistantId, "identities");
|
|
42334
43255
|
}
|
|
42335
43256
|
get indexPath() {
|
|
42336
|
-
return
|
|
43257
|
+
return join17(this.identitiesRoot, "index.json");
|
|
42337
43258
|
}
|
|
42338
43259
|
get activePath() {
|
|
42339
|
-
return
|
|
43260
|
+
return join17(this.identitiesRoot, "active.json");
|
|
42340
43261
|
}
|
|
42341
43262
|
identityPath(id) {
|
|
42342
|
-
return
|
|
43263
|
+
return join17(this.identitiesRoot, `${id}.json`);
|
|
42343
43264
|
}
|
|
42344
43265
|
assistantConfigPath() {
|
|
42345
|
-
return
|
|
43266
|
+
return join17(this.basePath, "assistants", this.assistantId, "config.json");
|
|
42346
43267
|
}
|
|
42347
43268
|
async initialize() {
|
|
42348
|
-
await
|
|
43269
|
+
await mkdir4(this.identitiesRoot, { recursive: true });
|
|
42349
43270
|
const index = await this.readIndex();
|
|
42350
43271
|
for (const id of index.identities) {
|
|
42351
43272
|
const identity = await this.readIdentity(id);
|
|
@@ -42452,7 +43373,7 @@ class IdentityManager {
|
|
|
42452
43373
|
return { identities: [] };
|
|
42453
43374
|
}
|
|
42454
43375
|
try {
|
|
42455
|
-
const raw = await
|
|
43376
|
+
const raw = await readFile7(this.indexPath, "utf-8");
|
|
42456
43377
|
const data = JSON.parse(raw);
|
|
42457
43378
|
return { identities: Array.isArray(data.identities) ? data.identities : [] };
|
|
42458
43379
|
} catch {
|
|
@@ -42464,33 +43385,33 @@ class IdentityManager {
|
|
|
42464
43385
|
if (!index.identities.includes(id)) {
|
|
42465
43386
|
index.identities.push(id);
|
|
42466
43387
|
}
|
|
42467
|
-
await
|
|
43388
|
+
await writeFile6(this.indexPath, JSON.stringify(index, null, 2));
|
|
42468
43389
|
}
|
|
42469
43390
|
async removeFromIndex(id) {
|
|
42470
43391
|
const index = await this.readIndex();
|
|
42471
43392
|
index.identities = index.identities.filter((identityId) => identityId !== id);
|
|
42472
|
-
await
|
|
43393
|
+
await writeFile6(this.indexPath, JSON.stringify(index, null, 2));
|
|
42473
43394
|
}
|
|
42474
43395
|
async readIdentity(id) {
|
|
42475
43396
|
const path2 = this.identityPath(id);
|
|
42476
43397
|
if (!existsSync9(path2))
|
|
42477
43398
|
return null;
|
|
42478
43399
|
try {
|
|
42479
|
-
const raw = await
|
|
43400
|
+
const raw = await readFile7(path2, "utf-8");
|
|
42480
43401
|
return JSON.parse(raw);
|
|
42481
43402
|
} catch {
|
|
42482
43403
|
return null;
|
|
42483
43404
|
}
|
|
42484
43405
|
}
|
|
42485
43406
|
async persistIdentity(identity) {
|
|
42486
|
-
await
|
|
42487
|
-
await
|
|
43407
|
+
await mkdir4(this.identitiesRoot, { recursive: true });
|
|
43408
|
+
await writeFile6(this.identityPath(identity.id), JSON.stringify(identity, null, 2));
|
|
42488
43409
|
}
|
|
42489
43410
|
async readActive() {
|
|
42490
43411
|
if (!existsSync9(this.activePath))
|
|
42491
43412
|
return null;
|
|
42492
43413
|
try {
|
|
42493
|
-
const raw = await
|
|
43414
|
+
const raw = await readFile7(this.activePath, "utf-8");
|
|
42494
43415
|
const data = JSON.parse(raw);
|
|
42495
43416
|
return data.id || null;
|
|
42496
43417
|
} catch {
|
|
@@ -42499,13 +43420,13 @@ class IdentityManager {
|
|
|
42499
43420
|
}
|
|
42500
43421
|
async setActive(id) {
|
|
42501
43422
|
this.activeId = id;
|
|
42502
|
-
await
|
|
43423
|
+
await writeFile6(this.activePath, JSON.stringify({ id }, null, 2));
|
|
42503
43424
|
}
|
|
42504
43425
|
async loadAssistant() {
|
|
42505
43426
|
if (!existsSync9(this.assistantConfigPath()))
|
|
42506
43427
|
return null;
|
|
42507
43428
|
try {
|
|
42508
|
-
const raw = await
|
|
43429
|
+
const raw = await readFile7(this.assistantConfigPath(), "utf-8");
|
|
42509
43430
|
return JSON.parse(raw);
|
|
42510
43431
|
} catch {
|
|
42511
43432
|
return null;
|
|
@@ -42526,19 +43447,19 @@ class AssistantManager {
|
|
|
42526
43447
|
this.basePath = basePath;
|
|
42527
43448
|
}
|
|
42528
43449
|
get assistantsRoot() {
|
|
42529
|
-
return
|
|
43450
|
+
return join18(this.basePath, "assistants");
|
|
42530
43451
|
}
|
|
42531
43452
|
get indexPath() {
|
|
42532
|
-
return
|
|
43453
|
+
return join18(this.assistantsRoot, "index.json");
|
|
42533
43454
|
}
|
|
42534
43455
|
get activePath() {
|
|
42535
|
-
return
|
|
43456
|
+
return join18(this.basePath, "active.json");
|
|
42536
43457
|
}
|
|
42537
43458
|
assistantConfigPath(id) {
|
|
42538
|
-
return
|
|
43459
|
+
return join18(this.assistantsRoot, id, "config.json");
|
|
42539
43460
|
}
|
|
42540
43461
|
async initialize() {
|
|
42541
|
-
await
|
|
43462
|
+
await mkdir5(this.assistantsRoot, { recursive: true });
|
|
42542
43463
|
const index = await this.readIndex();
|
|
42543
43464
|
for (const id of index.assistants) {
|
|
42544
43465
|
const assistant = await this.readAssistant(id);
|
|
@@ -42589,7 +43510,7 @@ class AssistantManager {
|
|
|
42589
43510
|
if (!this.assistants.has(id)) {
|
|
42590
43511
|
throw new Error(`Assistant ${id} not found`);
|
|
42591
43512
|
}
|
|
42592
|
-
await rm2(
|
|
43513
|
+
await rm2(join18(this.assistantsRoot, id), { recursive: true, force: true });
|
|
42593
43514
|
this.assistants.delete(id);
|
|
42594
43515
|
await this.removeFromIndex(id);
|
|
42595
43516
|
if (this.activeId === id) {
|
|
@@ -42624,7 +43545,7 @@ class AssistantManager {
|
|
|
42624
43545
|
return { assistants: [] };
|
|
42625
43546
|
}
|
|
42626
43547
|
try {
|
|
42627
|
-
const raw = await
|
|
43548
|
+
const raw = await readFile8(this.indexPath, "utf-8");
|
|
42628
43549
|
const data = JSON.parse(raw);
|
|
42629
43550
|
return { assistants: Array.isArray(data.assistants) ? data.assistants : [] };
|
|
42630
43551
|
} catch {
|
|
@@ -42636,34 +43557,34 @@ class AssistantManager {
|
|
|
42636
43557
|
if (!index.assistants.includes(id)) {
|
|
42637
43558
|
index.assistants.push(id);
|
|
42638
43559
|
}
|
|
42639
|
-
await
|
|
43560
|
+
await writeFile7(this.indexPath, JSON.stringify(index, null, 2));
|
|
42640
43561
|
}
|
|
42641
43562
|
async removeFromIndex(id) {
|
|
42642
43563
|
const index = await this.readIndex();
|
|
42643
43564
|
index.assistants = index.assistants.filter((assistantId) => assistantId !== id);
|
|
42644
|
-
await
|
|
43565
|
+
await writeFile7(this.indexPath, JSON.stringify(index, null, 2));
|
|
42645
43566
|
}
|
|
42646
43567
|
async readAssistant(id) {
|
|
42647
43568
|
const configPath = this.assistantConfigPath(id);
|
|
42648
43569
|
if (!existsSync10(configPath))
|
|
42649
43570
|
return null;
|
|
42650
43571
|
try {
|
|
42651
|
-
const raw = await
|
|
43572
|
+
const raw = await readFile8(configPath, "utf-8");
|
|
42652
43573
|
return JSON.parse(raw);
|
|
42653
43574
|
} catch {
|
|
42654
43575
|
return null;
|
|
42655
43576
|
}
|
|
42656
43577
|
}
|
|
42657
43578
|
async persistAssistant(assistant) {
|
|
42658
|
-
const dir =
|
|
42659
|
-
await
|
|
42660
|
-
await
|
|
43579
|
+
const dir = join18(this.assistantsRoot, assistant.id);
|
|
43580
|
+
await mkdir5(dir, { recursive: true });
|
|
43581
|
+
await writeFile7(this.assistantConfigPath(assistant.id), JSON.stringify(assistant, null, 2));
|
|
42661
43582
|
}
|
|
42662
43583
|
async readActive() {
|
|
42663
43584
|
if (!existsSync10(this.activePath))
|
|
42664
43585
|
return null;
|
|
42665
43586
|
try {
|
|
42666
|
-
const raw = await
|
|
43587
|
+
const raw = await readFile8(this.activePath, "utf-8");
|
|
42667
43588
|
const data = JSON.parse(raw);
|
|
42668
43589
|
return data.id || null;
|
|
42669
43590
|
} catch {
|
|
@@ -42672,7 +43593,7 @@ class AssistantManager {
|
|
|
42672
43593
|
}
|
|
42673
43594
|
async setActive(id) {
|
|
42674
43595
|
this.activeId = id;
|
|
42675
|
-
await
|
|
43596
|
+
await writeFile7(this.activePath, JSON.stringify({ id }, null, 2));
|
|
42676
43597
|
}
|
|
42677
43598
|
}
|
|
42678
43599
|
// packages/core/src/agent/loop.ts
|
|
@@ -42717,6 +43638,8 @@ class AgentLoop {
|
|
|
42717
43638
|
assistantManager = null;
|
|
42718
43639
|
identityManager = null;
|
|
42719
43640
|
identityContext = null;
|
|
43641
|
+
projectContext = null;
|
|
43642
|
+
activeProjectId = null;
|
|
42720
43643
|
assistantId = null;
|
|
42721
43644
|
onChunk;
|
|
42722
43645
|
onToolStart;
|
|
@@ -42729,7 +43652,7 @@ class AgentLoop {
|
|
|
42729
43652
|
this.context = new AgentContext;
|
|
42730
43653
|
this.toolRegistry = new ToolRegistry;
|
|
42731
43654
|
this.toolRegistry.setErrorAggregator(this.errorAggregator);
|
|
42732
|
-
this.connectorBridge = new ConnectorBridge;
|
|
43655
|
+
this.connectorBridge = new ConnectorBridge(this.cwd);
|
|
42733
43656
|
this.skillLoader = new SkillLoader;
|
|
42734
43657
|
this.skillExecutor = new SkillExecutor;
|
|
42735
43658
|
this.hookLoader = new HookLoader;
|
|
@@ -43032,9 +43955,13 @@ class AgentLoop {
|
|
|
43032
43955
|
});
|
|
43033
43956
|
if (preHookResult?.updatedInput) {
|
|
43034
43957
|
toolCall.input = { ...preHookResult.updatedInput };
|
|
43035
|
-
|
|
43036
|
-
|
|
43037
|
-
|
|
43958
|
+
}
|
|
43959
|
+
const input = toolCall.input;
|
|
43960
|
+
if (input.cwd === undefined) {
|
|
43961
|
+
input.cwd = this.cwd;
|
|
43962
|
+
}
|
|
43963
|
+
if (input.sessionId === undefined) {
|
|
43964
|
+
input.sessionId = this.sessionId;
|
|
43038
43965
|
}
|
|
43039
43966
|
if (preHookResult?.continue === false || preHookResult?.permissionDecision === "deny") {
|
|
43040
43967
|
const blockedResult = {
|
|
@@ -43158,6 +44085,13 @@ class AgentLoop {
|
|
|
43158
44085
|
switchIdentity: async (identityId) => {
|
|
43159
44086
|
await this.switchIdentity(identityId);
|
|
43160
44087
|
},
|
|
44088
|
+
getActiveProjectId: () => this.activeProjectId,
|
|
44089
|
+
setActiveProjectId: (projectId) => {
|
|
44090
|
+
this.activeProjectId = projectId;
|
|
44091
|
+
},
|
|
44092
|
+
setProjectContext: (content) => {
|
|
44093
|
+
this.setProjectContext(content);
|
|
44094
|
+
},
|
|
43161
44095
|
getVoiceState: () => this.getVoiceState(),
|
|
43162
44096
|
enableVoice: () => {
|
|
43163
44097
|
if (!this.voiceManager) {
|
|
@@ -43345,6 +44279,22 @@ class AgentLoop {
|
|
|
43345
44279
|
getSessionId() {
|
|
43346
44280
|
return this.sessionId;
|
|
43347
44281
|
}
|
|
44282
|
+
getActiveProjectId() {
|
|
44283
|
+
return this.activeProjectId;
|
|
44284
|
+
}
|
|
44285
|
+
setActiveProjectId(projectId) {
|
|
44286
|
+
this.activeProjectId = projectId;
|
|
44287
|
+
}
|
|
44288
|
+
setProjectContext(content) {
|
|
44289
|
+
const tag = "[Project Context]";
|
|
44290
|
+
this.projectContext = content;
|
|
44291
|
+
this.context.removeSystemMessages((message) => message.startsWith(tag));
|
|
44292
|
+
if (content && content.trim()) {
|
|
44293
|
+
this.context.addSystemMessage(`${tag}
|
|
44294
|
+
${content.trim()}`);
|
|
44295
|
+
}
|
|
44296
|
+
this.contextManager?.refreshState(this.context.getMessages());
|
|
44297
|
+
}
|
|
43348
44298
|
clearConversation() {
|
|
43349
44299
|
this.resetContext();
|
|
43350
44300
|
}
|
|
@@ -43356,7 +44306,7 @@ class AgentLoop {
|
|
|
43356
44306
|
const heartbeatConfig = this.buildHeartbeatConfig(this.config);
|
|
43357
44307
|
if (!heartbeatConfig)
|
|
43358
44308
|
return;
|
|
43359
|
-
const statePath =
|
|
44309
|
+
const statePath = join19(getConfigDir(), "state", `${this.sessionId}.json`);
|
|
43360
44310
|
this.heartbeatManager = new HeartbeatManager(heartbeatConfig);
|
|
43361
44311
|
this.heartbeatPersistence = new StatePersistence(statePath);
|
|
43362
44312
|
this.heartbeatRecovery = new RecoveryManager(this.heartbeatPersistence, heartbeatConfig.persistPath, heartbeatConfig.staleThresholdMs, {
|
|
@@ -43405,7 +44355,7 @@ class AgentLoop {
|
|
|
43405
44355
|
async startEnergySystem() {
|
|
43406
44356
|
if (!this.config || this.config.energy?.enabled === false)
|
|
43407
44357
|
return;
|
|
43408
|
-
const statePath =
|
|
44358
|
+
const statePath = join19(getConfigDir(), "energy", "state.json");
|
|
43409
44359
|
this.energyManager = new EnergyManager(this.config.energy, new EnergyStorage(statePath));
|
|
43410
44360
|
await this.energyManager.initialize();
|
|
43411
44361
|
this.refreshEnergyEffects();
|
|
@@ -43434,7 +44384,7 @@ ${effects.message}
|
|
|
43434
44384
|
const delay = this.energyEffects?.processingDelayMs ?? 0;
|
|
43435
44385
|
if (delay <= 0)
|
|
43436
44386
|
return;
|
|
43437
|
-
await new Promise((
|
|
44387
|
+
await new Promise((resolve5) => setTimeout(resolve5, delay));
|
|
43438
44388
|
}
|
|
43439
44389
|
applyEnergyPersonality(systemPrompt) {
|
|
43440
44390
|
if (!systemPrompt)
|
|
@@ -43461,6 +44411,9 @@ ${effects.message}
|
|
|
43461
44411
|
const now2 = Date.now();
|
|
43462
44412
|
const due = await getDueSchedules(this.cwd, now2);
|
|
43463
44413
|
for (const schedule of due) {
|
|
44414
|
+
if (schedule.sessionId && schedule.sessionId !== this.sessionId) {
|
|
44415
|
+
continue;
|
|
44416
|
+
}
|
|
43464
44417
|
const locked = await acquireScheduleLock(this.cwd, schedule.id, this.sessionId);
|
|
43465
44418
|
if (!locked)
|
|
43466
44419
|
continue;
|
|
@@ -43490,7 +44443,7 @@ ${effects.message}
|
|
|
43490
44443
|
if (!schedule)
|
|
43491
44444
|
break;
|
|
43492
44445
|
const current = await readSchedule(this.cwd, schedule.id);
|
|
43493
|
-
if (!current || current.status !== "active" || !current.nextRunAt || current.nextRunAt > Date.now()) {
|
|
44446
|
+
if (!current || current.status !== "active" || !current.nextRunAt || current.nextRunAt > Date.now() || current.sessionId && current.sessionId !== this.sessionId) {
|
|
43494
44447
|
await releaseScheduleLock(this.cwd, schedule.id, this.sessionId);
|
|
43495
44448
|
continue;
|
|
43496
44449
|
}
|
|
@@ -43542,6 +44495,9 @@ ${effects.message}
|
|
|
43542
44495
|
if (this.extraSystemPrompt) {
|
|
43543
44496
|
this.context.addSystemMessage(this.extraSystemPrompt);
|
|
43544
44497
|
}
|
|
44498
|
+
if (this.projectContext) {
|
|
44499
|
+
this.setProjectContext(this.projectContext);
|
|
44500
|
+
}
|
|
43545
44501
|
this.contextManager?.refreshState(this.context.getMessages());
|
|
43546
44502
|
}
|
|
43547
44503
|
buildSystemPrompt(messages) {
|
|
@@ -43628,7 +44584,7 @@ ${this.identityContext}`);
|
|
|
43628
44584
|
return null;
|
|
43629
44585
|
const intervalMs = Math.max(1000, config.heartbeat?.intervalMs ?? 15000);
|
|
43630
44586
|
const staleThresholdMs = Math.max(intervalMs * 2, config.heartbeat?.staleThresholdMs ?? 120000);
|
|
43631
|
-
const persistPath = config.heartbeat?.persistPath ??
|
|
44587
|
+
const persistPath = config.heartbeat?.persistPath ?? join19(getConfigDir(), "heartbeats", `${this.sessionId}.json`);
|
|
43632
44588
|
return {
|
|
43633
44589
|
intervalMs,
|
|
43634
44590
|
staleThresholdMs,
|
|
@@ -43720,17 +44676,17 @@ function parseErrorCode(message) {
|
|
|
43720
44676
|
init_src();
|
|
43721
44677
|
// packages/core/src/migration/migrate-to-assistants.ts
|
|
43722
44678
|
import { existsSync as existsSync11 } from "fs";
|
|
43723
|
-
import { mkdir as
|
|
43724
|
-
import { join as
|
|
44679
|
+
import { mkdir as mkdir6, readFile as readFile9, writeFile as writeFile8, rename, cp } from "fs/promises";
|
|
44680
|
+
import { join as join20 } from "path";
|
|
43725
44681
|
import { homedir as homedir10 } from "os";
|
|
43726
44682
|
var MIGRATION_MARKER = ".migrated-from-oldpal";
|
|
43727
44683
|
async function ensureDir(path2) {
|
|
43728
|
-
await
|
|
44684
|
+
await mkdir6(path2, { recursive: true });
|
|
43729
44685
|
}
|
|
43730
44686
|
async function copyIfExists(source, destination) {
|
|
43731
44687
|
if (!existsSync11(source))
|
|
43732
44688
|
return false;
|
|
43733
|
-
await ensureDir(
|
|
44689
|
+
await ensureDir(join20(destination, ".."));
|
|
43734
44690
|
await cp(source, destination, { recursive: true });
|
|
43735
44691
|
return true;
|
|
43736
44692
|
}
|
|
@@ -43738,7 +44694,7 @@ async function readJson(path2) {
|
|
|
43738
44694
|
if (!existsSync11(path2))
|
|
43739
44695
|
return null;
|
|
43740
44696
|
try {
|
|
43741
|
-
const raw = await
|
|
44697
|
+
const raw = await readFile9(path2, "utf-8");
|
|
43742
44698
|
return JSON.parse(raw);
|
|
43743
44699
|
} catch {
|
|
43744
44700
|
return null;
|
|
@@ -43751,14 +44707,14 @@ async function migrateFromOldpal() {
|
|
|
43751
44707
|
errors: []
|
|
43752
44708
|
};
|
|
43753
44709
|
const home = homedir10();
|
|
43754
|
-
const oldPath =
|
|
43755
|
-
const newPath =
|
|
44710
|
+
const oldPath = join20(home, ".oldpal");
|
|
44711
|
+
const newPath = join20(home, ".assistants");
|
|
43756
44712
|
if (!existsSync11(oldPath)) {
|
|
43757
44713
|
result.success = true;
|
|
43758
44714
|
return result;
|
|
43759
44715
|
}
|
|
43760
44716
|
if (existsSync11(newPath)) {
|
|
43761
|
-
const marker =
|
|
44717
|
+
const marker = join20(newPath, "migration", MIGRATION_MARKER);
|
|
43762
44718
|
if (existsSync11(marker)) {
|
|
43763
44719
|
result.success = true;
|
|
43764
44720
|
return result;
|
|
@@ -43768,31 +44724,31 @@ async function migrateFromOldpal() {
|
|
|
43768
44724
|
}
|
|
43769
44725
|
try {
|
|
43770
44726
|
await ensureDir(newPath);
|
|
43771
|
-
await ensureDir(
|
|
43772
|
-
await ensureDir(
|
|
43773
|
-
await ensureDir(
|
|
43774
|
-
await ensureDir(
|
|
43775
|
-
const config = await readJson(
|
|
44727
|
+
await ensureDir(join20(newPath, "assistants"));
|
|
44728
|
+
await ensureDir(join20(newPath, "shared", "skills"));
|
|
44729
|
+
await ensureDir(join20(newPath, "logs"));
|
|
44730
|
+
await ensureDir(join20(newPath, "migration"));
|
|
44731
|
+
const config = await readJson(join20(oldPath, "settings.json"));
|
|
43776
44732
|
if (config) {
|
|
43777
|
-
await
|
|
44733
|
+
await writeFile8(join20(newPath, "config.json"), JSON.stringify(config, null, 2));
|
|
43778
44734
|
result.migrated.push("config.json");
|
|
43779
44735
|
}
|
|
43780
|
-
if (await copyIfExists(
|
|
44736
|
+
if (await copyIfExists(join20(oldPath, "settings.local.json"), join20(newPath, "config.local.json"))) {
|
|
43781
44737
|
result.migrated.push("config.local.json");
|
|
43782
44738
|
}
|
|
43783
|
-
if (await copyIfExists(
|
|
44739
|
+
if (await copyIfExists(join20(oldPath, "hooks.json"), join20(newPath, "hooks.json"))) {
|
|
43784
44740
|
result.migrated.push("hooks.json");
|
|
43785
44741
|
}
|
|
43786
|
-
if (await copyIfExists(
|
|
44742
|
+
if (await copyIfExists(join20(oldPath, "commands"), join20(newPath, "commands"))) {
|
|
43787
44743
|
result.migrated.push("commands");
|
|
43788
44744
|
}
|
|
43789
|
-
if (await copyIfExists(
|
|
44745
|
+
if (await copyIfExists(join20(oldPath, "OLDPAL.md"), join20(newPath, "ASSISTANTS.md"))) {
|
|
43790
44746
|
result.migrated.push("ASSISTANTS.md");
|
|
43791
44747
|
}
|
|
43792
|
-
if (await copyIfExists(
|
|
44748
|
+
if (await copyIfExists(join20(oldPath, "skills"), join20(newPath, "shared", "skills"))) {
|
|
43793
44749
|
result.migrated.push("skills");
|
|
43794
44750
|
}
|
|
43795
|
-
if (await copyIfExists(
|
|
44751
|
+
if (await copyIfExists(join20(oldPath, "logs"), join20(newPath, "logs"))) {
|
|
43796
44752
|
result.migrated.push("logs");
|
|
43797
44753
|
}
|
|
43798
44754
|
const manager = new AssistantManager(newPath);
|
|
@@ -43807,10 +44763,10 @@ async function migrateFromOldpal() {
|
|
|
43807
44763
|
const identityManager = manager.getIdentityManager(assistant.id);
|
|
43808
44764
|
await identityManager.initialize();
|
|
43809
44765
|
await identityManager.createIdentity({ name: "Default" });
|
|
43810
|
-
if (await copyIfExists(
|
|
44766
|
+
if (await copyIfExists(join20(oldPath, "sessions"), join20(newPath, "assistants", assistant.id, "sessions"))) {
|
|
43811
44767
|
result.migrated.push("sessions");
|
|
43812
44768
|
}
|
|
43813
|
-
await
|
|
44769
|
+
await writeFile8(join20(newPath, "migration", MIGRATION_MARKER), JSON.stringify({ migratedAt: new Date().toISOString() }, null, 2));
|
|
43814
44770
|
const backupPath = `${oldPath}.backup`;
|
|
43815
44771
|
await rename(oldPath, backupPath);
|
|
43816
44772
|
result.backupPath = backupPath;
|
|
@@ -43828,17 +44784,17 @@ init_src();
|
|
|
43828
44784
|
|
|
43829
44785
|
// packages/core/src/logger.ts
|
|
43830
44786
|
import { existsSync as existsSync12, mkdirSync as mkdirSync6, appendFileSync, readdirSync as readdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
43831
|
-
import { join as
|
|
44787
|
+
import { join as join21 } from "path";
|
|
43832
44788
|
class Logger {
|
|
43833
44789
|
logDir;
|
|
43834
44790
|
logFile;
|
|
43835
44791
|
sessionId;
|
|
43836
44792
|
constructor(sessionId, basePath) {
|
|
43837
44793
|
this.sessionId = sessionId;
|
|
43838
|
-
this.logDir =
|
|
44794
|
+
this.logDir = join21(basePath || getConfigDir(), "logs");
|
|
43839
44795
|
this.ensureDir(this.logDir);
|
|
43840
44796
|
const date = new Date().toISOString().split("T")[0];
|
|
43841
|
-
this.logFile =
|
|
44797
|
+
this.logFile = join21(this.logDir, `${date}.log`);
|
|
43842
44798
|
}
|
|
43843
44799
|
ensureDir(dir) {
|
|
43844
44800
|
if (!existsSync12(dir)) {
|
|
@@ -43882,9 +44838,9 @@ class SessionStorage {
|
|
|
43882
44838
|
constructor(sessionId, basePath, assistantId) {
|
|
43883
44839
|
this.sessionId = sessionId;
|
|
43884
44840
|
const root = basePath || getConfigDir();
|
|
43885
|
-
this.sessionsDir = assistantId ?
|
|
44841
|
+
this.sessionsDir = assistantId ? join21(root, "assistants", assistantId, "sessions") : join21(root, "sessions");
|
|
43886
44842
|
this.ensureDir(this.sessionsDir);
|
|
43887
|
-
this.sessionFile =
|
|
44843
|
+
this.sessionFile = join21(this.sessionsDir, `${sessionId}.json`);
|
|
43888
44844
|
}
|
|
43889
44845
|
ensureDir(dir) {
|
|
43890
44846
|
if (!existsSync12(dir)) {
|
|
@@ -43910,7 +44866,7 @@ class SessionStorage {
|
|
|
43910
44866
|
}
|
|
43911
44867
|
static getActiveAssistantId() {
|
|
43912
44868
|
try {
|
|
43913
|
-
const activePath =
|
|
44869
|
+
const activePath = join21(getConfigDir(), "active.json");
|
|
43914
44870
|
if (!existsSync12(activePath))
|
|
43915
44871
|
return null;
|
|
43916
44872
|
const raw = readFileSync6(activePath, "utf-8");
|
|
@@ -43924,12 +44880,12 @@ class SessionStorage {
|
|
|
43924
44880
|
const root = getConfigDir();
|
|
43925
44881
|
const resolvedId = assistantId ?? SessionStorage.getActiveAssistantId();
|
|
43926
44882
|
if (resolvedId) {
|
|
43927
|
-
const assistantDir =
|
|
44883
|
+
const assistantDir = join21(root, "assistants", resolvedId, "sessions");
|
|
43928
44884
|
if (existsSync12(assistantDir)) {
|
|
43929
44885
|
return assistantDir;
|
|
43930
44886
|
}
|
|
43931
44887
|
}
|
|
43932
|
-
return
|
|
44888
|
+
return join21(root, "sessions");
|
|
43933
44889
|
}
|
|
43934
44890
|
static listSessions(assistantId) {
|
|
43935
44891
|
const sessionsDir = SessionStorage.resolveSessionsDir(assistantId);
|
|
@@ -43941,7 +44897,7 @@ class SessionStorage {
|
|
|
43941
44897
|
if (!file.endsWith(".json"))
|
|
43942
44898
|
continue;
|
|
43943
44899
|
try {
|
|
43944
|
-
const filePath =
|
|
44900
|
+
const filePath = join21(sessionsDir, file);
|
|
43945
44901
|
const stat = Bun.file(filePath);
|
|
43946
44902
|
const content = JSON.parse(readFileSync6(filePath, "utf-8"));
|
|
43947
44903
|
sessions.push({
|
|
@@ -43961,7 +44917,7 @@ class SessionStorage {
|
|
|
43961
44917
|
}
|
|
43962
44918
|
static loadSession(sessionId, assistantId) {
|
|
43963
44919
|
const sessionsDir = SessionStorage.resolveSessionsDir(assistantId);
|
|
43964
|
-
const sessionFile =
|
|
44920
|
+
const sessionFile = join21(sessionsDir, `${sessionId}.json`);
|
|
43965
44921
|
try {
|
|
43966
44922
|
if (!existsSync12(sessionFile))
|
|
43967
44923
|
return null;
|
|
@@ -43975,15 +44931,15 @@ function initAssistantsDir() {
|
|
|
43975
44931
|
const baseDir = getConfigDir();
|
|
43976
44932
|
const dirs = [
|
|
43977
44933
|
baseDir,
|
|
43978
|
-
|
|
43979
|
-
|
|
43980
|
-
|
|
43981
|
-
|
|
43982
|
-
|
|
43983
|
-
|
|
43984
|
-
|
|
43985
|
-
|
|
43986
|
-
|
|
44934
|
+
join21(baseDir, "logs"),
|
|
44935
|
+
join21(baseDir, "assistants"),
|
|
44936
|
+
join21(baseDir, "shared", "skills"),
|
|
44937
|
+
join21(baseDir, "commands"),
|
|
44938
|
+
join21(baseDir, "temp"),
|
|
44939
|
+
join21(baseDir, "heartbeats"),
|
|
44940
|
+
join21(baseDir, "state"),
|
|
44941
|
+
join21(baseDir, "energy"),
|
|
44942
|
+
join21(baseDir, "migration")
|
|
43987
44943
|
];
|
|
43988
44944
|
for (const dir of dirs) {
|
|
43989
44945
|
if (!existsSync12(dir)) {
|
|
@@ -44026,6 +44982,11 @@ class EmbeddedClient {
|
|
|
44026
44982
|
for (const callback of this.chunkCallbacks) {
|
|
44027
44983
|
callback(chunk);
|
|
44028
44984
|
}
|
|
44985
|
+
if (chunk.type === "done" || chunk.type === "error") {
|
|
44986
|
+
queueMicrotask(() => {
|
|
44987
|
+
this.drainQueue();
|
|
44988
|
+
});
|
|
44989
|
+
}
|
|
44029
44990
|
},
|
|
44030
44991
|
onToolStart: (toolCall) => {
|
|
44031
44992
|
this.logger.info("Tool started", { tool: toolCall.name, input: toolCall.input });
|
|
@@ -44068,12 +45029,11 @@ class EmbeddedClient {
|
|
|
44068
45029
|
if (!this.initialized) {
|
|
44069
45030
|
await this.initialize();
|
|
44070
45031
|
}
|
|
44071
|
-
|
|
44072
|
-
|
|
44073
|
-
this.
|
|
45032
|
+
this.messageQueue.push(message);
|
|
45033
|
+
if (this.agent.isProcessing() || this.processingQueue) {
|
|
45034
|
+
this.logger.info("Queuing message (agent busy)", { message, queueLength: this.messageQueue.length });
|
|
44074
45035
|
return;
|
|
44075
45036
|
}
|
|
44076
|
-
await this.processMessage(message);
|
|
44077
45037
|
await this.drainQueue();
|
|
44078
45038
|
}
|
|
44079
45039
|
async processMessage(message) {
|
|
@@ -44464,10 +45424,13 @@ var COMMANDS = [
|
|
|
44464
45424
|
{ name: "/model", description: "show model information" },
|
|
44465
45425
|
{ name: "/skills", description: "list available skills" },
|
|
44466
45426
|
{ name: "/config", description: "show configuration" },
|
|
45427
|
+
{ name: "/projects", description: "manage projects in this folder" },
|
|
45428
|
+
{ name: "/plans", description: "manage project plans" },
|
|
44467
45429
|
{ name: "/connectors", description: "list available connectors" },
|
|
44468
45430
|
{ name: "/init", description: "initialize assistants in project" },
|
|
44469
45431
|
{ name: "/compact", description: "summarize to save context" },
|
|
44470
45432
|
{ name: "/memory", description: "show what AI remembers" },
|
|
45433
|
+
{ name: "/context", description: "manage injected project context" },
|
|
44471
45434
|
{ name: "/feedback", description: "submit feedback on GitHub" },
|
|
44472
45435
|
{ name: "/schedule", description: "schedule a command" },
|
|
44473
45436
|
{ name: "/schedules", description: "list scheduled commands" },
|
|
@@ -44513,15 +45476,23 @@ function Input({ onSubmit, isProcessing, queueLength = 0, commands, skills = []
|
|
|
44513
45476
|
}, [value, autocompleteMode, skills]);
|
|
44514
45477
|
const autocompleteItems = autocompleteMode === "skill" ? filteredSkills : filteredCommands;
|
|
44515
45478
|
use_input_default((input, key) => {
|
|
44516
|
-
if (key.tab
|
|
44517
|
-
|
|
44518
|
-
|
|
44519
|
-
|
|
44520
|
-
|
|
44521
|
-
|
|
45479
|
+
if (key.tab) {
|
|
45480
|
+
if (autocompleteItems.length > 0) {
|
|
45481
|
+
const selected = autocompleteItems[selectedIndex] || autocompleteItems[0];
|
|
45482
|
+
if (autocompleteMode === "skill") {
|
|
45483
|
+
setValue("$" + selected.name + " ");
|
|
45484
|
+
} else {
|
|
45485
|
+
setValue(selected.name + " ");
|
|
45486
|
+
}
|
|
45487
|
+
setSelectedIndex(0);
|
|
45488
|
+
return;
|
|
45489
|
+
}
|
|
45490
|
+
if (value.trim()) {
|
|
45491
|
+
onSubmit(value, "queue");
|
|
45492
|
+
setValue("");
|
|
45493
|
+
setSelectedIndex(0);
|
|
45494
|
+
return;
|
|
44522
45495
|
}
|
|
44523
|
-
setSelectedIndex(0);
|
|
44524
|
-
return;
|
|
44525
45496
|
}
|
|
44526
45497
|
if (autocompleteItems.length > 0) {
|
|
44527
45498
|
if (key.downArrow) {
|
|
@@ -44555,18 +45526,14 @@ function Input({ onSubmit, isProcessing, queueLength = 0, commands, skills = []
|
|
|
44555
45526
|
if (autocompleteMode === "command" && filteredCommands.length > 0 && !submittedValue.includes(" ")) {
|
|
44556
45527
|
const selected = filteredCommands[selectedIndex] || filteredCommands[0];
|
|
44557
45528
|
if (selected) {
|
|
44558
|
-
|
|
44559
|
-
onSubmit(selected.name, "queue");
|
|
44560
|
-
} else {
|
|
44561
|
-
onSubmit(selected.name, "normal");
|
|
44562
|
-
}
|
|
45529
|
+
onSubmit(selected.name, isProcessing ? "inline" : "normal");
|
|
44563
45530
|
setValue("");
|
|
44564
45531
|
setSelectedIndex(0);
|
|
44565
45532
|
return;
|
|
44566
45533
|
}
|
|
44567
45534
|
}
|
|
44568
45535
|
if (isProcessing) {
|
|
44569
|
-
onSubmit(submittedValue, "
|
|
45536
|
+
onSubmit(submittedValue, "inline");
|
|
44570
45537
|
} else {
|
|
44571
45538
|
onSubmit(submittedValue, "normal");
|
|
44572
45539
|
}
|
|
@@ -44577,7 +45544,7 @@ function Input({ onSubmit, isProcessing, queueLength = 0, commands, skills = []
|
|
|
44577
45544
|
let placeholder = "Type a message...";
|
|
44578
45545
|
if (isProcessing) {
|
|
44579
45546
|
prompt = "\u22EF";
|
|
44580
|
-
placeholder = queueLength > 0 ? "Type to queue
|
|
45547
|
+
placeholder = queueLength > 0 ? "Type to send (Enter) or queue (Tab) \xB7 Shift+Enter to interrupt..." : "Type to send (Enter) or queue (Tab) \xB7 Shift+Enter to interrupt...";
|
|
44581
45548
|
}
|
|
44582
45549
|
const truncateDescription = (desc, maxLen = 60) => {
|
|
44583
45550
|
if (desc.length <= maxLen)
|
|
@@ -44718,7 +45685,12 @@ var import_react24 = __toESM(require_react(), 1);
|
|
|
44718
45685
|
|
|
44719
45686
|
// packages/terminal/src/components/Markdown.tsx
|
|
44720
45687
|
var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
|
|
44721
|
-
function Markdown({ content }) {
|
|
45688
|
+
function Markdown({ content, preRendered = false }) {
|
|
45689
|
+
if (preRendered) {
|
|
45690
|
+
return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
|
|
45691
|
+
children: content
|
|
45692
|
+
}, undefined, false, undefined, this);
|
|
45693
|
+
}
|
|
44722
45694
|
const { columns } = use_stdout_default();
|
|
44723
45695
|
const maxWidth = columns ? Math.max(20, columns - 2) : undefined;
|
|
44724
45696
|
const rendered = parseMarkdown(content, { maxWidth });
|
|
@@ -44726,6 +45698,9 @@ function Markdown({ content }) {
|
|
|
44726
45698
|
children: rendered
|
|
44727
45699
|
}, undefined, false, undefined, this);
|
|
44728
45700
|
}
|
|
45701
|
+
function renderMarkdown(text, options) {
|
|
45702
|
+
return parseMarkdown(text, { maxWidth: options?.maxWidth });
|
|
45703
|
+
}
|
|
44729
45704
|
function parseMarkdown(text, options) {
|
|
44730
45705
|
let result = text;
|
|
44731
45706
|
const codeBlocks = [];
|
|
@@ -44751,7 +45726,7 @@ function parseMarkdown(text, options) {
|
|
|
44751
45726
|
result = result.replace(/\b(Building|Running|Working|Queued|Pending|Connecting)\b/gi, (match) => source_default.yellow(match));
|
|
44752
45727
|
result = result.replace(/\b(Success|Succeeded|Done|Complete|Completed|Connected|Authenticated)\b/gi, (match) => source_default.green(match));
|
|
44753
45728
|
result = result.replace(/\b(Error|Failed|Failure|Denied|Blocked)\b/gi, (match) => source_default.red(match));
|
|
44754
|
-
result = formatMarkdownTables(result);
|
|
45729
|
+
result = formatMarkdownTables(result, options?.maxWidth);
|
|
44755
45730
|
result = result.replace(/@@BLOCKSECTION(\d+)@@/g, (_, index) => {
|
|
44756
45731
|
const section = blockSections[parseInt(index, 10)];
|
|
44757
45732
|
if (!section)
|
|
@@ -44765,6 +45740,7 @@ function parseMarkdown(text, options) {
|
|
|
44765
45740
|
});
|
|
44766
45741
|
return result.trimEnd();
|
|
44767
45742
|
}
|
|
45743
|
+
var ALLOWED_BLOCK_TYPES = new Set(["info", "success", "warning", "error", "note", "command"]);
|
|
44768
45744
|
function extractBlockSections(text, blocks) {
|
|
44769
45745
|
const lines = text.split(`
|
|
44770
45746
|
`);
|
|
@@ -44793,6 +45769,9 @@ function extractBlockSections(text, blocks) {
|
|
|
44793
45769
|
i += 1;
|
|
44794
45770
|
continue;
|
|
44795
45771
|
}
|
|
45772
|
+
if (parsed.warning) {
|
|
45773
|
+
output.push(createMalformedBlock(blocks, indent, "grid", parsed.warning));
|
|
45774
|
+
}
|
|
44796
45775
|
const bodyLines = stripIndent(parsed.bodyLines, indent);
|
|
44797
45776
|
const body = bodyLines.join(`
|
|
44798
45777
|
`);
|
|
@@ -44806,7 +45785,7 @@ function extractBlockSections(text, blocks) {
|
|
|
44806
45785
|
const indent = blockMatch[1] ?? "";
|
|
44807
45786
|
const header = blockMatch[2] ?? "";
|
|
44808
45787
|
const attrs = parseAttributes(header);
|
|
44809
|
-
|
|
45788
|
+
let type = String(attrs.type || "info");
|
|
44810
45789
|
const title = attrs.title ? String(attrs.title) : undefined;
|
|
44811
45790
|
const parsed = parseDelimitedBlock(lines, i, indent);
|
|
44812
45791
|
if (!parsed) {
|
|
@@ -44815,6 +45794,14 @@ function extractBlockSections(text, blocks) {
|
|
|
44815
45794
|
i += 1;
|
|
44816
45795
|
continue;
|
|
44817
45796
|
}
|
|
45797
|
+
const normalizedType = type.toLowerCase();
|
|
45798
|
+
if (!ALLOWED_BLOCK_TYPES.has(normalizedType)) {
|
|
45799
|
+
output.push(createMalformedBlock(blocks, indent, "block", `Unknown block type "${type}". Using info.`));
|
|
45800
|
+
type = "info";
|
|
45801
|
+
}
|
|
45802
|
+
if (parsed.warning) {
|
|
45803
|
+
output.push(createMalformedBlock(blocks, indent, "block", parsed.warning));
|
|
45804
|
+
}
|
|
44818
45805
|
const body = stripIndent(parsed.bodyLines, indent).join(`
|
|
44819
45806
|
`);
|
|
44820
45807
|
blocks.push({ kind: "block", type, title, body, indent });
|
|
@@ -44831,6 +45818,9 @@ function extractBlockSections(text, blocks) {
|
|
|
44831
45818
|
i += 1;
|
|
44832
45819
|
continue;
|
|
44833
45820
|
}
|
|
45821
|
+
if (parsed.warning) {
|
|
45822
|
+
output.push(createMalformedBlock(blocks, indent, "report", parsed.warning));
|
|
45823
|
+
}
|
|
44834
45824
|
const body = stripIndent(parsed.bodyLines, indent).join(`
|
|
44835
45825
|
`);
|
|
44836
45826
|
blocks.push({ kind: "report", body, indent });
|
|
@@ -44862,10 +45852,14 @@ function extractCards(body) {
|
|
|
44862
45852
|
const title = attrs.title ? String(attrs.title) : undefined;
|
|
44863
45853
|
const bodyLines = [];
|
|
44864
45854
|
let closed = false;
|
|
45855
|
+
let indentWarning;
|
|
44865
45856
|
i += 1;
|
|
44866
45857
|
while (i < lines.length) {
|
|
44867
45858
|
const current = lines[i];
|
|
44868
|
-
if (current.trim() === ":::"
|
|
45859
|
+
if (current.trim() === ":::") {
|
|
45860
|
+
if (indent.length > 0 && !current.startsWith(indent)) {
|
|
45861
|
+
indentWarning = "Card closing ::: indentation did not match opening.";
|
|
45862
|
+
}
|
|
44869
45863
|
closed = true;
|
|
44870
45864
|
i += 1;
|
|
44871
45865
|
break;
|
|
@@ -44882,6 +45876,13 @@ function extractCards(body) {
|
|
|
44882
45876
|
break;
|
|
44883
45877
|
}
|
|
44884
45878
|
const stripped = stripIndent(bodyLines, indent);
|
|
45879
|
+
if (indentWarning) {
|
|
45880
|
+
cards.push({
|
|
45881
|
+
type: "warning",
|
|
45882
|
+
title: "Malformed card",
|
|
45883
|
+
body: indentWarning
|
|
45884
|
+
});
|
|
45885
|
+
}
|
|
44885
45886
|
cards.push({ type, title, body: stripped.join(`
|
|
44886
45887
|
`) });
|
|
44887
45888
|
}
|
|
@@ -44890,6 +45891,7 @@ function extractCards(body) {
|
|
|
44890
45891
|
function parseDelimitedBlock(lines, startIndex, indent) {
|
|
44891
45892
|
const bodyLines = [];
|
|
44892
45893
|
let openCards = 0;
|
|
45894
|
+
let warning;
|
|
44893
45895
|
let i = startIndex + 1;
|
|
44894
45896
|
while (i < lines.length) {
|
|
44895
45897
|
const current = lines[i];
|
|
@@ -44900,14 +45902,18 @@ function parseDelimitedBlock(lines, startIndex, indent) {
|
|
|
44900
45902
|
i += 1;
|
|
44901
45903
|
continue;
|
|
44902
45904
|
}
|
|
44903
|
-
if (trimmed === ":::"
|
|
45905
|
+
if (trimmed === ":::") {
|
|
45906
|
+
const indentMismatch = indent.length > 0 && !current.startsWith(indent);
|
|
44904
45907
|
if (openCards > 0) {
|
|
44905
45908
|
openCards -= 1;
|
|
44906
45909
|
bodyLines.push(current);
|
|
44907
45910
|
i += 1;
|
|
44908
45911
|
continue;
|
|
44909
45912
|
}
|
|
44910
|
-
|
|
45913
|
+
if (indentMismatch) {
|
|
45914
|
+
warning = "Closing ::: indentation did not match opening. Adjust indentation for consistency.";
|
|
45915
|
+
}
|
|
45916
|
+
return { bodyLines, nextIndex: i + 1, warning };
|
|
44911
45917
|
}
|
|
44912
45918
|
bodyLines.push(current);
|
|
44913
45919
|
i += 1;
|
|
@@ -45074,7 +46080,7 @@ function formatBoxRow(line, width) {
|
|
|
45074
46080
|
const padded = len < width ? line + " ".repeat(width - len) : line;
|
|
45075
46081
|
return `\u2502 ${padded} \u2502`;
|
|
45076
46082
|
}
|
|
45077
|
-
function formatMarkdownTables(text) {
|
|
46083
|
+
function formatMarkdownTables(text, maxWidth) {
|
|
45078
46084
|
const lines = text.split(`
|
|
45079
46085
|
`);
|
|
45080
46086
|
const output = [];
|
|
@@ -45092,7 +46098,7 @@ function formatMarkdownTables(text) {
|
|
|
45092
46098
|
rows.push(parseTableRow(lines[i]));
|
|
45093
46099
|
i += 1;
|
|
45094
46100
|
}
|
|
45095
|
-
const table = renderTable(header, rows);
|
|
46101
|
+
const table = renderTable(header, rows, maxWidth);
|
|
45096
46102
|
output.push(...table);
|
|
45097
46103
|
continue;
|
|
45098
46104
|
}
|
|
@@ -45107,7 +46113,7 @@ function parseTableRow(line) {
|
|
|
45107
46113
|
const withoutEdges = trimmed.replace(/^\|/, "").replace(/\|$/, "");
|
|
45108
46114
|
return withoutEdges.split("|").map((cell) => cell.trim());
|
|
45109
46115
|
}
|
|
45110
|
-
function renderTable(header, rows) {
|
|
46116
|
+
function renderTable(header, rows, maxWidth) {
|
|
45111
46117
|
const colCount = Math.max(header.length, ...rows.map((r) => r.length));
|
|
45112
46118
|
const widths = new Array(colCount).fill(0);
|
|
45113
46119
|
const allRows = [header, ...rows];
|
|
@@ -45119,11 +46125,29 @@ function renderTable(header, rows) {
|
|
|
45119
46125
|
widths[i] = len;
|
|
45120
46126
|
}
|
|
45121
46127
|
}
|
|
46128
|
+
const minCellWidth = 4;
|
|
46129
|
+
const availableCellWidth = maxWidth ? Math.max(colCount * minCellWidth, maxWidth - (colCount - 1) * 3 - 4) : undefined;
|
|
46130
|
+
if (availableCellWidth) {
|
|
46131
|
+
const total = widths.reduce((sum, width) => sum + width, 0);
|
|
46132
|
+
if (total > availableCellWidth) {
|
|
46133
|
+
const minWidth = Math.max(1, Math.floor(availableCellWidth / colCount));
|
|
46134
|
+
while (widths.reduce((sum, width) => sum + width, 0) > availableCellWidth) {
|
|
46135
|
+
const maxWidthValue = Math.max(...widths);
|
|
46136
|
+
const idx = widths.findIndex((width) => width === maxWidthValue);
|
|
46137
|
+
if (idx === -1)
|
|
46138
|
+
break;
|
|
46139
|
+
if (widths[idx] <= minWidth)
|
|
46140
|
+
break;
|
|
46141
|
+
widths[idx] -= 1;
|
|
46142
|
+
}
|
|
46143
|
+
}
|
|
46144
|
+
}
|
|
45122
46145
|
const pad = (value, width) => {
|
|
45123
|
-
const
|
|
46146
|
+
const rendered = width > 0 ? truncateAnsi(value, width) : value;
|
|
46147
|
+
const len = stripAnsi2(rendered).length;
|
|
45124
46148
|
if (len >= width)
|
|
45125
|
-
return
|
|
45126
|
-
return
|
|
46149
|
+
return rendered;
|
|
46150
|
+
return rendered + " ".repeat(width - len);
|
|
45127
46151
|
};
|
|
45128
46152
|
const top = "\u250C" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u252C") + "\u2510";
|
|
45129
46153
|
const mid = "\u251C" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u253C") + "\u2524";
|
|
@@ -45201,7 +46225,8 @@ function renderReport(body, maxWidth, indent = "") {
|
|
|
45201
46225
|
}
|
|
45202
46226
|
if (tableLines.length > 0) {
|
|
45203
46227
|
output.push(indent + source_default.bold("Detailed Status Table"));
|
|
45204
|
-
const
|
|
46228
|
+
const adjustedWidth = maxWidth ? Math.max(20, maxWidth - indent.length) : undefined;
|
|
46229
|
+
const rendered = renderReportTable(tableLines, indent, adjustedWidth);
|
|
45205
46230
|
output.push(...rendered);
|
|
45206
46231
|
}
|
|
45207
46232
|
return output.join(`
|
|
@@ -45230,7 +46255,7 @@ function renderProgressLine(label, value, labelWidth, barWidth) {
|
|
|
45230
46255
|
const bar = source_default.gray("\u2591".repeat(empty));
|
|
45231
46256
|
return `${label.padEnd(labelWidth)} [${fill}${bar}] ${value}%`;
|
|
45232
46257
|
}
|
|
45233
|
-
function renderReportTable(lines, indent) {
|
|
46258
|
+
function renderReportTable(lines, indent, maxWidth) {
|
|
45234
46259
|
const tableLines = lines.map((line) => line.trim()).filter(Boolean);
|
|
45235
46260
|
if (tableLines.length < 2)
|
|
45236
46261
|
return [];
|
|
@@ -45254,7 +46279,7 @@ function renderReportTable(lines, indent) {
|
|
|
45254
46279
|
}
|
|
45255
46280
|
return next;
|
|
45256
46281
|
});
|
|
45257
|
-
return renderTable(header, styledRows).map((line) => indent + line);
|
|
46282
|
+
return renderTable(header, styledRows, maxWidth).map((line) => indent + line);
|
|
45258
46283
|
}
|
|
45259
46284
|
function decoratePriority(value) {
|
|
45260
46285
|
const normalized = value.toLowerCase();
|
|
@@ -45324,6 +46349,23 @@ function wrapAnsiLine(line, width) {
|
|
|
45324
46349
|
function truncateAnsi(line, width) {
|
|
45325
46350
|
if (stripAnsi2(line).length <= width)
|
|
45326
46351
|
return line;
|
|
46352
|
+
if (width <= 3) {
|
|
46353
|
+
let result = "";
|
|
46354
|
+
let visible2 = 0;
|
|
46355
|
+
let i2 = 0;
|
|
46356
|
+
while (i2 < line.length && visible2 < width) {
|
|
46357
|
+
const match = line.slice(i2).match(/^\x1b\[[0-9;]*m/);
|
|
46358
|
+
if (match) {
|
|
46359
|
+
result += match[0];
|
|
46360
|
+
i2 += match[0].length;
|
|
46361
|
+
continue;
|
|
46362
|
+
}
|
|
46363
|
+
result += line[i2];
|
|
46364
|
+
visible2 += 1;
|
|
46365
|
+
i2 += 1;
|
|
46366
|
+
}
|
|
46367
|
+
return result;
|
|
46368
|
+
}
|
|
45327
46369
|
const suffix = "...";
|
|
45328
46370
|
const target = Math.max(0, width - suffix.length);
|
|
45329
46371
|
let current = "";
|
|
@@ -45343,6 +46385,42 @@ function truncateAnsi(line, width) {
|
|
|
45343
46385
|
return current + suffix;
|
|
45344
46386
|
}
|
|
45345
46387
|
|
|
46388
|
+
// packages/terminal/src/components/messageLines.ts
|
|
46389
|
+
function estimateToolPanelLines(toolCalls, toolResults, hasContent) {
|
|
46390
|
+
if (!toolCalls || toolCalls.length === 0) {
|
|
46391
|
+
return 0;
|
|
46392
|
+
}
|
|
46393
|
+
const resultMap = new Set;
|
|
46394
|
+
for (const result of toolResults || []) {
|
|
46395
|
+
resultMap.add(result.toolCallId);
|
|
46396
|
+
}
|
|
46397
|
+
let lines = 3;
|
|
46398
|
+
if (hasContent) {
|
|
46399
|
+
lines += 1;
|
|
46400
|
+
}
|
|
46401
|
+
for (const call of toolCalls) {
|
|
46402
|
+
lines += 3;
|
|
46403
|
+
if (resultMap.has(call.id)) {
|
|
46404
|
+
lines += 1;
|
|
46405
|
+
}
|
|
46406
|
+
}
|
|
46407
|
+
return lines;
|
|
46408
|
+
}
|
|
46409
|
+
function estimateMessageLines(message) {
|
|
46410
|
+
if (message.role === "system") {
|
|
46411
|
+
return 0;
|
|
46412
|
+
}
|
|
46413
|
+
const content = message.content ?? "";
|
|
46414
|
+
const contentLines = content.length > 0 ? content.split(`
|
|
46415
|
+
`).length : 0;
|
|
46416
|
+
const hasContent = contentLines > 0;
|
|
46417
|
+
let lines = Math.max(1, contentLines);
|
|
46418
|
+
if (message.role === "assistant" && message.toolCalls?.length) {
|
|
46419
|
+
lines += estimateToolPanelLines(message.toolCalls, message.toolResults, hasContent);
|
|
46420
|
+
}
|
|
46421
|
+
return lines;
|
|
46422
|
+
}
|
|
46423
|
+
|
|
45346
46424
|
// packages/terminal/src/components/Messages.tsx
|
|
45347
46425
|
var jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
|
|
45348
46426
|
function Messages4({
|
|
@@ -45352,19 +46430,28 @@ function Messages4({
|
|
|
45352
46430
|
currentToolCall,
|
|
45353
46431
|
lastToolResult,
|
|
45354
46432
|
activityLog = [],
|
|
45355
|
-
|
|
45356
|
-
|
|
46433
|
+
scrollOffsetLines = 0,
|
|
46434
|
+
maxVisibleLines = 10,
|
|
45357
46435
|
queuedMessageIds
|
|
45358
46436
|
}) {
|
|
45359
46437
|
const [now2, setNow] = import_react24.useState(Date.now());
|
|
45360
46438
|
const combinedMessages = import_react24.useMemo(() => [...messages, ...streamingMessages], [messages, streamingMessages]);
|
|
45361
|
-
const
|
|
45362
|
-
|
|
45363
|
-
|
|
46439
|
+
const lineSpans = import_react24.useMemo(() => {
|
|
46440
|
+
let cursor = 0;
|
|
46441
|
+
return combinedMessages.map((message, index) => {
|
|
46442
|
+
const lines = estimateMessageLines(message);
|
|
46443
|
+
const start = cursor;
|
|
46444
|
+
cursor += lines;
|
|
46445
|
+
return { message, index, start, end: cursor, lines };
|
|
46446
|
+
});
|
|
46447
|
+
}, [combinedMessages]);
|
|
46448
|
+
const totalLines = lineSpans.length > 0 ? lineSpans[lineSpans.length - 1].end : 0;
|
|
46449
|
+
const endLine = Math.max(0, totalLines - scrollOffsetLines);
|
|
46450
|
+
const startLine = Math.max(0, endLine - maxVisibleLines);
|
|
46451
|
+
const visibleSpans = lineSpans.filter((span) => span.end > startLine && span.start < endLine);
|
|
45364
46452
|
const historicalCount = messages.length;
|
|
45365
|
-
const
|
|
45366
|
-
const
|
|
45367
|
-
const visibleStreaming = visibleCombined.slice(splitIndex);
|
|
46453
|
+
const visibleMessages = visibleSpans.filter((span) => span.index < historicalCount).map((span) => span.message);
|
|
46454
|
+
const visibleStreaming = visibleSpans.filter((span) => span.index >= historicalCount).map((span) => span.message);
|
|
45368
46455
|
const groupedMessages = groupConsecutiveToolMessages(visibleMessages);
|
|
45369
46456
|
const historicalItems = groupedMessages.map((group) => {
|
|
45370
46457
|
if (group.type === "single") {
|
|
@@ -45612,13 +46699,13 @@ function MessageBubble({ message, queuedMessageIds }) {
|
|
|
45612
46699
|
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
45613
46700
|
flexGrow: 1,
|
|
45614
46701
|
children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Markdown, {
|
|
45615
|
-
content: message.content
|
|
46702
|
+
content: message.content,
|
|
46703
|
+
preRendered: Boolean(message.__rendered)
|
|
45616
46704
|
}, undefined, false, undefined, this)
|
|
45617
46705
|
}, undefined, false, undefined, this)
|
|
45618
46706
|
]
|
|
45619
46707
|
}, undefined, true, undefined, this),
|
|
45620
46708
|
toolCalls.length > 0 && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
45621
|
-
marginLeft: hasContent ? 2 : 0,
|
|
45622
46709
|
marginTop: hasContent ? 1 : 0,
|
|
45623
46710
|
children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(ToolCallPanel, {
|
|
45624
46711
|
toolCalls,
|
|
@@ -45634,6 +46721,8 @@ function ToolCallPanel({
|
|
|
45634
46721
|
}) {
|
|
45635
46722
|
if (toolCalls.length === 0)
|
|
45636
46723
|
return null;
|
|
46724
|
+
const { columns } = use_stdout_default();
|
|
46725
|
+
const panelWidth = columns ? Math.max(24, columns - 4) : undefined;
|
|
45637
46726
|
const resultMap = new Map;
|
|
45638
46727
|
for (const result of toolResults || []) {
|
|
45639
46728
|
resultMap.set(result.toolCallId, result);
|
|
@@ -45646,7 +46735,7 @@ function ToolCallPanel({
|
|
|
45646
46735
|
borderStyle: "round",
|
|
45647
46736
|
borderColor,
|
|
45648
46737
|
paddingX: 1,
|
|
45649
|
-
width: "100%",
|
|
46738
|
+
width: panelWidth ?? "100%",
|
|
45650
46739
|
children: [
|
|
45651
46740
|
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
45652
46741
|
justifyContent: "space-between",
|
|
@@ -45672,6 +46761,8 @@ function ToolCallPanel({
|
|
|
45672
46761
|
const statusColor = result ? result.isError ? "red" : "green" : "yellow";
|
|
45673
46762
|
const displayName = getToolDisplayName(toolCall);
|
|
45674
46763
|
const context2 = getToolContext(toolCall);
|
|
46764
|
+
const maxLine = panelWidth ? Math.max(20, panelWidth - 8) : 80;
|
|
46765
|
+
const summaryLine = truncate(formatToolCall(toolCall), maxLine);
|
|
45675
46766
|
return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
45676
46767
|
flexDirection: "column",
|
|
45677
46768
|
marginTop: 1,
|
|
@@ -45701,7 +46792,7 @@ function ToolCallPanel({
|
|
|
45701
46792
|
}, undefined, true, undefined, this),
|
|
45702
46793
|
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
45703
46794
|
dimColor: true,
|
|
45704
|
-
children:
|
|
46795
|
+
children: summaryLine
|
|
45705
46796
|
}, undefined, false, undefined, this),
|
|
45706
46797
|
result && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
45707
46798
|
marginLeft: 2,
|
|
@@ -45736,7 +46827,7 @@ function getToolContext(toolCall) {
|
|
|
45736
46827
|
return truncate(String(input.pattern || ""), 20);
|
|
45737
46828
|
case "schedule":
|
|
45738
46829
|
return String(input.action || "");
|
|
45739
|
-
case "
|
|
46830
|
+
case "submit_feedback":
|
|
45740
46831
|
return String(input.type || "feedback");
|
|
45741
46832
|
case "web_search":
|
|
45742
46833
|
return truncate(String(input.query || ""), 20);
|
|
@@ -46017,46 +47108,7 @@ function formatSearchResult(content) {
|
|
|
46017
47108
|
|
|
46018
47109
|
// packages/terminal/src/components/Status.tsx
|
|
46019
47110
|
var import_react25 = __toESM(require_react(), 1);
|
|
46020
|
-
|
|
46021
|
-
// packages/terminal/src/components/EnergyBar.tsx
|
|
46022
47111
|
var jsx_dev_runtime4 = __toESM(require_jsx_dev_runtime(), 1);
|
|
46023
|
-
function EnergyBar({ current, max }) {
|
|
46024
|
-
const safeMax = Math.max(1, max);
|
|
46025
|
-
const percentage = Math.round(current / safeMax * 100);
|
|
46026
|
-
const barWidth = 16;
|
|
46027
|
-
const filled = Math.round(current / safeMax * barWidth);
|
|
46028
|
-
const empty = Math.max(0, barWidth - filled);
|
|
46029
|
-
const color = percentage > 50 ? "green" : percentage > 20 ? "yellow" : "red";
|
|
46030
|
-
const emoji = percentage > 70 ? "\u26A1" : percentage > 30 ? "\uD83D\uDD0B" : "\uD83E\uDEAB";
|
|
46031
|
-
return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
46032
|
-
children: [
|
|
46033
|
-
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
46034
|
-
children: [
|
|
46035
|
-
emoji,
|
|
46036
|
-
" "
|
|
46037
|
-
]
|
|
46038
|
-
}, undefined, true, undefined, this),
|
|
46039
|
-
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
46040
|
-
color,
|
|
46041
|
-
children: "\u2588".repeat(filled)
|
|
46042
|
-
}, undefined, false, undefined, this),
|
|
46043
|
-
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
46044
|
-
color: "gray",
|
|
46045
|
-
children: "\u2591".repeat(empty)
|
|
46046
|
-
}, undefined, false, undefined, this),
|
|
46047
|
-
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
46048
|
-
children: [
|
|
46049
|
-
" ",
|
|
46050
|
-
percentage,
|
|
46051
|
-
"%"
|
|
46052
|
-
]
|
|
46053
|
-
}, undefined, true, undefined, this)
|
|
46054
|
-
]
|
|
46055
|
-
}, undefined, true, undefined, this);
|
|
46056
|
-
}
|
|
46057
|
-
|
|
46058
|
-
// packages/terminal/src/components/Status.tsx
|
|
46059
|
-
var jsx_dev_runtime5 = __toESM(require_jsx_dev_runtime(), 1);
|
|
46060
47112
|
function Status({
|
|
46061
47113
|
isProcessing,
|
|
46062
47114
|
cwd: cwd2,
|
|
@@ -46094,74 +47146,51 @@ function Status({
|
|
|
46094
47146
|
let contextInfo = "";
|
|
46095
47147
|
if (tokenUsage && tokenUsage.maxContextTokens > 0) {
|
|
46096
47148
|
const percent = Math.round(tokenUsage.totalTokens / tokenUsage.maxContextTokens * 100);
|
|
46097
|
-
contextInfo = `${percent}
|
|
47149
|
+
contextInfo = `${percent}%`;
|
|
46098
47150
|
}
|
|
46099
|
-
const sessionInfo = sessionIndex && sessionCount ?
|
|
46100
|
-
const bgIndicator = backgroundProcessingCount > 0 ? `
|
|
46101
|
-
const
|
|
46102
|
-
|
|
46103
|
-
return /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Box_default, {
|
|
47151
|
+
const sessionInfo = sessionIndex && sessionCount && sessionCount > 1 ? `${sessionIndex}/${sessionCount}` : "";
|
|
47152
|
+
const bgIndicator = backgroundProcessingCount > 0 ? ` +${backgroundProcessingCount}` : "";
|
|
47153
|
+
const voiceIcon = voiceState?.enabled ? voiceState.isListening ? "\uD83C\uDFA4" : voiceState.isSpeaking ? "\uD83D\uDD0A" : "\uD83C\uDF99" : "";
|
|
47154
|
+
return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
46104
47155
|
marginTop: 1,
|
|
46105
47156
|
justifyContent: "space-between",
|
|
46106
47157
|
children: [
|
|
46107
|
-
/* @__PURE__ */
|
|
47158
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
46108
47159
|
dimColor: true,
|
|
46109
47160
|
children: [
|
|
46110
|
-
"/help
|
|
46111
|
-
sessionCount && sessionCount > 1 ? "
|
|
47161
|
+
"/help",
|
|
47162
|
+
sessionCount && sessionCount > 1 ? " \xB7 Ctrl+S" : ""
|
|
46112
47163
|
]
|
|
46113
47164
|
}, undefined, true, undefined, this),
|
|
46114
|
-
/* @__PURE__ */
|
|
47165
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
46115
47166
|
children: [
|
|
46116
|
-
|
|
46117
|
-
marginRight: 2,
|
|
46118
|
-
children: /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(EnergyBar, {
|
|
46119
|
-
current: energyState.current,
|
|
46120
|
-
max: energyState.max
|
|
46121
|
-
}, undefined, false, undefined, this)
|
|
46122
|
-
}, undefined, false, undefined, this),
|
|
46123
|
-
identityLabel && /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
46124
|
-
dimColor: true,
|
|
46125
|
-
children: [
|
|
46126
|
-
identityLabel,
|
|
46127
|
-
" \xB7 "
|
|
46128
|
-
]
|
|
46129
|
-
}, undefined, true, undefined, this),
|
|
46130
|
-
voiceInfo && /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
47167
|
+
voiceIcon && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
46131
47168
|
dimColor: true,
|
|
46132
47169
|
children: [
|
|
46133
|
-
|
|
46134
|
-
"
|
|
47170
|
+
voiceIcon,
|
|
47171
|
+
" "
|
|
46135
47172
|
]
|
|
46136
47173
|
}, undefined, true, undefined, this),
|
|
46137
|
-
isProcessing && /* @__PURE__ */
|
|
47174
|
+
isProcessing && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
46138
47175
|
dimColor: true,
|
|
46139
|
-
children: "esc
|
|
47176
|
+
children: "esc \xB7 "
|
|
46140
47177
|
}, undefined, false, undefined, this),
|
|
46141
|
-
sessionInfo && /* @__PURE__ */
|
|
47178
|
+
sessionInfo && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
46142
47179
|
dimColor: true,
|
|
46143
47180
|
children: [
|
|
46144
47181
|
sessionInfo,
|
|
46145
47182
|
bgIndicator,
|
|
46146
|
-
|
|
47183
|
+
" \xB7 "
|
|
46147
47184
|
]
|
|
46148
47185
|
}, undefined, true, undefined, this),
|
|
46149
|
-
contextInfo && /* @__PURE__ */
|
|
47186
|
+
contextInfo && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
46150
47187
|
dimColor: true,
|
|
46151
47188
|
children: contextInfo
|
|
46152
47189
|
}, undefined, false, undefined, this),
|
|
46153
|
-
|
|
46154
|
-
dimColor: true,
|
|
46155
|
-
children: [
|
|
46156
|
-
sessionInfo || contextInfo ? " \xB7 " : "",
|
|
46157
|
-
"id ",
|
|
46158
|
-
sessionId
|
|
46159
|
-
]
|
|
46160
|
-
}, undefined, true, undefined, this),
|
|
46161
|
-
isProcessing && processingStartTime && /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
47190
|
+
isProcessing && processingStartTime && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
46162
47191
|
dimColor: true,
|
|
46163
47192
|
children: [
|
|
46164
|
-
" \xB7
|
|
47193
|
+
" \xB7 ",
|
|
46165
47194
|
formatDuration2(elapsed)
|
|
46166
47195
|
]
|
|
46167
47196
|
}, undefined, true, undefined, this)
|
|
@@ -46193,17 +47222,17 @@ function Spinner({ type = "dots" }) {
|
|
|
46193
47222
|
var build_default2 = Spinner;
|
|
46194
47223
|
|
|
46195
47224
|
// packages/terminal/src/components/Spinner.tsx
|
|
46196
|
-
var
|
|
47225
|
+
var jsx_dev_runtime5 = __toESM(require_jsx_dev_runtime(), 1);
|
|
46197
47226
|
function Spinner2({ label }) {
|
|
46198
|
-
return /* @__PURE__ */
|
|
47227
|
+
return /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Box_default, {
|
|
46199
47228
|
children: [
|
|
46200
|
-
/* @__PURE__ */
|
|
47229
|
+
/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
46201
47230
|
dimColor: true,
|
|
46202
|
-
children: /* @__PURE__ */
|
|
47231
|
+
children: /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(build_default2, {
|
|
46203
47232
|
type: "dots"
|
|
46204
47233
|
}, undefined, false, undefined, this)
|
|
46205
47234
|
}, undefined, false, undefined, this),
|
|
46206
|
-
label && /* @__PURE__ */
|
|
47235
|
+
label && /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
46207
47236
|
dimColor: true,
|
|
46208
47237
|
children: [
|
|
46209
47238
|
" ",
|
|
@@ -46216,7 +47245,7 @@ function Spinner2({ label }) {
|
|
|
46216
47245
|
|
|
46217
47246
|
// packages/terminal/src/components/ProcessingIndicator.tsx
|
|
46218
47247
|
var import_react27 = __toESM(require_react(), 1);
|
|
46219
|
-
var
|
|
47248
|
+
var jsx_dev_runtime6 = __toESM(require_jsx_dev_runtime(), 1);
|
|
46220
47249
|
function ProcessingIndicator({
|
|
46221
47250
|
isProcessing,
|
|
46222
47251
|
startTime,
|
|
@@ -46260,14 +47289,14 @@ function ProcessingIndicator({
|
|
|
46260
47289
|
parts.push("thinking");
|
|
46261
47290
|
}
|
|
46262
47291
|
const label = isThinking ? "Metamorphosing" : "Working";
|
|
46263
|
-
return /* @__PURE__ */
|
|
47292
|
+
return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
|
|
46264
47293
|
marginY: 1,
|
|
46265
47294
|
children: [
|
|
46266
|
-
/* @__PURE__ */
|
|
47295
|
+
/* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
|
|
46267
47296
|
dimColor: true,
|
|
46268
47297
|
children: "\u2736 "
|
|
46269
47298
|
}, undefined, false, undefined, this),
|
|
46270
|
-
/* @__PURE__ */
|
|
47299
|
+
/* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
|
|
46271
47300
|
dimColor: true,
|
|
46272
47301
|
children: [
|
|
46273
47302
|
" ",
|
|
@@ -46275,7 +47304,7 @@ function ProcessingIndicator({
|
|
|
46275
47304
|
"... "
|
|
46276
47305
|
]
|
|
46277
47306
|
}, undefined, true, undefined, this),
|
|
46278
|
-
/* @__PURE__ */
|
|
47307
|
+
/* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
|
|
46279
47308
|
dimColor: true,
|
|
46280
47309
|
children: [
|
|
46281
47310
|
"(",
|
|
@@ -46288,31 +47317,31 @@ function ProcessingIndicator({
|
|
|
46288
47317
|
}
|
|
46289
47318
|
|
|
46290
47319
|
// packages/terminal/src/components/WelcomeBanner.tsx
|
|
46291
|
-
var
|
|
47320
|
+
var jsx_dev_runtime7 = __toESM(require_jsx_dev_runtime(), 1);
|
|
46292
47321
|
function WelcomeBanner({ version, model, directory }) {
|
|
46293
47322
|
const homeDir = process.env.HOME || "";
|
|
46294
47323
|
const displayDir = directory.startsWith(homeDir) ? "~" + directory.slice(homeDir.length) : directory;
|
|
46295
|
-
return /* @__PURE__ */
|
|
47324
|
+
return /* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Box_default, {
|
|
46296
47325
|
flexDirection: "column",
|
|
46297
47326
|
marginBottom: 1,
|
|
46298
47327
|
children: [
|
|
46299
|
-
/* @__PURE__ */
|
|
47328
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Box_default, {
|
|
46300
47329
|
children: [
|
|
46301
|
-
/* @__PURE__ */
|
|
47330
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
46302
47331
|
color: "cyan",
|
|
46303
47332
|
bold: true,
|
|
46304
47333
|
children: ">"
|
|
46305
47334
|
}, undefined, false, undefined, this),
|
|
46306
|
-
/* @__PURE__ */
|
|
47335
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
46307
47336
|
color: "cyan",
|
|
46308
47337
|
bold: true,
|
|
46309
47338
|
children: "_ "
|
|
46310
47339
|
}, undefined, false, undefined, this),
|
|
46311
|
-
/* @__PURE__ */
|
|
47340
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
46312
47341
|
bold: true,
|
|
46313
47342
|
children: "assistants"
|
|
46314
47343
|
}, undefined, false, undefined, this),
|
|
46315
|
-
/* @__PURE__ */
|
|
47344
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
46316
47345
|
dimColor: true,
|
|
46317
47346
|
children: [
|
|
46318
47347
|
" (v",
|
|
@@ -46322,29 +47351,29 @@ function WelcomeBanner({ version, model, directory }) {
|
|
|
46322
47351
|
}, undefined, true, undefined, this)
|
|
46323
47352
|
]
|
|
46324
47353
|
}, undefined, true, undefined, this),
|
|
46325
|
-
/* @__PURE__ */
|
|
47354
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Box_default, {
|
|
46326
47355
|
marginTop: 1,
|
|
46327
47356
|
children: [
|
|
46328
|
-
/* @__PURE__ */
|
|
47357
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
46329
47358
|
dimColor: true,
|
|
46330
47359
|
children: "model: "
|
|
46331
47360
|
}, undefined, false, undefined, this),
|
|
46332
|
-
/* @__PURE__ */
|
|
47361
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
46333
47362
|
children: model
|
|
46334
47363
|
}, undefined, false, undefined, this),
|
|
46335
|
-
/* @__PURE__ */
|
|
47364
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
46336
47365
|
dimColor: true,
|
|
46337
47366
|
children: " /model to change"
|
|
46338
47367
|
}, undefined, false, undefined, this)
|
|
46339
47368
|
]
|
|
46340
47369
|
}, undefined, true, undefined, this),
|
|
46341
|
-
/* @__PURE__ */
|
|
47370
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Box_default, {
|
|
46342
47371
|
children: [
|
|
46343
|
-
/* @__PURE__ */
|
|
47372
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
46344
47373
|
dimColor: true,
|
|
46345
47374
|
children: "directory: "
|
|
46346
47375
|
}, undefined, false, undefined, this),
|
|
46347
|
-
/* @__PURE__ */
|
|
47376
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
46348
47377
|
children: displayDir
|
|
46349
47378
|
}, undefined, false, undefined, this)
|
|
46350
47379
|
]
|
|
@@ -46355,7 +47384,7 @@ function WelcomeBanner({ version, model, directory }) {
|
|
|
46355
47384
|
|
|
46356
47385
|
// packages/terminal/src/components/SessionSelector.tsx
|
|
46357
47386
|
var import_react28 = __toESM(require_react(), 1);
|
|
46358
|
-
var
|
|
47387
|
+
var jsx_dev_runtime8 = __toESM(require_jsx_dev_runtime(), 1);
|
|
46359
47388
|
function formatSessionTime(timestamp) {
|
|
46360
47389
|
const date = new Date(timestamp);
|
|
46361
47390
|
const now2 = new Date;
|
|
@@ -46421,13 +47450,13 @@ function SessionSelector({
|
|
|
46421
47450
|
return;
|
|
46422
47451
|
}
|
|
46423
47452
|
});
|
|
46424
|
-
return /* @__PURE__ */
|
|
47453
|
+
return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
46425
47454
|
flexDirection: "column",
|
|
46426
47455
|
paddingY: 1,
|
|
46427
47456
|
children: [
|
|
46428
|
-
/* @__PURE__ */
|
|
47457
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
46429
47458
|
marginBottom: 1,
|
|
46430
|
-
children: /* @__PURE__ */
|
|
47459
|
+
children: /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
46431
47460
|
bold: true,
|
|
46432
47461
|
children: "Sessions"
|
|
46433
47462
|
}, undefined, false, undefined, this)
|
|
@@ -46439,8 +47468,8 @@ function SessionSelector({
|
|
|
46439
47468
|
const time = formatSessionTime(session.updatedAt);
|
|
46440
47469
|
const path2 = formatPath(session.cwd);
|
|
46441
47470
|
const processing = session.isProcessing ? " (processing)" : "";
|
|
46442
|
-
return /* @__PURE__ */
|
|
46443
|
-
children: /* @__PURE__ */
|
|
47471
|
+
return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
47472
|
+
children: /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
46444
47473
|
inverse: isSelected,
|
|
46445
47474
|
color: isActive ? "green" : undefined,
|
|
46446
47475
|
dimColor: !isSelected && !isActive,
|
|
@@ -46457,17 +47486,17 @@ function SessionSelector({
|
|
|
46457
47486
|
}, undefined, true, undefined, this)
|
|
46458
47487
|
}, session.id, false, undefined, this);
|
|
46459
47488
|
}),
|
|
46460
|
-
/* @__PURE__ */
|
|
47489
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
46461
47490
|
marginTop: 1,
|
|
46462
|
-
children: /* @__PURE__ */
|
|
47491
|
+
children: /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
46463
47492
|
inverse: selectedIndex === sessions.length,
|
|
46464
47493
|
dimColor: selectedIndex !== sessions.length,
|
|
46465
47494
|
children: "+ New session (n)"
|
|
46466
47495
|
}, undefined, false, undefined, this)
|
|
46467
47496
|
}, undefined, false, undefined, this),
|
|
46468
|
-
/* @__PURE__ */
|
|
47497
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
46469
47498
|
marginTop: 1,
|
|
46470
|
-
children: /* @__PURE__ */
|
|
47499
|
+
children: /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
46471
47500
|
dimColor: true,
|
|
46472
47501
|
children: [
|
|
46473
47502
|
"Enter to select | Esc to cancel | 1-",
|
|
@@ -46481,32 +47510,8 @@ function SessionSelector({
|
|
|
46481
47510
|
}
|
|
46482
47511
|
|
|
46483
47512
|
// packages/terminal/src/components/App.tsx
|
|
46484
|
-
var
|
|
47513
|
+
var jsx_dev_runtime9 = __toESM(require_jsx_dev_runtime(), 1);
|
|
46485
47514
|
var SHOW_ERROR_CODES = process.env.ASSISTANTS_DEBUG === "1" || process.env.OLDPAL_DEBUG === "1";
|
|
46486
|
-
function formatToolName(toolCall) {
|
|
46487
|
-
const { name, input } = toolCall;
|
|
46488
|
-
switch (name) {
|
|
46489
|
-
case "bash":
|
|
46490
|
-
return `bash`;
|
|
46491
|
-
case "read":
|
|
46492
|
-
const path2 = String(input.path || input.file_path || "");
|
|
46493
|
-
return `read ${path2.split("/").pop() || ""}`;
|
|
46494
|
-
case "write":
|
|
46495
|
-
const writePath = String(input.filename || input.path || input.file_path || "");
|
|
46496
|
-
return `write ${writePath.split("/").pop() || ""}`;
|
|
46497
|
-
case "glob":
|
|
46498
|
-
return `glob`;
|
|
46499
|
-
case "grep":
|
|
46500
|
-
return `grep`;
|
|
46501
|
-
case "web_search":
|
|
46502
|
-
return `search`;
|
|
46503
|
-
case "web_fetch":
|
|
46504
|
-
case "curl":
|
|
46505
|
-
return `fetch`;
|
|
46506
|
-
default:
|
|
46507
|
-
return name;
|
|
46508
|
-
}
|
|
46509
|
-
}
|
|
46510
47515
|
function parseErrorMessage(error) {
|
|
46511
47516
|
const lines = error.split(`
|
|
46512
47517
|
`);
|
|
@@ -46528,7 +47533,65 @@ function parseErrorMessage(error) {
|
|
|
46528
47533
|
}
|
|
46529
47534
|
var MESSAGE_CHUNK_LINES = 12;
|
|
46530
47535
|
var MESSAGE_WRAP_CHARS = 120;
|
|
46531
|
-
function
|
|
47536
|
+
function wrapTextLines(text, wrapChars) {
|
|
47537
|
+
const rawLines = text.split(`
|
|
47538
|
+
`);
|
|
47539
|
+
const lines = [];
|
|
47540
|
+
for (const line of rawLines) {
|
|
47541
|
+
if (line.length <= wrapChars) {
|
|
47542
|
+
lines.push(line);
|
|
47543
|
+
continue;
|
|
47544
|
+
}
|
|
47545
|
+
for (let i = 0;i < line.length; i += wrapChars) {
|
|
47546
|
+
lines.push(line.slice(i, i + wrapChars));
|
|
47547
|
+
}
|
|
47548
|
+
}
|
|
47549
|
+
return lines;
|
|
47550
|
+
}
|
|
47551
|
+
function stripAnsi3(text) {
|
|
47552
|
+
return text.replace(/\x1B\[[0-9;]*m/g, "");
|
|
47553
|
+
}
|
|
47554
|
+
function chunkRenderedLines(lines, chunkLines) {
|
|
47555
|
+
const chunks = [];
|
|
47556
|
+
let current = [];
|
|
47557
|
+
let i = 0;
|
|
47558
|
+
const isBoxStart = (line) => stripAnsi3(line).trimStart().startsWith("\u250C");
|
|
47559
|
+
const isBoxEnd = (line) => stripAnsi3(line).trimStart().startsWith("\u2514");
|
|
47560
|
+
while (i < lines.length) {
|
|
47561
|
+
const line = lines[i];
|
|
47562
|
+
if (isBoxStart(line)) {
|
|
47563
|
+
let end = i + 1;
|
|
47564
|
+
while (end < lines.length && !isBoxEnd(lines[end])) {
|
|
47565
|
+
end += 1;
|
|
47566
|
+
}
|
|
47567
|
+
if (end < lines.length)
|
|
47568
|
+
end += 1;
|
|
47569
|
+
const boxLines = lines.slice(i, end);
|
|
47570
|
+
if (current.length > 0 && current.length + boxLines.length > chunkLines) {
|
|
47571
|
+
chunks.push(current);
|
|
47572
|
+
current = [];
|
|
47573
|
+
}
|
|
47574
|
+
if (boxLines.length >= chunkLines) {
|
|
47575
|
+
chunks.push(boxLines);
|
|
47576
|
+
} else {
|
|
47577
|
+
current.push(...boxLines);
|
|
47578
|
+
}
|
|
47579
|
+
i = end;
|
|
47580
|
+
continue;
|
|
47581
|
+
}
|
|
47582
|
+
if (current.length >= chunkLines) {
|
|
47583
|
+
chunks.push(current);
|
|
47584
|
+
current = [];
|
|
47585
|
+
}
|
|
47586
|
+
current.push(line);
|
|
47587
|
+
i += 1;
|
|
47588
|
+
}
|
|
47589
|
+
if (current.length > 0) {
|
|
47590
|
+
chunks.push(current);
|
|
47591
|
+
}
|
|
47592
|
+
return chunks;
|
|
47593
|
+
}
|
|
47594
|
+
function buildDisplayMessages(messages, chunkLines, wrapChars, options) {
|
|
46532
47595
|
const display = [];
|
|
46533
47596
|
for (const msg of messages) {
|
|
46534
47597
|
const content = msg.content ?? "";
|
|
@@ -46537,32 +47600,34 @@ function buildDisplayMessages(messages, chunkLines, wrapChars) {
|
|
|
46537
47600
|
display.push(msg);
|
|
46538
47601
|
continue;
|
|
46539
47602
|
}
|
|
46540
|
-
const
|
|
46541
|
-
`);
|
|
46542
|
-
const lines = [];
|
|
46543
|
-
for (const line of rawLines) {
|
|
46544
|
-
if (line.length <= wrapChars) {
|
|
46545
|
-
lines.push(line);
|
|
46546
|
-
continue;
|
|
46547
|
-
}
|
|
46548
|
-
for (let i = 0;i < line.length; i += wrapChars) {
|
|
46549
|
-
lines.push(line.slice(i, i + wrapChars));
|
|
46550
|
-
}
|
|
46551
|
-
}
|
|
47603
|
+
const lines = wrapTextLines(content, wrapChars);
|
|
46552
47604
|
if (lines.length <= chunkLines) {
|
|
46553
|
-
|
|
47605
|
+
if (msg.role === "assistant") {
|
|
47606
|
+
const rendered2 = renderMarkdown(lines.join(`
|
|
47607
|
+
`), { maxWidth: options?.maxWidth });
|
|
47608
|
+
display.push({ ...msg, content: rendered2, __rendered: true });
|
|
47609
|
+
} else {
|
|
47610
|
+
display.push(msg);
|
|
47611
|
+
}
|
|
46554
47612
|
continue;
|
|
46555
47613
|
}
|
|
46556
|
-
const
|
|
46557
|
-
|
|
46558
|
-
|
|
47614
|
+
const baseContent = lines.join(`
|
|
47615
|
+
`);
|
|
47616
|
+
const renderAssistant = msg.role === "assistant";
|
|
47617
|
+
const rendered = renderAssistant ? renderMarkdown(baseContent, { maxWidth: options?.maxWidth }) : baseContent;
|
|
47618
|
+
const renderedLines = rendered.split(`
|
|
47619
|
+
`);
|
|
47620
|
+
const chunks = chunkRenderedLines(renderedLines, chunkLines);
|
|
47621
|
+
for (let i = 0;i < chunks.length; i++) {
|
|
47622
|
+
const chunkContent = chunks[i].join(`
|
|
46559
47623
|
`);
|
|
46560
47624
|
display.push({
|
|
46561
47625
|
...msg,
|
|
46562
47626
|
id: `${msg.id}::chunk-${i}`,
|
|
46563
47627
|
content: chunkContent,
|
|
46564
|
-
|
|
46565
|
-
|
|
47628
|
+
__rendered: renderAssistant,
|
|
47629
|
+
toolCalls: i === chunks.length - 1 ? msg.toolCalls : undefined,
|
|
47630
|
+
toolResults: i === chunks.length - 1 ? msg.toolResults : undefined
|
|
46566
47631
|
});
|
|
46567
47632
|
}
|
|
46568
47633
|
}
|
|
@@ -46597,7 +47662,7 @@ function App2({ cwd: cwd2, version }) {
|
|
|
46597
47662
|
const toolCallsRef = import_react29.useRef([]);
|
|
46598
47663
|
const toolResultsRef = import_react29.useRef([]);
|
|
46599
47664
|
const activityLogRef = import_react29.useRef([]);
|
|
46600
|
-
const
|
|
47665
|
+
const prevDisplayLineCountRef = import_react29.useRef(0);
|
|
46601
47666
|
const skipNextDoneRef = import_react29.useRef(false);
|
|
46602
47667
|
const isProcessingRef = import_react29.useRef(isProcessing);
|
|
46603
47668
|
import_react29.useEffect(() => {
|
|
@@ -46919,9 +47984,10 @@ function App2({ cwd: cwd2, version }) {
|
|
|
46919
47984
|
await activeSession2.client.send(nextMessage.content);
|
|
46920
47985
|
}, [activeSessionId]);
|
|
46921
47986
|
const activeQueue = activeSessionId ? messageQueue.filter((msg) => msg.sessionId === activeSessionId) : [];
|
|
46922
|
-
const queuedMessageIds = import_react29.useMemo(() => new Set(activeQueue.map((msg) => msg.id)), [activeQueue]);
|
|
47987
|
+
const queuedMessageIds = import_react29.useMemo(() => new Set(activeQueue.filter((msg) => msg.mode === "queued").map((msg) => msg.id)), [activeQueue]);
|
|
46923
47988
|
const wrapChars = columns ? Math.max(40, columns - 4) : MESSAGE_WRAP_CHARS;
|
|
46924
|
-
const
|
|
47989
|
+
const renderWidth = columns ? Math.max(20, columns - 2) : undefined;
|
|
47990
|
+
const displayMessages = import_react29.useMemo(() => buildDisplayMessages(messages, MESSAGE_CHUNK_LINES, wrapChars, { maxWidth: renderWidth }), [messages, wrapChars, renderWidth]);
|
|
46925
47991
|
const streamingMessages = import_react29.useMemo(() => {
|
|
46926
47992
|
if (!isProcessing || !currentResponse.trim())
|
|
46927
47993
|
return [];
|
|
@@ -46931,9 +47997,12 @@ function App2({ cwd: cwd2, version }) {
|
|
|
46931
47997
|
content: currentResponse,
|
|
46932
47998
|
timestamp: now()
|
|
46933
47999
|
};
|
|
46934
|
-
return buildDisplayMessages([streamingMessage], MESSAGE_CHUNK_LINES, wrapChars);
|
|
46935
|
-
}, [currentResponse, isProcessing, wrapChars]);
|
|
46936
|
-
const
|
|
48000
|
+
return buildDisplayMessages([streamingMessage], MESSAGE_CHUNK_LINES, wrapChars, { maxWidth: renderWidth });
|
|
48001
|
+
}, [currentResponse, isProcessing, wrapChars, renderWidth]);
|
|
48002
|
+
const displayLineCount = import_react29.useMemo(() => {
|
|
48003
|
+
const combined = [...displayMessages, ...streamingMessages];
|
|
48004
|
+
return combined.reduce((sum, msg) => sum + estimateMessageLines(msg), 0);
|
|
48005
|
+
}, [displayMessages, streamingMessages]);
|
|
46937
48006
|
import_react29.useEffect(() => {
|
|
46938
48007
|
if (!isProcessing && activeQueue.length > 0) {
|
|
46939
48008
|
processQueue();
|
|
@@ -46943,23 +48012,21 @@ function App2({ cwd: cwd2, version }) {
|
|
|
46943
48012
|
if (autoScroll) {
|
|
46944
48013
|
setScrollOffset(0);
|
|
46945
48014
|
}
|
|
46946
|
-
}, [
|
|
48015
|
+
}, [displayLineCount, autoScroll]);
|
|
46947
48016
|
import_react29.useEffect(() => {
|
|
46948
|
-
const prevCount =
|
|
46949
|
-
if (!autoScroll &&
|
|
46950
|
-
const delta =
|
|
48017
|
+
const prevCount = prevDisplayLineCountRef.current;
|
|
48018
|
+
if (!autoScroll && displayLineCount > prevCount) {
|
|
48019
|
+
const delta = displayLineCount - prevCount;
|
|
46951
48020
|
setScrollOffset((prev) => prev + delta);
|
|
46952
48021
|
}
|
|
46953
|
-
|
|
46954
|
-
}, [
|
|
48022
|
+
prevDisplayLineCountRef.current = displayLineCount;
|
|
48023
|
+
}, [displayLineCount, autoScroll]);
|
|
46955
48024
|
const reservedLines = 8;
|
|
46956
|
-
const
|
|
46957
|
-
const toolCallsHeight = isProcessing ? Math.min(toolCallsRef.current.length, 5) : 0;
|
|
46958
|
-
const maxVisibleMessages = Math.max(3, baseMaxVisible - toolCallsHeight);
|
|
48025
|
+
const maxVisibleLines = rows ? Math.max(6, rows - reservedLines) : 20;
|
|
46959
48026
|
import_react29.useEffect(() => {
|
|
46960
|
-
const maxOffset = Math.max(0,
|
|
48027
|
+
const maxOffset = Math.max(0, displayLineCount - maxVisibleLines);
|
|
46961
48028
|
setScrollOffset((prev) => Math.min(prev, maxOffset));
|
|
46962
|
-
}, [
|
|
48029
|
+
}, [displayLineCount, maxVisibleLines]);
|
|
46963
48030
|
const sessions = registry2.listSessions();
|
|
46964
48031
|
const activeSession = registry2.getActiveSession();
|
|
46965
48032
|
const sessionIndex = activeSessionId ? registry2.getSessionIndex(activeSessionId) : 0;
|
|
@@ -47038,8 +48105,9 @@ function App2({ cwd: cwd2, version }) {
|
|
|
47038
48105
|
}
|
|
47039
48106
|
if (key.pageUp || key.shift && key.upArrow) {
|
|
47040
48107
|
setScrollOffset((prev) => {
|
|
47041
|
-
const maxOffset = Math.max(0,
|
|
47042
|
-
const
|
|
48108
|
+
const maxOffset = Math.max(0, displayLineCount - maxVisibleLines);
|
|
48109
|
+
const step = Math.max(3, Math.floor(maxVisibleLines / 2));
|
|
48110
|
+
const newOffset = Math.min(prev + step, maxOffset);
|
|
47043
48111
|
if (newOffset > 0)
|
|
47044
48112
|
setAutoScroll(false);
|
|
47045
48113
|
return newOffset;
|
|
@@ -47047,14 +48115,15 @@ function App2({ cwd: cwd2, version }) {
|
|
|
47047
48115
|
}
|
|
47048
48116
|
if (key.pageDown || key.shift && key.downArrow) {
|
|
47049
48117
|
setScrollOffset((prev) => {
|
|
47050
|
-
const
|
|
48118
|
+
const step = Math.max(3, Math.floor(maxVisibleLines / 2));
|
|
48119
|
+
const newOffset = Math.max(0, prev - step);
|
|
47051
48120
|
if (newOffset === 0)
|
|
47052
48121
|
setAutoScroll(true);
|
|
47053
48122
|
return newOffset;
|
|
47054
48123
|
});
|
|
47055
48124
|
}
|
|
47056
48125
|
if (key.ctrl && input === "u") {
|
|
47057
|
-
const maxOffset = Math.max(0,
|
|
48126
|
+
const maxOffset = Math.max(0, displayLineCount - maxVisibleLines);
|
|
47058
48127
|
setScrollOffset(maxOffset);
|
|
47059
48128
|
setAutoScroll(false);
|
|
47060
48129
|
}
|
|
@@ -47085,13 +48154,19 @@ function App2({ cwd: cwd2, version }) {
|
|
|
47085
48154
|
setShowSessionSelector(true);
|
|
47086
48155
|
return;
|
|
47087
48156
|
}
|
|
47088
|
-
if (mode === "queue" ||
|
|
48157
|
+
if (mode === "queue" || mode === "inline") {
|
|
47089
48158
|
if (!activeSessionId)
|
|
47090
48159
|
return;
|
|
47091
48160
|
const queuedId = generateId();
|
|
47092
48161
|
setMessageQueue((prev) => [
|
|
47093
48162
|
...prev,
|
|
47094
|
-
{
|
|
48163
|
+
{
|
|
48164
|
+
id: queuedId,
|
|
48165
|
+
sessionId: activeSessionId,
|
|
48166
|
+
content: trimmedInput,
|
|
48167
|
+
queuedAt: now(),
|
|
48168
|
+
mode: mode === "inline" ? "inline" : "queued"
|
|
48169
|
+
}
|
|
47095
48170
|
]);
|
|
47096
48171
|
setMessages((prev) => [
|
|
47097
48172
|
...prev,
|
|
@@ -47155,19 +48230,19 @@ function App2({ cwd: cwd2, version }) {
|
|
|
47155
48230
|
activeSessionId
|
|
47156
48231
|
]);
|
|
47157
48232
|
if (isInitializing) {
|
|
47158
|
-
return /* @__PURE__ */
|
|
48233
|
+
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
47159
48234
|
flexDirection: "column",
|
|
47160
48235
|
padding: 1,
|
|
47161
|
-
children: /* @__PURE__ */
|
|
48236
|
+
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Spinner2, {
|
|
47162
48237
|
label: "Initializing..."
|
|
47163
48238
|
}, undefined, false, undefined, this)
|
|
47164
48239
|
}, undefined, false, undefined, this);
|
|
47165
48240
|
}
|
|
47166
48241
|
if (showSessionSelector) {
|
|
47167
|
-
return /* @__PURE__ */
|
|
48242
|
+
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
47168
48243
|
flexDirection: "column",
|
|
47169
48244
|
padding: 1,
|
|
47170
|
-
children: /* @__PURE__ */
|
|
48245
|
+
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(SessionSelector, {
|
|
47171
48246
|
sessions,
|
|
47172
48247
|
activeSessionId,
|
|
47173
48248
|
onSelect: handleSessionSwitch,
|
|
@@ -47187,19 +48262,21 @@ function App2({ cwd: cwd2, version }) {
|
|
|
47187
48262
|
return text;
|
|
47188
48263
|
return text.slice(0, maxLen - 3) + "...";
|
|
47189
48264
|
};
|
|
48265
|
+
const queuedCount = activeQueue.filter((msg) => msg.mode === "queued").length;
|
|
48266
|
+
const inlineCount = activeQueue.filter((msg) => msg.mode === "inline").length;
|
|
47190
48267
|
const showWelcome = messages.length === 0 && !isProcessing;
|
|
47191
|
-
return /* @__PURE__ */
|
|
48268
|
+
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
47192
48269
|
flexDirection: "column",
|
|
47193
48270
|
padding: 1,
|
|
47194
48271
|
children: [
|
|
47195
|
-
showWelcome && /* @__PURE__ */
|
|
47196
|
-
version: version ?? "
|
|
48272
|
+
showWelcome && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(WelcomeBanner, {
|
|
48273
|
+
version: version ?? "unknown",
|
|
47197
48274
|
model: "claude-sonnet-4",
|
|
47198
48275
|
directory: activeSession?.cwd || cwd2
|
|
47199
48276
|
}, undefined, false, undefined, this),
|
|
47200
|
-
backgroundProcessingCount > 0 && /* @__PURE__ */
|
|
48277
|
+
backgroundProcessingCount > 0 && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
47201
48278
|
marginBottom: 1,
|
|
47202
|
-
children: /* @__PURE__ */
|
|
48279
|
+
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
47203
48280
|
color: "yellow",
|
|
47204
48281
|
children: [
|
|
47205
48282
|
backgroundProcessingCount,
|
|
@@ -47209,17 +48286,17 @@ function App2({ cwd: cwd2, version }) {
|
|
|
47209
48286
|
]
|
|
47210
48287
|
}, undefined, true, undefined, this)
|
|
47211
48288
|
}, undefined, false, undefined, this),
|
|
47212
|
-
scrollOffset > 0 && /* @__PURE__ */
|
|
47213
|
-
children: /* @__PURE__ */
|
|
48289
|
+
scrollOffset > 0 && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
48290
|
+
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
47214
48291
|
dimColor: true,
|
|
47215
48292
|
children: [
|
|
47216
48293
|
"\u2191 ",
|
|
47217
48294
|
scrollOffset,
|
|
47218
|
-
" more
|
|
48295
|
+
" more lines above (Shift+\u2193 or Page Down to scroll down)"
|
|
47219
48296
|
]
|
|
47220
48297
|
}, undefined, true, undefined, this)
|
|
47221
48298
|
}, undefined, false, undefined, this),
|
|
47222
|
-
/* @__PURE__ */
|
|
48299
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Messages4, {
|
|
47223
48300
|
messages: displayMessages,
|
|
47224
48301
|
currentResponse: undefined,
|
|
47225
48302
|
streamingMessages,
|
|
@@ -47227,61 +48304,34 @@ function App2({ cwd: cwd2, version }) {
|
|
|
47227
48304
|
lastToolResult: undefined,
|
|
47228
48305
|
activityLog: isProcessing ? activityLog : [],
|
|
47229
48306
|
queuedMessageIds,
|
|
47230
|
-
scrollOffset,
|
|
47231
|
-
|
|
48307
|
+
scrollOffsetLines: scrollOffset,
|
|
48308
|
+
maxVisibleLines
|
|
47232
48309
|
}, activeSessionId || "default", false, undefined, this),
|
|
47233
|
-
|
|
47234
|
-
marginY: 1,
|
|
47235
|
-
flexDirection: "column",
|
|
47236
|
-
children: [
|
|
47237
|
-
toolCallEntries.slice(-3).map(({ toolCall, result }) => /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
|
|
47238
|
-
children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
47239
|
-
dimColor: true,
|
|
47240
|
-
children: [
|
|
47241
|
-
result ? "\u2713" : "\u2699",
|
|
47242
|
-
" ",
|
|
47243
|
-
formatToolName(toolCall),
|
|
47244
|
-
result?.isError && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
47245
|
-
color: "red",
|
|
47246
|
-
children: " (error)"
|
|
47247
|
-
}, undefined, false, undefined, this)
|
|
47248
|
-
]
|
|
47249
|
-
}, undefined, true, undefined, this)
|
|
47250
|
-
}, toolCall.id, false, undefined, this)),
|
|
47251
|
-
toolCallEntries.length > 3 && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
47252
|
-
dimColor: true,
|
|
47253
|
-
children: [
|
|
47254
|
-
" ... and ",
|
|
47255
|
-
toolCallEntries.length - 3,
|
|
47256
|
-
" more tools"
|
|
47257
|
-
]
|
|
47258
|
-
}, undefined, true, undefined, this)
|
|
47259
|
-
]
|
|
47260
|
-
}, undefined, true, undefined, this),
|
|
47261
|
-
activeQueue.length > 0 && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
|
|
48310
|
+
activeQueue.length > 0 && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
47262
48311
|
marginY: 1,
|
|
47263
48312
|
flexDirection: "column",
|
|
47264
48313
|
children: [
|
|
47265
|
-
/* @__PURE__ */
|
|
48314
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
47266
48315
|
dimColor: true,
|
|
47267
48316
|
children: [
|
|
47268
48317
|
activeQueue.length,
|
|
47269
|
-
" message",
|
|
48318
|
+
" pending message",
|
|
47270
48319
|
activeQueue.length > 1 ? "s" : "",
|
|
47271
|
-
|
|
48320
|
+
inlineCount > 0 || queuedCount > 0 ? ` \xB7 ${inlineCount} in-stream \xB7 ${queuedCount} queued` : ""
|
|
47272
48321
|
]
|
|
47273
48322
|
}, undefined, true, undefined, this),
|
|
47274
|
-
activeQueue.slice(0, MAX_QUEUED_PREVIEW).map((queued) => /* @__PURE__ */
|
|
48323
|
+
activeQueue.slice(0, MAX_QUEUED_PREVIEW).map((queued) => /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
47275
48324
|
marginLeft: 2,
|
|
47276
|
-
children: /* @__PURE__ */
|
|
48325
|
+
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
47277
48326
|
dimColor: true,
|
|
47278
48327
|
children: [
|
|
47279
|
-
"\
|
|
48328
|
+
queued.mode === "inline" ? "\u21B3" : "\u23F3",
|
|
48329
|
+
" ",
|
|
47280
48330
|
truncateQueued(queued.content)
|
|
47281
48331
|
]
|
|
47282
48332
|
}, undefined, true, undefined, this)
|
|
47283
48333
|
}, queued.id, false, undefined, this)),
|
|
47284
|
-
activeQueue.length > MAX_QUEUED_PREVIEW && /* @__PURE__ */
|
|
48334
|
+
activeQueue.length > MAX_QUEUED_PREVIEW && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
47285
48335
|
dimColor: true,
|
|
47286
48336
|
children: [
|
|
47287
48337
|
" ... and ",
|
|
@@ -47295,18 +48345,18 @@ function App2({ cwd: cwd2, version }) {
|
|
|
47295
48345
|
const parsed = parseErrorMessage(error);
|
|
47296
48346
|
const severity = parsed.code && /TIMEOUT|RATE_LIMITED/.test(parsed.code) ? "yellow" : "red";
|
|
47297
48347
|
const prefix = SHOW_ERROR_CODES && parsed.code ? `${parsed.code}: ` : "";
|
|
47298
|
-
return /* @__PURE__ */
|
|
48348
|
+
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
47299
48349
|
marginY: 1,
|
|
47300
48350
|
flexDirection: "column",
|
|
47301
48351
|
children: [
|
|
47302
|
-
/* @__PURE__ */
|
|
48352
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
47303
48353
|
color: severity,
|
|
47304
48354
|
children: [
|
|
47305
48355
|
prefix,
|
|
47306
48356
|
parsed.message
|
|
47307
48357
|
]
|
|
47308
48358
|
}, undefined, true, undefined, this),
|
|
47309
|
-
parsed.suggestion && /* @__PURE__ */
|
|
48359
|
+
parsed.suggestion && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
47310
48360
|
color: severity,
|
|
47311
48361
|
children: [
|
|
47312
48362
|
"Suggestion: ",
|
|
@@ -47316,19 +48366,19 @@ function App2({ cwd: cwd2, version }) {
|
|
|
47316
48366
|
]
|
|
47317
48367
|
}, undefined, true, undefined, this);
|
|
47318
48368
|
})(),
|
|
47319
|
-
/* @__PURE__ */
|
|
48369
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(ProcessingIndicator, {
|
|
47320
48370
|
isProcessing,
|
|
47321
48371
|
startTime: processingStartTime,
|
|
47322
48372
|
tokenCount: currentTurnTokens,
|
|
47323
48373
|
isThinking
|
|
47324
48374
|
}, undefined, false, undefined, this),
|
|
47325
|
-
/* @__PURE__ */
|
|
48375
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Input, {
|
|
47326
48376
|
onSubmit: handleSubmit,
|
|
47327
48377
|
isProcessing,
|
|
47328
48378
|
queueLength: activeQueue.length,
|
|
47329
48379
|
skills
|
|
47330
48380
|
}, undefined, false, undefined, this),
|
|
47331
|
-
/* @__PURE__ */
|
|
48381
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Status, {
|
|
47332
48382
|
isProcessing,
|
|
47333
48383
|
cwd: activeSession?.cwd || cwd2,
|
|
47334
48384
|
queueLength: activeQueue.length,
|
|
@@ -47520,8 +48570,9 @@ function formatStreamEvent(chunk) {
|
|
|
47520
48570
|
}
|
|
47521
48571
|
|
|
47522
48572
|
// packages/terminal/src/index.tsx
|
|
47523
|
-
var
|
|
47524
|
-
var VERSION3 = "0.6.
|
|
48573
|
+
var jsx_dev_runtime10 = __toESM(require_jsx_dev_runtime(), 1);
|
|
48574
|
+
var VERSION3 = "0.6.20";
|
|
48575
|
+
process.env.ASSISTANTS_VERSION ??= VERSION3;
|
|
47525
48576
|
function parseArgs(argv) {
|
|
47526
48577
|
const args = argv.slice(2);
|
|
47527
48578
|
const options = {
|
|
@@ -47675,7 +48726,7 @@ if (options.print !== null) {
|
|
|
47675
48726
|
process.exit(1);
|
|
47676
48727
|
});
|
|
47677
48728
|
} else {
|
|
47678
|
-
const { waitUntilExit } = render_default(/* @__PURE__ */
|
|
48729
|
+
const { waitUntilExit } = render_default(/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(App2, {
|
|
47679
48730
|
cwd: options.cwd,
|
|
47680
48731
|
version: VERSION3
|
|
47681
48732
|
}, undefined, false, undefined, this));
|
|
@@ -47684,4 +48735,4 @@ if (options.print !== null) {
|
|
|
47684
48735
|
});
|
|
47685
48736
|
}
|
|
47686
48737
|
|
|
47687
|
-
//# debugId=
|
|
48738
|
+
//# debugId=F2C1A670F9E8793164756E2164756E21
|