@hasna/assistants 0.6.34 → 0.6.36

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
@@ -17712,14 +17712,13 @@ function sleep(ms) {
17712
17712
  return new Promise((resolve) => setTimeout(resolve, ms));
17713
17713
  }
17714
17714
  function parseFrontmatter(content) {
17715
- const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
17715
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
17716
17716
  if (!match) {
17717
17717
  return { frontmatter: {}, content };
17718
17718
  }
17719
17719
  const [, yamlContent, markdownContent] = match;
17720
17720
  const frontmatter = {};
17721
- const lines = yamlContent.split(`
17722
- `);
17721
+ const lines = yamlContent.split(/\r?\n/);
17723
17722
  for (const line of lines) {
17724
17723
  const colonIndex = line.indexOf(":");
17725
17724
  if (colonIndex === -1)
@@ -28327,14 +28326,14 @@ var exports_anthropic = {};
28327
28326
  __export(exports_anthropic, {
28328
28327
  AnthropicClient: () => AnthropicClient
28329
28328
  });
28330
- import { readFileSync as readFileSync4, existsSync as existsSync8 } from "fs";
28331
- import { homedir as homedir9 } from "os";
28329
+ import { readFileSync as readFileSync4, existsSync as existsSync9 } from "fs";
28330
+ import { homedir as homedir11 } from "os";
28332
28331
  import { join as join14 } from "path";
28333
28332
  function loadApiKeyFromSecrets() {
28334
28333
  const envHome = process.env.HOME || process.env.USERPROFILE;
28335
- const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir9();
28334
+ const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir11();
28336
28335
  const secretsPath = join14(homeDir, ".secrets");
28337
- if (existsSync8(secretsPath)) {
28336
+ if (existsSync9(secretsPath)) {
28338
28337
  try {
28339
28338
  const content = readFileSync4(secretsPath, "utf-8");
28340
28339
  const match = content.match(/export\s+ANTHROPIC_API_KEY\s*=\s*["']?([^"'\n]+)["']?/);
@@ -37325,15 +37324,15 @@ var DEFAULT_CONFIG = {
37325
37324
  },
37326
37325
  energy: {
37327
37326
  enabled: true,
37328
- regenRate: 5,
37329
- lowEnergyThreshold: 30,
37330
- criticalThreshold: 10,
37331
- maxEnergy: 100,
37327
+ regenRate: 500,
37328
+ lowEnergyThreshold: 3000,
37329
+ criticalThreshold: 1000,
37330
+ maxEnergy: 1e4,
37332
37331
  costs: {
37333
- message: 2,
37334
- toolCall: 5,
37335
- llmCall: 3,
37336
- longContext: 10
37332
+ message: 200,
37333
+ toolCall: 500,
37334
+ llmCall: 300,
37335
+ longContext: 1000
37337
37336
  }
37338
37337
  },
37339
37338
  validation: {
@@ -37747,7 +37746,7 @@ function isErrorResult(result) {
37747
37746
  // packages/core/src/tools/connector.ts
37748
37747
  init_errors();
37749
37748
  import { homedir as homedir2 } from "os";
37750
- import { join as join3, delimiter, dirname as dirname2 } from "path";
37749
+ import { join as join3, delimiter, dirname as dirname2, extname } from "path";
37751
37750
  import { readdirSync, statSync, existsSync as existsSync2, mkdirSync, writeFileSync, readFileSync as readFileSync2 } from "fs";
37752
37751
  function resolveTimeout(resolve) {
37753
37752
  resolve({ exitCode: 1 });
@@ -37835,7 +37834,11 @@ class ConnectorBridge {
37835
37834
  if (!stats.isFile()) {
37836
37835
  continue;
37837
37836
  }
37838
- const name = file.replace("connect-", "");
37837
+ const ext = extname(file);
37838
+ let name = file.replace("connect-", "");
37839
+ if (ext && [".exe", ".cmd", ".bat", ".ps1"].includes(ext.toLowerCase())) {
37840
+ name = name.slice(0, -ext.length);
37841
+ }
37839
37842
  if (name && !name.includes(".") && name.length > 1) {
37840
37843
  connectorNames.add(name);
37841
37844
  }
@@ -37889,6 +37892,7 @@ class ConnectorBridge {
37889
37892
  async discover(connectorNames) {
37890
37893
  const names = connectorNames && connectorNames.length > 0 ? connectorNames : this.autoDiscoverConnectorNames();
37891
37894
  if (names.length === 0) {
37895
+ this.connectors = new Map;
37892
37896
  return [];
37893
37897
  }
37894
37898
  const uncached = [];
@@ -37932,16 +37936,17 @@ class ConnectorBridge {
37932
37936
  };
37933
37937
  }
37934
37938
  async populateCache(name) {
37935
- const cli = `connect-${name}`;
37939
+ const cli = await this.resolveConnectorCli(name);
37936
37940
  try {
37937
37941
  let timeoutId = null;
37938
37942
  const timeoutPromise = new Promise((resolve) => {
37939
37943
  timeoutId = setTimeout(resolveTimeout, 500, resolve);
37940
37944
  });
37941
- const result = await Promise.race([
37942
- Bun.$`which ${cli}`.quiet().nothrow(),
37943
- timeoutPromise
37944
- ]);
37945
+ if (!cli) {
37946
+ ConnectorBridge.cache.set(name, null);
37947
+ return;
37948
+ }
37949
+ const result = await Promise.race([Bun.$`which ${cli}`.quiet().nothrow(), timeoutPromise]);
37945
37950
  if (timeoutId) {
37946
37951
  clearTimeout(timeoutId);
37947
37952
  }
@@ -37955,6 +37960,30 @@ class ConnectorBridge {
37955
37960
  ConnectorBridge.cache.set(name, null);
37956
37961
  }
37957
37962
  }
37963
+ async resolveConnectorCli(name) {
37964
+ const base2 = `connect-${name}`;
37965
+ const candidates = [base2];
37966
+ const extCandidates = [".exe", ".cmd", ".bat", ".ps1"];
37967
+ for (const ext of extCandidates) {
37968
+ candidates.push(`${base2}${ext}`);
37969
+ }
37970
+ for (const candidate of candidates) {
37971
+ try {
37972
+ let timeoutId = null;
37973
+ const timeoutPromise = new Promise((resolve) => {
37974
+ timeoutId = setTimeout(resolveTimeout, 500, resolve);
37975
+ });
37976
+ const result = await Promise.race([Bun.$`which ${candidate}`.quiet().nothrow(), timeoutPromise]);
37977
+ if (timeoutId) {
37978
+ clearTimeout(timeoutId);
37979
+ }
37980
+ if (result.exitCode === 0) {
37981
+ return candidate;
37982
+ }
37983
+ } catch {}
37984
+ }
37985
+ return null;
37986
+ }
37958
37987
  async discoverConnector(name, cli) {
37959
37988
  try {
37960
37989
  const helpResult = await Bun.$`${cli} --help`.quiet();
@@ -38494,14 +38523,16 @@ ${stderr || stdout}`.trim(), {
38494
38523
 
38495
38524
  // packages/core/src/tools/filesystem.ts
38496
38525
  import { join as join4, resolve as resolve3, dirname as dirname3, sep } from "path";
38526
+ import { homedir as homedir5 } from "os";
38497
38527
  init_errors();
38498
38528
  var {Glob } = globalThis.Bun;
38499
38529
 
38500
38530
  // packages/core/src/validation/paths.ts
38501
- import { resolve, normalize } from "path";
38531
+ import { resolve, normalize, relative, isAbsolute } from "path";
38532
+ import { homedir as homedir3 } from "os";
38502
38533
  import { lstat, realpath } from "fs/promises";
38503
38534
  async function validatePath(inputPath, options = {}) {
38504
- const normalized = normalize(inputPath);
38535
+ const normalized = normalize(expandHome(inputPath));
38505
38536
  const resolved = resolve(normalized);
38506
38537
  const allowedPaths = options.allowedPaths?.map((p) => resolve(p));
38507
38538
  const blockedPaths = options.blockedPaths?.map((p) => resolve(p));
@@ -38522,7 +38553,7 @@ async function validatePath(inputPath, options = {}) {
38522
38553
  }
38523
38554
  } catch {}
38524
38555
  }
38525
- if (blockedPaths && blockedPaths.some((blocked) => resolved.startsWith(blocked))) {
38556
+ if (blockedPaths && blockedPaths.some((blocked) => isWithinPath(resolved, blocked))) {
38526
38557
  return { valid: false, resolved, error: "Path is in blocked list" };
38527
38558
  }
38528
38559
  if (!isWithinAllowed(resolved, allowedPaths)) {
@@ -38530,15 +38561,35 @@ async function validatePath(inputPath, options = {}) {
38530
38561
  }
38531
38562
  return { valid: true, resolved };
38532
38563
  }
38564
+ function expandHome(value) {
38565
+ if (value === "~")
38566
+ return homedir3();
38567
+ if (value.startsWith("~/")) {
38568
+ return resolve(homedir3(), value.slice(2));
38569
+ }
38570
+ return value;
38571
+ }
38533
38572
  function isWithinAllowed(path, allowed) {
38534
38573
  if (!allowed || allowed.length === 0)
38535
38574
  return true;
38536
38575
  return allowed.some((allowedPath) => path === allowedPath || path.startsWith(`${allowedPath}/`));
38537
38576
  }
38577
+ function isWithinPath(target, base2) {
38578
+ if (target === base2)
38579
+ return true;
38580
+ const rel = relative(base2, target);
38581
+ if (!rel || rel === "")
38582
+ return true;
38583
+ if (rel.startsWith(".."))
38584
+ return false;
38585
+ if (isAbsolute(rel))
38586
+ return false;
38587
+ return true;
38588
+ }
38538
38589
 
38539
38590
  // packages/core/src/security/path-validator.ts
38540
- import { homedir as homedir3 } from "os";
38541
- import { resolve as resolve2 } from "path";
38591
+ import { homedir as homedir4 } from "os";
38592
+ import { resolve as resolve2, relative as relative2, isAbsolute as isAbsolute2 } from "path";
38542
38593
  import { lstat as lstat2, realpath as realpath2 } from "fs/promises";
38543
38594
  var PROTECTED_PATHS = [
38544
38595
  "/etc/passwd",
@@ -38550,11 +38601,12 @@ var PROTECTED_PATHS = [
38550
38601
  "~/.kube/config"
38551
38602
  ];
38552
38603
  async function isPathSafe(targetPath, operation, options = {}) {
38553
- const resolved = resolve2(targetPath);
38554
- const home = homedir3();
38604
+ const expandedTarget = expandHome2(targetPath);
38605
+ const resolved = resolve2(expandedTarget);
38606
+ const home = homedir4();
38555
38607
  for (const protectedPath of PROTECTED_PATHS) {
38556
38608
  const expanded = protectedPath.replace("~", home);
38557
- if (resolved.startsWith(expanded)) {
38609
+ if (isWithinPath2(resolved, expanded)) {
38558
38610
  return {
38559
38611
  safe: false,
38560
38612
  reason: `Cannot ${operation} protected path: ${protectedPath}`
@@ -38576,6 +38628,24 @@ async function isPathSafe(targetPath, operation, options = {}) {
38576
38628
  } catch {}
38577
38629
  return { safe: true };
38578
38630
  }
38631
+ function expandHome2(value) {
38632
+ if (value === "~")
38633
+ return homedir4();
38634
+ if (value.startsWith("~/")) {
38635
+ return resolve2(homedir4(), value.slice(2));
38636
+ }
38637
+ return value;
38638
+ }
38639
+ function isWithinPath2(target, base2) {
38640
+ const rel = relative2(base2, target);
38641
+ if (rel === "")
38642
+ return true;
38643
+ if (rel.startsWith(".."))
38644
+ return false;
38645
+ if (isAbsolute2(rel))
38646
+ return false;
38647
+ return true;
38648
+ }
38579
38649
 
38580
38650
  // packages/core/src/tools/filesystem.ts
38581
38651
  var currentSessionId = "default";
@@ -38592,6 +38662,17 @@ function isInScriptsFolder(path, cwd2, sessionId) {
38592
38662
  }
38593
38663
 
38594
38664
  class FilesystemTools {
38665
+ static resolveInputPath(baseCwd, inputPath) {
38666
+ const envHome = process.env.HOME || process.env.USERPROFILE;
38667
+ const home = envHome && envHome.trim().length > 0 ? envHome : homedir5();
38668
+ if (inputPath === "~") {
38669
+ return home;
38670
+ }
38671
+ if (inputPath.startsWith("~/")) {
38672
+ return resolve3(home, inputPath.slice(2));
38673
+ }
38674
+ return resolve3(baseCwd, inputPath);
38675
+ }
38595
38676
  static registerAll(registry, sessionId) {
38596
38677
  if (sessionId) {
38597
38678
  currentSessionId = sessionId;
@@ -38644,7 +38725,7 @@ class FilesystemTools {
38644
38725
  suggestion: "Provide a valid file path."
38645
38726
  });
38646
38727
  }
38647
- const path = resolve3(baseCwd, rawPath);
38728
+ const path = FilesystemTools.resolveInputPath(baseCwd, rawPath);
38648
38729
  const offset = (input.offset || 1) - 1;
38649
38730
  const limitRaw = input.limit;
38650
38731
  const limit = typeof limitRaw === "number" && limitRaw > 0 ? Math.floor(limitRaw) : undefined;
@@ -38703,7 +38784,10 @@ class FilesystemTools {
38703
38784
  });
38704
38785
  }
38705
38786
  const content = await file.text();
38706
- const lines = content.split(`
38787
+ const normalized = content.replace(/\r\n/g, `
38788
+ `).replace(/\r/g, `
38789
+ `);
38790
+ const lines = normalized.split(`
38707
38791
  `);
38708
38792
  const startLine = Math.max(0, offset);
38709
38793
  const endLine = limit ? startLine + limit : lines.length;
@@ -38859,7 +38943,7 @@ class FilesystemTools {
38859
38943
  static globExecutor = async (input) => {
38860
38944
  const pattern = String(input.pattern || "").trim();
38861
38945
  const baseCwd = input.cwd || process.cwd();
38862
- const searchPath = resolve3(baseCwd, input.path || ".");
38946
+ const searchPath = FilesystemTools.resolveInputPath(baseCwd, input.path || ".");
38863
38947
  try {
38864
38948
  if (!pattern) {
38865
38949
  throw new ToolExecutionError("Pattern is required", {
@@ -38960,7 +39044,7 @@ class FilesystemTools {
38960
39044
  static grepExecutor = async (input) => {
38961
39045
  const pattern = String(input.pattern || "").trim();
38962
39046
  const baseCwd = input.cwd || process.cwd();
38963
- const searchPath = resolve3(baseCwd, input.path || ".");
39047
+ const searchPath = FilesystemTools.resolveInputPath(baseCwd, input.path || ".");
38964
39048
  const globPattern = input.glob || "**/*";
38965
39049
  const caseSensitive = input.caseSensitive || false;
38966
39050
  try {
@@ -39064,7 +39148,7 @@ class FilesystemTools {
39064
39148
  };
39065
39149
  static readPdfExecutor = async (input) => {
39066
39150
  const baseCwd = input.cwd || process.cwd();
39067
- const path = resolve3(baseCwd, input.path);
39151
+ const path = FilesystemTools.resolveInputPath(baseCwd, String(input.path || ""));
39068
39152
  try {
39069
39153
  const safety = await isPathSafe(path, "read", { cwd: baseCwd });
39070
39154
  if (!safety.safe) {
@@ -39983,13 +40067,19 @@ function getNextCronRun(expression, fromTime, timeZone) {
39983
40067
 
39984
40068
  // packages/core/src/scheduler/store.ts
39985
40069
  var DEFAULT_LOCK_TTL_MS = 10 * 60 * 1000;
40070
+ var SAFE_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
39986
40071
  function schedulesDir(cwd2) {
39987
40072
  return join6(getProjectConfigDir(cwd2), "schedules");
39988
40073
  }
39989
40074
  function locksDir(cwd2) {
39990
40075
  return join6(schedulesDir(cwd2), "locks");
39991
40076
  }
40077
+ function isSafeId(id) {
40078
+ return SAFE_ID_PATTERN.test(id);
40079
+ }
39992
40080
  function schedulePath(cwd2, id) {
40081
+ if (!isSafeId(id))
40082
+ return null;
39993
40083
  return join6(schedulesDir(cwd2), `${id}.json`);
39994
40084
  }
39995
40085
  function lockPath(cwd2, id) {
@@ -40022,11 +40112,17 @@ async function listSchedules(cwd2) {
40022
40112
  async function saveSchedule(cwd2, schedule) {
40023
40113
  await ensureDirs(cwd2);
40024
40114
  const path = schedulePath(cwd2, schedule.id);
40115
+ if (!path) {
40116
+ throw new Error(`Invalid schedule id: ${schedule.id}`);
40117
+ }
40025
40118
  await writeFile(path, JSON.stringify(schedule, null, 2), "utf-8");
40026
40119
  }
40027
40120
  async function deleteSchedule(cwd2, id) {
40028
40121
  try {
40029
- await unlink(schedulePath(cwd2, id));
40122
+ const path = schedulePath(cwd2, id);
40123
+ if (!path)
40124
+ return false;
40125
+ await unlink(path);
40030
40126
  return true;
40031
40127
  } catch {
40032
40128
  return false;
@@ -40064,7 +40160,10 @@ async function getDueSchedules(cwd2, nowTime) {
40064
40160
  }
40065
40161
  async function updateSchedule(cwd2, id, updater) {
40066
40162
  try {
40067
- const raw = await readFile(schedulePath(cwd2, id), "utf-8");
40163
+ const path = schedulePath(cwd2, id);
40164
+ if (!path)
40165
+ return null;
40166
+ const raw = await readFile(path, "utf-8");
40068
40167
  const schedule = JSON.parse(raw);
40069
40168
  const updated = updater(schedule);
40070
40169
  await saveSchedule(cwd2, updated);
@@ -40074,6 +40173,8 @@ async function updateSchedule(cwd2, id, updater) {
40074
40173
  }
40075
40174
  }
40076
40175
  async function acquireScheduleLock(cwd2, id, ownerId, ttlMs = DEFAULT_LOCK_TTL_MS, allowRetry = true) {
40176
+ if (!isSafeId(id))
40177
+ return false;
40077
40178
  await ensureDirs(cwd2);
40078
40179
  const path = lockPath(cwd2, id);
40079
40180
  const now2 = Date.now();
@@ -40106,6 +40207,8 @@ async function acquireScheduleLock(cwd2, id, ownerId, ttlMs = DEFAULT_LOCK_TTL_M
40106
40207
  return false;
40107
40208
  }
40108
40209
  async function releaseScheduleLock(cwd2, id, ownerId) {
40210
+ if (!isSafeId(id))
40211
+ return;
40109
40212
  const path = lockPath(cwd2, id);
40110
40213
  try {
40111
40214
  const raw = await readFile(path, "utf-8");
@@ -40116,6 +40219,8 @@ async function releaseScheduleLock(cwd2, id, ownerId) {
40116
40219
  } catch {}
40117
40220
  }
40118
40221
  async function refreshScheduleLock(cwd2, id, ownerId) {
40222
+ if (!isSafeId(id))
40223
+ return;
40119
40224
  const path = lockPath(cwd2, id);
40120
40225
  try {
40121
40226
  const raw = await readFile(path, "utf-8");
@@ -40128,7 +40233,10 @@ async function refreshScheduleLock(cwd2, id, ownerId) {
40128
40233
  }
40129
40234
  async function readSchedule(cwd2, id) {
40130
40235
  try {
40131
- const raw = await readFile(schedulePath(cwd2, id), "utf-8");
40236
+ const path = schedulePath(cwd2, id);
40237
+ if (!path)
40238
+ return null;
40239
+ const raw = await readFile(path, "utf-8");
40132
40240
  const schedule = JSON.parse(raw);
40133
40241
  if (!schedule?.id)
40134
40242
  return null;
@@ -40344,7 +40452,7 @@ init_src();
40344
40452
  import { existsSync as existsSync4, writeFileSync as writeFileSync3, unlinkSync } from "fs";
40345
40453
  import { tmpdir } from "os";
40346
40454
  import { join as join7 } from "path";
40347
- import { homedir as homedir4 } from "os";
40455
+ import { homedir as homedir6 } from "os";
40348
40456
  async function getViuPath() {
40349
40457
  const explicitPath = process.env.ASSISTANTS_VIU_PATH || process.env.VIU_PATH;
40350
40458
  if (explicitPath) {
@@ -40356,7 +40464,7 @@ async function getViuPath() {
40356
40464
  } catch {}
40357
40465
  }
40358
40466
  const envHome = process.env.HOME || process.env.USERPROFILE;
40359
- const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir4();
40467
+ const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir6();
40360
40468
  const locations = [
40361
40469
  "viu",
40362
40470
  join7(homeDir, ".cargo", "bin", "viu"),
@@ -40505,14 +40613,14 @@ Respond with ALLOW or DENY on the first line, followed by a short reason.`,
40505
40613
  // packages/core/src/skills/loader.ts
40506
40614
  init_src();
40507
40615
  import { join as join8, basename, dirname as dirname4 } from "path";
40508
- import { homedir as homedir5 } from "os";
40616
+ import { homedir as homedir7 } from "os";
40509
40617
  var {Glob: Glob2 } = globalThis.Bun;
40510
40618
 
40511
40619
  class SkillLoader {
40512
40620
  skills = new Map;
40513
40621
  async loadAll(projectDir = process.cwd()) {
40514
40622
  const envHome = process.env.HOME || process.env.USERPROFILE;
40515
- const userHome = envHome && envHome.trim().length > 0 ? envHome : homedir5();
40623
+ const userHome = envHome && envHome.trim().length > 0 ? envHome : homedir7();
40516
40624
  const userSkillsDir = join8(userHome, ".assistants", "shared", "skills");
40517
40625
  await this.loadFromDirectory(userSkillsDir);
40518
40626
  const projectSkillsDir = join8(projectDir, ".assistants", "skills");
@@ -40728,6 +40836,7 @@ class HookLoader {
40728
40836
  }
40729
40837
  // packages/core/src/hooks/executor.ts
40730
40838
  init_src();
40839
+ import { existsSync as existsSync5 } from "fs";
40731
40840
  function killSpawnedProcess(proc) {
40732
40841
  proc.kill();
40733
40842
  }
@@ -40813,8 +40922,9 @@ class HookExecutor {
40813
40922
  if (!hook.command)
40814
40923
  return null;
40815
40924
  try {
40925
+ const cwd2 = input.cwd && existsSync5(input.cwd) ? input.cwd : process.cwd();
40816
40926
  const proc = Bun.spawn(["bash", "-c", hook.command], {
40817
- cwd: input.cwd || process.cwd(),
40927
+ cwd: cwd2,
40818
40928
  stdin: "pipe",
40819
40929
  stdout: "pipe",
40820
40930
  stderr: "pipe"
@@ -41191,7 +41301,7 @@ init_src();
41191
41301
  // packages/core/src/sessions/verification.ts
41192
41302
  init_src();
41193
41303
  import { join as join9 } from "path";
41194
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4, readdirSync as readdirSync2 } from "fs";
41304
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4, readdirSync as readdirSync2 } from "fs";
41195
41305
 
41196
41306
  class VerificationSessionStore {
41197
41307
  basePath;
@@ -41202,7 +41312,7 @@ class VerificationSessionStore {
41202
41312
  this.ensureDirectory();
41203
41313
  }
41204
41314
  ensureDirectory() {
41205
- if (!existsSync5(this.basePath)) {
41315
+ if (!existsSync6(this.basePath)) {
41206
41316
  mkdirSync3(this.basePath, { recursive: true });
41207
41317
  }
41208
41318
  }
@@ -41228,7 +41338,7 @@ class VerificationSessionStore {
41228
41338
  }
41229
41339
  get(id) {
41230
41340
  const filePath = join9(this.basePath, `${id}.json`);
41231
- if (!existsSync5(filePath)) {
41341
+ if (!existsSync6(filePath)) {
41232
41342
  return null;
41233
41343
  }
41234
41344
  try {
@@ -41276,7 +41386,7 @@ class VerificationSessionStore {
41276
41386
  this.save(session);
41277
41387
  }
41278
41388
  listFiles() {
41279
- if (!existsSync5(this.basePath)) {
41389
+ if (!existsSync6(this.basePath)) {
41280
41390
  return [];
41281
41391
  }
41282
41392
  return readdirSync2(this.basePath).filter((f) => f.endsWith(".json"));
@@ -41467,9 +41577,9 @@ function createScopeVerificationHook() {
41467
41577
  };
41468
41578
  }
41469
41579
  // packages/core/src/commands/loader.ts
41470
- import { existsSync as existsSync6, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
41471
- import { join as join10, basename as basename2, extname } from "path";
41472
- import { homedir as homedir6 } from "os";
41580
+ import { existsSync as existsSync7, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
41581
+ import { join as join10, basename as basename2, extname as extname2 } from "path";
41582
+ import { homedir as homedir8 } from "os";
41473
41583
 
41474
41584
  class CommandLoader {
41475
41585
  commands = new Map;
@@ -41480,14 +41590,14 @@ class CommandLoader {
41480
41590
  async loadAll() {
41481
41591
  this.commands.clear();
41482
41592
  const envHome = process.env.HOME || process.env.USERPROFILE;
41483
- const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir6();
41593
+ const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir8();
41484
41594
  const globalDir = join10(homeDir, ".assistants", "commands");
41485
41595
  await this.loadFromDirectory(globalDir, "global");
41486
41596
  const projectDir = join10(this.cwd, ".assistants", "commands");
41487
41597
  await this.loadFromDirectory(projectDir, "project");
41488
41598
  }
41489
41599
  async loadFromDirectory(dir, source, prefix = "") {
41490
- if (!existsSync6(dir))
41600
+ if (!existsSync7(dir))
41491
41601
  return;
41492
41602
  const entries = readdirSync3(dir);
41493
41603
  for (const entry of entries) {
@@ -41496,7 +41606,7 @@ class CommandLoader {
41496
41606
  if (stat.isDirectory()) {
41497
41607
  const newPrefix = prefix ? `${prefix}:${entry}` : entry;
41498
41608
  await this.loadFromDirectory(fullPath, source, newPrefix);
41499
- } else if (stat.isFile() && extname(entry) === ".md") {
41609
+ } else if (stat.isFile() && extname2(entry) === ".md") {
41500
41610
  const command = await this.loadCommandFile(fullPath, prefix);
41501
41611
  if (command) {
41502
41612
  this.commands.set(command.name, command);
@@ -41527,15 +41637,14 @@ class CommandLoader {
41527
41637
  }
41528
41638
  }
41529
41639
  parseFrontmatter(content) {
41530
- const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/;
41640
+ const frontmatterRegex = /^---\s*\r?\n([\s\S]*?)\r?\n---\s*\r?\n?([\s\S]*)$/;
41531
41641
  const match = content.match(frontmatterRegex);
41532
41642
  if (!match) {
41533
41643
  return { frontmatter: {}, body: content };
41534
41644
  }
41535
41645
  const [, yamlContent, body] = match;
41536
41646
  const frontmatter = {};
41537
- const lines = yamlContent.split(`
41538
- `);
41647
+ const lines = yamlContent.split(/\r?\n/);
41539
41648
  let currentListKey = null;
41540
41649
  for (const rawLine of lines) {
41541
41650
  const line = rawLine.trimEnd();
@@ -41667,10 +41776,16 @@ Use /help to see available commands.
41667
41776
  }
41668
41777
  if (!inCodeBlock && trimmed.startsWith("!")) {
41669
41778
  const command = trimmed.slice(1).trim();
41779
+ if (!command) {
41780
+ processedLines.push(line);
41781
+ continue;
41782
+ }
41670
41783
  const output = await this.executeShell(command, cwd2);
41671
- processedLines.push(`\`\`\`
41672
- ${output}
41673
- \`\`\``);
41784
+ const indent = line.match(/^\s*/)?.[0] ?? "";
41785
+ const fenced = [`${indent}\`\`\``, ...output.split(`
41786
+ `).map((o) => `${indent}${o}`), `${indent}\`\`\``];
41787
+ processedLines.push(fenced.join(`
41788
+ `));
41674
41789
  } else {
41675
41790
  processedLines.push(line);
41676
41791
  }
@@ -41723,18 +41838,24 @@ ${stderr}`;
41723
41838
  }
41724
41839
  // packages/core/src/commands/builtin.ts
41725
41840
  import { join as join13 } from "path";
41726
- import { homedir as homedir8, platform as platform2, release, arch } from "os";
41727
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
41841
+ import { homedir as homedir10, platform as platform2, release, arch } from "os";
41842
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
41728
41843
  init_src();
41729
41844
 
41730
41845
  // packages/core/src/projects/store.ts
41731
41846
  init_src();
41732
41847
  import { join as join11 } from "path";
41733
41848
  import { mkdir as mkdir3, readdir as readdir2, readFile as readFile2, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
41849
+ var SAFE_ID_PATTERN2 = /^[a-zA-Z0-9_-]+$/;
41734
41850
  function projectsDir(cwd2) {
41735
41851
  return join11(cwd2, ".assistants", "projects");
41736
41852
  }
41853
+ function isSafeId2(id) {
41854
+ return SAFE_ID_PATTERN2.test(id);
41855
+ }
41737
41856
  function projectPath(cwd2, id) {
41857
+ if (!isSafeId2(id))
41858
+ return null;
41738
41859
  return join11(projectsDir(cwd2), `${id}.json`);
41739
41860
  }
41740
41861
  async function ensureProjectsDir(cwd2) {
@@ -41766,7 +41887,10 @@ async function listProjects(cwd2) {
41766
41887
  }
41767
41888
  async function readProject(cwd2, id) {
41768
41889
  try {
41769
- const raw = await readFile2(projectPath(cwd2, id), "utf-8");
41890
+ const path = projectPath(cwd2, id);
41891
+ if (!path)
41892
+ return null;
41893
+ const raw = await readFile2(path, "utf-8");
41770
41894
  const project = JSON.parse(raw);
41771
41895
  if (!project?.id || !project?.name)
41772
41896
  return null;
@@ -41782,11 +41906,18 @@ async function findProjectByName(cwd2, name) {
41782
41906
  }
41783
41907
  async function saveProject(cwd2, project) {
41784
41908
  await ensureProjectsDir(cwd2);
41785
- await writeFile2(projectPath(cwd2, project.id), JSON.stringify(project, null, 2), "utf-8");
41909
+ const path = projectPath(cwd2, project.id);
41910
+ if (!path) {
41911
+ throw new Error(`Invalid project id: ${project.id}`);
41912
+ }
41913
+ await writeFile2(path, JSON.stringify(project, null, 2), "utf-8");
41786
41914
  }
41787
41915
  async function deleteProject(cwd2, id) {
41788
41916
  try {
41789
- await unlink2(projectPath(cwd2, id));
41917
+ const path = projectPath(cwd2, id);
41918
+ if (!path)
41919
+ return false;
41920
+ await unlink2(path);
41790
41921
  return true;
41791
41922
  } catch {
41792
41923
  return false;
@@ -41827,7 +41958,7 @@ function hasProjectNameConflict(projects, name) {
41827
41958
 
41828
41959
  // packages/core/src/projects/context.ts
41829
41960
  import { readFile as readFile3 } from "fs/promises";
41830
- import { homedir as homedir7 } from "os";
41961
+ import { homedir as homedir9 } from "os";
41831
41962
  import { resolve as resolve4, join as join12 } from "path";
41832
41963
  var DEFAULT_MAX_FILE_BYTES = 12000;
41833
41964
  function singleLine(value) {
@@ -41847,7 +41978,7 @@ function normalizeEntryLabel(entry) {
41847
41978
  }
41848
41979
  async function renderFileEntry(entry, options) {
41849
41980
  const rawPath = entry.value.trim();
41850
- const expandedPath = rawPath === "~" ? homedir7() : rawPath.startsWith("~/") ? join12(homedir7(), rawPath.slice(2)) : rawPath;
41981
+ const expandedPath = rawPath === "~" ? homedir9() : rawPath.startsWith("~/") ? join12(homedir9(), rawPath.slice(2)) : rawPath;
41851
41982
  const resolved = resolve4(options.cwd, expandedPath);
41852
41983
  const validation = await validatePath(resolved, { allowedPaths: [options.cwd] });
41853
41984
  if (!validation.valid) {
@@ -43679,12 +43810,12 @@ Format the summary as a brief bullet-point list. This summary will replace the c
43679
43810
  message += `**Config File Locations:**
43680
43811
  `;
43681
43812
  for (const path of configPaths) {
43682
- const exists = existsSync7(path);
43813
+ const exists = existsSync8(path);
43683
43814
  message += ` ${exists ? "\u2713" : "\u25CB"} ${path}
43684
43815
  `;
43685
43816
  }
43686
43817
  const envHome = process.env.HOME || process.env.USERPROFILE;
43687
- const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir8();
43818
+ const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir10();
43688
43819
  message += `
43689
43820
  **Commands Directories:**
43690
43821
  `;
@@ -43723,7 +43854,7 @@ Please summarize the last interaction and suggest 2-3 next steps.
43723
43854
  - Ask a follow-up question if needed
43724
43855
  `;
43725
43856
  const examplePath = join13(commandsDir, "reflect.md");
43726
- if (!existsSync7(examplePath)) {
43857
+ if (!existsSync8(examplePath)) {
43727
43858
  writeFileSync5(examplePath, exampleCommand);
43728
43859
  }
43729
43860
  let message = `
@@ -44652,18 +44783,18 @@ class RecoveryManager {
44652
44783
  }
44653
44784
  // packages/core/src/energy/types.ts
44654
44785
  var DEFAULT_ENERGY_COSTS = {
44655
- message: 2,
44656
- toolCall: 5,
44657
- llmCall: 3,
44658
- longContext: 10
44786
+ message: 200,
44787
+ toolCall: 500,
44788
+ llmCall: 300,
44789
+ longContext: 1000
44659
44790
  };
44660
44791
  var DEFAULT_ENERGY_CONFIG = {
44661
44792
  enabled: true,
44662
44793
  costs: DEFAULT_ENERGY_COSTS,
44663
- regenRate: 5,
44664
- lowEnergyThreshold: 30,
44665
- criticalThreshold: 10,
44666
- maxEnergy: 100
44794
+ regenRate: 500,
44795
+ lowEnergyThreshold: 3000,
44796
+ criticalThreshold: 1000,
44797
+ maxEnergy: 1e4
44667
44798
  };
44668
44799
  function buildEnergyConfig(config) {
44669
44800
  return {
@@ -44887,15 +45018,15 @@ function validateToolCalls(toolCalls, tools) {
44887
45018
  }
44888
45019
 
44889
45020
  // packages/core/src/voice/utils.ts
44890
- import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
44891
- import { homedir as homedir10 } from "os";
45021
+ import { existsSync as existsSync10, readFileSync as readFileSync5 } from "fs";
45022
+ import { homedir as homedir12 } from "os";
44892
45023
  import { join as join15 } from "path";
44893
45024
  import { spawnSync } from "child_process";
44894
45025
  function loadApiKeyFromSecrets2(key) {
44895
45026
  const envHome = process.env.HOME || process.env.USERPROFILE;
44896
- const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir10();
45027
+ const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir12();
44897
45028
  const secretsPath = join15(homeDir, ".secrets");
44898
- if (!existsSync9(secretsPath))
45029
+ if (!existsSync10(secretsPath))
44899
45030
  return;
44900
45031
  try {
44901
45032
  const content = readFileSync5(secretsPath, "utf-8");
@@ -45399,13 +45530,13 @@ class VoiceManager {
45399
45530
  }
45400
45531
  // packages/core/src/identity/assistant-manager.ts
45401
45532
  init_src();
45402
- import { existsSync as existsSync11 } from "fs";
45533
+ import { existsSync as existsSync12 } from "fs";
45403
45534
  import { mkdir as mkdir5, readFile as readFile8, writeFile as writeFile7, rm as rm2 } from "fs/promises";
45404
45535
  import { join as join20 } from "path";
45405
45536
 
45406
45537
  // packages/core/src/identity/identity-manager.ts
45407
45538
  init_src();
45408
- import { existsSync as existsSync10 } from "fs";
45539
+ import { existsSync as existsSync11 } from "fs";
45409
45540
  import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile6, rm } from "fs/promises";
45410
45541
  import { join as join19 } from "path";
45411
45542
  var DEFAULT_PROFILE = {
@@ -45555,7 +45686,7 @@ class IdentityManager {
45555
45686
  `);
45556
45687
  }
45557
45688
  async readIndex() {
45558
- if (!existsSync10(this.indexPath)) {
45689
+ if (!existsSync11(this.indexPath)) {
45559
45690
  return { identities: [] };
45560
45691
  }
45561
45692
  try {
@@ -45580,7 +45711,7 @@ class IdentityManager {
45580
45711
  }
45581
45712
  async readIdentity(id) {
45582
45713
  const path2 = this.identityPath(id);
45583
- if (!existsSync10(path2))
45714
+ if (!existsSync11(path2))
45584
45715
  return null;
45585
45716
  try {
45586
45717
  const raw = await readFile7(path2, "utf-8");
@@ -45594,7 +45725,7 @@ class IdentityManager {
45594
45725
  await writeFile6(this.identityPath(identity.id), JSON.stringify(identity, null, 2));
45595
45726
  }
45596
45727
  async readActive() {
45597
- if (!existsSync10(this.activePath))
45728
+ if (!existsSync11(this.activePath))
45598
45729
  return null;
45599
45730
  try {
45600
45731
  const raw = await readFile7(this.activePath, "utf-8");
@@ -45609,7 +45740,7 @@ class IdentityManager {
45609
45740
  await writeFile6(this.activePath, JSON.stringify({ id }, null, 2));
45610
45741
  }
45611
45742
  async loadAssistant() {
45612
- if (!existsSync10(this.assistantConfigPath()))
45743
+ if (!existsSync11(this.assistantConfigPath()))
45613
45744
  return null;
45614
45745
  try {
45615
45746
  const raw = await readFile7(this.assistantConfigPath(), "utf-8");
@@ -45727,7 +45858,7 @@ class AssistantManager {
45727
45858
  return new IdentityManager(assistantId, this.basePath);
45728
45859
  }
45729
45860
  async readIndex() {
45730
- if (!existsSync11(this.indexPath)) {
45861
+ if (!existsSync12(this.indexPath)) {
45731
45862
  return { assistants: [] };
45732
45863
  }
45733
45864
  try {
@@ -45752,7 +45883,7 @@ class AssistantManager {
45752
45883
  }
45753
45884
  async readAssistant(id) {
45754
45885
  const configPath = this.assistantConfigPath(id);
45755
- if (!existsSync11(configPath))
45886
+ if (!existsSync12(configPath))
45756
45887
  return null;
45757
45888
  try {
45758
45889
  const raw = await readFile8(configPath, "utf-8");
@@ -45767,7 +45898,7 @@ class AssistantManager {
45767
45898
  await writeFile7(this.assistantConfigPath(assistant.id), JSON.stringify(assistant, null, 2));
45768
45899
  }
45769
45900
  async readActive() {
45770
- if (!existsSync11(this.activePath))
45901
+ if (!existsSync12(this.activePath))
45771
45902
  return null;
45772
45903
  try {
45773
45904
  const raw = await readFile8(this.activePath, "utf-8");
@@ -46222,7 +46353,7 @@ class AgentLoop {
46222
46353
  if (toolInput.cwd === undefined) {
46223
46354
  toolInput.cwd = this.cwd;
46224
46355
  }
46225
- if (toolInput.sessionId === undefined) {
46356
+ if (typeof toolInput.sessionId !== "string" || toolInput.sessionId.length === 0) {
46226
46357
  toolInput.sessionId = this.sessionId;
46227
46358
  }
46228
46359
  toolCall.input = toolInput;
@@ -46258,7 +46389,7 @@ class AgentLoop {
46258
46389
  if (input.cwd === undefined) {
46259
46390
  input.cwd = this.cwd;
46260
46391
  }
46261
- if (input.sessionId === undefined) {
46392
+ if (typeof input.sessionId !== "string" || input.sessionId.length === 0) {
46262
46393
  input.sessionId = this.sessionId;
46263
46394
  }
46264
46395
  if (preHookResult?.continue === false || preHookResult?.permissionDecision === "deny") {
@@ -46995,7 +47126,7 @@ init_anthropic();
46995
47126
  init_src();
46996
47127
 
46997
47128
  // packages/core/src/logger.ts
46998
- import { existsSync as existsSync12, mkdirSync as mkdirSync8, appendFileSync, readdirSync as readdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
47129
+ import { existsSync as existsSync13, mkdirSync as mkdirSync8, appendFileSync, readdirSync as readdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
46999
47130
  import { join as join22 } from "path";
47000
47131
  class Logger {
47001
47132
  logDir;
@@ -47009,7 +47140,7 @@ class Logger {
47009
47140
  this.logFile = join22(this.logDir, `${date}.log`);
47010
47141
  }
47011
47142
  ensureDir(dir) {
47012
- if (!existsSync12(dir)) {
47143
+ if (!existsSync13(dir)) {
47013
47144
  mkdirSync8(dir, { recursive: true });
47014
47145
  }
47015
47146
  }
@@ -47055,7 +47186,7 @@ class SessionStorage {
47055
47186
  this.sessionFile = join22(this.sessionsDir, `${sessionId}.json`);
47056
47187
  }
47057
47188
  ensureDir(dir) {
47058
- if (!existsSync12(dir)) {
47189
+ if (!existsSync13(dir)) {
47059
47190
  mkdirSync8(dir, { recursive: true });
47060
47191
  }
47061
47192
  }
@@ -47069,7 +47200,7 @@ class SessionStorage {
47069
47200
  }
47070
47201
  load() {
47071
47202
  try {
47072
- if (!existsSync12(this.sessionFile))
47203
+ if (!existsSync13(this.sessionFile))
47073
47204
  return null;
47074
47205
  return JSON.parse(readFileSync8(this.sessionFile, "utf-8"));
47075
47206
  } catch {
@@ -47079,7 +47210,7 @@ class SessionStorage {
47079
47210
  static getActiveAssistantId() {
47080
47211
  try {
47081
47212
  const activePath = join22(getConfigDir(), "active.json");
47082
- if (!existsSync12(activePath))
47213
+ if (!existsSync13(activePath))
47083
47214
  return null;
47084
47215
  const raw = readFileSync8(activePath, "utf-8");
47085
47216
  const data = JSON.parse(raw);
@@ -47093,7 +47224,7 @@ class SessionStorage {
47093
47224
  const resolvedId = assistantId ?? SessionStorage.getActiveAssistantId();
47094
47225
  if (resolvedId) {
47095
47226
  const assistantDir = join22(root, "assistants", resolvedId, "sessions");
47096
- if (existsSync12(assistantDir)) {
47227
+ if (existsSync13(assistantDir)) {
47097
47228
  return assistantDir;
47098
47229
  }
47099
47230
  }
@@ -47101,7 +47232,7 @@ class SessionStorage {
47101
47232
  }
47102
47233
  static listSessions(assistantId) {
47103
47234
  const sessionsDir = SessionStorage.resolveSessionsDir(assistantId);
47104
- if (!existsSync12(sessionsDir))
47235
+ if (!existsSync13(sessionsDir))
47105
47236
  return [];
47106
47237
  const sessions = [];
47107
47238
  const files = readdirSync4(sessionsDir);
@@ -47131,7 +47262,7 @@ class SessionStorage {
47131
47262
  const sessionsDir = SessionStorage.resolveSessionsDir(assistantId);
47132
47263
  const sessionFile = join22(sessionsDir, `${sessionId}.json`);
47133
47264
  try {
47134
- if (!existsSync12(sessionFile))
47265
+ if (!existsSync13(sessionFile))
47135
47266
  return null;
47136
47267
  return JSON.parse(readFileSync8(sessionFile, "utf-8"));
47137
47268
  } catch {
@@ -47154,7 +47285,7 @@ function initAssistantsDir() {
47154
47285
  join22(baseDir, "migration")
47155
47286
  ];
47156
47287
  for (const dir of dirs) {
47157
- if (!existsSync12(dir)) {
47288
+ if (!existsSync13(dir)) {
47158
47289
  mkdirSync8(dir, { recursive: true });
47159
47290
  }
47160
47291
  }
@@ -47978,14 +48109,19 @@ function parseMarkdown(text, options) {
47978
48109
  codeBlocks.push(match);
47979
48110
  return `@@CODEBLOCK${codeBlocks.length - 1}@@`;
47980
48111
  });
48112
+ const inlineCodeBlocks = [];
48113
+ result = result.replace(/`([^`\n]+)`/g, (_, code) => {
48114
+ inlineCodeBlocks.push(code);
48115
+ return `@@INLINECODE${inlineCodeBlocks.length - 1}@@`;
48116
+ });
47981
48117
  const blockSections = [];
47982
48118
  if (!options?.skipBlocks) {
47983
48119
  result = extractBlockSections(result, blockSections);
47984
48120
  }
47985
- result = result.replace(/\*\*(.+?)\*\*/g, (_, text2) => source_default.bold(text2));
47986
- result = result.replace(/__(.+?)__/g, (_, text2) => source_default.bold(text2));
47987
- result = result.replace(/\*(.+?)\*/g, (_, text2) => source_default.italic(text2));
47988
- result = result.replace(/_(.+?)_/g, (_, text2) => source_default.italic(text2));
48121
+ result = result.replace(/(^|[\s([{>])\*\*([^*]+?)\*\*(?=[\s)\]}<.,!?;:]|$)/gm, (_, lead, text2) => `${lead}${source_default.bold(text2)}`);
48122
+ result = result.replace(/(^|[\s([{>])__([^_]+?)__(?=[\s)\]}<.,!?;:]|$)/gm, (_, lead, text2) => `${lead}${source_default.bold(text2)}`);
48123
+ result = result.replace(/(^|[\s([{>])\*([^*\n]+?)\*(?=[\s)\]}<.,!?;:]|$)/gm, (_, lead, text2) => `${lead}${source_default.italic(text2)}`);
48124
+ result = result.replace(/(^|[\s([{>])_([^_\n]+?)_(?=[\s)\]}<.,!?;:]|$)/gm, (_, lead, text2) => `${lead}${source_default.italic(text2)}`);
47989
48125
  result = result.replace(/`([^`]+)`/g, (_, code) => source_default.dim(code));
47990
48126
  result = result.replace(/^### (.+)$/gm, (_, text2) => source_default.bold(text2));
47991
48127
  result = result.replace(/^## (.+)$/gm, (_, text2) => source_default.bold(text2));
@@ -48008,6 +48144,10 @@ function parseMarkdown(text, options) {
48008
48144
  const code = block.replace(/```\w*\n?/g, "").replace(/```$/g, "").trim();
48009
48145
  return source_default.dim(code);
48010
48146
  });
48147
+ result = result.replace(/@@INLINECODE(\d+)@@/g, (_, index) => {
48148
+ const code = inlineCodeBlocks[parseInt(index, 10)] ?? "";
48149
+ return source_default.dim(code);
48150
+ });
48011
48151
  return result.trimEnd();
48012
48152
  }
48013
48153
  var ALLOWED_BLOCK_TYPES = new Set(["info", "success", "warning", "error", "note", "command"]);
@@ -48243,7 +48383,7 @@ function renderBlockSection(section, maxWidth) {
48243
48383
  if (section.kind === "grid") {
48244
48384
  const adjustedWidth2 = maxWidth ? Math.max(20, maxWidth - section.indent.length) : undefined;
48245
48385
  if (section.cards.length === 0) {
48246
- return renderCard({ type: "note", title: "Grid", body: section.body }, adjustedWidth2, section.indent).join(`
48386
+ return renderCard({ type: "note", title: "Grid", body: section.body }, adjustedWidth2, section.indent, Boolean(adjustedWidth2)).join(`
48247
48387
  `);
48248
48388
  }
48249
48389
  return renderCardGrid(section.cards, section.columns, adjustedWidth2, section.indent);
@@ -48375,7 +48515,15 @@ function formatMarkdownTables(text, maxWidth) {
48375
48515
  const lines = text.split(`
48376
48516
  `);
48377
48517
  const output = [];
48378
- const isSeparator = (line) => /^\s*\|?[\s:-]+\|?[\s:-]*$/.test(line);
48518
+ const isSeparator = (line) => {
48519
+ const trimmed = line.trim();
48520
+ if (!trimmed)
48521
+ return false;
48522
+ const withoutPipes = trimmed.replace(/\|/g, "");
48523
+ if (!withoutPipes)
48524
+ return false;
48525
+ return /^[\s:-]+$/.test(withoutPipes);
48526
+ };
48379
48527
  const hasPipes = (line) => line.includes("|");
48380
48528
  let i = 0;
48381
48529
  while (i < lines.length) {
@@ -48402,7 +48550,31 @@ function formatMarkdownTables(text, maxWidth) {
48402
48550
  function parseTableRow(line) {
48403
48551
  const trimmed = line.trim();
48404
48552
  const withoutEdges = trimmed.replace(/^\|/, "").replace(/\|$/, "");
48405
- return withoutEdges.split("|").map((cell) => cell.replace(/[\r\n]+/g, " ").trim());
48553
+ const cells = [];
48554
+ let current = "";
48555
+ let escaping = false;
48556
+ for (let i = 0;i < withoutEdges.length; i += 1) {
48557
+ const ch = withoutEdges[i];
48558
+ if (escaping) {
48559
+ current += ch;
48560
+ escaping = false;
48561
+ continue;
48562
+ }
48563
+ if (ch === "\\") {
48564
+ escaping = true;
48565
+ continue;
48566
+ }
48567
+ if (ch === "|") {
48568
+ cells.push(current);
48569
+ current = "";
48570
+ continue;
48571
+ }
48572
+ current += ch;
48573
+ }
48574
+ if (escaping)
48575
+ current += "\\";
48576
+ cells.push(current);
48577
+ return cells.map((cell) => cell.replace(/[\r\n]+/g, " ").trim());
48406
48578
  }
48407
48579
  function renderTable(header, rows, maxWidth) {
48408
48580
  const colCount = Math.max(header.length, ...rows.map((r) => r.length));
@@ -48616,11 +48788,17 @@ function wrapAnsiLine(line, width) {
48616
48788
  const result = [];
48617
48789
  let current = "";
48618
48790
  let visible = 0;
48791
+ let activeAnsi = "";
48619
48792
  let i = 0;
48620
48793
  while (i < line.length) {
48621
48794
  const match = line.slice(i).match(/^\x1b\[[0-9;]*m/);
48622
48795
  if (match) {
48623
48796
  current += match[0];
48797
+ if (match[0] === "\x1B[0m") {
48798
+ activeAnsi = "";
48799
+ } else {
48800
+ activeAnsi += match[0];
48801
+ }
48624
48802
  i += match[0].length;
48625
48803
  continue;
48626
48804
  }
@@ -48629,7 +48807,7 @@ function wrapAnsiLine(line, width) {
48629
48807
  i += 1;
48630
48808
  if (visible >= width) {
48631
48809
  result.push(current);
48632
- current = "";
48810
+ current = activeAnsi;
48633
48811
  visible = 0;
48634
48812
  }
48635
48813
  }
@@ -48640,6 +48818,7 @@ function wrapAnsiLine(line, width) {
48640
48818
  function truncateAnsi(line, width) {
48641
48819
  if (stripAnsi2(line).length <= width)
48642
48820
  return line;
48821
+ const hasAnsi = /\x1b\[[0-9;]*m/.test(line);
48643
48822
  if (width <= 3) {
48644
48823
  let result = "";
48645
48824
  let visible2 = 0;
@@ -48655,7 +48834,7 @@ function truncateAnsi(line, width) {
48655
48834
  visible2 += 1;
48656
48835
  i2 += 1;
48657
48836
  }
48658
- return result;
48837
+ return hasAnsi && !result.endsWith("\x1B[0m") ? result + "\x1B[0m" : result;
48659
48838
  }
48660
48839
  const suffix = "...";
48661
48840
  const target = Math.max(0, width - suffix.length);
@@ -48673,7 +48852,8 @@ function truncateAnsi(line, width) {
48673
48852
  visible += 1;
48674
48853
  i += 1;
48675
48854
  }
48676
- return current + suffix;
48855
+ const truncated = current + suffix;
48856
+ return hasAnsi && !truncated.endsWith("\x1B[0m") ? truncated + "\x1B[0m" : truncated;
48677
48857
  }
48678
48858
 
48679
48859
  // packages/terminal/src/components/toolDisplay.ts
@@ -48866,7 +49046,7 @@ function estimateMessageLines(message, maxWidth) {
48866
49046
  const hasContent = contentLines.length > 0;
48867
49047
  const prefixWidth = message.role === "user" || message.role === "assistant" ? 2 : 0;
48868
49048
  const effectiveWidth = maxWidth ? Math.max(1, maxWidth - prefixWidth) : maxWidth;
48869
- const wrappedLines = contentLines.length > 0 ? countWrappedLines(contentLines, effectiveWidth) : 0;
49049
+ const wrappedLines = typeof message.__lineCount === "number" ? message.__lineCount : contentLines.length > 0 ? countWrappedLines(contentLines, effectiveWidth) : 0;
48870
49050
  let lines = hasContent ? Math.max(1, wrappedLines) : 0;
48871
49051
  if (message.role === "assistant" && message.toolCalls?.length) {
48872
49052
  lines += estimateToolPanelLines(message.toolCalls, message.toolResults, hasContent);
@@ -48878,6 +49058,27 @@ function estimateMessageLines(message, maxWidth) {
48878
49058
  }
48879
49059
  return lines;
48880
49060
  }
49061
+ function estimateGroupedToolMessagesLines(messages, maxWidth) {
49062
+ const toolCalls = [];
49063
+ const toolResults = [];
49064
+ for (const msg of messages) {
49065
+ if (msg.toolCalls)
49066
+ toolCalls.push(...msg.toolCalls);
49067
+ if (msg.toolResults)
49068
+ toolResults.push(...msg.toolResults);
49069
+ }
49070
+ if (toolCalls.length === 0)
49071
+ return 0;
49072
+ const synthetic = {
49073
+ id: "grouped-tool-call",
49074
+ role: "assistant",
49075
+ content: "",
49076
+ timestamp: 0,
49077
+ toolCalls,
49078
+ toolResults: toolResults.length > 0 ? toolResults : undefined
49079
+ };
49080
+ return estimateMessageLines(synthetic, maxWidth);
49081
+ }
48881
49082
  function countWrappedLines(lines, maxWidth) {
48882
49083
  if (!maxWidth || maxWidth <= 0) {
48883
49084
  return lines.length;
@@ -48927,6 +49128,34 @@ function isContinuationChunk(id) {
48927
49128
  const idx = Number(match[1]);
48928
49129
  return Number.isFinite(idx) && idx > 0;
48929
49130
  }
49131
+ function groupConsecutiveToolMessages(messages) {
49132
+ const groups = [];
49133
+ let currentToolGroup = [];
49134
+ for (const msg of messages) {
49135
+ const isToolOnlyAssistant = msg.role === "assistant" && (!msg.content || !msg.content.trim()) && msg.toolCalls && msg.toolCalls.length > 0;
49136
+ if (isToolOnlyAssistant) {
49137
+ currentToolGroup.push(msg);
49138
+ } else {
49139
+ if (currentToolGroup.length > 0) {
49140
+ if (currentToolGroup.length === 1) {
49141
+ groups.push({ type: "single", message: currentToolGroup[0] });
49142
+ } else {
49143
+ groups.push({ type: "grouped", messages: currentToolGroup });
49144
+ }
49145
+ currentToolGroup = [];
49146
+ }
49147
+ groups.push({ type: "single", message: msg });
49148
+ }
49149
+ }
49150
+ if (currentToolGroup.length > 0) {
49151
+ if (currentToolGroup.length === 1) {
49152
+ groups.push({ type: "single", message: currentToolGroup[0] });
49153
+ } else {
49154
+ groups.push({ type: "grouped", messages: currentToolGroup });
49155
+ }
49156
+ }
49157
+ return groups;
49158
+ }
48930
49159
 
48931
49160
  // packages/terminal/src/components/Messages.tsx
48932
49161
  var jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
@@ -48946,11 +49175,13 @@ function Messages3({
48946
49175
  const columns = stdout?.columns ?? 80;
48947
49176
  const messageWidth = Math.max(1, columns - 2);
48948
49177
  const wrapWidth = messageWidth;
49178
+ const messageGroups = import_react24.useMemo(() => groupConsecutiveToolMessages(messages), [messages]);
49179
+ const messageItems = import_react24.useMemo(() => {
49180
+ return messageGroups.map((group) => group.type === "single" ? { kind: "message", message: group.message } : { kind: "grouped", messages: group.messages });
49181
+ }, [messageGroups]);
48949
49182
  const items = import_react24.useMemo(() => {
48950
49183
  const output = [];
48951
- for (const message of messages) {
48952
- output.push({ kind: "message", message });
48953
- }
49184
+ output.push(...messageItems);
48954
49185
  for (const entry of activityLog) {
48955
49186
  output.push({ kind: "activity", entry });
48956
49187
  }
@@ -48962,7 +49193,7 @@ function Messages3({
48962
49193
  const lineSpans = import_react24.useMemo(() => {
48963
49194
  let cursor = 0;
48964
49195
  return items.map((item, index) => {
48965
- const lines = item.kind === "activity" ? estimateActivityEntryLines(item.entry, wrapWidth, messageWidth) : estimateMessageLines(item.message, messageWidth);
49196
+ const lines = item.kind === "activity" ? estimateActivityEntryLines(item.entry, wrapWidth, messageWidth) : item.kind === "grouped" ? estimateGroupedToolMessagesLines(item.messages, messageWidth) : estimateMessageLines(item.message, messageWidth);
48966
49197
  const start = cursor;
48967
49198
  cursor += lines;
48968
49199
  return { item, index, start, end: cursor, lines };
@@ -48972,16 +49203,15 @@ function Messages3({
48972
49203
  const endLine = Math.max(0, totalLines - scrollOffsetLines);
48973
49204
  const startLine = Math.max(0, endLine - maxVisibleLines);
48974
49205
  const visibleSpans = lineSpans.filter((span) => span.end > startLine && span.start < endLine);
48975
- const visibleMessages = visibleSpans.filter((span) => span.item.kind === "message").map((span) => span.item.message);
49206
+ const visibleMessageItems = visibleSpans.filter((span) => span.item.kind === "message" || span.item.kind === "grouped").map((span) => span.item);
48976
49207
  const visibleActivity = visibleSpans.filter((span) => span.item.kind === "activity").map((span) => span.item.entry);
48977
49208
  const visibleStreaming = visibleSpans.filter((span) => span.item.kind === "streaming").map((span) => span.item.message);
48978
49209
  const showCurrentResponse = Boolean(currentResponse) && streamingMessages.length === 0;
48979
- const groupedMessages = groupConsecutiveToolMessages(visibleMessages);
48980
- const historicalItems = groupedMessages.map((group) => {
48981
- if (group.type === "single") {
48982
- return { id: group.message.id, group };
49210
+ const historicalItems = visibleMessageItems.map((item) => {
49211
+ if (item.kind === "message") {
49212
+ return { id: item.message.id, item };
48983
49213
  }
48984
- return { id: group.messages[0].id, group };
49214
+ return { id: item.messages[0].id, item };
48985
49215
  });
48986
49216
  const toolResultMap = import_react24.useMemo(() => {
48987
49217
  const map = new Map;
@@ -49015,14 +49245,14 @@ function Messages3({
49015
49245
  width: "100%",
49016
49246
  children: [
49017
49247
  historicalItems.map((item) => {
49018
- if (item.group.type === "single") {
49248
+ if (item.item.kind === "message") {
49019
49249
  return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(MessageBubble, {
49020
- message: item.group.message,
49250
+ message: item.item.message,
49021
49251
  queuedMessageIds
49022
49252
  }, item.id, false, undefined, this);
49023
49253
  }
49024
49254
  return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(CombinedToolMessage, {
49025
- messages: item.group.messages
49255
+ messages: item.item.messages
49026
49256
  }, item.id, false, undefined, this);
49027
49257
  }),
49028
49258
  visibleActivity.map((entry) => {
@@ -49127,34 +49357,6 @@ function formatDuration(ms) {
49127
49357
  const secs = totalSeconds % 60;
49128
49358
  return `${mins}m ${secs}s`;
49129
49359
  }
49130
- function groupConsecutiveToolMessages(messages) {
49131
- const groups = [];
49132
- let currentToolGroup = [];
49133
- for (const msg of messages) {
49134
- const isToolOnlyAssistant = msg.role === "assistant" && (!msg.content || !msg.content.trim()) && msg.toolCalls && msg.toolCalls.length > 0;
49135
- if (isToolOnlyAssistant) {
49136
- currentToolGroup.push(msg);
49137
- } else {
49138
- if (currentToolGroup.length > 0) {
49139
- if (currentToolGroup.length === 1) {
49140
- groups.push({ type: "single", message: currentToolGroup[0] });
49141
- } else {
49142
- groups.push({ type: "grouped", messages: currentToolGroup });
49143
- }
49144
- currentToolGroup = [];
49145
- }
49146
- groups.push({ type: "single", message: msg });
49147
- }
49148
- }
49149
- if (currentToolGroup.length > 0) {
49150
- if (currentToolGroup.length === 1) {
49151
- groups.push({ type: "single", message: currentToolGroup[0] });
49152
- } else {
49153
- groups.push({ type: "grouped", messages: currentToolGroup });
49154
- }
49155
- }
49156
- return groups;
49157
- }
49158
49360
  function CombinedToolMessage({ messages }) {
49159
49361
  const allToolCalls = [];
49160
49362
  const allToolResults = [];
@@ -49166,9 +49368,12 @@ function CombinedToolMessage({ messages }) {
49166
49368
  allToolResults.push(...msg.toolResults);
49167
49369
  }
49168
49370
  }
49169
- return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(ToolCallPanel, {
49170
- toolCalls: allToolCalls,
49171
- toolResults: allToolResults
49371
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
49372
+ marginY: 1,
49373
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(ToolCallPanel, {
49374
+ toolCalls: allToolCalls,
49375
+ toolResults: allToolResults
49376
+ }, undefined, false, undefined, this)
49172
49377
  }, undefined, false, undefined, this);
49173
49378
  }
49174
49379
  function MessageBubble({ message, queuedMessageIds }) {
@@ -49317,7 +49522,7 @@ function ToolCallPanel({
49317
49522
  const statusColor = result ? result.isError ? "red" : "green" : "yellow";
49318
49523
  const displayName = getToolDisplayName(toolCall);
49319
49524
  const context2 = getToolContext(toolCall);
49320
- const maxLine = Math.max(16, innerWidth - 2);
49525
+ const maxLine = Math.max(1, innerWidth - 2);
49321
49526
  const summaryLine = truncate(formatToolCall(toolCall), maxLine);
49322
49527
  const resultText = result ? indentMultiline(truncateToolResult(result, 4, 400), " ") : "";
49323
49528
  return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
@@ -49493,8 +49698,9 @@ function formatScheduleCall(input) {
49493
49698
  return "Listing scheduled tasks";
49494
49699
  case "create":
49495
49700
  const cmd = truncate(String(input.command || ""), 30);
49496
- const schedule = String(input.schedule || "");
49497
- return `Creating schedule: "${cmd}" (${schedule})`;
49701
+ const when = input.cron ? `cron ${input.cron}` : String(input.at || "");
49702
+ const schedule = when ? ` (${truncate(String(when), 40)})` : "";
49703
+ return `Creating schedule: "${cmd}"${schedule}`;
49498
49704
  case "update":
49499
49705
  return `Updating schedule: ${input.id || "unknown"}`;
49500
49706
  case "delete":
@@ -49991,6 +50197,16 @@ function wrapTextLines(text, wrapChars) {
49991
50197
  function stripAnsi6(text) {
49992
50198
  return text.replace(/\x1B\[[0-9;]*m/g, "");
49993
50199
  }
50200
+ function countWrappedLines2(lines, maxWidth) {
50201
+ if (!maxWidth || maxWidth <= 0)
50202
+ return lines.length;
50203
+ let total = 0;
50204
+ for (const line of lines) {
50205
+ const visible = stripAnsi6(line).length;
50206
+ total += Math.max(1, Math.ceil(visible / maxWidth));
50207
+ }
50208
+ return total;
50209
+ }
49994
50210
  function chunkRenderedLines(lines, chunkLines) {
49995
50211
  const chunks = [];
49996
50212
  let current = [];
@@ -50046,18 +50262,21 @@ function buildDisplayMessages(messages, chunkLines, wrapChars, options) {
50046
50262
  const renderedLines = rendered.split(`
50047
50263
  `);
50048
50264
  if (renderedLines.length <= chunkLines) {
50049
- display.push({ ...msg, content: rendered, __rendered: true });
50265
+ const lineCount = countWrappedLines2(renderedLines, assistantWidth);
50266
+ display.push({ ...msg, content: rendered, __rendered: true, __lineCount: lineCount });
50050
50267
  continue;
50051
50268
  }
50052
50269
  const chunks2 = chunkRenderedLines(renderedLines, chunkLines);
50053
50270
  for (let i = 0;i < chunks2.length; i++) {
50054
50271
  const chunkContent = chunks2[i].join(`
50055
50272
  `);
50273
+ const lineCount = countWrappedLines2(chunks2[i], assistantWidth);
50056
50274
  display.push({
50057
50275
  ...msg,
50058
50276
  id: `${msg.id}::chunk-${i}`,
50059
50277
  content: chunkContent,
50060
50278
  __rendered: true,
50279
+ __lineCount: lineCount,
50061
50280
  toolCalls: i === chunks2.length - 1 ? msg.toolCalls : undefined,
50062
50281
  toolResults: i === chunks2.length - 1 ? msg.toolResults : undefined
50063
50282
  });
@@ -50067,7 +50286,7 @@ function buildDisplayMessages(messages, chunkLines, wrapChars, options) {
50067
50286
  const effectiveWrap = msg.role === "user" ? Math.max(1, wrapChars - 2) : wrapChars;
50068
50287
  const lines = wrapTextLines(content, effectiveWrap);
50069
50288
  if (lines.length <= chunkLines) {
50070
- display.push(msg);
50289
+ display.push({ ...msg, __lineCount: lines.length });
50071
50290
  continue;
50072
50291
  }
50073
50292
  const chunks = chunkRenderedLines(lines, chunkLines);
@@ -50078,6 +50297,7 @@ function buildDisplayMessages(messages, chunkLines, wrapChars, options) {
50078
50297
  ...msg,
50079
50298
  id: `${msg.id}::chunk-${i}`,
50080
50299
  content: chunkContent,
50300
+ __lineCount: chunks[i].length,
50081
50301
  toolCalls: i === chunks.length - 1 ? msg.toolCalls : undefined,
50082
50302
  toolResults: i === chunks.length - 1 ? msg.toolResults : undefined
50083
50303
  });
@@ -50113,6 +50333,7 @@ function App2({ cwd: cwd2, version }) {
50113
50333
  const [scrollOffset, setScrollOffset] = import_react29.useState(0);
50114
50334
  const [autoScroll, setAutoScroll] = import_react29.useState(true);
50115
50335
  const [skills, setSkills] = import_react29.useState([]);
50336
+ const [commands, setCommands] = import_react29.useState([]);
50116
50337
  const responseRef = import_react29.useRef("");
50117
50338
  const toolCallsRef = import_react29.useRef([]);
50118
50339
  const toolResultsRef = import_react29.useRef([]);
@@ -50141,6 +50362,25 @@ function App2({ cwd: cwd2, version }) {
50141
50362
  return parts.join(`
50142
50363
  `).trim();
50143
50364
  }, []);
50365
+ const loadSessionMetadata = import_react29.useCallback(async (session) => {
50366
+ try {
50367
+ const [loadedSkills, loadedCommands] = await Promise.all([
50368
+ session.client.getSkills(),
50369
+ session.client.getCommands()
50370
+ ]);
50371
+ setSkills(loadedSkills.map((s) => ({
50372
+ name: s.name,
50373
+ description: s.description || "",
50374
+ argumentHint: s.argumentHint
50375
+ })));
50376
+ setCommands(loadedCommands.map((cmd) => ({
50377
+ name: cmd.name.startsWith("/") ? cmd.name : `/${cmd.name}`,
50378
+ description: cmd.description || ""
50379
+ })));
50380
+ } catch (err) {
50381
+ setError(err instanceof Error ? err.message : String(err));
50382
+ }
50383
+ }, []);
50144
50384
  const finalizeResponse = import_react29.useCallback((status) => {
50145
50385
  const baseContent = buildFullResponse();
50146
50386
  const hasContent = baseContent.length > 0;
@@ -50409,12 +50649,7 @@ function App2({ cwd: cwd2, version }) {
50409
50649
  });
50410
50650
  const session = await registry.createSession(cwd2);
50411
50651
  setActiveSessionId(session.id);
50412
- const loadedSkills = await session.client.getSkills();
50413
- setSkills(loadedSkills.map((s) => ({
50414
- name: s.name,
50415
- description: s.description || "",
50416
- argumentHint: s.argumentHint
50417
- })));
50652
+ await loadSessionMetadata(session);
50418
50653
  setEnergyState(session.client.getEnergyState() ?? undefined);
50419
50654
  setVoiceState(session.client.getVoiceState() ?? undefined);
50420
50655
  setIdentityInfo(session.client.getIdentityInfo() ?? undefined);
@@ -50428,7 +50663,7 @@ function App2({ cwd: cwd2, version }) {
50428
50663
  return () => {
50429
50664
  registry.closeAll();
50430
50665
  };
50431
- }, [cwd2, registry, handleChunk, finalizeResponse, resetTurnState]);
50666
+ }, [cwd2, registry, handleChunk, finalizeResponse, resetTurnState, loadSessionMetadata]);
50432
50667
  const processQueue = import_react29.useCallback(async () => {
50433
50668
  const activeSession2 = registryRef.current.getActiveSession();
50434
50669
  if (!activeSession2 || !activeSessionId)
@@ -50498,6 +50733,8 @@ function App2({ cwd: cwd2, version }) {
50498
50733
  }, [activityLog, renderWidth, wrapChars]);
50499
50734
  const reservedLines = import_react29.useMemo(() => {
50500
50735
  let lines = 0;
50736
+ const wrapWidth = Math.max(1, (columns ?? 80) - 2);
50737
+ lines += 2;
50501
50738
  if (showWelcome) {
50502
50739
  lines += 4;
50503
50740
  }
@@ -50512,16 +50749,23 @@ function App2({ cwd: cwd2, version }) {
50512
50749
  const hasMore = activeQueue.length + inlineCount > MAX_QUEUED_PREVIEW;
50513
50750
  lines += 2;
50514
50751
  lines += 1;
50515
- lines += previewCount;
50752
+ const previewWidth = Math.max(1, wrapWidth - 2);
50753
+ const previewItems = [...activeInline, ...activeQueue].slice(0, MAX_QUEUED_PREVIEW);
50754
+ const previewLines = previewItems.reduce((sum, queued) => {
50755
+ const label = queued.mode === "inline" ? "\u21B3" : "\u23F3";
50756
+ const text = `${label} ${truncateQueued(queued.content)}`;
50757
+ return sum + countWrappedLines2([text], previewWidth);
50758
+ }, 0);
50759
+ lines += Math.max(previewCount, previewLines);
50516
50760
  if (hasMore)
50517
50761
  lines += 1;
50518
50762
  }
50519
50763
  if (error2) {
50520
50764
  const parsed = parseErrorMessage(error2);
50521
- const messageLines = parsed.message ? parsed.message.split(`
50522
- `).length : 1;
50523
- const suggestionLines = parsed.suggestion ? parsed.suggestion.split(`
50524
- `).length : 0;
50765
+ const messageLines = parsed.message ? countWrappedLines2(parsed.message.split(`
50766
+ `), wrapWidth) : 1;
50767
+ const suggestionLines = parsed.suggestion ? countWrappedLines2(parsed.suggestion.split(`
50768
+ `), wrapWidth) : 0;
50525
50769
  lines += 2;
50526
50770
  lines += Math.max(1, messageLines) + suggestionLines;
50527
50771
  }
@@ -50529,9 +50773,9 @@ function App2({ cwd: cwd2, version }) {
50529
50773
  lines += 3;
50530
50774
  }
50531
50775
  lines += 1;
50532
- lines += 1;
50776
+ lines += 3;
50533
50777
  if (isProcessing) {
50534
- lines += 2;
50778
+ lines += 1;
50535
50779
  }
50536
50780
  lines += 2;
50537
50781
  return lines;
@@ -50542,7 +50786,8 @@ function App2({ cwd: cwd2, version }) {
50542
50786
  scrollOffset,
50543
50787
  error2,
50544
50788
  isProcessing,
50545
- showWelcome
50789
+ showWelcome,
50790
+ columns
50546
50791
  ]);
50547
50792
  const displayMessages = import_react29.useMemo(() => buildDisplayMessages(messages, MESSAGE_CHUNK_LINES, wrapChars, { maxWidth: renderWidth }), [messages, wrapChars, renderWidth]);
50548
50793
  const streamingMessages = import_react29.useMemo(() => {
@@ -50557,8 +50802,15 @@ function App2({ cwd: cwd2, version }) {
50557
50802
  return buildDisplayMessages([streamingMessage], MESSAGE_CHUNK_LINES, wrapChars, { maxWidth: renderWidth });
50558
50803
  }, [currentResponse, isProcessing, wrapChars, renderWidth]);
50559
50804
  const displayLineCount = import_react29.useMemo(() => {
50560
- const combined = [...displayMessages, ...streamingMessages];
50561
- return combined.reduce((sum, msg) => sum + estimateMessageLines(msg, renderWidth), 0);
50805
+ const grouped = groupConsecutiveToolMessages(displayMessages);
50806
+ const groupedLines = grouped.reduce((sum, group) => {
50807
+ if (group.type === "single") {
50808
+ return sum + estimateMessageLines(group.message, renderWidth);
50809
+ }
50810
+ return sum + estimateGroupedToolMessagesLines(group.messages, renderWidth);
50811
+ }, 0);
50812
+ const streamingLines = streamingMessages.reduce((sum, msg) => sum + estimateMessageLines(msg, renderWidth), 0);
50813
+ return groupedLines + streamingLines;
50562
50814
  }, [displayMessages, streamingMessages, renderWidth]);
50563
50815
  const totalLineCount = displayLineCount + activityLogLineCount;
50564
50816
  import_react29.useEffect(() => {
@@ -50598,6 +50850,7 @@ function App2({ cwd: cwd2, version }) {
50598
50850
  setEnergyState(session.client.getEnergyState() ?? undefined);
50599
50851
  setVoiceState(session.client.getVoiceState() ?? undefined);
50600
50852
  setIdentityInfo(session.client.getIdentityInfo() ?? undefined);
50853
+ await loadSessionMetadata(session);
50601
50854
  }
50602
50855
  await registry.switchSession(sessionId);
50603
50856
  setActiveSessionId(sessionId);
@@ -50615,6 +50868,7 @@ function App2({ cwd: cwd2, version }) {
50615
50868
  setEnergyState(newSession.client.getEnergyState() ?? undefined);
50616
50869
  setVoiceState(newSession.client.getVoiceState() ?? undefined);
50617
50870
  setIdentityInfo(newSession.client.getIdentityInfo() ?? undefined);
50871
+ await loadSessionMetadata(newSession);
50618
50872
  } catch (err) {
50619
50873
  setError(err instanceof Error ? err.message : "Failed to create session");
50620
50874
  }
@@ -50945,6 +51199,7 @@ function App2({ cwd: cwd2, version }) {
50945
51199
  onSubmit: handleSubmit,
50946
51200
  isProcessing,
50947
51201
  queueLength: activeQueue.length + inlineCount,
51202
+ commands,
50948
51203
  skills
50949
51204
  }, undefined, false, undefined, this),
50950
51205
  /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Status, {
@@ -51140,7 +51395,7 @@ function formatStreamEvent(chunk) {
51140
51395
 
51141
51396
  // packages/terminal/src/index.tsx
51142
51397
  var jsx_dev_runtime10 = __toESM(require_jsx_dev_runtime(), 1);
51143
- var VERSION3 = "0.6.34";
51398
+ var VERSION3 = "0.6.36";
51144
51399
  process.env.ASSISTANTS_VERSION ??= VERSION3;
51145
51400
  function parseArgs(argv) {
51146
51401
  const args = argv.slice(2);
@@ -51296,4 +51551,4 @@ if (options.print !== null) {
51296
51551
  });
51297
51552
  }
51298
51553
 
51299
- //# debugId=83E7550093AA9F2D64756E2164756E21
51554
+ //# debugId=D20D9C4F4FE5D66664756E2164756E21