@hasna/assistants 0.6.32 → 0.6.34

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
@@ -28328,12 +28328,12 @@ __export(exports_anthropic, {
28328
28328
  AnthropicClient: () => AnthropicClient
28329
28329
  });
28330
28330
  import { readFileSync as readFileSync4, existsSync as existsSync8 } from "fs";
28331
- import { homedir as homedir8 } from "os";
28332
- import { join as join13 } from "path";
28331
+ import { homedir as homedir9 } from "os";
28332
+ import { join as join14 } from "path";
28333
28333
  function loadApiKeyFromSecrets() {
28334
28334
  const envHome = process.env.HOME || process.env.USERPROFILE;
28335
- const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir8();
28336
- const secretsPath = join13(homeDir, ".secrets");
28335
+ const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir9();
28336
+ const secretsPath = join14(homeDir, ".secrets");
28337
28337
  if (existsSync8(secretsPath)) {
28338
28338
  try {
28339
28339
  const content = readFileSync4(secretsPath, "utf-8");
@@ -36578,7 +36578,7 @@ var import_react29 = __toESM(require_react(), 1);
36578
36578
 
36579
36579
  // packages/core/src/agent/loop.ts
36580
36580
  init_src();
36581
- import { join as join20 } from "path";
36581
+ import { join as join21 } from "path";
36582
36582
 
36583
36583
  // packages/core/src/agent/context.ts
36584
36584
  init_src();
@@ -36650,6 +36650,9 @@ class AgentContext {
36650
36650
  try {
36651
36651
  const parsed = JSON.parse(content);
36652
36652
  if (parsed && parsed.__pdf_attachment__ === true) {
36653
+ if (!parsed.data || typeof parsed.data !== "string") {
36654
+ return null;
36655
+ }
36653
36656
  return {
36654
36657
  type: "pdf",
36655
36658
  source: {
@@ -36701,8 +36704,11 @@ class AgentContext {
36701
36704
  if (this.messages.length <= this.maxMessages) {
36702
36705
  return;
36703
36706
  }
36704
- const systemMessages = this.messages.filter((m) => m.role === "system");
36707
+ let systemMessages = this.messages.filter((m) => m.role === "system");
36705
36708
  const nonSystemMessages = this.messages.filter((m) => m.role !== "system");
36709
+ if (systemMessages.length > this.maxMessages) {
36710
+ systemMessages = systemMessages.slice(-this.maxMessages);
36711
+ }
36706
36712
  const targetCount = Math.max(0, this.maxMessages - systemMessages.length);
36707
36713
  let recentMessages = targetCount > 0 ? nonSystemMessages.slice(-targetCount) : [];
36708
36714
  while (recentMessages.length > 0 && recentMessages[0].toolResults) {
@@ -36871,7 +36877,33 @@ class ContextManager {
36871
36877
  summarizedCount: 0
36872
36878
  };
36873
36879
  }
36874
- const summary = await this.summarizer.summarize(toSummarize);
36880
+ let summary = "";
36881
+ try {
36882
+ summary = await this.summarizer.summarize(toSummarize);
36883
+ } catch {
36884
+ const tokens = this.tokenCounter.countMessages(messages);
36885
+ this.state.totalTokens = tokens;
36886
+ this.state.messageCount = messages.length;
36887
+ return {
36888
+ messages,
36889
+ summarized: false,
36890
+ tokensBefore: tokens,
36891
+ tokensAfter: tokens,
36892
+ summarizedCount: 0
36893
+ };
36894
+ }
36895
+ if (!summary.trim()) {
36896
+ const tokens = this.tokenCounter.countMessages(messages);
36897
+ this.state.totalTokens = tokens;
36898
+ this.state.messageCount = messages.length;
36899
+ return {
36900
+ messages,
36901
+ summarized: false,
36902
+ tokensBefore: tokens,
36903
+ tokensAfter: tokens,
36904
+ summarizedCount: 0
36905
+ };
36906
+ }
36875
36907
  const summaryMessage = {
36876
36908
  id: generateId(),
36877
36909
  role: "system",
@@ -38523,12 +38555,10 @@ async function isPathSafe(targetPath, operation, options = {}) {
38523
38555
  for (const protectedPath of PROTECTED_PATHS) {
38524
38556
  const expanded = protectedPath.replace("~", home);
38525
38557
  if (resolved.startsWith(expanded)) {
38526
- if (operation === "write" || operation === "delete") {
38527
- return {
38528
- safe: false,
38529
- reason: `Cannot ${operation} protected path: ${protectedPath}`
38530
- };
38531
- }
38558
+ return {
38559
+ safe: false,
38560
+ reason: `Cannot ${operation} protected path: ${protectedPath}`
38561
+ };
38532
38562
  }
38533
38563
  }
38534
38564
  try {
@@ -38603,9 +38633,21 @@ class FilesystemTools {
38603
38633
  };
38604
38634
  static readExecutor = async (input) => {
38605
38635
  const baseCwd = input.cwd || process.cwd();
38606
- const path = resolve3(baseCwd, input.path);
38636
+ const rawPath = String(input.path || "").trim();
38637
+ if (!rawPath) {
38638
+ throw new ToolExecutionError("File path is required", {
38639
+ toolName: "read",
38640
+ toolInput: input,
38641
+ code: ErrorCodes.VALIDATION_OUT_OF_RANGE,
38642
+ recoverable: false,
38643
+ retryable: false,
38644
+ suggestion: "Provide a valid file path."
38645
+ });
38646
+ }
38647
+ const path = resolve3(baseCwd, rawPath);
38607
38648
  const offset = (input.offset || 1) - 1;
38608
- const limit = input.limit;
38649
+ const limitRaw = input.limit;
38650
+ const limit = typeof limitRaw === "number" && limitRaw > 0 ? Math.floor(limitRaw) : undefined;
38609
38651
  try {
38610
38652
  const safety = await isPathSafe(path, "read", { cwd: baseCwd });
38611
38653
  if (!safety.safe) {
@@ -38711,6 +38753,16 @@ class FilesystemTools {
38711
38753
  const filename = input.filename || input.path;
38712
38754
  const content = input.content;
38713
38755
  const baseCwd = input.cwd || process.cwd();
38756
+ if (typeof content !== "string") {
38757
+ throw new ToolExecutionError("Content must be a string", {
38758
+ toolName: "write",
38759
+ toolInput: input,
38760
+ code: ErrorCodes.VALIDATION_OUT_OF_RANGE,
38761
+ recoverable: false,
38762
+ retryable: false,
38763
+ suggestion: "Provide string content to write."
38764
+ });
38765
+ }
38714
38766
  const scriptsFolder = getScriptsFolder(baseCwd, input.sessionId);
38715
38767
  if (!filename || !filename.trim()) {
38716
38768
  throw new ToolExecutionError("Filename is required", {
@@ -38805,13 +38857,55 @@ class FilesystemTools {
38805
38857
  }
38806
38858
  };
38807
38859
  static globExecutor = async (input) => {
38808
- const pattern = input.pattern;
38860
+ const pattern = String(input.pattern || "").trim();
38809
38861
  const baseCwd = input.cwd || process.cwd();
38810
38862
  const searchPath = resolve3(baseCwd, input.path || ".");
38811
38863
  try {
38864
+ if (!pattern) {
38865
+ throw new ToolExecutionError("Pattern is required", {
38866
+ toolName: "glob",
38867
+ toolInput: input,
38868
+ code: ErrorCodes.VALIDATION_OUT_OF_RANGE,
38869
+ recoverable: false,
38870
+ retryable: false
38871
+ });
38872
+ }
38873
+ const safety = await isPathSafe(searchPath, "read", { cwd: baseCwd });
38874
+ if (!safety.safe) {
38875
+ getSecurityLogger().log({
38876
+ eventType: "path_violation",
38877
+ severity: "high",
38878
+ details: {
38879
+ tool: "glob",
38880
+ path: searchPath,
38881
+ reason: safety.reason || "Blocked path"
38882
+ },
38883
+ sessionId: input.sessionId || "unknown"
38884
+ });
38885
+ throw new ToolExecutionError(safety.reason || "Blocked path", {
38886
+ toolName: "glob",
38887
+ toolInput: input,
38888
+ code: ErrorCodes.TOOL_PERMISSION_DENIED,
38889
+ recoverable: false,
38890
+ retryable: false
38891
+ });
38892
+ }
38893
+ const validated = await validatePath(searchPath, {
38894
+ allowSymlinks: true,
38895
+ allowedPaths: [baseCwd, searchPath]
38896
+ });
38897
+ if (!validated.valid) {
38898
+ throw new ToolExecutionError(validated.error || "Invalid path", {
38899
+ toolName: "glob",
38900
+ toolInput: input,
38901
+ code: ErrorCodes.VALIDATION_OUT_OF_RANGE,
38902
+ recoverable: false,
38903
+ retryable: false
38904
+ });
38905
+ }
38812
38906
  const glob = new Glob(pattern);
38813
38907
  const matches = [];
38814
- for await (const file of glob.scan({ cwd: searchPath })) {
38908
+ for await (const file of glob.scan({ cwd: validated.resolved })) {
38815
38909
  matches.push(file);
38816
38910
  if (matches.length >= 1000)
38817
38911
  break;
@@ -38864,18 +38958,60 @@ class FilesystemTools {
38864
38958
  }
38865
38959
  };
38866
38960
  static grepExecutor = async (input) => {
38867
- const pattern = input.pattern;
38961
+ const pattern = String(input.pattern || "").trim();
38868
38962
  const baseCwd = input.cwd || process.cwd();
38869
38963
  const searchPath = resolve3(baseCwd, input.path || ".");
38870
38964
  const globPattern = input.glob || "**/*";
38871
38965
  const caseSensitive = input.caseSensitive || false;
38872
38966
  try {
38967
+ if (!pattern) {
38968
+ throw new ToolExecutionError("Pattern is required", {
38969
+ toolName: "grep",
38970
+ toolInput: input,
38971
+ code: ErrorCodes.VALIDATION_OUT_OF_RANGE,
38972
+ recoverable: false,
38973
+ retryable: false
38974
+ });
38975
+ }
38976
+ const safety = await isPathSafe(searchPath, "read", { cwd: baseCwd });
38977
+ if (!safety.safe) {
38978
+ getSecurityLogger().log({
38979
+ eventType: "path_violation",
38980
+ severity: "high",
38981
+ details: {
38982
+ tool: "grep",
38983
+ path: searchPath,
38984
+ reason: safety.reason || "Blocked path"
38985
+ },
38986
+ sessionId: input.sessionId || "unknown"
38987
+ });
38988
+ throw new ToolExecutionError(safety.reason || "Blocked path", {
38989
+ toolName: "grep",
38990
+ toolInput: input,
38991
+ code: ErrorCodes.TOOL_PERMISSION_DENIED,
38992
+ recoverable: false,
38993
+ retryable: false
38994
+ });
38995
+ }
38996
+ const validated = await validatePath(searchPath, {
38997
+ allowSymlinks: true,
38998
+ allowedPaths: [baseCwd, searchPath]
38999
+ });
39000
+ if (!validated.valid) {
39001
+ throw new ToolExecutionError(validated.error || "Invalid path", {
39002
+ toolName: "grep",
39003
+ toolInput: input,
39004
+ code: ErrorCodes.VALIDATION_OUT_OF_RANGE,
39005
+ recoverable: false,
39006
+ retryable: false
39007
+ });
39008
+ }
38873
39009
  const flags = caseSensitive ? "" : "i";
38874
39010
  const regex2 = new RegExp(pattern, flags);
38875
39011
  const results = [];
38876
39012
  const glob = new Glob(globPattern);
38877
- for await (const file of glob.scan({ cwd: searchPath })) {
38878
- const filePath = join4(searchPath, file);
39013
+ for await (const file of glob.scan({ cwd: validated.resolved })) {
39014
+ const filePath = join4(validated.resolved, file);
38879
39015
  try {
38880
39016
  const content = await Bun.file(filePath).text();
38881
39017
  const lines = content.split(`
@@ -39902,7 +40038,10 @@ function computeNextRun(schedule, fromTime) {
39902
40038
  if (schedule.schedule.kind === "once") {
39903
40039
  if (!schedule.schedule.at)
39904
40040
  return;
39905
- return parseScheduledTime(schedule.schedule.at, validTimezone);
40041
+ const next = parseScheduledTime(schedule.schedule.at, validTimezone);
40042
+ if (!next || next <= fromTime)
40043
+ return;
40044
+ return next;
39906
40045
  }
39907
40046
  if (schedule.schedule.kind === "cron") {
39908
40047
  if (!schedule.schedule.cron)
@@ -39918,6 +40057,8 @@ async function getDueSchedules(cwd2, nowTime) {
39918
40057
  return false;
39919
40058
  if (!schedule.nextRunAt)
39920
40059
  return false;
40060
+ if (!Number.isFinite(schedule.nextRunAt))
40061
+ return false;
39921
40062
  return schedule.nextRunAt <= nowTime;
39922
40063
  });
39923
40064
  }
@@ -40033,6 +40174,9 @@ function parseDateTime(value) {
40033
40174
  if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day) || !Number.isFinite(hour) || !Number.isFinite(minute) || !Number.isFinite(second)) {
40034
40175
  return null;
40035
40176
  }
40177
+ if (month < 1 || month > 12 || day < 1 || day > 31 || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
40178
+ return null;
40179
+ }
40036
40180
  return { year, month, day, hour, minute, second };
40037
40181
  }
40038
40182
  function hasTimeZoneOffset(value) {
@@ -40171,11 +40315,21 @@ class SchedulerTool {
40171
40315
  const id = String(input.id || "").trim();
40172
40316
  if (!id)
40173
40317
  return "Error: id is required.";
40318
+ let nextRunAt;
40319
+ if (action === "resume") {
40320
+ const schedule = await readSchedule(cwd2, id);
40321
+ if (!schedule)
40322
+ return `Schedule ${id} not found.`;
40323
+ nextRunAt = computeNextRun(schedule, Date.now());
40324
+ if (!nextRunAt) {
40325
+ return `Error: unable to compute next run for schedule ${id}.`;
40326
+ }
40327
+ }
40174
40328
  const updated = await updateSchedule(cwd2, id, (s) => ({
40175
40329
  ...s,
40176
40330
  status: action === "pause" ? "paused" : "active",
40177
40331
  updatedAt: Date.now(),
40178
- nextRunAt: action === "resume" ? computeNextRun(s, Date.now()) : s.nextRunAt
40332
+ nextRunAt: action === "resume" ? nextRunAt : s.nextRunAt
40179
40333
  }));
40180
40334
  if (!updated)
40181
40335
  return `Schedule ${id} not found.`;
@@ -40660,6 +40814,7 @@ class HookExecutor {
40660
40814
  return null;
40661
40815
  try {
40662
40816
  const proc = Bun.spawn(["bash", "-c", hook.command], {
40817
+ cwd: input.cwd || process.cwd(),
40663
40818
  stdin: "pipe",
40664
40819
  stdout: "pipe",
40665
40820
  stderr: "pipe"
@@ -41567,8 +41722,8 @@ ${stderr}`;
41567
41722
  }
41568
41723
  }
41569
41724
  // packages/core/src/commands/builtin.ts
41570
- import { join as join12 } from "path";
41571
- import { homedir as homedir7, platform as platform2, release, arch } from "os";
41725
+ import { join as join13 } from "path";
41726
+ import { homedir as homedir8, platform as platform2, release, arch } from "os";
41572
41727
  import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
41573
41728
  init_src();
41574
41729
 
@@ -41672,23 +41827,28 @@ function hasProjectNameConflict(projects, name) {
41672
41827
 
41673
41828
  // packages/core/src/projects/context.ts
41674
41829
  import { readFile as readFile3 } from "fs/promises";
41675
- import { resolve as resolve4 } from "path";
41830
+ import { homedir as homedir7 } from "os";
41831
+ import { resolve as resolve4, join as join12 } from "path";
41676
41832
  var DEFAULT_MAX_FILE_BYTES = 12000;
41833
+ function singleLine(value) {
41834
+ return value.replace(/[\r\n]+/g, " ").trim();
41835
+ }
41677
41836
  function formatPlan(plan) {
41678
41837
  const lines = [];
41679
- lines.push(`- ${plan.title} (${plan.steps.length} steps)`);
41838
+ lines.push(`- ${singleLine(plan.title)} (${plan.steps.length} steps)`);
41680
41839
  for (const step of plan.steps) {
41681
- lines.push(` - [${step.status}] ${step.text}`);
41840
+ lines.push(` - [${step.status}] ${singleLine(step.text)}`);
41682
41841
  }
41683
41842
  return lines.join(`
41684
41843
  `);
41685
41844
  }
41686
41845
  function normalizeEntryLabel(entry) {
41687
- return entry.label ? entry.label.trim() : entry.value.trim();
41846
+ return entry.label ? singleLine(entry.label) : singleLine(entry.value);
41688
41847
  }
41689
41848
  async function renderFileEntry(entry, options) {
41690
41849
  const rawPath = entry.value.trim();
41691
- const resolved = resolve4(options.cwd, rawPath);
41850
+ const expandedPath = rawPath === "~" ? homedir7() : rawPath.startsWith("~/") ? join12(homedir7(), rawPath.slice(2)) : rawPath;
41851
+ const resolved = resolve4(options.cwd, expandedPath);
41692
41852
  const validation = await validatePath(resolved, { allowedPaths: [options.cwd] });
41693
41853
  if (!validation.valid) {
41694
41854
  return `- File: ${rawPath} (unavailable: ${validation.error || "invalid path"})`;
@@ -41820,7 +41980,7 @@ function splitArgs(input) {
41820
41980
  args.push(current);
41821
41981
  return args;
41822
41982
  }
41823
- function singleLine(value) {
41983
+ function singleLine2(value) {
41824
41984
  return value.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
41825
41985
  }
41826
41986
 
@@ -42659,12 +42819,12 @@ No context entries for project "${project.name}".
42659
42819
  return { handled: true };
42660
42820
  }
42661
42821
  let output = `
42662
- **Context Entries (${singleLine(project.name)})**
42822
+ **Context Entries (${singleLine2(project.name)})**
42663
42823
 
42664
42824
  `;
42665
42825
  for (const entry of project.context) {
42666
- const label = entry.label ? ` (${singleLine(entry.label)})` : "";
42667
- output += `- ${entry.id} [${entry.type}] ${singleLine(entry.value)}${label}
42826
+ const label = entry.label ? ` (${singleLine2(entry.label)})` : "";
42827
+ output += `- ${entry.id} [${entry.type}] ${singleLine2(entry.value)}${label}
42668
42828
  `;
42669
42829
  }
42670
42830
  context.emit("text", output);
@@ -42811,7 +42971,7 @@ No projects found. Use /projects new <name>.
42811
42971
  `;
42812
42972
  for (const project of projects) {
42813
42973
  const marker = project.id === activeId ? "*" : " ";
42814
- output += `${marker} ${singleLine(project.name)} (${project.id})
42974
+ output += `${marker} ${singleLine2(project.name)} (${project.id})
42815
42975
  `;
42816
42976
  }
42817
42977
  context.emit("text", output);
@@ -42873,13 +43033,13 @@ No projects found. Use /projects new <name>.
42873
43033
  return { handled: true };
42874
43034
  }
42875
43035
  let output = `
42876
- **Project: ${singleLine(project.name)}**
43036
+ **Project: ${singleLine2(project.name)}**
42877
43037
 
42878
43038
  `;
42879
43039
  output += `ID: ${project.id}
42880
43040
  `;
42881
43041
  if (project.description) {
42882
- output += `Description: ${singleLine(project.description)}
43042
+ output += `Description: ${singleLine2(project.description)}
42883
43043
  `;
42884
43044
  }
42885
43045
  output += `Context entries: ${project.context.length}
@@ -43005,11 +43165,11 @@ No plans for project "${project.name}".
43005
43165
  return { handled: true };
43006
43166
  }
43007
43167
  let output = `
43008
- **Plans (${singleLine(project.name)})**
43168
+ **Plans (${singleLine2(project.name)})**
43009
43169
 
43010
43170
  `;
43011
43171
  for (const plan of project.plans) {
43012
- output += `- ${plan.id} ${singleLine(plan.title)} (${plan.steps.length} steps)
43172
+ output += `- ${plan.id} ${singleLine2(plan.title)} (${plan.steps.length} steps)
43013
43173
  `;
43014
43174
  }
43015
43175
  context.emit("text", output);
@@ -43065,7 +43225,7 @@ No plans for project "${project.name}".
43065
43225
  return { handled: true };
43066
43226
  }
43067
43227
  let output = `
43068
- **Plan: ${singleLine(plan.title)}**
43228
+ **Plan: ${singleLine2(plan.title)}**
43069
43229
 
43070
43230
  `;
43071
43231
  output += `ID: ${plan.id}
@@ -43075,7 +43235,7 @@ No plans for project "${project.name}".
43075
43235
  `;
43076
43236
  } else {
43077
43237
  for (const step of plan.steps) {
43078
- output += `- ${step.id} [${step.status}] ${singleLine(step.text)}
43238
+ output += `- ${step.id} [${step.status}] ${singleLine2(step.text)}
43079
43239
  `;
43080
43240
  }
43081
43241
  }
@@ -43508,9 +43668,9 @@ Format the summary as a brief bullet-point list. This summary will replace the c
43508
43668
  content: "",
43509
43669
  handler: async (args, context) => {
43510
43670
  const configPaths = [
43511
- join12(context.cwd, ".assistants", "config.json"),
43512
- join12(context.cwd, ".assistants", "config.local.json"),
43513
- join12(getConfigDir(), "config.json")
43671
+ join13(context.cwd, ".assistants", "config.json"),
43672
+ join13(context.cwd, ".assistants", "config.local.json"),
43673
+ join13(getConfigDir(), "config.json")
43514
43674
  ];
43515
43675
  let message = `
43516
43676
  **Configuration**
@@ -43524,13 +43684,13 @@ Format the summary as a brief bullet-point list. This summary will replace the c
43524
43684
  `;
43525
43685
  }
43526
43686
  const envHome = process.env.HOME || process.env.USERPROFILE;
43527
- const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir7();
43687
+ const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir8();
43528
43688
  message += `
43529
43689
  **Commands Directories:**
43530
43690
  `;
43531
- message += ` - Project: ${join12(context.cwd, ".assistants", "commands")}
43691
+ message += ` - Project: ${join13(context.cwd, ".assistants", "commands")}
43532
43692
  `;
43533
- message += ` - Global: ${join12(homeDir, ".assistants", "commands")}
43693
+ message += ` - Global: ${join13(homeDir, ".assistants", "commands")}
43534
43694
  `;
43535
43695
  context.emit("text", message);
43536
43696
  context.emit("done");
@@ -43546,7 +43706,7 @@ Format the summary as a brief bullet-point list. This summary will replace the c
43546
43706
  selfHandled: true,
43547
43707
  content: "",
43548
43708
  handler: async (args, context) => {
43549
- const commandsDir = join12(context.cwd, ".assistants", "commands");
43709
+ const commandsDir = join13(context.cwd, ".assistants", "commands");
43550
43710
  mkdirSync4(commandsDir, { recursive: true });
43551
43711
  const exampleCommand = `---
43552
43712
  name: reflect
@@ -43562,7 +43722,7 @@ Please summarize the last interaction and suggest 2-3 next steps.
43562
43722
  - Focus on clarity
43563
43723
  - Ask a follow-up question if needed
43564
43724
  `;
43565
- const examplePath = join12(commandsDir, "reflect.md");
43725
+ const examplePath = join13(commandsDir, "reflect.md");
43566
43726
  if (!existsSync7(examplePath)) {
43567
43727
  writeFileSync5(examplePath, exampleCommand);
43568
43728
  }
@@ -44728,13 +44888,13 @@ function validateToolCalls(toolCalls, tools) {
44728
44888
 
44729
44889
  // packages/core/src/voice/utils.ts
44730
44890
  import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
44731
- import { homedir as homedir9 } from "os";
44732
- import { join as join14 } from "path";
44891
+ import { homedir as homedir10 } from "os";
44892
+ import { join as join15 } from "path";
44733
44893
  import { spawnSync } from "child_process";
44734
44894
  function loadApiKeyFromSecrets2(key) {
44735
44895
  const envHome = process.env.HOME || process.env.USERPROFILE;
44736
- const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir9();
44737
- const secretsPath = join14(homeDir, ".secrets");
44896
+ const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir10();
44897
+ const secretsPath = join15(homeDir, ".secrets");
44738
44898
  if (!existsSync9(secretsPath))
44739
44899
  return;
44740
44900
  try {
@@ -44808,7 +44968,7 @@ class SystemSTT {
44808
44968
  // packages/core/src/voice/tts.ts
44809
44969
  import { spawnSync as spawnSync2 } from "child_process";
44810
44970
  import { tmpdir as tmpdir2 } from "os";
44811
- import { join as join15 } from "path";
44971
+ import { join as join16 } from "path";
44812
44972
  import { readFileSync as readFileSync6, unlinkSync as unlinkSync2 } from "fs";
44813
44973
  class ElevenLabsTTS {
44814
44974
  apiKey;
@@ -44912,7 +45072,7 @@ class SystemTTS {
44912
45072
  if (!say) {
44913
45073
  throw new Error('System TTS not available: missing "say" command.');
44914
45074
  }
44915
- const output = join15(tmpdir2(), `assistants-tts-${Date.now()}.aiff`);
45075
+ const output = join16(tmpdir2(), `assistants-tts-${Date.now()}.aiff`);
44916
45076
  const args = [];
44917
45077
  if (this.voiceId) {
44918
45078
  args.push("-v", this.voiceId);
@@ -44934,7 +45094,7 @@ class SystemTTS {
44934
45094
  }
44935
45095
  const espeak = findExecutable("espeak") || findExecutable("espeak-ng");
44936
45096
  if (espeak) {
44937
- const output = join15(tmpdir2(), `assistants-tts-${Date.now()}.wav`);
45097
+ const output = join16(tmpdir2(), `assistants-tts-${Date.now()}.wav`);
44938
45098
  const args = ["-w", output];
44939
45099
  if (this.voiceId) {
44940
45100
  args.push("-v", this.voiceId);
@@ -44961,14 +45121,14 @@ class SystemTTS {
44961
45121
  // packages/core/src/voice/player.ts
44962
45122
  import { spawn } from "child_process";
44963
45123
  import { tmpdir as tmpdir3 } from "os";
44964
- import { join as join16 } from "path";
45124
+ import { join as join17 } from "path";
44965
45125
  import { unlink as unlink4, writeFileSync as writeFileSync6 } from "fs";
44966
45126
  class AudioPlayer {
44967
45127
  currentProcess = null;
44968
45128
  playing = false;
44969
45129
  async play(audio, options = {}) {
44970
45130
  const format = options.format ?? "mp3";
44971
- const tempFile = join16(tmpdir3(), `assistants-audio-${Date.now()}.${format}`);
45131
+ const tempFile = join17(tmpdir3(), `assistants-audio-${Date.now()}.${format}`);
44972
45132
  writeFileSync6(tempFile, Buffer.from(audio));
44973
45133
  const player = this.resolvePlayer(format);
44974
45134
  if (!player) {
@@ -45036,7 +45196,7 @@ class AudioPlayer {
45036
45196
  // packages/core/src/voice/recorder.ts
45037
45197
  import { spawn as spawn2 } from "child_process";
45038
45198
  import { tmpdir as tmpdir4 } from "os";
45039
- import { join as join17 } from "path";
45199
+ import { join as join18 } from "path";
45040
45200
  import { readFileSync as readFileSync7, unlink as unlink5 } from "fs";
45041
45201
  class AudioRecorder {
45042
45202
  currentProcess = null;
@@ -45047,7 +45207,7 @@ class AudioRecorder {
45047
45207
  const duration = options.durationSeconds ?? 5;
45048
45208
  const sampleRate = options.sampleRate ?? 16000;
45049
45209
  const channels = options.channels ?? 1;
45050
- const output = join17(tmpdir4(), `assistants-record-${Date.now()}.wav`);
45210
+ const output = join18(tmpdir4(), `assistants-record-${Date.now()}.wav`);
45051
45211
  const recorder = this.resolveRecorder(sampleRate, channels, duration, output);
45052
45212
  if (!recorder) {
45053
45213
  throw new Error("No supported audio recorder found. Install sox or ffmpeg.");
@@ -45241,13 +45401,13 @@ class VoiceManager {
45241
45401
  init_src();
45242
45402
  import { existsSync as existsSync11 } from "fs";
45243
45403
  import { mkdir as mkdir5, readFile as readFile8, writeFile as writeFile7, rm as rm2 } from "fs/promises";
45244
- import { join as join19 } from "path";
45404
+ import { join as join20 } from "path";
45245
45405
 
45246
45406
  // packages/core/src/identity/identity-manager.ts
45247
45407
  init_src();
45248
45408
  import { existsSync as existsSync10 } from "fs";
45249
45409
  import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile6, rm } from "fs/promises";
45250
- import { join as join18 } from "path";
45410
+ import { join as join19 } from "path";
45251
45411
  var DEFAULT_PROFILE = {
45252
45412
  displayName: "Assistant",
45253
45413
  timezone: "UTC",
@@ -45277,19 +45437,19 @@ class IdentityManager {
45277
45437
  this.basePath = basePath;
45278
45438
  }
45279
45439
  get identitiesRoot() {
45280
- return join18(this.basePath, "assistants", this.assistantId, "identities");
45440
+ return join19(this.basePath, "assistants", this.assistantId, "identities");
45281
45441
  }
45282
45442
  get indexPath() {
45283
- return join18(this.identitiesRoot, "index.json");
45443
+ return join19(this.identitiesRoot, "index.json");
45284
45444
  }
45285
45445
  get activePath() {
45286
- return join18(this.identitiesRoot, "active.json");
45446
+ return join19(this.identitiesRoot, "active.json");
45287
45447
  }
45288
45448
  identityPath(id) {
45289
- return join18(this.identitiesRoot, `${id}.json`);
45449
+ return join19(this.identitiesRoot, `${id}.json`);
45290
45450
  }
45291
45451
  assistantConfigPath() {
45292
- return join18(this.basePath, "assistants", this.assistantId, "config.json");
45452
+ return join19(this.basePath, "assistants", this.assistantId, "config.json");
45293
45453
  }
45294
45454
  async initialize() {
45295
45455
  await mkdir4(this.identitiesRoot, { recursive: true });
@@ -45473,16 +45633,16 @@ class AssistantManager {
45473
45633
  this.basePath = basePath;
45474
45634
  }
45475
45635
  get assistantsRoot() {
45476
- return join19(this.basePath, "assistants");
45636
+ return join20(this.basePath, "assistants");
45477
45637
  }
45478
45638
  get indexPath() {
45479
- return join19(this.assistantsRoot, "index.json");
45639
+ return join20(this.assistantsRoot, "index.json");
45480
45640
  }
45481
45641
  get activePath() {
45482
- return join19(this.basePath, "active.json");
45642
+ return join20(this.basePath, "active.json");
45483
45643
  }
45484
45644
  assistantConfigPath(id) {
45485
- return join19(this.assistantsRoot, id, "config.json");
45645
+ return join20(this.assistantsRoot, id, "config.json");
45486
45646
  }
45487
45647
  async initialize() {
45488
45648
  await mkdir5(this.assistantsRoot, { recursive: true });
@@ -45536,7 +45696,7 @@ class AssistantManager {
45536
45696
  if (!this.assistants.has(id)) {
45537
45697
  throw new Error(`Assistant ${id} not found`);
45538
45698
  }
45539
- await rm2(join19(this.assistantsRoot, id), { recursive: true, force: true });
45699
+ await rm2(join20(this.assistantsRoot, id), { recursive: true, force: true });
45540
45700
  this.assistants.delete(id);
45541
45701
  await this.removeFromIndex(id);
45542
45702
  if (this.activeId === id) {
@@ -45602,7 +45762,7 @@ class AssistantManager {
45602
45762
  }
45603
45763
  }
45604
45764
  async persistAssistant(assistant) {
45605
- const dir = join19(this.assistantsRoot, assistant.id);
45765
+ const dir = join20(this.assistantsRoot, assistant.id);
45606
45766
  await mkdir5(dir, { recursive: true });
45607
45767
  await writeFile7(this.assistantConfigPath(assistant.id), JSON.stringify(assistant, null, 2));
45608
45768
  }
@@ -46444,7 +46604,7 @@ ${content.trim()}`);
46444
46604
  const heartbeatConfig = this.buildHeartbeatConfig(this.config);
46445
46605
  if (!heartbeatConfig)
46446
46606
  return;
46447
- const statePath = join20(getConfigDir(), "state", `${this.sessionId}.json`);
46607
+ const statePath = join21(getConfigDir(), "state", `${this.sessionId}.json`);
46448
46608
  this.heartbeatManager = new HeartbeatManager(heartbeatConfig);
46449
46609
  this.heartbeatPersistence = new StatePersistence(statePath);
46450
46610
  this.heartbeatRecovery = new RecoveryManager(this.heartbeatPersistence, heartbeatConfig.persistPath, heartbeatConfig.staleThresholdMs, {
@@ -46493,7 +46653,7 @@ ${content.trim()}`);
46493
46653
  async startEnergySystem() {
46494
46654
  if (!this.config || this.config.energy?.enabled === false)
46495
46655
  return;
46496
- const statePath = join20(getConfigDir(), "energy", "state.json");
46656
+ const statePath = join21(getConfigDir(), "energy", "state.json");
46497
46657
  this.energyManager = new EnergyManager(this.config.energy, new EnergyStorage(statePath));
46498
46658
  await this.energyManager.initialize();
46499
46659
  this.refreshEnergyEffects();
@@ -46739,7 +46899,7 @@ ${this.identityContext}`);
46739
46899
  return null;
46740
46900
  const intervalMs = Math.max(1000, config.heartbeat?.intervalMs ?? 15000);
46741
46901
  const staleThresholdMs = Math.max(intervalMs * 2, config.heartbeat?.staleThresholdMs ?? 120000);
46742
- const persistPath = config.heartbeat?.persistPath ?? join20(getConfigDir(), "heartbeats", `${this.sessionId}.json`);
46902
+ const persistPath = config.heartbeat?.persistPath ?? join21(getConfigDir(), "heartbeats", `${this.sessionId}.json`);
46743
46903
  return {
46744
46904
  intervalMs,
46745
46905
  staleThresholdMs,
@@ -46836,17 +46996,17 @@ init_src();
46836
46996
 
46837
46997
  // packages/core/src/logger.ts
46838
46998
  import { existsSync as existsSync12, mkdirSync as mkdirSync8, appendFileSync, readdirSync as readdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
46839
- import { join as join21 } from "path";
46999
+ import { join as join22 } from "path";
46840
47000
  class Logger {
46841
47001
  logDir;
46842
47002
  logFile;
46843
47003
  sessionId;
46844
47004
  constructor(sessionId, basePath) {
46845
47005
  this.sessionId = sessionId;
46846
- this.logDir = join21(basePath || getConfigDir(), "logs");
47006
+ this.logDir = join22(basePath || getConfigDir(), "logs");
46847
47007
  this.ensureDir(this.logDir);
46848
47008
  const date = new Date().toISOString().split("T")[0];
46849
- this.logFile = join21(this.logDir, `${date}.log`);
47009
+ this.logFile = join22(this.logDir, `${date}.log`);
46850
47010
  }
46851
47011
  ensureDir(dir) {
46852
47012
  if (!existsSync12(dir)) {
@@ -46890,9 +47050,9 @@ class SessionStorage {
46890
47050
  constructor(sessionId, basePath, assistantId) {
46891
47051
  this.sessionId = sessionId;
46892
47052
  const root = basePath || getConfigDir();
46893
- this.sessionsDir = assistantId ? join21(root, "assistants", assistantId, "sessions") : join21(root, "sessions");
47053
+ this.sessionsDir = assistantId ? join22(root, "assistants", assistantId, "sessions") : join22(root, "sessions");
46894
47054
  this.ensureDir(this.sessionsDir);
46895
- this.sessionFile = join21(this.sessionsDir, `${sessionId}.json`);
47055
+ this.sessionFile = join22(this.sessionsDir, `${sessionId}.json`);
46896
47056
  }
46897
47057
  ensureDir(dir) {
46898
47058
  if (!existsSync12(dir)) {
@@ -46918,7 +47078,7 @@ class SessionStorage {
46918
47078
  }
46919
47079
  static getActiveAssistantId() {
46920
47080
  try {
46921
- const activePath = join21(getConfigDir(), "active.json");
47081
+ const activePath = join22(getConfigDir(), "active.json");
46922
47082
  if (!existsSync12(activePath))
46923
47083
  return null;
46924
47084
  const raw = readFileSync8(activePath, "utf-8");
@@ -46932,12 +47092,12 @@ class SessionStorage {
46932
47092
  const root = getConfigDir();
46933
47093
  const resolvedId = assistantId ?? SessionStorage.getActiveAssistantId();
46934
47094
  if (resolvedId) {
46935
- const assistantDir = join21(root, "assistants", resolvedId, "sessions");
47095
+ const assistantDir = join22(root, "assistants", resolvedId, "sessions");
46936
47096
  if (existsSync12(assistantDir)) {
46937
47097
  return assistantDir;
46938
47098
  }
46939
47099
  }
46940
- return join21(root, "sessions");
47100
+ return join22(root, "sessions");
46941
47101
  }
46942
47102
  static listSessions(assistantId) {
46943
47103
  const sessionsDir = SessionStorage.resolveSessionsDir(assistantId);
@@ -46949,7 +47109,7 @@ class SessionStorage {
46949
47109
  if (!file.endsWith(".json"))
46950
47110
  continue;
46951
47111
  try {
46952
- const filePath = join21(sessionsDir, file);
47112
+ const filePath = join22(sessionsDir, file);
46953
47113
  const stat = Bun.file(filePath);
46954
47114
  const content = JSON.parse(readFileSync8(filePath, "utf-8"));
46955
47115
  sessions.push({
@@ -46969,7 +47129,7 @@ class SessionStorage {
46969
47129
  }
46970
47130
  static loadSession(sessionId, assistantId) {
46971
47131
  const sessionsDir = SessionStorage.resolveSessionsDir(assistantId);
46972
- const sessionFile = join21(sessionsDir, `${sessionId}.json`);
47132
+ const sessionFile = join22(sessionsDir, `${sessionId}.json`);
46973
47133
  try {
46974
47134
  if (!existsSync12(sessionFile))
46975
47135
  return null;
@@ -46983,15 +47143,15 @@ function initAssistantsDir() {
46983
47143
  const baseDir = getConfigDir();
46984
47144
  const dirs = [
46985
47145
  baseDir,
46986
- join21(baseDir, "logs"),
46987
- join21(baseDir, "assistants"),
46988
- join21(baseDir, "shared", "skills"),
46989
- join21(baseDir, "commands"),
46990
- join21(baseDir, "temp"),
46991
- join21(baseDir, "heartbeats"),
46992
- join21(baseDir, "state"),
46993
- join21(baseDir, "energy"),
46994
- join21(baseDir, "migration")
47146
+ join22(baseDir, "logs"),
47147
+ join22(baseDir, "assistants"),
47148
+ join22(baseDir, "shared", "skills"),
47149
+ join22(baseDir, "commands"),
47150
+ join22(baseDir, "temp"),
47151
+ join22(baseDir, "heartbeats"),
47152
+ join22(baseDir, "state"),
47153
+ join22(baseDir, "energy"),
47154
+ join22(baseDir, "migration")
46995
47155
  ];
46996
47156
  for (const dir of dirs) {
46997
47157
  if (!existsSync12(dir)) {
@@ -47647,7 +47807,7 @@ function Input({ onSubmit, isProcessing, queueLength = 0, commands, skills = []
47647
47807
  const visibleSkills = getVisibleItems(filteredSkills);
47648
47808
  const visibleCommands = getVisibleItems(filteredCommands);
47649
47809
  const { stdout } = use_stdout_default();
47650
- const terminalWidth = stdout?.columns ?? 80;
47810
+ const terminalWidth = Math.max(10, (stdout?.columns ?? 80) - 2);
47651
47811
  const lines = value.split(`
47652
47812
  `);
47653
47813
  const lineCount = lines.length;
@@ -47657,8 +47817,8 @@ function Input({ onSubmit, isProcessing, queueLength = 0, commands, skills = []
47657
47817
  children: [
47658
47818
  /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
47659
47819
  children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
47660
- color: "gray",
47661
- children: "\u2500".repeat(terminalWidth)
47820
+ color: "#666666",
47821
+ children: "-".repeat(terminalWidth)
47662
47822
  }, undefined, false, undefined, this)
47663
47823
  }, undefined, false, undefined, this),
47664
47824
  /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
@@ -47692,8 +47852,8 @@ function Input({ onSubmit, isProcessing, queueLength = 0, commands, skills = []
47692
47852
  }, undefined, false, undefined, this),
47693
47853
  /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
47694
47854
  children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
47695
- color: "gray",
47696
- children: "\u2500".repeat(terminalWidth)
47855
+ color: "#666666",
47856
+ children: "-".repeat(terminalWidth)
47697
47857
  }, undefined, false, undefined, this)
47698
47858
  }, undefined, false, undefined, this),
47699
47859
  isProcessing && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
@@ -48242,7 +48402,7 @@ function formatMarkdownTables(text, maxWidth) {
48242
48402
  function parseTableRow(line) {
48243
48403
  const trimmed = line.trim();
48244
48404
  const withoutEdges = trimmed.replace(/^\|/, "").replace(/\|$/, "");
48245
- return withoutEdges.split("|").map((cell) => cell.trim());
48405
+ return withoutEdges.split("|").map((cell) => cell.replace(/[\r\n]+/g, " ").trim());
48246
48406
  }
48247
48407
  function renderTable(header, rows, maxWidth) {
48248
48408
  const colCount = Math.max(header.length, ...rows.map((r) => r.length));
@@ -48537,7 +48697,7 @@ function truncateToolResult(toolResult, maxLines = 15, maxChars = 3000) {
48537
48697
  if (content.length > maxChars) {
48538
48698
  content = content.slice(0, maxChars) + "...";
48539
48699
  }
48540
- return prefix + content.trim();
48700
+ return prefix + content.trimEnd();
48541
48701
  }
48542
48702
  function formatToolResultNicely(toolName, content, isError) {
48543
48703
  if (isError) {
@@ -49589,7 +49749,7 @@ function ProcessingIndicator({
49589
49749
  var jsx_dev_runtime7 = __toESM(require_jsx_dev_runtime(), 1);
49590
49750
  function WelcomeBanner({ version, model, directory }) {
49591
49751
  const homeDir = process.env.HOME || "";
49592
- const displayDir = directory.startsWith(homeDir) ? "~" + directory.slice(homeDir.length) : directory;
49752
+ const displayDir = homeDir && directory.startsWith(homeDir) ? "~" + directory.slice(homeDir.length) : directory;
49593
49753
  return /* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Box_default, {
49594
49754
  flexDirection: "column",
49595
49755
  marginBottom: 1,
@@ -49675,7 +49835,7 @@ function formatSessionTime(timestamp) {
49675
49835
  }
49676
49836
  function formatPath(cwd2) {
49677
49837
  const home = process.env.HOME || "";
49678
- if (cwd2.startsWith(home)) {
49838
+ if (home && cwd2.startsWith(home)) {
49679
49839
  return "~" + cwd2.slice(home.length);
49680
49840
  }
49681
49841
  return cwd2;
@@ -49881,7 +50041,8 @@ function buildDisplayMessages(messages, chunkLines, wrapChars, options) {
49881
50041
  continue;
49882
50042
  }
49883
50043
  if (msg.role === "assistant") {
49884
- const rendered = renderMarkdown(content, { maxWidth: options?.maxWidth });
50044
+ const assistantWidth = options?.maxWidth ? Math.max(1, options.maxWidth - 2) : undefined;
50045
+ const rendered = renderMarkdown(content, { maxWidth: assistantWidth });
49885
50046
  const renderedLines = rendered.split(`
49886
50047
  `);
49887
50048
  if (renderedLines.length <= chunkLines) {
@@ -49903,7 +50064,8 @@ function buildDisplayMessages(messages, chunkLines, wrapChars, options) {
49903
50064
  }
49904
50065
  continue;
49905
50066
  }
49906
- const lines = wrapTextLines(content, wrapChars);
50067
+ const effectiveWrap = msg.role === "user" ? Math.max(1, wrapChars - 2) : wrapChars;
50068
+ const lines = wrapTextLines(content, effectiveWrap);
49907
50069
  if (lines.length <= chunkLines) {
49908
50070
  display.push(msg);
49909
50071
  continue;
@@ -50978,7 +51140,7 @@ function formatStreamEvent(chunk) {
50978
51140
 
50979
51141
  // packages/terminal/src/index.tsx
50980
51142
  var jsx_dev_runtime10 = __toESM(require_jsx_dev_runtime(), 1);
50981
- var VERSION3 = "0.6.32";
51143
+ var VERSION3 = "0.6.34";
50982
51144
  process.env.ASSISTANTS_VERSION ??= VERSION3;
50983
51145
  function parseArgs(argv) {
50984
51146
  const args = argv.slice(2);
@@ -51134,4 +51296,4 @@ if (options.print !== null) {
51134
51296
  });
51135
51297
  }
51136
51298
 
51137
- //# debugId=E7E53BFBEA38084764756E2164756E21
51299
+ //# debugId=83E7550093AA9F2D64756E2164756E21