@hasna/assistants 0.6.15 → 0.6.16

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 CHANGED
@@ -27290,14 +27290,14 @@ var exports_anthropic = {};
27290
27290
  __export(exports_anthropic, {
27291
27291
  AnthropicClient: () => AnthropicClient
27292
27292
  });
27293
- import { readFileSync as readFileSync2, existsSync as existsSync5 } from "fs";
27293
+ import { readFileSync as readFileSync2, existsSync as existsSync7 } from "fs";
27294
27294
  import { homedir as homedir8 } from "os";
27295
27295
  import { join as join11 } 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
27299
  const secretsPath = join11(homeDir, ".secrets");
27300
- if (existsSync5(secretsPath)) {
27300
+ if (existsSync7(secretsPath)) {
27301
27301
  try {
27302
27302
  const content = readFileSync2(secretsPath, "utf-8");
27303
27303
  const match = content.match(/export\s+ANTHROPIC_API_KEY\s*=\s*["']?([^"'\n]+)["']?/);
@@ -36989,6 +36989,34 @@ function validateBashCommand(command) {
36989
36989
  function killProcess(proc) {
36990
36990
  proc.kill();
36991
36991
  }
36992
+ function stripQuotedSegments(input) {
36993
+ let result = "";
36994
+ let quote = null;
36995
+ let escaped = false;
36996
+ for (let i = 0;i < input.length; i += 1) {
36997
+ const char = input[i];
36998
+ if (quote) {
36999
+ if (quote === '"' && !escaped && char === "\\") {
37000
+ escaped = true;
37001
+ continue;
37002
+ }
37003
+ if (!escaped && char === quote) {
37004
+ quote = null;
37005
+ result += char;
37006
+ continue;
37007
+ }
37008
+ escaped = false;
37009
+ continue;
37010
+ }
37011
+ if (char === '"' || char === "'") {
37012
+ quote = char;
37013
+ result += char;
37014
+ continue;
37015
+ }
37016
+ result += char;
37017
+ }
37018
+ return result;
37019
+ }
36992
37020
 
36993
37021
  class BashTool {
36994
37022
  static tool = {
@@ -37109,6 +37137,7 @@ class BashTool {
37109
37137
  const cwd2 = input.cwd || process.cwd();
37110
37138
  const timeout = input.timeout || 30000;
37111
37139
  const commandForChecks = command.replace(/\s*2>&1\s*/g, " ");
37140
+ const commandSansQuotes = stripQuotedSegments(commandForChecks);
37112
37141
  const securityCheck = validateBashCommand(commandForChecks);
37113
37142
  if (!securityCheck.valid) {
37114
37143
  getSecurityLogger().log({
@@ -37131,7 +37160,7 @@ class BashTool {
37131
37160
  });
37132
37161
  }
37133
37162
  for (const pattern of this.BLOCKED_PATTERNS) {
37134
- if (pattern.test(commandForChecks)) {
37163
+ if (pattern.test(commandSansQuotes)) {
37135
37164
  getSecurityLogger().log({
37136
37165
  eventType: "blocked_command",
37137
37166
  severity: "high",
@@ -37220,6 +37249,7 @@ ${stderr || stdout}`.trim(), {
37220
37249
 
37221
37250
  // packages/core/src/tools/filesystem.ts
37222
37251
  import { join as join4, resolve as resolve3, dirname as dirname2, sep } from "path";
37252
+ import { existsSync as existsSync2 } from "fs";
37223
37253
  init_errors();
37224
37254
  var {Glob } = globalThis.Bun;
37225
37255
 
@@ -37308,6 +37338,10 @@ async function isPathSafe(targetPath, operation, options = {}) {
37308
37338
  // packages/core/src/tools/filesystem.ts
37309
37339
  var currentSessionId = "default";
37310
37340
  function getScriptsFolder(cwd2) {
37341
+ const legacyDir = join4(cwd2, ".oldpal");
37342
+ if (existsSync2(legacyDir)) {
37343
+ return join4(legacyDir, "scripts", currentSessionId);
37344
+ }
37311
37345
  return join4(getProjectConfigDir(cwd2), "scripts", currentSessionId);
37312
37346
  }
37313
37347
  function isInScriptsFolder(path2, cwd2) {
@@ -37443,13 +37477,13 @@ class FilesystemTools {
37443
37477
  };
37444
37478
  static writeTool = {
37445
37479
  name: "write",
37446
- description: "Write content to a file. RESTRICTED: Can only write to .assistants/scripts/{session}/ in the current project. Provide a filename and it will be saved under the scripts folder.",
37480
+ description: "Write content to a file. RESTRICTED: Can only write to the project scripts folder (.oldpal/scripts/{session} or .assistants/scripts/{session}). Provide a filename and it will be saved under the scripts folder.",
37447
37481
  parameters: {
37448
37482
  type: "object",
37449
37483
  properties: {
37450
37484
  filename: {
37451
37485
  type: "string",
37452
- description: "The filename to write to (will be saved in .assistants/scripts)"
37486
+ description: "The filename to write to (saved in the project scripts folder)"
37453
37487
  },
37454
37488
  content: {
37455
37489
  type: "string",
@@ -37487,7 +37521,7 @@ class FilesystemTools {
37487
37521
  code: ErrorCodes.TOOL_PERMISSION_DENIED,
37488
37522
  recoverable: false,
37489
37523
  retryable: false,
37490
- suggestion: "Write only within the .assistants/scripts/ folder."
37524
+ suggestion: "Write only within the project scripts folder."
37491
37525
  });
37492
37526
  }
37493
37527
  try {
@@ -38230,7 +38264,7 @@ function isPrivateIPv4(octets) {
38230
38264
  // packages/core/src/tools/feedback.ts
38231
38265
  init_src();
38232
38266
  import { join as join5 } from "path";
38233
- import { mkdirSync, writeFileSync } from "fs";
38267
+ import { existsSync as existsSync3, mkdirSync, writeFileSync } from "fs";
38234
38268
  function normalizeTags(value) {
38235
38269
  if (Array.isArray(value)) {
38236
38270
  const tags = value.map((t) => String(t).trim()).filter(Boolean);
@@ -38242,8 +38276,16 @@ function normalizeTags(value) {
38242
38276
  }
38243
38277
  return;
38244
38278
  }
38245
- function saveFeedbackEntry(entry) {
38246
- const feedbackDir = join5(getConfigDir(), "feedback");
38279
+ function resolveFeedbackDir(cwd2) {
38280
+ const baseCwd = cwd2 && cwd2.trim().length > 0 ? cwd2 : process.cwd();
38281
+ const legacyDir = join5(baseCwd, ".oldpal");
38282
+ if (existsSync3(legacyDir)) {
38283
+ return join5(legacyDir, "feedback");
38284
+ }
38285
+ return join5(getConfigDir(), "feedback");
38286
+ }
38287
+ function saveFeedbackEntry(entry, cwd2) {
38288
+ const feedbackDir = resolveFeedbackDir(cwd2);
38247
38289
  mkdirSync(feedbackDir, { recursive: true });
38248
38290
  const path2 = join5(feedbackDir, `${entry.id}.json`);
38249
38291
  writeFileSync(path2, JSON.stringify(entry, null, 2));
@@ -38330,7 +38372,7 @@ class FeedbackTool {
38330
38372
  static executor = async (input) => {
38331
38373
  try {
38332
38374
  const entry = buildEntry(input, { source: input.source || "tool" });
38333
- const { path: path2 } = saveFeedbackEntry(entry);
38375
+ const { path: path2 } = saveFeedbackEntry(entry, typeof input.cwd === "string" ? input.cwd : undefined);
38334
38376
  return `Feedback saved locally.
38335
38377
  ID: ${entry.id}
38336
38378
  Path: ${path2}`;
@@ -38802,7 +38844,7 @@ class SchedulerTool {
38802
38844
 
38803
38845
  // packages/core/src/tools/image.ts
38804
38846
  init_src();
38805
- import { existsSync as existsSync2, writeFileSync as writeFileSync2, unlinkSync } from "fs";
38847
+ import { existsSync as existsSync4, writeFileSync as writeFileSync2, unlinkSync } from "fs";
38806
38848
  import { tmpdir } from "os";
38807
38849
  import { join as join7 } from "path";
38808
38850
  import { homedir as homedir4 } from "os";
@@ -38889,7 +38931,7 @@ class ImageDisplayTool {
38889
38931
  return `Error: Failed to fetch image: ${error instanceof Error ? error.message : String(error)}`;
38890
38932
  }
38891
38933
  }
38892
- if (!existsSync2(localPath)) {
38934
+ if (!existsSync4(localPath)) {
38893
38935
  return `Error: Image file not found: ${localPath}`;
38894
38936
  }
38895
38937
  try {
@@ -38914,7 +38956,7 @@ class ImageDisplayTool {
38914
38956
  } catch (error) {
38915
38957
  return `Error: ${error instanceof Error ? error.message : String(error)}`;
38916
38958
  } finally {
38917
- if (tempFile && existsSync2(tempFile)) {
38959
+ if (tempFile && existsSync4(tempFile)) {
38918
38960
  try {
38919
38961
  unlinkSync(tempFile);
38920
38962
  } catch {}
@@ -39418,7 +39460,7 @@ Respond with JSON only: {"allow": boolean, "reason": string}`;
39418
39460
  }
39419
39461
  }
39420
39462
  // packages/core/src/commands/loader.ts
39421
- import { existsSync as existsSync3, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
39463
+ import { existsSync as existsSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
39422
39464
  import { join as join9, basename as basename2, extname } from "path";
39423
39465
  import { homedir as homedir6 } from "os";
39424
39466
 
@@ -39442,7 +39484,7 @@ class CommandLoader {
39442
39484
  await this.loadFromDirectory(legacyProjectDir, "project");
39443
39485
  }
39444
39486
  async loadFromDirectory(dir, source, prefix = "") {
39445
- if (!existsSync3(dir))
39487
+ if (!existsSync5(dir))
39446
39488
  return;
39447
39489
  const entries = readdirSync2(dir);
39448
39490
  for (const entry of entries) {
@@ -39673,7 +39715,7 @@ ${stderr}`;
39673
39715
  // packages/core/src/commands/builtin.ts
39674
39716
  import { join as join10 } from "path";
39675
39717
  import { homedir as homedir7, platform as platform2, release, arch } from "os";
39676
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
39718
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
39677
39719
  init_src();
39678
39720
  var VERSION = "0.6.14";
39679
39721
  function resolveAuthTimeout(resolve4) {
@@ -40608,7 +40650,7 @@ Format the summary as a brief bullet-point list. This summary will replace the c
40608
40650
  message += `**Config File Locations:**
40609
40651
  `;
40610
40652
  for (const path2 of configPaths) {
40611
- const exists = existsSync4(path2);
40653
+ const exists = existsSync6(path2);
40612
40654
  message += ` ${exists ? "\u2713" : "\u25CB"} ${path2}
40613
40655
  `;
40614
40656
  }
@@ -40652,7 +40694,7 @@ Please summarize the last interaction and suggest 2-3 next steps.
40652
40694
  - Ask a follow-up question if needed
40653
40695
  `;
40654
40696
  const examplePath = join10(commandsDir, "reflect.md");
40655
- if (!existsSync4(examplePath)) {
40697
+ if (!existsSync6(examplePath)) {
40656
40698
  writeFileSync3(examplePath, exampleCommand);
40657
40699
  }
40658
40700
  let message = `
@@ -41230,7 +41272,7 @@ No security events recorded.
41230
41272
  };
41231
41273
  let localPath = "";
41232
41274
  try {
41233
- const saved = saveFeedbackEntry(localEntry);
41275
+ const saved = saveFeedbackEntry(localEntry, context.cwd);
41234
41276
  localPath = saved.path;
41235
41277
  } catch {
41236
41278
  localPath = "";
@@ -41719,7 +41761,7 @@ function validateToolCalls(toolCalls, tools) {
41719
41761
  }
41720
41762
 
41721
41763
  // packages/core/src/voice/utils.ts
41722
- import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
41764
+ import { existsSync as existsSync8, readFileSync as readFileSync3 } from "fs";
41723
41765
  import { homedir as homedir9 } from "os";
41724
41766
  import { join as join12 } from "path";
41725
41767
  import { spawnSync } from "child_process";
@@ -41727,7 +41769,7 @@ function loadApiKeyFromSecrets2(key) {
41727
41769
  const envHome = process.env.HOME || process.env.USERPROFILE;
41728
41770
  const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir9();
41729
41771
  const secretsPath = join12(homeDir, ".secrets");
41730
- if (!existsSync6(secretsPath))
41772
+ if (!existsSync8(secretsPath))
41731
41773
  return;
41732
41774
  try {
41733
41775
  const content = readFileSync3(secretsPath, "utf-8");
@@ -42231,13 +42273,13 @@ class VoiceManager {
42231
42273
  }
42232
42274
  // packages/core/src/identity/assistant-manager.ts
42233
42275
  init_src();
42234
- import { existsSync as existsSync8 } from "fs";
42276
+ import { existsSync as existsSync10 } from "fs";
42235
42277
  import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile6, rm as rm2 } from "fs/promises";
42236
42278
  import { join as join17 } from "path";
42237
42279
 
42238
42280
  // packages/core/src/identity/identity-manager.ts
42239
42281
  init_src();
42240
- import { existsSync as existsSync7 } from "fs";
42282
+ import { existsSync as existsSync9 } from "fs";
42241
42283
  import { mkdir as mkdir3, readFile as readFile5, writeFile as writeFile5, rm } from "fs/promises";
42242
42284
  import { join as join16 } from "path";
42243
42285
  var DEFAULT_PROFILE = {
@@ -42387,7 +42429,7 @@ class IdentityManager {
42387
42429
  `);
42388
42430
  }
42389
42431
  async readIndex() {
42390
- if (!existsSync7(this.indexPath)) {
42432
+ if (!existsSync9(this.indexPath)) {
42391
42433
  return { identities: [] };
42392
42434
  }
42393
42435
  try {
@@ -42412,7 +42454,7 @@ class IdentityManager {
42412
42454
  }
42413
42455
  async readIdentity(id) {
42414
42456
  const path2 = this.identityPath(id);
42415
- if (!existsSync7(path2))
42457
+ if (!existsSync9(path2))
42416
42458
  return null;
42417
42459
  try {
42418
42460
  const raw = await readFile5(path2, "utf-8");
@@ -42426,7 +42468,7 @@ class IdentityManager {
42426
42468
  await writeFile5(this.identityPath(identity.id), JSON.stringify(identity, null, 2));
42427
42469
  }
42428
42470
  async readActive() {
42429
- if (!existsSync7(this.activePath))
42471
+ if (!existsSync9(this.activePath))
42430
42472
  return null;
42431
42473
  try {
42432
42474
  const raw = await readFile5(this.activePath, "utf-8");
@@ -42441,7 +42483,7 @@ class IdentityManager {
42441
42483
  await writeFile5(this.activePath, JSON.stringify({ id }, null, 2));
42442
42484
  }
42443
42485
  async loadAssistant() {
42444
- if (!existsSync7(this.assistantConfigPath()))
42486
+ if (!existsSync9(this.assistantConfigPath()))
42445
42487
  return null;
42446
42488
  try {
42447
42489
  const raw = await readFile5(this.assistantConfigPath(), "utf-8");
@@ -42559,7 +42601,7 @@ class AssistantManager {
42559
42601
  return new IdentityManager(assistantId, this.basePath);
42560
42602
  }
42561
42603
  async readIndex() {
42562
- if (!existsSync8(this.indexPath)) {
42604
+ if (!existsSync10(this.indexPath)) {
42563
42605
  return { assistants: [] };
42564
42606
  }
42565
42607
  try {
@@ -42584,7 +42626,7 @@ class AssistantManager {
42584
42626
  }
42585
42627
  async readAssistant(id) {
42586
42628
  const configPath = this.assistantConfigPath(id);
42587
- if (!existsSync8(configPath))
42629
+ if (!existsSync10(configPath))
42588
42630
  return null;
42589
42631
  try {
42590
42632
  const raw = await readFile6(configPath, "utf-8");
@@ -42599,7 +42641,7 @@ class AssistantManager {
42599
42641
  await writeFile6(this.assistantConfigPath(assistant.id), JSON.stringify(assistant, null, 2));
42600
42642
  }
42601
42643
  async readActive() {
42602
- if (!existsSync8(this.activePath))
42644
+ if (!existsSync10(this.activePath))
42603
42645
  return null;
42604
42646
  try {
42605
42647
  const raw = await readFile6(this.activePath, "utf-8");
@@ -42700,6 +42742,7 @@ class AgentLoop {
42700
42742
  await this.initializeIdentitySystem();
42701
42743
  const connectorNames = this.config.connectors && this.config.connectors.length > 0 && !this.config.connectors.includes("*") ? this.config.connectors : undefined;
42702
42744
  this.connectorBridge.fastDiscover(connectorNames);
42745
+ this.connectorBridge.registerAll(this.toolRegistry);
42703
42746
  this.connectorDiscovery = this.connectorBridge.discover(connectorNames).then(() => {
42704
42747
  this.connectorBridge.registerAll(this.toolRegistry);
42705
42748
  }).catch(() => {});
@@ -43657,7 +43700,7 @@ function parseErrorCode(message) {
43657
43700
  // packages/core/src/memory/sessions.ts
43658
43701
  init_src();
43659
43702
  // packages/core/src/migration/migrate-to-assistants.ts
43660
- import { existsSync as existsSync9 } from "fs";
43703
+ import { existsSync as existsSync11 } from "fs";
43661
43704
  import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile7, rename, cp } from "fs/promises";
43662
43705
  import { join as join19 } from "path";
43663
43706
  import { homedir as homedir10 } from "os";
@@ -43666,14 +43709,14 @@ async function ensureDir(path2) {
43666
43709
  await mkdir5(path2, { recursive: true });
43667
43710
  }
43668
43711
  async function copyIfExists(source, destination) {
43669
- if (!existsSync9(source))
43712
+ if (!existsSync11(source))
43670
43713
  return false;
43671
43714
  await ensureDir(join19(destination, ".."));
43672
43715
  await cp(source, destination, { recursive: true });
43673
43716
  return true;
43674
43717
  }
43675
43718
  async function readJson(path2) {
43676
- if (!existsSync9(path2))
43719
+ if (!existsSync11(path2))
43677
43720
  return null;
43678
43721
  try {
43679
43722
  const raw = await readFile7(path2, "utf-8");
@@ -43691,13 +43734,13 @@ async function migrateFromOldpal() {
43691
43734
  const home = homedir10();
43692
43735
  const oldPath = join19(home, ".oldpal");
43693
43736
  const newPath = join19(home, ".assistants");
43694
- if (!existsSync9(oldPath)) {
43737
+ if (!existsSync11(oldPath)) {
43695
43738
  result.success = true;
43696
43739
  return result;
43697
43740
  }
43698
- if (existsSync9(newPath)) {
43741
+ if (existsSync11(newPath)) {
43699
43742
  const marker = join19(newPath, "migration", MIGRATION_MARKER);
43700
- if (existsSync9(marker)) {
43743
+ if (existsSync11(marker)) {
43701
43744
  result.success = true;
43702
43745
  return result;
43703
43746
  }
@@ -43765,7 +43808,7 @@ init_anthropic();
43765
43808
  init_src();
43766
43809
 
43767
43810
  // packages/core/src/logger.ts
43768
- import { existsSync as existsSync10, mkdirSync as mkdirSync6, appendFileSync, readdirSync as readdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
43811
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, appendFileSync, readdirSync as readdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
43769
43812
  import { join as join20 } from "path";
43770
43813
  class Logger {
43771
43814
  logDir;
@@ -43779,7 +43822,7 @@ class Logger {
43779
43822
  this.logFile = join20(this.logDir, `${date}.log`);
43780
43823
  }
43781
43824
  ensureDir(dir) {
43782
- if (!existsSync10(dir)) {
43825
+ if (!existsSync12(dir)) {
43783
43826
  mkdirSync6(dir, { recursive: true });
43784
43827
  }
43785
43828
  }
@@ -43825,7 +43868,7 @@ class SessionStorage {
43825
43868
  this.sessionFile = join20(this.sessionsDir, `${sessionId}.json`);
43826
43869
  }
43827
43870
  ensureDir(dir) {
43828
- if (!existsSync10(dir)) {
43871
+ if (!existsSync12(dir)) {
43829
43872
  mkdirSync6(dir, { recursive: true });
43830
43873
  }
43831
43874
  }
@@ -43839,7 +43882,7 @@ class SessionStorage {
43839
43882
  }
43840
43883
  load() {
43841
43884
  try {
43842
- if (!existsSync10(this.sessionFile))
43885
+ if (!existsSync12(this.sessionFile))
43843
43886
  return null;
43844
43887
  return JSON.parse(readFileSync6(this.sessionFile, "utf-8"));
43845
43888
  } catch {
@@ -43849,7 +43892,7 @@ class SessionStorage {
43849
43892
  static getActiveAssistantId() {
43850
43893
  try {
43851
43894
  const activePath = join20(getConfigDir(), "active.json");
43852
- if (!existsSync10(activePath))
43895
+ if (!existsSync12(activePath))
43853
43896
  return null;
43854
43897
  const raw = readFileSync6(activePath, "utf-8");
43855
43898
  const data = JSON.parse(raw);
@@ -43863,7 +43906,7 @@ class SessionStorage {
43863
43906
  const resolvedId = assistantId ?? SessionStorage.getActiveAssistantId();
43864
43907
  if (resolvedId) {
43865
43908
  const assistantDir = join20(root, "assistants", resolvedId, "sessions");
43866
- if (existsSync10(assistantDir)) {
43909
+ if (existsSync12(assistantDir)) {
43867
43910
  return assistantDir;
43868
43911
  }
43869
43912
  }
@@ -43871,7 +43914,7 @@ class SessionStorage {
43871
43914
  }
43872
43915
  static listSessions(assistantId) {
43873
43916
  const sessionsDir = SessionStorage.resolveSessionsDir(assistantId);
43874
- if (!existsSync10(sessionsDir))
43917
+ if (!existsSync12(sessionsDir))
43875
43918
  return [];
43876
43919
  const sessions = [];
43877
43920
  const files = readdirSync3(sessionsDir);
@@ -43901,7 +43944,7 @@ class SessionStorage {
43901
43944
  const sessionsDir = SessionStorage.resolveSessionsDir(assistantId);
43902
43945
  const sessionFile = join20(sessionsDir, `${sessionId}.json`);
43903
43946
  try {
43904
- if (!existsSync10(sessionFile))
43947
+ if (!existsSync12(sessionFile))
43905
43948
  return null;
43906
43949
  return JSON.parse(readFileSync6(sessionFile, "utf-8"));
43907
43950
  } catch {
@@ -43924,7 +43967,7 @@ function initAssistantsDir() {
43924
43967
  join20(baseDir, "migration")
43925
43968
  ];
43926
43969
  for (const dir of dirs) {
43927
- if (!existsSync10(dir)) {
43970
+ if (!existsSync12(dir)) {
43928
43971
  mkdirSync6(dir, { recursive: true });
43929
43972
  }
43930
43973
  }
@@ -43943,6 +43986,8 @@ class EmbeddedClient {
43943
43986
  startedAt;
43944
43987
  initialMessages = null;
43945
43988
  assistantId = null;
43989
+ messageQueue = [];
43990
+ processingQueue = false;
43946
43991
  constructor(cwd2, options) {
43947
43992
  initAssistantsDir();
43948
43993
  const sessionId = options?.sessionId || generateId();
@@ -44004,6 +44049,15 @@ class EmbeddedClient {
44004
44049
  if (!this.initialized) {
44005
44050
  await this.initialize();
44006
44051
  }
44052
+ if (this.agent.isProcessing()) {
44053
+ this.logger.info("Queuing message (agent busy)", { message, queueLength: this.messageQueue.length + 1 });
44054
+ this.messageQueue.push(message);
44055
+ return;
44056
+ }
44057
+ await this.processMessage(message);
44058
+ await this.drainQueue();
44059
+ }
44060
+ async processMessage(message) {
44007
44061
  this.logger.info("User message", { message });
44008
44062
  try {
44009
44063
  await this.agent.process(message);
@@ -44028,6 +44082,21 @@ class EmbeddedClient {
44028
44082
  }
44029
44083
  }
44030
44084
  }
44085
+ async drainQueue() {
44086
+ if (this.processingQueue)
44087
+ return;
44088
+ this.processingQueue = true;
44089
+ try {
44090
+ while (this.messageQueue.length > 0 && !this.agent.isProcessing()) {
44091
+ const nextMessage = this.messageQueue.shift();
44092
+ if (nextMessage) {
44093
+ await this.processMessage(nextMessage);
44094
+ }
44095
+ }
44096
+ } finally {
44097
+ this.processingQueue = false;
44098
+ }
44099
+ }
44031
44100
  saveSession() {
44032
44101
  this.session.save({
44033
44102
  messages: this.messages,
@@ -44109,6 +44178,13 @@ class EmbeddedClient {
44109
44178
  getMessages() {
44110
44179
  return [...this.messages];
44111
44180
  }
44181
+ getQueueLength() {
44182
+ return this.messageQueue.length;
44183
+ }
44184
+ clearQueue() {
44185
+ this.messageQueue = [];
44186
+ this.logger.info("Message queue cleared");
44187
+ }
44112
44188
  }
44113
44189
  // packages/core/src/sessions/registry.ts
44114
44190
  class SessionRegistry {
@@ -44684,7 +44760,13 @@ function extractBlockSections(text, blocks) {
44684
44760
  const indent = gridMatch[1] ?? "";
44685
44761
  const header = gridMatch[2] ?? "";
44686
44762
  const attrs = parseAttributes(header);
44687
- const columns = Math.max(1, Math.min(4, Number(attrs.columns || attrs.cols || 2)));
44763
+ const rawColumns = attrs.columns || attrs.cols;
44764
+ let columns = Number(rawColumns ?? 2);
44765
+ if (!Number.isFinite(columns) || columns <= 0) {
44766
+ output.push(createMalformedBlock(blocks, indent, "grid", `Invalid columns value "${rawColumns ?? ""}". Using 2.`));
44767
+ columns = 2;
44768
+ }
44769
+ columns = Math.max(1, Math.min(4, Math.round(columns)));
44688
44770
  const parsed = parseDelimitedBlock(lines, i, indent);
44689
44771
  if (!parsed) {
44690
44772
  output.push(line);
@@ -44750,24 +44832,38 @@ function extractCards(body) {
44750
44832
  let i = 0;
44751
44833
  while (i < lines.length) {
44752
44834
  const line = lines[i];
44753
- const match = line.match(/^\s*:::card(.*)$/);
44835
+ const match = line.match(/^(\s*):::card(.*)$/);
44754
44836
  if (!match) {
44755
44837
  i += 1;
44756
44838
  continue;
44757
44839
  }
44758
- const attrs = parseAttributes(match[1] ?? "");
44840
+ const indent = match[1] ?? "";
44841
+ const attrs = parseAttributes(match[2] ?? "");
44759
44842
  const type = String(attrs.type || "note");
44760
44843
  const title = attrs.title ? String(attrs.title) : undefined;
44761
44844
  const bodyLines = [];
44845
+ let closed = false;
44762
44846
  i += 1;
44763
- while (i < lines.length && lines[i].trim() !== ":::") {
44764
- bodyLines.push(lines[i]);
44847
+ while (i < lines.length) {
44848
+ const current = lines[i];
44849
+ if (current.trim() === ":::" && current.startsWith(indent)) {
44850
+ closed = true;
44851
+ i += 1;
44852
+ break;
44853
+ }
44854
+ bodyLines.push(current);
44765
44855
  i += 1;
44766
44856
  }
44767
- if (i < lines.length && lines[i].trim() === ":::") {
44768
- i += 1;
44857
+ if (!closed) {
44858
+ cards.push({
44859
+ type: "warning",
44860
+ title: "Malformed card",
44861
+ body: "Missing closing ::: for card."
44862
+ });
44863
+ break;
44769
44864
  }
44770
- cards.push({ type, title, body: bodyLines.join(`
44865
+ const stripped = stripIndent(bodyLines, indent);
44866
+ cards.push({ type, title, body: stripped.join(`
44771
44867
  `) });
44772
44868
  }
44773
44869
  return cards;
@@ -44804,12 +44900,12 @@ function stripIndent(lines, indent) {
44804
44900
  return lines;
44805
44901
  return lines.map((line) => line.startsWith(indent) ? line.slice(indent.length) : line);
44806
44902
  }
44807
- function createMalformedBlock(blocks, indent, kind2) {
44903
+ function createMalformedBlock(blocks, indent, kind2, message) {
44808
44904
  blocks.push({
44809
44905
  kind: "block",
44810
44906
  type: "warning",
44811
44907
  title: "Malformed block",
44812
- body: `Missing closing ::: for ${kind2}.`,
44908
+ body: message || `Missing closing ::: for ${kind2}.`,
44813
44909
  indent
44814
44910
  });
44815
44911
  return `@@BLOCKSECTION${blocks.length - 1}@@`;
@@ -44848,7 +44944,7 @@ function renderBlock(type, title, body, maxWidth, indent = "") {
44848
44944
  const content = parseMarkdown(body, { skipBlocks: true, maxWidth });
44849
44945
  const lines = content ? content.split(`
44850
44946
  `) : [];
44851
- return renderBox(header, lines, type, maxWidth, indent);
44947
+ return renderBox(header, lines, type, maxWidth, indent, Boolean(maxWidth));
44852
44948
  }
44853
44949
  function renderCard(card, maxWidth, indent = "", forceWidth = false) {
44854
44950
  const header = formatBlockHeader(card.type, card.title);
@@ -44860,11 +44956,17 @@ function renderCard(card, maxWidth, indent = "", forceWidth = false) {
44860
44956
  function renderCardGrid(cards, columns, maxWidth, indent = "") {
44861
44957
  const gap = 2;
44862
44958
  const totalWidth = maxWidth ? Math.max(20, maxWidth) : undefined;
44863
- const cardTotalWidth = totalWidth ? Math.max(20, Math.floor((totalWidth - gap * (columns - 1)) / columns)) : undefined;
44959
+ let effectiveColumns = columns;
44960
+ if (totalWidth) {
44961
+ const minCardWidth = 18;
44962
+ const maxColumns = Math.max(1, Math.floor((totalWidth + gap) / (minCardWidth + gap)));
44963
+ effectiveColumns = Math.min(columns, maxColumns);
44964
+ }
44965
+ const cardTotalWidth = totalWidth ? Math.max(8, Math.floor((totalWidth - gap * (effectiveColumns - 1)) / effectiveColumns)) : undefined;
44864
44966
  const cardLines = cards.map((card) => renderCard(card, cardTotalWidth, "", true));
44865
44967
  const rows = [];
44866
- for (let i = 0;i < cardLines.length; i += columns) {
44867
- rows.push(cardLines.slice(i, i + columns));
44968
+ for (let i = 0;i < cardLines.length; i += effectiveColumns) {
44969
+ rows.push(cardLines.slice(i, i + effectiveColumns));
44868
44970
  }
44869
44971
  const output = [];
44870
44972
  for (const row of rows) {
@@ -44907,8 +45009,8 @@ function getBlockIcon(type) {
44907
45009
  return "\u2139";
44908
45010
  }
44909
45011
  }
44910
- function renderBox(header, lines, type, maxWidth, indent = "") {
44911
- return renderBoxLines(header, lines, type, maxWidth, indent).join(`
45012
+ function renderBox(header, lines, type, maxWidth, indent = "", forceWidth = false) {
45013
+ return renderBoxLines(header, lines, type, maxWidth, indent, forceWidth).join(`
44912
45014
  `);
44913
45015
  }
44914
45016
  function renderBoxLines(header, lines, type, maxWidth, indent = "", forceWidth = false) {
@@ -45227,6 +45329,7 @@ var jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
45227
45329
  function Messages4({
45228
45330
  messages,
45229
45331
  currentResponse,
45332
+ streamingMessages = [],
45230
45333
  currentToolCall,
45231
45334
  lastToolResult,
45232
45335
  activityLog = [],
@@ -45235,9 +45338,14 @@ function Messages4({
45235
45338
  queuedMessageIds
45236
45339
  }) {
45237
45340
  const [now2, setNow] = import_react24.useState(Date.now());
45238
- const endIndex = messages.length - scrollOffset;
45341
+ const combinedMessages = import_react24.useMemo(() => [...messages, ...streamingMessages], [messages, streamingMessages]);
45342
+ const endIndex = combinedMessages.length - scrollOffset;
45239
45343
  const startIndex = Math.max(0, endIndex - maxVisible);
45240
- const visibleMessages = messages.slice(startIndex, endIndex);
45344
+ const visibleCombined = combinedMessages.slice(startIndex, endIndex);
45345
+ const historicalCount = messages.length;
45346
+ const splitIndex = Math.max(0, Math.min(visibleCombined.length, historicalCount - startIndex));
45347
+ const visibleMessages = visibleCombined.slice(0, splitIndex);
45348
+ const visibleStreaming = visibleCombined.slice(splitIndex);
45241
45349
  const groupedMessages = groupConsecutiveToolMessages(visibleMessages);
45242
45350
  const historicalItems = groupedMessages.map((group) => {
45243
45351
  if (group.type === "single") {
@@ -45311,19 +45419,30 @@ function Messages4({
45311
45419
  const elapsedText = formatDuration(elapsedMs);
45312
45420
  return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
45313
45421
  marginY: 1,
45422
+ flexDirection: "column",
45314
45423
  children: [
45315
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
45316
- dimColor: true,
45317
- children: "\u2699 "
45318
- }, undefined, false, undefined, this),
45319
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
45320
- dimColor: true,
45424
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
45321
45425
  children: [
45322
- formatToolCall(entry.toolCall),
45323
- " \xB7 ",
45324
- elapsedText
45426
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
45427
+ dimColor: true,
45428
+ children: "\u2699 "
45429
+ }, undefined, false, undefined, this),
45430
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
45431
+ dimColor: true,
45432
+ children: formatToolCall(entry.toolCall)
45433
+ }, undefined, false, undefined, this)
45325
45434
  ]
45326
- }, undefined, true, undefined, this)
45435
+ }, undefined, true, undefined, this),
45436
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
45437
+ marginLeft: 2,
45438
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
45439
+ dimColor: true,
45440
+ children: [
45441
+ elapsedText,
45442
+ " elapsed"
45443
+ ]
45444
+ }, undefined, true, undefined, this)
45445
+ }, undefined, false, undefined, this)
45327
45446
  ]
45328
45447
  }, entry.id, true, undefined, this);
45329
45448
  }
@@ -45348,6 +45467,10 @@ function Messages4({
45348
45467
  }
45349
45468
  return null;
45350
45469
  }),
45470
+ visibleStreaming.map((message) => /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(MessageBubble, {
45471
+ message,
45472
+ queuedMessageIds
45473
+ }, message.id, false, undefined, this)),
45351
45474
  currentResponse && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
45352
45475
  marginY: 1,
45353
45476
  children: [
@@ -46472,6 +46595,10 @@ function App2({ cwd: cwd2, version }) {
46472
46595
  setError(chunk.error);
46473
46596
  setIsProcessing(false);
46474
46597
  isProcessingRef.current = false;
46598
+ const active = registryRef.current.getActiveSession();
46599
+ if (active) {
46600
+ registryRef.current.setProcessing(active.id, false);
46601
+ }
46475
46602
  } else if (chunk.type === "exit") {
46476
46603
  registry2.closeAll();
46477
46604
  exit();
@@ -46486,6 +46613,10 @@ function App2({ cwd: cwd2, version }) {
46486
46613
  }
46487
46614
  setIsProcessing(false);
46488
46615
  isProcessingRef.current = false;
46616
+ const active = registryRef.current.getActiveSession();
46617
+ if (active) {
46618
+ registryRef.current.setProcessing(active.id, false);
46619
+ }
46489
46620
  queueMicrotask(() => {
46490
46621
  resetTurnState();
46491
46622
  });
@@ -46511,6 +46642,10 @@ function App2({ cwd: cwd2, version }) {
46511
46642
  setError(err.message);
46512
46643
  setIsProcessing(false);
46513
46644
  isProcessingRef.current = false;
46645
+ const active = registryRef.current.getActiveSession();
46646
+ if (active) {
46647
+ registryRef.current.setProcessing(active.id, false);
46648
+ }
46514
46649
  });
46515
46650
  const session = await registry2.createSession(cwd2);
46516
46651
  setActiveSessionId(session.id);
@@ -46581,6 +46716,18 @@ function App2({ cwd: cwd2, version }) {
46581
46716
  const queuedMessageIds = import_react29.useMemo(() => new Set(activeQueue.map((msg) => msg.id)), [activeQueue]);
46582
46717
  const wrapChars = columns ? Math.max(40, columns - 4) : MESSAGE_WRAP_CHARS;
46583
46718
  const displayMessages = import_react29.useMemo(() => buildDisplayMessages(messages, MESSAGE_CHUNK_LINES, wrapChars), [messages, wrapChars]);
46719
+ const streamingMessages = import_react29.useMemo(() => {
46720
+ if (!isProcessing || !currentResponse.trim())
46721
+ return [];
46722
+ const streamingMessage = {
46723
+ id: "streaming-response",
46724
+ role: "assistant",
46725
+ content: currentResponse,
46726
+ timestamp: now()
46727
+ };
46728
+ return buildDisplayMessages([streamingMessage], MESSAGE_CHUNK_LINES, wrapChars);
46729
+ }, [currentResponse, isProcessing, wrapChars]);
46730
+ const displayCount = displayMessages.length + streamingMessages.length;
46584
46731
  import_react29.useEffect(() => {
46585
46732
  if (!isProcessing && activeQueue.length > 0) {
46586
46733
  processQueue();
@@ -46590,23 +46737,23 @@ function App2({ cwd: cwd2, version }) {
46590
46737
  if (autoScroll) {
46591
46738
  setScrollOffset(0);
46592
46739
  }
46593
- }, [displayMessages.length, autoScroll]);
46740
+ }, [displayCount, autoScroll]);
46594
46741
  import_react29.useEffect(() => {
46595
46742
  const prevCount = prevDisplayCountRef.current;
46596
- if (!autoScroll && displayMessages.length > prevCount) {
46597
- const delta = displayMessages.length - prevCount;
46743
+ if (!autoScroll && displayCount > prevCount) {
46744
+ const delta = displayCount - prevCount;
46598
46745
  setScrollOffset((prev) => prev + delta);
46599
46746
  }
46600
- prevDisplayCountRef.current = displayMessages.length;
46601
- }, [displayMessages.length, autoScroll]);
46747
+ prevDisplayCountRef.current = displayCount;
46748
+ }, [displayCount, autoScroll]);
46602
46749
  const reservedLines = 8;
46603
46750
  const baseMaxVisible = rows ? Math.max(3, rows - reservedLines) : 10;
46604
46751
  const toolCallsHeight = isProcessing ? Math.min(toolCallsRef.current.length, 5) : 0;
46605
46752
  const maxVisibleMessages = Math.max(3, baseMaxVisible - toolCallsHeight);
46606
46753
  import_react29.useEffect(() => {
46607
- const maxOffset = Math.max(0, displayMessages.length - maxVisibleMessages);
46754
+ const maxOffset = Math.max(0, displayCount - maxVisibleMessages);
46608
46755
  setScrollOffset((prev) => Math.min(prev, maxOffset));
46609
- }, [displayMessages.length, maxVisibleMessages]);
46756
+ }, [displayCount, maxVisibleMessages]);
46610
46757
  const sessions = registry2.listSessions();
46611
46758
  const activeSession = registry2.getActiveSession();
46612
46759
  const sessionIndex = activeSessionId ? registry2.getSessionIndex(activeSessionId) : 0;
@@ -46685,7 +46832,7 @@ function App2({ cwd: cwd2, version }) {
46685
46832
  }
46686
46833
  if (key.pageUp || key.shift && key.upArrow) {
46687
46834
  setScrollOffset((prev) => {
46688
- const maxOffset = Math.max(0, displayMessages.length - maxVisibleMessages);
46835
+ const maxOffset = Math.max(0, displayCount - maxVisibleMessages);
46689
46836
  const newOffset = Math.min(prev + 3, maxOffset);
46690
46837
  if (newOffset > 0)
46691
46838
  setAutoScroll(false);
@@ -46701,7 +46848,7 @@ function App2({ cwd: cwd2, version }) {
46701
46848
  });
46702
46849
  }
46703
46850
  if (key.ctrl && input === "u") {
46704
- const maxOffset = Math.max(0, displayMessages.length - maxVisibleMessages);
46851
+ const maxOffset = Math.max(0, displayCount - maxVisibleMessages);
46705
46852
  setScrollOffset(maxOffset);
46706
46853
  setAutoScroll(false);
46707
46854
  }
@@ -46760,6 +46907,7 @@ function App2({ cwd: cwd2, version }) {
46760
46907
  resetTurnState();
46761
46908
  setIsProcessing(false);
46762
46909
  isProcessingRef.current = false;
46910
+ registry2.setProcessing(activeSession.id, false);
46763
46911
  await new Promise((r) => setTimeout(r, 100));
46764
46912
  }
46765
46913
  const userMessage = {
@@ -46861,13 +47009,14 @@ function App2({ cwd: cwd2, version }) {
46861
47009
  children: [
46862
47010
  "\u2191 ",
46863
47011
  scrollOffset,
46864
- " more messages above (Shift+\u2193 or Ctrl+D to scroll down)"
47012
+ " more messages above (Shift+\u2193 or Page Down to scroll down)"
46865
47013
  ]
46866
47014
  }, undefined, true, undefined, this)
46867
47015
  }, undefined, false, undefined, this),
46868
47016
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Messages4, {
46869
47017
  messages: displayMessages,
46870
- currentResponse: isProcessing ? currentResponse : undefined,
47018
+ currentResponse: undefined,
47019
+ streamingMessages,
46871
47020
  currentToolCall: undefined,
46872
47021
  lastToolResult: undefined,
46873
47022
  activityLog: isProcessing ? activityLog : [],
@@ -47166,7 +47315,7 @@ function formatStreamEvent(chunk) {
47166
47315
 
47167
47316
  // packages/terminal/src/index.tsx
47168
47317
  var jsx_dev_runtime11 = __toESM(require_jsx_dev_runtime(), 1);
47169
- var VERSION3 = "0.6.15";
47318
+ var VERSION3 = "0.6.16";
47170
47319
  function parseArgs(argv) {
47171
47320
  const args = argv.slice(2);
47172
47321
  const options = {
@@ -47329,4 +47478,4 @@ if (options.print !== null) {
47329
47478
  });
47330
47479
  }
47331
47480
 
47332
- //# debugId=E5501B17CB0867B264756E2164756E21
47481
+ //# debugId=4013F70DB4CACA3C64756E2164756E21