@hasna/assistants 1.1.21 → 1.1.22

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
@@ -18677,11 +18677,28 @@ async function getDueSchedules(cwd, nowTime) {
18677
18677
  return schedule.nextRunAt <= nowTime;
18678
18678
  });
18679
18679
  }
18680
- async function updateSchedule(cwd, id, updater) {
18681
- try {
18682
- const path = schedulePath(cwd, id);
18683
- if (!path)
18680
+ async function updateSchedule(cwd, id, updater, options) {
18681
+ const path = schedulePath(cwd, id);
18682
+ if (!path)
18683
+ return null;
18684
+ const ownerId = options?.ownerId;
18685
+ let locked = false;
18686
+ let lockOwner = ownerId;
18687
+ if (!lockOwner) {
18688
+ lockOwner = generateId();
18689
+ locked = await acquireScheduleLock(cwd, id, lockOwner);
18690
+ if (!locked)
18684
18691
  return null;
18692
+ } else {
18693
+ try {
18694
+ const raw = await readFile5(lockPath(cwd, id), "utf-8");
18695
+ const lock = JSON.parse(raw);
18696
+ if (lock?.ownerId && lock.ownerId !== lockOwner) {
18697
+ return null;
18698
+ }
18699
+ } catch {}
18700
+ }
18701
+ try {
18685
18702
  const raw = await readFile5(path, "utf-8");
18686
18703
  const schedule = JSON.parse(raw);
18687
18704
  const updated = updater(schedule);
@@ -18689,6 +18706,10 @@ async function updateSchedule(cwd, id, updater) {
18689
18706
  return updated;
18690
18707
  } catch {
18691
18708
  return null;
18709
+ } finally {
18710
+ if (locked && lockOwner) {
18711
+ await releaseScheduleLock(cwd, id, lockOwner);
18712
+ }
18692
18713
  }
18693
18714
  }
18694
18715
  async function acquireScheduleLock(cwd, id, ownerId, ttlMs = DEFAULT_LOCK_TTL_MS, retryDepth = 0) {
@@ -18835,6 +18856,7 @@ function getTimeZoneOffsetMs(date, timeZone) {
18835
18856
  }
18836
18857
  var DEFAULT_LOCK_TTL_MS, SAFE_ID_PATTERN4, MAX_LOCK_RETRIES = 2;
18837
18858
  var init_store3 = __esm(async () => {
18859
+ init_src2();
18838
18860
  init_atomic_write();
18839
18861
  init_cron();
18840
18862
  await init_config();
@@ -26541,16 +26563,78 @@ var init_types3 = __esm(() => {
26541
26563
 
26542
26564
  // packages/core/src/tasks/store.ts
26543
26565
  import { join as join21 } from "path";
26544
- import { mkdir as mkdir9, readFile as readFile8, writeFile as writeFile6 } from "fs/promises";
26566
+ import { mkdir as mkdir9, readFile as readFile8, open as open3, unlink as unlink6 } from "fs/promises";
26545
26567
  function tasksDir(cwd) {
26546
26568
  return join21(cwd, TASKS_DIR);
26547
26569
  }
26548
26570
  function tasksPath(cwd) {
26549
26571
  return join21(tasksDir(cwd), TASKS_FILE);
26550
26572
  }
26573
+ function taskLockPath(cwd) {
26574
+ return join21(tasksDir(cwd), TASKS_LOCK_FILE);
26575
+ }
26551
26576
  async function ensureTasksDir(cwd) {
26552
26577
  await mkdir9(tasksDir(cwd), { recursive: true });
26553
26578
  }
26579
+ async function acquireTaskLock(cwd, ownerId, ttlMs = DEFAULT_TASK_LOCK_TTL_MS, retryDepth = 0) {
26580
+ if (retryDepth >= MAX_TASK_LOCK_RETRIES)
26581
+ return false;
26582
+ await ensureTasksDir(cwd);
26583
+ const path = taskLockPath(cwd);
26584
+ const now2 = Date.now();
26585
+ try {
26586
+ const handle = await open3(path, "wx");
26587
+ await handle.writeFile(JSON.stringify({ ownerId, createdAt: now2, updatedAt: now2, ttlMs }, null, 2), "utf-8");
26588
+ await handle.close();
26589
+ return true;
26590
+ } catch {
26591
+ try {
26592
+ const raw = await readFile8(path, "utf-8");
26593
+ const lock = JSON.parse(raw);
26594
+ const updatedAt = lock?.updatedAt || lock?.createdAt || 0;
26595
+ const ttl = lock?.ttlMs ?? ttlMs;
26596
+ if (now2 - updatedAt > ttl) {
26597
+ await unlink6(path);
26598
+ return acquireTaskLock(cwd, ownerId, ttlMs, retryDepth + 1);
26599
+ }
26600
+ } catch {
26601
+ if (retryDepth < MAX_TASK_LOCK_RETRIES) {
26602
+ try {
26603
+ await unlink6(path);
26604
+ return acquireTaskLock(cwd, ownerId, ttlMs, retryDepth + 1);
26605
+ } catch {
26606
+ return false;
26607
+ }
26608
+ }
26609
+ }
26610
+ }
26611
+ return false;
26612
+ }
26613
+ async function releaseTaskLock(cwd, ownerId) {
26614
+ const path = taskLockPath(cwd);
26615
+ try {
26616
+ const raw = await readFile8(path, "utf-8");
26617
+ const lock = JSON.parse(raw);
26618
+ if (lock?.ownerId === ownerId) {
26619
+ await unlink6(path);
26620
+ }
26621
+ } catch {}
26622
+ }
26623
+ async function withTaskStoreLock(cwd, fn) {
26624
+ const ownerId = generateId();
26625
+ const locked = await acquireTaskLock(cwd, ownerId);
26626
+ if (!locked) {
26627
+ throw new Error("Task store is locked");
26628
+ }
26629
+ try {
26630
+ const data = await loadTaskStore(cwd);
26631
+ const result = await fn(data);
26632
+ await saveTaskStore(cwd, data);
26633
+ return result;
26634
+ } finally {
26635
+ await releaseTaskLock(cwd, ownerId);
26636
+ }
26637
+ }
26554
26638
  function defaultStoreData() {
26555
26639
  return {
26556
26640
  tasks: [],
@@ -26576,7 +26660,7 @@ async function loadTaskStore(cwd) {
26576
26660
  }
26577
26661
  async function saveTaskStore(cwd, data) {
26578
26662
  await ensureTasksDir(cwd);
26579
- await writeFile6(tasksPath(cwd), JSON.stringify(data, null, 2), "utf-8");
26663
+ await atomicWriteFile(tasksPath(cwd), JSON.stringify(data, null, 2));
26580
26664
  }
26581
26665
  async function getTasks(cwd) {
26582
26666
  const data = await loadTaskStore(cwd);
@@ -26612,109 +26696,107 @@ function calculateNextRunAt(recurrence, fromTime) {
26612
26696
  return;
26613
26697
  }
26614
26698
  async function addTask(cwd, options, priority = "normal", projectId) {
26615
- const data = await loadTaskStore(cwd);
26616
- const now2 = Date.now();
26617
- const opts = typeof options === "string" ? { description: options, priority, projectId } : options;
26618
- let recurrence;
26619
- let nextRunAt;
26620
- let isRecurringTemplate = false;
26621
- if (opts.recurrence) {
26622
- recurrence = {
26623
- kind: opts.recurrence.kind,
26624
- cron: opts.recurrence.cron,
26625
- intervalMs: opts.recurrence.intervalMs,
26626
- timezone: opts.recurrence.timezone,
26627
- maxOccurrences: opts.recurrence.maxOccurrences,
26628
- endAt: opts.recurrence.endAt,
26629
- occurrenceCount: 0
26630
- };
26631
- nextRunAt = calculateNextRunAt(recurrence, now2);
26632
- isRecurringTemplate = true;
26633
- }
26634
- const task = {
26635
- id: generateId(),
26636
- description: opts.description.trim(),
26637
- status: "pending",
26638
- priority: opts.priority ?? "normal",
26639
- createdAt: now2,
26640
- projectId: opts.projectId,
26641
- blockedBy: opts.blockedBy?.length ? opts.blockedBy : undefined,
26642
- blocks: opts.blocks?.length ? opts.blocks : undefined,
26643
- assignee: opts.assignee || undefined,
26644
- recurrence,
26645
- isRecurringTemplate,
26646
- nextRunAt
26647
- };
26648
- if (opts.blocks?.length) {
26649
- for (const blockedId of opts.blocks) {
26650
- const blockedTask = data.tasks.find((t) => t.id === blockedId);
26651
- if (blockedTask) {
26652
- blockedTask.blockedBy = blockedTask.blockedBy || [];
26653
- if (!blockedTask.blockedBy.includes(task.id)) {
26654
- blockedTask.blockedBy.push(task.id);
26699
+ return withTaskStoreLock(cwd, async (data) => {
26700
+ const now2 = Date.now();
26701
+ const opts = typeof options === "string" ? { description: options, priority, projectId } : options;
26702
+ let recurrence;
26703
+ let nextRunAt;
26704
+ let isRecurringTemplate = false;
26705
+ if (opts.recurrence) {
26706
+ recurrence = {
26707
+ kind: opts.recurrence.kind,
26708
+ cron: opts.recurrence.cron,
26709
+ intervalMs: opts.recurrence.intervalMs,
26710
+ timezone: opts.recurrence.timezone,
26711
+ maxOccurrences: opts.recurrence.maxOccurrences,
26712
+ endAt: opts.recurrence.endAt,
26713
+ occurrenceCount: 0
26714
+ };
26715
+ nextRunAt = calculateNextRunAt(recurrence, now2);
26716
+ isRecurringTemplate = true;
26717
+ }
26718
+ const task = {
26719
+ id: generateId(),
26720
+ description: opts.description.trim(),
26721
+ status: "pending",
26722
+ priority: opts.priority ?? "normal",
26723
+ createdAt: now2,
26724
+ projectId: opts.projectId,
26725
+ blockedBy: opts.blockedBy?.length ? opts.blockedBy : undefined,
26726
+ blocks: opts.blocks?.length ? opts.blocks : undefined,
26727
+ assignee: opts.assignee || undefined,
26728
+ recurrence,
26729
+ isRecurringTemplate,
26730
+ nextRunAt
26731
+ };
26732
+ if (opts.blocks?.length) {
26733
+ for (const blockedId of opts.blocks) {
26734
+ const blockedTask = data.tasks.find((t) => t.id === blockedId);
26735
+ if (blockedTask) {
26736
+ blockedTask.blockedBy = blockedTask.blockedBy || [];
26737
+ if (!blockedTask.blockedBy.includes(task.id)) {
26738
+ blockedTask.blockedBy.push(task.id);
26739
+ }
26655
26740
  }
26656
26741
  }
26657
26742
  }
26658
- }
26659
- if (opts.blockedBy?.length) {
26660
- for (const blockingId of opts.blockedBy) {
26661
- const blockingTask = data.tasks.find((t) => t.id === blockingId);
26662
- if (blockingTask) {
26663
- blockingTask.blocks = blockingTask.blocks || [];
26664
- if (!blockingTask.blocks.includes(task.id)) {
26665
- blockingTask.blocks.push(task.id);
26743
+ if (opts.blockedBy?.length) {
26744
+ for (const blockingId of opts.blockedBy) {
26745
+ const blockingTask = data.tasks.find((t) => t.id === blockingId);
26746
+ if (blockingTask) {
26747
+ blockingTask.blocks = blockingTask.blocks || [];
26748
+ if (!blockingTask.blocks.includes(task.id)) {
26749
+ blockingTask.blocks.push(task.id);
26750
+ }
26666
26751
  }
26667
26752
  }
26668
26753
  }
26669
- }
26670
- data.tasks.push(task);
26671
- await saveTaskStore(cwd, data);
26672
- return task;
26754
+ data.tasks.push(task);
26755
+ return task;
26756
+ });
26673
26757
  }
26674
26758
  async function updateTask(cwd, id, updates) {
26675
- const data = await loadTaskStore(cwd);
26676
- const task = data.tasks.find((t) => t.id === id);
26677
- if (!task)
26678
- return null;
26679
- if (updates.status !== undefined)
26680
- task.status = updates.status;
26681
- if (updates.priority !== undefined)
26682
- task.priority = updates.priority;
26683
- if (updates.result !== undefined)
26684
- task.result = updates.result;
26685
- if (updates.error !== undefined)
26686
- task.error = updates.error;
26687
- if (updates.startedAt !== undefined)
26688
- task.startedAt = updates.startedAt;
26689
- if (updates.completedAt !== undefined)
26690
- task.completedAt = updates.completedAt;
26691
- await saveTaskStore(cwd, data);
26692
- return task;
26759
+ return withTaskStoreLock(cwd, async (data) => {
26760
+ const task = data.tasks.find((t) => t.id === id);
26761
+ if (!task)
26762
+ return null;
26763
+ if (updates.status !== undefined)
26764
+ task.status = updates.status;
26765
+ if (updates.priority !== undefined)
26766
+ task.priority = updates.priority;
26767
+ if (updates.result !== undefined)
26768
+ task.result = updates.result;
26769
+ if (updates.error !== undefined)
26770
+ task.error = updates.error;
26771
+ if (updates.startedAt !== undefined)
26772
+ task.startedAt = updates.startedAt;
26773
+ if (updates.completedAt !== undefined)
26774
+ task.completedAt = updates.completedAt;
26775
+ return task;
26776
+ });
26693
26777
  }
26694
26778
  async function deleteTask(cwd, id) {
26695
- const data = await loadTaskStore(cwd);
26696
- const index = data.tasks.findIndex((t) => t.id === id);
26697
- if (index === -1)
26698
- return false;
26699
- data.tasks.splice(index, 1);
26700
- await saveTaskStore(cwd, data);
26701
- return true;
26779
+ return withTaskStoreLock(cwd, async (data) => {
26780
+ const index = data.tasks.findIndex((t) => t.id === id);
26781
+ if (index === -1)
26782
+ return false;
26783
+ data.tasks.splice(index, 1);
26784
+ return true;
26785
+ });
26702
26786
  }
26703
26787
  async function clearPendingTasks(cwd) {
26704
- const data = await loadTaskStore(cwd);
26705
- const before = data.tasks.length;
26706
- data.tasks = data.tasks.filter((t) => t.status !== "pending");
26707
- const cleared = before - data.tasks.length;
26708
- await saveTaskStore(cwd, data);
26709
- return cleared;
26788
+ return withTaskStoreLock(cwd, async (data) => {
26789
+ const before = data.tasks.length;
26790
+ data.tasks = data.tasks.filter((t) => t.status !== "pending");
26791
+ return before - data.tasks.length;
26792
+ });
26710
26793
  }
26711
26794
  async function clearCompletedTasks(cwd) {
26712
- const data = await loadTaskStore(cwd);
26713
- const before = data.tasks.length;
26714
- data.tasks = data.tasks.filter((t) => t.status !== "completed" && t.status !== "failed");
26715
- const cleared = before - data.tasks.length;
26716
- await saveTaskStore(cwd, data);
26717
- return cleared;
26795
+ return withTaskStoreLock(cwd, async (data) => {
26796
+ const before = data.tasks.length;
26797
+ data.tasks = data.tasks.filter((t) => t.status !== "completed" && t.status !== "failed");
26798
+ return before - data.tasks.length;
26799
+ });
26718
26800
  }
26719
26801
  async function getNextTask(cwd) {
26720
26802
  const data = await loadTaskStore(cwd);
@@ -26742,18 +26824,18 @@ async function isPaused(cwd) {
26742
26824
  return data.paused;
26743
26825
  }
26744
26826
  async function setPaused(cwd, paused) {
26745
- const data = await loadTaskStore(cwd);
26746
- data.paused = paused;
26747
- await saveTaskStore(cwd, data);
26827
+ await withTaskStoreLock(cwd, async (data) => {
26828
+ data.paused = paused;
26829
+ });
26748
26830
  }
26749
26831
  async function isAutoRun(cwd) {
26750
26832
  const data = await loadTaskStore(cwd);
26751
26833
  return data.autoRun;
26752
26834
  }
26753
26835
  async function setAutoRun(cwd, autoRun) {
26754
- const data = await loadTaskStore(cwd);
26755
- data.autoRun = autoRun;
26756
- await saveTaskStore(cwd, data);
26836
+ await withTaskStoreLock(cwd, async (data) => {
26837
+ data.autoRun = autoRun;
26838
+ });
26757
26839
  }
26758
26840
  async function startTask(cwd, id) {
26759
26841
  return updateTask(cwd, id, {
@@ -26798,34 +26880,34 @@ async function getDueRecurringTasks(cwd) {
26798
26880
  return data.tasks.filter((t) => t.isRecurringTemplate && t.nextRunAt && t.nextRunAt <= now2);
26799
26881
  }
26800
26882
  async function createRecurringInstance(cwd, templateId) {
26801
- const data = await loadTaskStore(cwd);
26802
- const template = data.tasks.find((t) => t.id === templateId && t.isRecurringTemplate);
26803
- if (!template || !template.recurrence)
26804
- return null;
26805
- const now2 = Date.now();
26806
- const instance = {
26807
- id: generateId(),
26808
- description: template.description,
26809
- status: "pending",
26810
- priority: template.priority,
26811
- createdAt: now2,
26812
- projectId: template.projectId,
26813
- assignee: template.assignee,
26814
- recurrence: {
26815
- ...template.recurrence,
26816
- parentId: template.id
26817
- }
26818
- };
26819
- template.recurrence.occurrenceCount = (template.recurrence.occurrenceCount ?? 0) + 1;
26820
- template.nextRunAt = calculateNextRunAt(template.recurrence, now2);
26821
- if (!template.nextRunAt) {
26822
- template.status = "completed";
26823
- template.completedAt = now2;
26824
- template.result = `Recurring task completed after ${template.recurrence.occurrenceCount} occurrence(s)`;
26825
- }
26826
- data.tasks.push(instance);
26827
- await saveTaskStore(cwd, data);
26828
- return instance;
26883
+ return withTaskStoreLock(cwd, async (data) => {
26884
+ const template = data.tasks.find((t) => t.id === templateId && t.isRecurringTemplate);
26885
+ if (!template || !template.recurrence)
26886
+ return null;
26887
+ const now2 = Date.now();
26888
+ const instance = {
26889
+ id: generateId(),
26890
+ description: template.description,
26891
+ status: "pending",
26892
+ priority: template.priority,
26893
+ createdAt: now2,
26894
+ projectId: template.projectId,
26895
+ assignee: template.assignee,
26896
+ recurrence: {
26897
+ ...template.recurrence,
26898
+ parentId: template.id
26899
+ }
26900
+ };
26901
+ template.recurrence.occurrenceCount = (template.recurrence.occurrenceCount ?? 0) + 1;
26902
+ template.nextRunAt = calculateNextRunAt(template.recurrence, now2);
26903
+ if (!template.nextRunAt) {
26904
+ template.status = "completed";
26905
+ template.completedAt = now2;
26906
+ template.result = `Recurring task completed after ${template.recurrence.occurrenceCount} occurrence(s)`;
26907
+ }
26908
+ data.tasks.push(instance);
26909
+ return instance;
26910
+ });
26829
26911
  }
26830
26912
  async function processDueRecurringTasks(cwd) {
26831
26913
  const dueTasks = await getDueRecurringTasks(cwd);
@@ -26839,22 +26921,24 @@ async function processDueRecurringTasks(cwd) {
26839
26921
  return createdInstances;
26840
26922
  }
26841
26923
  async function cancelRecurringTask(cwd, id) {
26842
- const data = await loadTaskStore(cwd);
26843
- const task = data.tasks.find((t) => t.id === id && t.isRecurringTemplate);
26844
- if (!task)
26845
- return null;
26846
- task.status = "completed";
26847
- task.completedAt = Date.now();
26848
- task.nextRunAt = undefined;
26849
- task.result = "Recurring task cancelled";
26850
- await saveTaskStore(cwd, data);
26851
- return task;
26924
+ return withTaskStoreLock(cwd, async (data) => {
26925
+ const task = data.tasks.find((t) => t.id === id && t.isRecurringTemplate);
26926
+ if (!task)
26927
+ return null;
26928
+ task.status = "completed";
26929
+ task.completedAt = Date.now();
26930
+ task.nextRunAt = undefined;
26931
+ task.result = "Recurring task cancelled";
26932
+ return task;
26933
+ });
26852
26934
  }
26853
- var TASKS_DIR = ".assistants/tasks", TASKS_FILE = "tasks.json";
26935
+ var TASKS_DIR = ".assistants/tasks", TASKS_FILE = "tasks.json", TASKS_LOCK_FILE = "tasks.lock.json", DEFAULT_TASK_LOCK_TTL_MS, MAX_TASK_LOCK_RETRIES = 2;
26854
26936
  var init_store4 = __esm(() => {
26855
26937
  init_src2();
26856
26938
  init_types3();
26857
26939
  init_cron();
26940
+ init_atomic_write();
26941
+ DEFAULT_TASK_LOCK_TTL_MS = 10 * 1000;
26858
26942
  });
26859
26943
 
26860
26944
  // packages/core/src/tasks/index.ts
@@ -67635,12 +67719,14 @@ Maximum ${this.config.maxTasks} tasks.`;
67635
67719
  async executeTaskGraph(plan) {
67636
67720
  const completed = new Set;
67637
67721
  const failed = new Set;
67722
+ const blocked = new Set;
67638
67723
  const running = new Map;
67639
67724
  while (!this.stopped) {
67640
67725
  const readyTasks = plan.tasks.filter((task) => task.status === "pending" && task.dependsOn.every((dep) => completed.has(dep)));
67641
67726
  plan.tasks.forEach((task) => {
67642
- if (task.status === "pending" && task.dependsOn.some((dep) => failed.has(dep))) {
67727
+ if (task.status === "pending" && task.dependsOn.some((dep) => failed.has(dep) || blocked.has(dep))) {
67643
67728
  task.status = "blocked";
67729
+ blocked.add(task.id);
67644
67730
  }
67645
67731
  });
67646
67732
  const pendingCount = plan.tasks.filter((t) => t.status === "pending" || t.status === "running").length;
@@ -67680,9 +67766,14 @@ Maximum ${this.config.maxTasks} tasks.`;
67680
67766
  if (running.size > 0) {
67681
67767
  await Promise.race(Array.from(running.values()));
67682
67768
  } else if (readyTasks.length === 0 && pendingCount > 0) {
67683
- const blockedTasks = plan.tasks.filter((t) => t.status === "pending" || t.status === "blocked");
67769
+ const stillPending = plan.tasks.filter((t) => t.status === "pending");
67770
+ for (const task of stillPending) {
67771
+ task.status = "blocked";
67772
+ blocked.add(task.id);
67773
+ }
67774
+ const blockedTasks = plan.tasks.filter((t) => t.status === "blocked");
67684
67775
  const blockedIds = blockedTasks.map((t) => t.id).join(", ");
67685
- const error = `Deadlock detected: ${blockedTasks.length} task(s) cannot proceed due to failed dependencies (${blockedIds})`;
67776
+ const error = `Deadlock detected: ${blockedTasks.length} task(s) cannot proceed due to failed or blocked dependencies (${blockedIds})`;
67686
67777
  this.state.errors.push(error);
67687
67778
  this.streamText(`
67688
67779
  \u26A0\uFE0F ${error}
@@ -67690,6 +67781,16 @@ Maximum ${this.config.maxTasks} tasks.`;
67690
67781
  break;
67691
67782
  }
67692
67783
  }
67784
+ if (running.size > 0) {
67785
+ await Promise.allSettled(Array.from(running.values()));
67786
+ }
67787
+ if (this.stopped) {
67788
+ for (const task of plan.tasks) {
67789
+ if (task.status === "pending" || task.status === "running") {
67790
+ task.status = "cancelled";
67791
+ }
67792
+ }
67793
+ }
67693
67794
  }
67694
67795
  async executeTask(task) {
67695
67796
  if (this.stopped || this.budgetExceeded || this.timeoutExceeded) {
@@ -67962,6 +68063,15 @@ ${blockedSummaries}
67962
68063
  }
67963
68064
  async spawnAssistant(params) {
67964
68065
  const { role, task, tools, trackInternal } = params;
68066
+ const targetDepth = this.context.depth + 1;
68067
+ if (this.config.maxDepth > 0 && targetDepth > this.config.maxDepth) {
68068
+ return {
68069
+ success: false,
68070
+ error: `Swarm maxDepth (${this.config.maxDepth}) exceeded`,
68071
+ turns: 0,
68072
+ toolCalls: 0
68073
+ };
68074
+ }
67965
68075
  const systemPrompt = ROLE_SYSTEM_PROMPTS[role];
67966
68076
  const fullTask = `${systemPrompt}
67967
68077
 
@@ -68131,7 +68241,10 @@ class TaskGraph {
68131
68241
  return false;
68132
68242
  for (const depId of deps) {
68133
68243
  const depTask = this.tasks.get(depId);
68134
- if (depTask && depTask.status === "failed") {
68244
+ if (!depTask) {
68245
+ return true;
68246
+ }
68247
+ if (depTask.status === "failed" || depTask.status === "blocked" || depTask.status === "cancelled") {
68135
68248
  return true;
68136
68249
  }
68137
68250
  }
@@ -79402,7 +79515,7 @@ ${repoUrl}/issues/new
79402
79515
  context.setProjectContext(projectContext);
79403
79516
  }
79404
79517
  }
79405
- var VERSION = "1.1.21";
79518
+ var VERSION = "1.1.22";
79406
79519
  var init_builtin = __esm(async () => {
79407
79520
  init_src2();
79408
79521
  init_store();
@@ -90402,7 +90515,7 @@ var init_client3 = __esm(() => {
90402
90515
  // packages/core/src/heartbeat/manager.ts
90403
90516
  import { dirname as dirname13 } from "path";
90404
90517
  import { mkdirSync as mkdirSync13 } from "fs";
90405
- import { readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
90518
+ import { readFile as readFile9, writeFile as writeFile6 } from "fs/promises";
90406
90519
 
90407
90520
  class HeartbeatManager {
90408
90521
  config;
@@ -90504,7 +90617,7 @@ class HeartbeatManager {
90504
90617
  }
90505
90618
  async persist(heartbeat) {
90506
90619
  try {
90507
- await writeFile7(this.config.persistPath, JSON.stringify(heartbeat, null, 2));
90620
+ await writeFile6(this.config.persistPath, JSON.stringify(heartbeat, null, 2));
90508
90621
  if (this.config.historyPath) {
90509
90622
  await appendHeartbeatHistory(this.config.historyPath, heartbeat);
90510
90623
  }
@@ -90528,7 +90641,7 @@ var init_manager2 = __esm(async () => {
90528
90641
  // packages/core/src/heartbeat/persistence.ts
90529
90642
  import { dirname as dirname14 } from "path";
90530
90643
  import { mkdirSync as mkdirSync14 } from "fs";
90531
- import { readFile as readFile10, writeFile as writeFile8, unlink as unlink6 } from "fs/promises";
90644
+ import { readFile as readFile10, writeFile as writeFile7, unlink as unlink7 } from "fs/promises";
90532
90645
 
90533
90646
  class StatePersistence {
90534
90647
  path;
@@ -90538,7 +90651,7 @@ class StatePersistence {
90538
90651
  }
90539
90652
  async save(state) {
90540
90653
  try {
90541
- await writeFile8(this.path, JSON.stringify(state, null, 2));
90654
+ await writeFile7(this.path, JSON.stringify(state, null, 2));
90542
90655
  } catch {}
90543
90656
  }
90544
90657
  async load() {
@@ -90551,7 +90664,7 @@ class StatePersistence {
90551
90664
  }
90552
90665
  async clear() {
90553
90666
  try {
90554
- await unlink6(this.path);
90667
+ await unlink7(this.path);
90555
90668
  } catch {}
90556
90669
  }
90557
90670
  }
@@ -90792,7 +90905,7 @@ var init_watchdog = __esm(async () => {
90792
90905
  // packages/core/src/heartbeat/install-skills.ts
90793
90906
  import { join as join30 } from "path";
90794
90907
  async function writeSkillIfMissing(dir, skillName, content) {
90795
- const { mkdir: mkdir10, writeFile: writeFile9, access } = await import("fs/promises");
90908
+ const { mkdir: mkdir10, writeFile: writeFile8, access } = await import("fs/promises");
90796
90909
  const skillDir = join30(dir, `skill-${skillName}`);
90797
90910
  const skillFile = join30(skillDir, "SKILL.md");
90798
90911
  try {
@@ -90800,7 +90913,7 @@ async function writeSkillIfMissing(dir, skillName, content) {
90800
90913
  return false;
90801
90914
  } catch {}
90802
90915
  await mkdir10(skillDir, { recursive: true });
90803
- await writeFile9(skillFile, content, "utf-8");
90916
+ await writeFile8(skillFile, content, "utf-8");
90804
90917
  return true;
90805
90918
  }
90806
90919
  async function installHeartbeatSkills() {
@@ -91070,7 +91183,7 @@ var init_manager3 = __esm(() => {
91070
91183
  // packages/core/src/energy/storage.ts
91071
91184
  import { dirname as dirname15 } from "path";
91072
91185
  import { mkdirSync as mkdirSync15 } from "fs";
91073
- import { readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
91186
+ import { readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
91074
91187
 
91075
91188
  class EnergyStorage {
91076
91189
  path;
@@ -91080,7 +91193,7 @@ class EnergyStorage {
91080
91193
  }
91081
91194
  async save(state) {
91082
91195
  try {
91083
- await writeFile9(this.path, JSON.stringify(state, null, 2));
91196
+ await writeFile8(this.path, JSON.stringify(state, null, 2));
91084
91197
  } catch {}
91085
91198
  }
91086
91199
  async load() {
@@ -91435,7 +91548,7 @@ var init_tts = __esm(() => {
91435
91548
  import { spawn } from "child_process";
91436
91549
  import { tmpdir as tmpdir3 } from "os";
91437
91550
  import { join as join33 } from "path";
91438
- import { unlink as unlink7, writeFileSync as writeFileSync13, appendFileSync as appendFileSync3 } from "fs";
91551
+ import { unlink as unlink8, writeFileSync as writeFileSync13, appendFileSync as appendFileSync3 } from "fs";
91439
91552
 
91440
91553
  class AudioPlayer {
91441
91554
  currentProcess = null;
@@ -91454,7 +91567,7 @@ class AudioPlayer {
91454
91567
  this.currentProcess.on("close", () => {
91455
91568
  this.playing = false;
91456
91569
  this.currentProcess = null;
91457
- unlink7(tempFile, () => {});
91570
+ unlink8(tempFile, () => {});
91458
91571
  resolve5();
91459
91572
  });
91460
91573
  this.currentProcess.on("error", (error3) => {
@@ -91463,7 +91576,7 @@ class AudioPlayer {
91463
91576
  this.currentProcess.kill();
91464
91577
  this.currentProcess = null;
91465
91578
  }
91466
- unlink7(tempFile, () => {});
91579
+ unlink8(tempFile, () => {});
91467
91580
  reject(error3);
91468
91581
  });
91469
91582
  });
@@ -91477,7 +91590,7 @@ class AudioPlayer {
91477
91590
  }
91478
91591
  const player = this.resolvePlayer(format);
91479
91592
  if (!player) {
91480
- unlink7(tempFile, () => {});
91593
+ unlink8(tempFile, () => {});
91481
91594
  throw new Error("No supported audio player found.");
91482
91595
  }
91483
91596
  return new Promise((resolve5, reject) => {
@@ -91486,7 +91599,7 @@ class AudioPlayer {
91486
91599
  this.currentProcess.on("close", () => {
91487
91600
  this.playing = false;
91488
91601
  this.currentProcess = null;
91489
- unlink7(tempFile, () => {});
91602
+ unlink8(tempFile, () => {});
91490
91603
  resolve5();
91491
91604
  });
91492
91605
  this.currentProcess.on("error", (error3) => {
@@ -91495,7 +91608,7 @@ class AudioPlayer {
91495
91608
  this.currentProcess.kill();
91496
91609
  this.currentProcess = null;
91497
91610
  }
91498
- unlink7(tempFile, () => {});
91611
+ unlink8(tempFile, () => {});
91499
91612
  reject(error3);
91500
91613
  });
91501
91614
  });
@@ -91540,7 +91653,7 @@ var init_player = __esm(() => {
91540
91653
  import { spawn as spawn2 } from "child_process";
91541
91654
  import { tmpdir as tmpdir4 } from "os";
91542
91655
  import { join as join34 } from "path";
91543
- import { readFileSync as readFileSync16, unlink as unlink8 } from "fs";
91656
+ import { readFileSync as readFileSync16, unlink as unlink9 } from "fs";
91544
91657
 
91545
91658
  class AudioRecorder {
91546
91659
  currentProcess = null;
@@ -91576,7 +91689,7 @@ class AudioRecorder {
91576
91689
  });
91577
91690
  });
91578
91691
  const data = readFileSync16(output);
91579
- unlink8(output, () => {});
91692
+ unlink9(output, () => {});
91580
91693
  this.currentOutputPath = null;
91581
91694
  return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
91582
91695
  }
@@ -91763,7 +91876,7 @@ var init_manager4 = __esm(() => {
91763
91876
  });
91764
91877
  // packages/core/src/identity/identity-manager.ts
91765
91878
  import { existsSync as existsSync23 } from "fs";
91766
- import { mkdir as mkdir10, readFile as readFile12, writeFile as writeFile10, rm as rm2 } from "fs/promises";
91879
+ import { mkdir as mkdir10, readFile as readFile12, writeFile as writeFile9, rm as rm2 } from "fs/promises";
91767
91880
  import { join as join35 } from "path";
91768
91881
  function isValidId2(id) {
91769
91882
  return typeof id === "string" && id.length > 0 && SAFE_ID_PATTERN6.test(id);
@@ -91941,12 +92054,12 @@ class IdentityManager {
91941
92054
  if (!index.identities.includes(id)) {
91942
92055
  index.identities.push(id);
91943
92056
  }
91944
- await writeFile10(this.indexPath, JSON.stringify(index, null, 2));
92057
+ await writeFile9(this.indexPath, JSON.stringify(index, null, 2));
91945
92058
  }
91946
92059
  async removeFromIndex(id) {
91947
92060
  const index = await this.readIndex();
91948
92061
  index.identities = index.identities.filter((identityId) => identityId !== id);
91949
- await writeFile10(this.indexPath, JSON.stringify(index, null, 2));
92062
+ await writeFile9(this.indexPath, JSON.stringify(index, null, 2));
91950
92063
  }
91951
92064
  async readIdentity(id) {
91952
92065
  const path3 = this.identityPath(id);
@@ -91961,7 +92074,7 @@ class IdentityManager {
91961
92074
  }
91962
92075
  async persistIdentity(identity) {
91963
92076
  await mkdir10(this.identitiesRoot, { recursive: true });
91964
- await writeFile10(this.identityPath(identity.id), JSON.stringify(identity, null, 2));
92077
+ await writeFile9(this.identityPath(identity.id), JSON.stringify(identity, null, 2));
91965
92078
  }
91966
92079
  async readActive() {
91967
92080
  if (!existsSync23(this.activePath))
@@ -91980,7 +92093,7 @@ class IdentityManager {
91980
92093
  }
91981
92094
  async setActive(id) {
91982
92095
  this.activeId = id;
91983
- await writeFile10(this.activePath, JSON.stringify({ id }, null, 2));
92096
+ await writeFile9(this.activePath, JSON.stringify({ id }, null, 2));
91984
92097
  }
91985
92098
  async loadAssistant() {
91986
92099
  if (!existsSync23(this.assistantConfigPath()))
@@ -92020,7 +92133,7 @@ var init_identity_manager = __esm(() => {
92020
92133
 
92021
92134
  // packages/core/src/identity/assistant-manager.ts
92022
92135
  import { existsSync as existsSync24 } from "fs";
92023
- import { mkdir as mkdir11, readFile as readFile13, writeFile as writeFile11, rm as rm3 } from "fs/promises";
92136
+ import { mkdir as mkdir11, readFile as readFile13, writeFile as writeFile10, rm as rm3 } from "fs/promises";
92024
92137
  import { join as join36 } from "path";
92025
92138
  function isValidId3(id) {
92026
92139
  return typeof id === "string" && id.length > 0 && SAFE_ID_PATTERN7.test(id);
@@ -92152,12 +92265,12 @@ class AssistantManager {
92152
92265
  if (!index.assistants.includes(id)) {
92153
92266
  index.assistants.push(id);
92154
92267
  }
92155
- await writeFile11(this.indexPath, JSON.stringify(index, null, 2));
92268
+ await writeFile10(this.indexPath, JSON.stringify(index, null, 2));
92156
92269
  }
92157
92270
  async removeFromIndex(id) {
92158
92271
  const index = await this.readIndex();
92159
92272
  index.assistants = index.assistants.filter((assistantId) => assistantId !== id);
92160
- await writeFile11(this.indexPath, JSON.stringify(index, null, 2));
92273
+ await writeFile10(this.indexPath, JSON.stringify(index, null, 2));
92161
92274
  }
92162
92275
  async readAssistant(id) {
92163
92276
  const configPath = this.assistantConfigPath(id);
@@ -92174,7 +92287,7 @@ class AssistantManager {
92174
92287
  validateId2(assistant.id, "assistantId");
92175
92288
  const dir = join36(this.assistantsRoot, assistant.id);
92176
92289
  await mkdir11(dir, { recursive: true });
92177
- await writeFile11(this.assistantConfigPath(assistant.id), JSON.stringify(assistant, null, 2));
92290
+ await writeFile10(this.assistantConfigPath(assistant.id), JSON.stringify(assistant, null, 2));
92178
92291
  }
92179
92292
  async readActive() {
92180
92293
  if (!existsSync24(this.activePath))
@@ -92193,7 +92306,7 @@ class AssistantManager {
92193
92306
  }
92194
92307
  async setActive(id) {
92195
92308
  this.activeId = id;
92196
- await writeFile11(this.activePath, JSON.stringify({ id }, null, 2));
92309
+ await writeFile10(this.activePath, JSON.stringify({ id }, null, 2));
92197
92310
  }
92198
92311
  }
92199
92312
  var SAFE_ID_PATTERN7, DEFAULT_SETTINGS;
@@ -117043,14 +117156,14 @@ var init_validateTokenKey = __esm(() => {
117043
117156
 
117044
117157
  // node_modules/.bun/@aws-sdk+token-providers@3.985.0/node_modules/@aws-sdk/token-providers/dist-es/writeSSOTokenToFile.js
117045
117158
  import { promises as fsPromises } from "fs";
117046
- var import_shared_ini_file_loader, writeFile12, writeSSOTokenToFile = (id, ssoToken) => {
117159
+ var import_shared_ini_file_loader, writeFile11, writeSSOTokenToFile = (id, ssoToken) => {
117047
117160
  const tokenFilepath = import_shared_ini_file_loader.getSSOTokenFilepath(id);
117048
117161
  const tokenString = JSON.stringify(ssoToken, null, 2);
117049
- return writeFile12(tokenFilepath, tokenString);
117162
+ return writeFile11(tokenFilepath, tokenString);
117050
117163
  };
117051
117164
  var init_writeSSOTokenToFile = __esm(() => {
117052
117165
  import_shared_ini_file_loader = __toESM(require_dist_cjs35(), 1);
117053
- ({ writeFile: writeFile12 } = fsPromises);
117166
+ ({ writeFile: writeFile11 } = fsPromises);
117054
117167
  });
117055
117168
 
117056
117169
  // node_modules/.bun/@aws-sdk+token-providers@3.985.0/node_modules/@aws-sdk/token-providers/dist-es/fromSso.js
@@ -124506,7 +124619,7 @@ var init_s3_client = __esm(() => {
124506
124619
 
124507
124620
  // packages/core/src/inbox/storage/local-cache.ts
124508
124621
  import { join as join38, basename as basename5 } from "path";
124509
- import { mkdir as mkdir12, readFile as readFile15, writeFile as writeFile13, rm as rm4, readdir as readdir4, stat as stat3 } from "fs/promises";
124622
+ import { mkdir as mkdir12, readFile as readFile15, writeFile as writeFile12, rm as rm4, readdir as readdir4, stat as stat3 } from "fs/promises";
124510
124623
  import { createHash as createHash5 } from "crypto";
124511
124624
  function isValidAssistantId(id) {
124512
124625
  return typeof id === "string" && id.length > 0 && STRICT_ID_PATTERN.test(id);
@@ -124565,7 +124678,7 @@ class LocalInboxCache {
124565
124678
  return;
124566
124679
  await this.ensureDirectories();
124567
124680
  const indexPath = join38(this.cacheDir, "index.json");
124568
- await writeFile13(indexPath, JSON.stringify(this.index, null, 2));
124681
+ await writeFile12(indexPath, JSON.stringify(this.index, null, 2));
124569
124682
  }
124570
124683
  async saveEmail(email) {
124571
124684
  const filename = emailIdToFilename(email.id);
@@ -124574,7 +124687,7 @@ class LocalInboxCache {
124574
124687
  }
124575
124688
  await this.ensureDirectories();
124576
124689
  const emailPath = join38(this.cacheDir, "emails", `${filename}.json`);
124577
- await writeFile13(emailPath, JSON.stringify(email, null, 2));
124690
+ await writeFile12(emailPath, JSON.stringify(email, null, 2));
124578
124691
  const index = await this.loadIndex();
124579
124692
  const existingIdx = index.emails.findIndex((e3) => e3.id === email.id);
124580
124693
  const entry = {
@@ -124671,7 +124784,7 @@ class LocalInboxCache {
124671
124784
  const attachmentDir = join38(this.cacheDir, "attachments", emailFilename);
124672
124785
  await mkdir12(attachmentDir, { recursive: true });
124673
124786
  const attachmentPath = join38(attachmentDir, safeFilename);
124674
- await writeFile13(attachmentPath, content);
124787
+ await writeFile12(attachmentPath, content);
124675
124788
  return attachmentPath;
124676
124789
  }
124677
124790
  async getAttachmentPath(emailId, filename) {
@@ -170416,9 +170529,8 @@ class LocalMessagesStorage {
170416
170529
  }
170417
170530
  }
170418
170531
  async saveIndex(assistantId, index) {
170419
- const runtime = getRuntime();
170420
170532
  await this.ensureDirectories(assistantId);
170421
- await runtime.write(this.getIndexPath(assistantId), JSON.stringify(index, null, 2));
170533
+ await atomicWriteFile(this.getIndexPath(assistantId), JSON.stringify(index, null, 2));
170422
170534
  }
170423
170535
  async rebuildIndexStats(assistantId, index) {
170424
170536
  const threadIds = new Set;
@@ -170437,10 +170549,9 @@ class LocalMessagesStorage {
170437
170549
  index.lastCheck = new Date().toISOString();
170438
170550
  }
170439
170551
  async saveMessage(message) {
170440
- const runtime = getRuntime();
170441
170552
  await this.ensureDirectories(message.toAssistantId);
170442
170553
  const messagePath = this.getMessagePath(message.toAssistantId, message.id);
170443
- await runtime.write(messagePath, JSON.stringify(message, null, 2));
170554
+ await atomicWriteFile(messagePath, JSON.stringify(message, null, 2));
170444
170555
  const index = await this.loadIndex(message.toAssistantId);
170445
170556
  const listItem = {
170446
170557
  id: message.id,
@@ -170457,10 +170568,9 @@ class LocalMessagesStorage {
170457
170568
  };
170458
170569
  index.messages.unshift(listItem);
170459
170570
  if (message.parentId) {
170460
- for (const msg of index.messages) {
170461
- if (msg.threadId === message.threadId && msg.id !== message.id) {
170462
- msg.replyCount = (msg.replyCount || 0) + 1;
170463
- }
170571
+ const parent = index.messages.find((m5) => m5.id === message.parentId);
170572
+ if (parent) {
170573
+ parent.replyCount = (parent.replyCount || 0) + 1;
170464
170574
  }
170465
170575
  }
170466
170576
  await this.rebuildIndexStats(message.toAssistantId, index);
@@ -170480,17 +170590,17 @@ class LocalMessagesStorage {
170480
170590
  }
170481
170591
  }
170482
170592
  async updateMessageStatus(assistantId, messageId, status, timestamp) {
170483
- const runtime = getRuntime();
170484
170593
  const message = await this.loadMessage(assistantId, messageId);
170485
170594
  if (!message)
170486
170595
  return;
170596
+ const previousStatus = message.status;
170487
170597
  message.status = status;
170488
170598
  if (status === "read" && timestamp) {
170489
170599
  message.readAt = timestamp;
170490
170600
  } else if (status === "injected" && timestamp) {
170491
170601
  message.injectedAt = timestamp;
170492
170602
  }
170493
- await runtime.write(this.getMessagePath(assistantId, messageId), JSON.stringify(message, null, 2));
170603
+ await atomicWriteFile(this.getMessagePath(assistantId, messageId), JSON.stringify(message, null, 2));
170494
170604
  const index = await this.loadIndex(assistantId);
170495
170605
  const indexItem = index.messages.find((m5) => m5.id === messageId);
170496
170606
  if (indexItem) {
@@ -170498,22 +170608,32 @@ class LocalMessagesStorage {
170498
170608
  }
170499
170609
  await this.rebuildIndexStats(assistantId, index);
170500
170610
  await this.saveIndex(assistantId, index);
170611
+ if (previousStatus !== status && message.threadId) {
170612
+ await this.updateThreadFromIndex(assistantId, message.threadId, index);
170613
+ }
170501
170614
  }
170502
170615
  async deleteMessage(assistantId, messageId) {
170503
- const runtime = getRuntime();
170504
170616
  const messagePath = this.getMessagePath(assistantId, messageId);
170505
170617
  try {
170506
- const file = runtime.file(messagePath);
170507
- if (!await file.exists()) {
170618
+ const message = await this.loadMessage(assistantId, messageId);
170619
+ if (!message)
170508
170620
  return false;
170509
- }
170510
170621
  await rm5(messagePath);
170511
170622
  const index = await this.loadIndex(assistantId);
170623
+ if (message.parentId) {
170624
+ const parent = index.messages.find((m5) => m5.id === message.parentId);
170625
+ if (parent && parent.replyCount) {
170626
+ parent.replyCount = Math.max(0, parent.replyCount - 1);
170627
+ }
170628
+ }
170512
170629
  const msgIndex = index.messages.findIndex((m5) => m5.id === messageId);
170513
170630
  if (msgIndex >= 0) {
170514
170631
  index.messages.splice(msgIndex, 1);
170515
170632
  await this.rebuildIndexStats(assistantId, index);
170516
170633
  await this.saveIndex(assistantId, index);
170634
+ if (message.threadId) {
170635
+ await this.updateThreadFromIndex(assistantId, message.threadId, index);
170636
+ }
170517
170637
  }
170518
170638
  return true;
170519
170639
  } catch {
@@ -170538,11 +170658,10 @@ class LocalMessagesStorage {
170538
170658
  return messages;
170539
170659
  }
170540
170660
  async updateThread(assistantId, message) {
170541
- const runtime = getRuntime();
170542
170661
  const threadPath = this.getThreadPath(assistantId, message.threadId);
170543
170662
  let thread;
170544
170663
  try {
170545
- const file = runtime.file(threadPath);
170664
+ const file = getRuntime().file(threadPath);
170546
170665
  if (await file.exists()) {
170547
170666
  thread = await file.json();
170548
170667
  } else {
@@ -170601,7 +170720,44 @@ class LocalMessagesStorage {
170601
170720
  replyCount: 0
170602
170721
  };
170603
170722
  thread.updatedAt = message.createdAt;
170604
- await runtime.write(threadPath, JSON.stringify(thread, null, 2));
170723
+ await atomicWriteFile(threadPath, JSON.stringify(thread, null, 2));
170724
+ }
170725
+ async updateThreadFromIndex(assistantId, threadId, index) {
170726
+ const threadPath = this.getThreadPath(assistantId, threadId);
170727
+ let thread = null;
170728
+ try {
170729
+ const file = getRuntime().file(threadPath);
170730
+ if (await file.exists()) {
170731
+ thread = await file.json();
170732
+ }
170733
+ } catch {
170734
+ thread = null;
170735
+ }
170736
+ const threadMessages = index.messages.filter((m5) => m5.threadId === threadId);
170737
+ if (threadMessages.length === 0) {
170738
+ try {
170739
+ await rm5(threadPath);
170740
+ } catch {}
170741
+ return;
170742
+ }
170743
+ if (!thread) {
170744
+ thread = {
170745
+ threadId,
170746
+ subject: threadMessages[0].subject,
170747
+ participants: [],
170748
+ messageCount: 0,
170749
+ unreadCount: 0,
170750
+ lastMessage: threadMessages[0],
170751
+ createdAt: threadMessages[threadMessages.length - 1].createdAt,
170752
+ updatedAt: threadMessages[0].createdAt
170753
+ };
170754
+ }
170755
+ thread.messageCount = threadMessages.length;
170756
+ thread.unreadCount = threadMessages.filter((m5) => m5.status === "unread" || m5.status === "injected").length;
170757
+ thread.lastMessage = threadMessages[0];
170758
+ thread.subject = thread.lastMessage.subject ?? thread.subject;
170759
+ thread.updatedAt = thread.lastMessage.createdAt;
170760
+ await atomicWriteFile(threadPath, JSON.stringify(thread, null, 2));
170605
170761
  }
170606
170762
  async loadThread(assistantId, threadId) {
170607
170763
  try {
@@ -170680,9 +170836,11 @@ class LocalMessagesStorage {
170680
170836
  return toDelete.length;
170681
170837
  }
170682
170838
  }
170683
- var SAFE_ID_PATTERN8;
170839
+ var INDEX_LOCK_TTL_MS, SAFE_ID_PATTERN8;
170684
170840
  var init_local_storage = __esm(async () => {
170841
+ init_atomic_write();
170685
170842
  await init_runtime();
170843
+ INDEX_LOCK_TTL_MS = 10 * 1000;
170686
170844
  SAFE_ID_PATTERN8 = /^[a-zA-Z0-9_-]+$/;
170687
170845
  });
170688
170846
 
@@ -174027,7 +174185,7 @@ var init_channels = __esm(async () => {
174027
174185
 
174028
174186
  // packages/core/src/people/store.ts
174029
174187
  import { existsSync as existsSync28 } from "fs";
174030
- import { mkdir as mkdir15, readFile as readFile16, writeFile as writeFile14, rm as rm7 } from "fs/promises";
174188
+ import { mkdir as mkdir15, readFile as readFile16, writeFile as writeFile13, rm as rm7 } from "fs/promises";
174031
174189
  import { join as join45 } from "path";
174032
174190
  function isValidId4(id) {
174033
174191
  return typeof id === "string" && id.length > 0 && SAFE_ID_PATTERN10.test(id);
@@ -174152,7 +174310,7 @@ class PeopleStore {
174152
174310
  }
174153
174311
  this.activeId = id;
174154
174312
  try {
174155
- await writeFile14(this.activePath, JSON.stringify({ personId: id }, null, 2));
174313
+ await writeFile13(this.activePath, JSON.stringify({ personId: id }, null, 2));
174156
174314
  } catch {}
174157
174315
  }
174158
174316
  async readIndex() {
@@ -174165,7 +174323,7 @@ class PeopleStore {
174165
174323
  return { people: [] };
174166
174324
  }
174167
174325
  async writeIndex(index) {
174168
- await writeFile14(this.indexPath, JSON.stringify(index, null, 2));
174326
+ await writeFile13(this.indexPath, JSON.stringify(index, null, 2));
174169
174327
  }
174170
174328
  async appendToIndex(id) {
174171
174329
  const index = await this.readIndex();
@@ -174203,7 +174361,7 @@ class PeopleStore {
174203
174361
  async persist(person) {
174204
174362
  const dir = join45(this.basePath, person.id);
174205
174363
  await mkdir15(dir, { recursive: true });
174206
- await writeFile14(this.personConfigPath(person.id), JSON.stringify(person, null, 2));
174364
+ await writeFile13(this.personConfigPath(person.id), JSON.stringify(person, null, 2));
174207
174365
  }
174208
174366
  }
174209
174367
  var SAFE_ID_PATTERN10;
@@ -181626,6 +181784,14 @@ class SubassistantManager {
181626
181784
  subassistantId
181627
181785
  };
181628
181786
  }
181787
+ const info = {
181788
+ id: subassistantId,
181789
+ task: config.task,
181790
+ status: "running",
181791
+ startedAt: Date.now(),
181792
+ depth: config.depth
181793
+ };
181794
+ this.activeSubassistants.set(subassistantId, info);
181629
181795
  if (this.context.fireHook) {
181630
181796
  const hookInput = {
181631
181797
  session_id: config.parentSessionId,
@@ -181640,6 +181806,7 @@ class SubassistantManager {
181640
181806
  };
181641
181807
  const hookResult = await this.context.fireHook(hookInput);
181642
181808
  if (hookResult && hookResult.continue === false) {
181809
+ this.activeSubassistants.delete(subassistantId);
181643
181810
  return {
181644
181811
  success: false,
181645
181812
  error: hookResult.stopReason || "Blocked by SubassistantStart hook",
@@ -181663,14 +181830,7 @@ ${hookResult.additionalContext}` : hookResult.additionalContext
181663
181830
  };
181664
181831
  }
181665
181832
  }
181666
- const info = {
181667
- id: subassistantId,
181668
- task: config.task,
181669
- status: "running",
181670
- startedAt: Date.now(),
181671
- depth: config.depth
181672
- };
181673
- this.activeSubassistants.set(subassistantId, info);
181833
+ info.task = config.task;
181674
181834
  try {
181675
181835
  const tools = this.filterToolsForSubassistant(config.tools, config.depth);
181676
181836
  const maxTurns = Math.min(config.maxTurns ?? this.config.maxTurns, MAX_ALLOWED_TURNS);
@@ -184988,7 +185148,7 @@ ${effects.message}
184988
185148
  sessionId: this.sessionId,
184989
185149
  updatedAt: Date.now()
184990
185150
  };
184991
- });
185151
+ }, { ownerId: this.sessionId });
184992
185152
  if (!claimed || claimed.sessionId && claimed.sessionId !== this.sessionId) {
184993
185153
  await releaseScheduleLock(this.cwd, schedule.id, this.sessionId);
184994
185154
  continue;
@@ -185050,7 +185210,7 @@ ${effects.message}
185050
185210
  updated.nextRunAt = computeNextRun2(updated, now2);
185051
185211
  }
185052
185212
  return updated;
185053
- });
185213
+ }, { ownerId: this.sessionId });
185054
185214
  } finally {
185055
185215
  clearInterval(leaseTimer);
185056
185216
  await releaseScheduleLock(this.cwd, schedule.id, this.sessionId);
@@ -186368,12 +186528,12 @@ async function loadHistory() {
186368
186528
  }
186369
186529
  async function saveHistory(history) {
186370
186530
  try {
186371
- const { writeFile: writeFile15, mkdir: mkdir16 } = await import("fs/promises");
186531
+ const { writeFile: writeFile14, mkdir: mkdir16 } = await import("fs/promises");
186372
186532
  const { dirname: dirname25 } = await import("path");
186373
186533
  const historyPath = getHistoryPath();
186374
186534
  await mkdir16(dirname25(historyPath), { recursive: true });
186375
186535
  const trimmedHistory = history.slice(-MAX_HISTORY_SIZE);
186376
- await writeFile15(historyPath, trimmedHistory.join(`
186536
+ await writeFile14(historyPath, trimmedHistory.join(`
186377
186537
  `) + `
186378
186538
  `, "utf-8");
186379
186539
  } catch (error3) {
@@ -186384,7 +186544,7 @@ async function appendToHistory(command) {
186384
186544
  if (!command.trim())
186385
186545
  return;
186386
186546
  try {
186387
- const { appendFile: appendFile3, mkdir: mkdir16, stat: stat5, readFile: readFile17, writeFile: writeFile15 } = await import("fs/promises");
186547
+ const { appendFile: appendFile3, mkdir: mkdir16, stat: stat5, readFile: readFile17, writeFile: writeFile14 } = await import("fs/promises");
186388
186548
  const { dirname: dirname25 } = await import("path");
186389
186549
  const historyPath = getHistoryPath();
186390
186550
  await mkdir16(dirname25(historyPath), { recursive: true });
@@ -186396,7 +186556,7 @@ async function appendToHistory(command) {
186396
186556
  `).filter((line) => line.trim().length > 0);
186397
186557
  const trimmedLines = lines.slice(-MAX_HISTORY_SIZE + 1);
186398
186558
  trimmedLines.push(command);
186399
- await writeFile15(historyPath, trimmedLines.join(`
186559
+ await writeFile14(historyPath, trimmedLines.join(`
186400
186560
  `) + `
186401
186561
  `, "utf-8");
186402
186562
  return;
@@ -204344,18 +204504,18 @@ var proto = Object.defineProperties(() => {}, {
204344
204504
  }
204345
204505
  }
204346
204506
  });
204347
- var createStyler = (open3, close, parent) => {
204507
+ var createStyler = (open4, close, parent) => {
204348
204508
  let openAll;
204349
204509
  let closeAll;
204350
204510
  if (parent === undefined) {
204351
- openAll = open3;
204511
+ openAll = open4;
204352
204512
  closeAll = close;
204353
204513
  } else {
204354
- openAll = parent.openAll + open3;
204514
+ openAll = parent.openAll + open4;
204355
204515
  closeAll = close + parent.closeAll;
204356
204516
  }
204357
204517
  return {
204358
- open: open3,
204518
+ open: open4,
204359
204519
  close,
204360
204520
  openAll,
204361
204521
  closeAll,
@@ -206437,6 +206597,8 @@ function useSafeInput(handler, options = {}) {
206437
206597
  return;
206438
206598
  const handleData = (data) => {
206439
206599
  const keypress = parseKeypress2(data);
206600
+ const isReturn = keypress.name === "return" || keypress.sequence === "\x1B\r" || keypress.sequence === `\x1B
206601
+ `;
206440
206602
  const key = {
206441
206603
  upArrow: keypress.name === "up",
206442
206604
  downArrow: keypress.name === "down",
@@ -206446,7 +206608,7 @@ function useSafeInput(handler, options = {}) {
206446
206608
  pageUp: keypress.name === "pageup",
206447
206609
  home: keypress.name === "home",
206448
206610
  end: keypress.name === "end",
206449
- return: keypress.name === "return",
206611
+ return: isReturn,
206450
206612
  escape: keypress.name === "escape",
206451
206613
  ctrl: keypress.ctrl,
206452
206614
  shift: keypress.shift,
@@ -206459,9 +206621,6 @@ function useSafeInput(handler, options = {}) {
206459
206621
  if (NON_ALPHA_KEYS.includes(keypress.name)) {
206460
206622
  input = "";
206461
206623
  }
206462
- if (input.startsWith("\x1B")) {
206463
- input = input.slice(1);
206464
- }
206465
206624
  if (input.length === 1 && typeof input[0] === "string" && /[A-Z]/.test(input[0])) {
206466
206625
  key.shift = true;
206467
206626
  }
@@ -206478,6 +206637,25 @@ function useSafeInput(handler, options = {}) {
206478
206637
 
206479
206638
  // packages/terminal/src/components/Input.tsx
206480
206639
  var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
206640
+ var ASSISTANT_COLORS = [
206641
+ "#6B4C9A",
206642
+ "#2E86AB",
206643
+ "#A23B72",
206644
+ "#1B813E",
206645
+ "#C1440E",
206646
+ "#5B5EA6",
206647
+ "#9B2335",
206648
+ "#2D6A4F",
206649
+ "#7C4DFF",
206650
+ "#D4621B"
206651
+ ];
206652
+ function getAssistantColor(name2) {
206653
+ let hash = 0;
206654
+ for (let i5 = 0;i5 < name2.length; i5++) {
206655
+ hash = (hash << 5) - hash + name2.charCodeAt(i5) | 0;
206656
+ }
206657
+ return ASSISTANT_COLORS[Math.abs(hash) % ASSISTANT_COLORS.length];
206658
+ }
206481
206659
  var COMMANDS = [
206482
206660
  { name: "/help", description: "show available commands" },
206483
206661
  { name: "/clear", description: "clear the conversation" },
@@ -206994,7 +207172,7 @@ var Input = import_react28.default.forwardRef(function Input2({
206994
207172
  children: " "
206995
207173
  }, undefined, false, undefined, this),
206996
207174
  /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text3, {
206997
- backgroundColor: "#4a8ba4",
207175
+ backgroundColor: getAssistantColor(assistantName),
206998
207176
  color: "white",
206999
207177
  bold: true,
207000
207178
  children: [
@@ -219258,6 +219436,26 @@ function WebhooksPanel({ manager, onClose }) {
219258
219436
  // packages/terminal/src/components/ChannelsPanel.tsx
219259
219437
  var import_react46 = __toESM(require_react(), 1);
219260
219438
  var jsx_dev_runtime23 = __toESM(require_jsx_dev_runtime(), 1);
219439
+ var SLACK_COLOR = "#4A154B";
219440
+ var ASSISTANT_COLORS2 = [
219441
+ "#6B4C9A",
219442
+ "#2E86AB",
219443
+ "#A23B72",
219444
+ "#1B813E",
219445
+ "#C1440E",
219446
+ "#5B5EA6",
219447
+ "#9B2335",
219448
+ "#2D6A4F",
219449
+ "#7C4DFF",
219450
+ "#D4621B"
219451
+ ];
219452
+ function getAssistantColor2(name2) {
219453
+ let hash = 0;
219454
+ for (let i5 = 0;i5 < name2.length; i5++) {
219455
+ hash = (hash << 5) - hash + name2.charCodeAt(i5) | 0;
219456
+ }
219457
+ return ASSISTANT_COLORS2[Math.abs(hash) % ASSISTANT_COLORS2.length];
219458
+ }
219261
219459
  function formatRelativeTime5(isoDate) {
219262
219460
  if (!isoDate)
219263
219461
  return "never";
@@ -219469,9 +219667,10 @@ function ChannelsPanel({ manager, onClose, activePersonId, activePersonName, onP
219469
219667
  marginBottom: 1,
219470
219668
  children: [
219471
219669
  /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
219670
+ backgroundColor: SLACK_COLOR,
219671
+ color: "white",
219472
219672
  bold: true,
219473
- color: "blue",
219474
- children: "Channels"
219673
+ children: " Channels "
219475
219674
  }, undefined, false, undefined, this),
219476
219675
  /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
219477
219676
  color: "gray",
@@ -219565,11 +219764,13 @@ function ChannelsPanel({ manager, onClose, activePersonId, activePersonName, onP
219565
219764
  marginBottom: 1,
219566
219765
  children: [
219567
219766
  /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
219767
+ backgroundColor: SLACK_COLOR,
219768
+ color: "white",
219568
219769
  bold: true,
219569
- color: "blue",
219570
219770
  children: [
219571
- "#",
219572
- selectedChannel.name
219771
+ " #",
219772
+ selectedChannel.name,
219773
+ " "
219573
219774
  ]
219574
219775
  }, undefined, true, undefined, this),
219575
219776
  selectedChannel.description && /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
@@ -219592,16 +219793,21 @@ function ChannelsPanel({ manager, onClose, activePersonId, activePersonName, onP
219592
219793
  marginBottom: 0,
219593
219794
  children: [
219594
219795
  /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
219595
- color: "cyan",
219796
+ backgroundColor: getAssistantColor2(msg.senderName),
219797
+ color: "white",
219596
219798
  bold: true,
219597
- children: msg.senderName
219598
- }, undefined, false, undefined, this),
219799
+ children: [
219800
+ " ",
219801
+ msg.senderName,
219802
+ " "
219803
+ ]
219804
+ }, undefined, true, undefined, this),
219599
219805
  /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
219600
219806
  color: "gray",
219601
219807
  children: [
219602
- " (",
219808
+ " ",
219603
219809
  formatRelativeTime5(msg.createdAt),
219604
- "): "
219810
+ ": "
219605
219811
  ]
219606
219812
  }, undefined, true, undefined, this),
219607
219813
  /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
@@ -219708,17 +219914,27 @@ function ChannelsPanel({ manager, onClose, activePersonId, activePersonName, onP
219708
219914
  /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Box_default, {
219709
219915
  paddingX: 1,
219710
219916
  marginBottom: 1,
219711
- children: /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
219712
- bold: true,
219713
- children: [
219714
- "#",
219715
- selectedChannel.name,
219716
- " \u2014 Members (",
219717
- members.length,
219718
- ")"
219719
- ]
219720
- }, undefined, true, undefined, this)
219721
- }, undefined, false, undefined, this),
219917
+ children: [
219918
+ /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
219919
+ backgroundColor: SLACK_COLOR,
219920
+ color: "white",
219921
+ bold: true,
219922
+ children: [
219923
+ " #",
219924
+ selectedChannel.name,
219925
+ " "
219926
+ ]
219927
+ }, undefined, true, undefined, this),
219928
+ /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
219929
+ bold: true,
219930
+ children: [
219931
+ " Members (",
219932
+ members.length,
219933
+ ")"
219934
+ ]
219935
+ }, undefined, true, undefined, this)
219936
+ ]
219937
+ }, undefined, true, undefined, this),
219722
219938
  /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Box_default, {
219723
219939
  flexDirection: "column",
219724
219940
  paddingX: 1,
@@ -219728,9 +219944,15 @@ function ChannelsPanel({ manager, onClose, activePersonId, activePersonName, onP
219728
219944
  children: " "
219729
219945
  }, undefined, false, undefined, this),
219730
219946
  /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
219947
+ backgroundColor: getAssistantColor2(m5.assistantName),
219948
+ color: "white",
219731
219949
  bold: true,
219732
- children: m5.assistantName
219733
- }, undefined, false, undefined, this),
219950
+ children: [
219951
+ " ",
219952
+ m5.assistantName,
219953
+ " "
219954
+ ]
219955
+ }, undefined, true, undefined, this),
219734
219956
  m5.role === "owner" && /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text3, {
219735
219957
  color: "yellow",
219736
219958
  children: " (owner)"
@@ -221128,6 +221350,9 @@ function OnboardingPanel({
221128
221350
  process.stdin.on("data", handleData);
221129
221351
  return () => {
221130
221352
  process.stdin.removeListener("data", handleData);
221353
+ if (isRawModeSupported && setRawMode) {
221354
+ setRawMode(false);
221355
+ }
221131
221356
  };
221132
221357
  }, [onCancel, isRawModeSupported, setRawMode]);
221133
221358
  const [connectorKeys, setConnectorKeys] = import_react51.useState({});
@@ -232060,6 +232285,7 @@ function App2({ cwd: cwd2, version: version3 }) {
232060
232285
  setIsProcessing(true);
232061
232286
  isProcessingRef.current = true;
232062
232287
  registryRef.current.setProcessing(activeSession2.id, true);
232288
+ pendingSendsRef.current.push({ id: nextMessage.id, sessionId: activeSessionId, mode: "queued" });
232063
232289
  try {
232064
232290
  await activeSession2.client.send(nextMessage.content);
232065
232291
  } catch (err) {
@@ -233835,7 +234061,7 @@ When done, report the result.`);
233835
234061
  }
233836
234062
  if (showConfigPanel && currentConfig) {
233837
234063
  const handleConfigSave = async (location, updates) => {
233838
- const { writeFile: writeFile15, mkdir: mkdir16 } = await import("fs/promises");
234064
+ const { writeFile: writeFile14, mkdir: mkdir16 } = await import("fs/promises");
233839
234065
  const { dirname: dirname25 } = await import("path");
233840
234066
  let configPath;
233841
234067
  let existingConfig;
@@ -233855,7 +234081,7 @@ When done, report the result.`);
233855
234081
  }
233856
234082
  const newConfig = deepMerge(existingConfig || {}, updates);
233857
234083
  await mkdir16(dirname25(configPath), { recursive: true });
233858
- await writeFile15(configPath, JSON.stringify(newConfig, null, 2));
234084
+ await writeFile14(configPath, JSON.stringify(newConfig, null, 2));
233859
234085
  await loadConfigFiles();
233860
234086
  };
233861
234087
  return /* @__PURE__ */ jsx_dev_runtime43.jsxDEV(Box_default, {
@@ -234714,7 +234940,7 @@ Interactive Mode:
234714
234940
  // packages/terminal/src/index.tsx
234715
234941
  var jsx_dev_runtime44 = __toESM(require_jsx_dev_runtime(), 1);
234716
234942
  setRuntime(bunRuntime);
234717
- var VERSION4 = "1.1.21";
234943
+ var VERSION4 = "1.1.22";
234718
234944
  var SYNC_START = "\x1B[?2026h";
234719
234945
  var SYNC_END = "\x1B[?2026l";
234720
234946
  function enableSynchronizedOutput() {
@@ -234854,4 +235080,4 @@ export {
234854
235080
  main
234855
235081
  };
234856
235082
 
234857
- //# debugId=2ACD58D0B6B9265864756E2164756E21
235083
+ //# debugId=94E39B1F6C1DFA4D64756E2164756E21