heyio 4.3.2 → 4.3.4

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.
@@ -80,7 +80,7 @@ var init_constants = __esm({
80
80
  "packages/shared/dist/constants.js"() {
81
81
  "use strict";
82
82
  APP_NAME = "io";
83
- APP_VERSION = "4.3.2";
83
+ APP_VERSION = "4.3.4";
84
84
  API_PORT = 7777;
85
85
  API_HOST = "0.0.0.0";
86
86
  DEFAULT_MODEL = "gpt-4.1-mini";
@@ -68368,6 +68368,7 @@ async function refreshModelPricing(logger2) {
68368
68368
  }
68369
68369
  const db = await getDatabase();
68370
68370
  const now = nowIso();
68371
+ await db.execute("DELETE FROM model_pricing WHERE id LIKE '%/%'");
68371
68372
  for (const model of modelMap.values()) {
68372
68373
  if (model.tokenInputMultiplier == null) {
68373
68374
  continue;
@@ -68473,7 +68474,7 @@ async function upsertModel(db, model) {
68473
68474
  }
68474
68475
  function rowToModelPricing(row) {
68475
68476
  return {
68476
- id: asString(row.id),
68477
+ id: stripVendorPrefix(asString(row.id)),
68477
68478
  displayName: asString(row.display_name),
68478
68479
  premiumMultiplier: asNullableNumber(row.premium_multiplier),
68479
68480
  tokenInputMultiplier: asNullableNumber(row.token_input_multiplier),
@@ -69532,18 +69533,21 @@ var init_manager2 = __esm({
69532
69533
  });
69533
69534
 
69534
69535
  // packages/daemon/src/squad/model-selector.ts
69535
- import { CopilotClient as CopilotClient2, approveAll as approveAll2 } from "@github/copilot-sdk";
69536
+ function classifyTaskComplexity(taskDescription) {
69537
+ const tiers = ["ultra", "premium", "standard", "fast", "trivial"];
69538
+ for (const tier of tiers) {
69539
+ if (TIER_KEYWORDS[tier].some((pattern) => pattern.test(taskDescription))) {
69540
+ return tier;
69541
+ }
69542
+ }
69543
+ return "standard";
69544
+ }
69536
69545
  async function selectModelForTask(taskDescription) {
69537
69546
  const classifierModel = await getCheapestAvailableModel();
69538
69547
  if (!classifierModel) {
69539
69548
  throw new Error("No models available in pricing database");
69540
69549
  }
69541
- let tier;
69542
- try {
69543
- tier = await classifyTaskComplexity(taskDescription, classifierModel.id);
69544
- } catch {
69545
- return classifierModel.id;
69546
- }
69550
+ const tier = classifyTaskComplexity(taskDescription);
69547
69551
  const selectedModel = await getCheapestInTier(tier);
69548
69552
  if (selectedModel) {
69549
69553
  return selectedModel.id;
@@ -69557,46 +69561,18 @@ async function selectModelForTask(taskDescription) {
69557
69561
  }
69558
69562
  return classifierModel.id;
69559
69563
  }
69560
- async function classifyTaskComplexity(taskDescription, modelId) {
69561
- let client2 = null;
69562
- try {
69563
- client2 = new CopilotClient2();
69564
- await client2.start();
69565
- const session = await client2.createSession({
69566
- model: modelId,
69567
- onPermissionRequest: approveAll2,
69568
- systemMessage: { content: CLASSIFICATION_PROMPT }
69569
- });
69570
- try {
69571
- const response = await session.sendAndWait({ prompt: `Task: ${taskDescription}` }, 15e3);
69572
- const raw = (response.text ?? "").trim().toLowerCase();
69573
- const tier = VALID_TIERS.find((t) => raw.includes(t));
69574
- return tier ?? "standard";
69575
- } finally {
69576
- await session.disconnect().catch(() => void 0);
69577
- }
69578
- } finally {
69579
- if (client2) {
69580
- await client2.stop().catch(() => void 0);
69581
- }
69582
- }
69583
- }
69584
- var VALID_TIERS, CLASSIFICATION_PROMPT;
69564
+ var TIER_KEYWORDS;
69585
69565
  var init_model_selector = __esm({
69586
69566
  "packages/daemon/src/squad/model-selector.ts"() {
69587
69567
  "use strict";
69588
69568
  init_registry();
69589
- VALID_TIERS = ["trivial", "fast", "standard", "premium", "ultra"];
69590
- CLASSIFICATION_PROMPT = `You are a task complexity classifier. Given a task description, classify its complexity into exactly one tier.
69591
-
69592
- Tiers (from simplest to most complex):
69593
- - trivial: Typos, renames, comment changes, config tweaks, formatting
69594
- - fast: Simple bug fixes, small features, documentation updates, single-file changes
69595
- - standard: Feature implementation, multi-file changes, moderate refactoring
69596
- - premium: Architecture changes, complex refactoring, security work, performance optimization
69597
- - ultra: System-wide redesigns, critical infrastructure, cross-cutting concerns
69598
-
69599
- Reply with ONLY the tier name (one word, lowercase). Nothing else.`;
69569
+ TIER_KEYWORDS = {
69570
+ ultra: [/system[- ]wide/i, /redesign/i, /infrastructure/i, /cross[- ]cutting/i, /migration/i],
69571
+ premium: [/architect/i, /security/i, /performance/i, /complex refactor/i, /optimization/i],
69572
+ standard: [/implement/i, /feature/i, /multi[- ]file/i, /refactor/i, /integration/i],
69573
+ fast: [/fix/i, /bug/i, /update/i, /documentation/i, /single[- ]file/i, /small/i],
69574
+ trivial: [/typo/i, /rename/i, /comment/i, /config/i, /format/i]
69575
+ };
69600
69576
  }
69601
69577
  });
69602
69578
 
@@ -69637,8 +69613,8 @@ import { mkdir as mkdir9, readFile as readFile7, readdir as readdir5, stat as st
69637
69613
  import { dirname as dirname8, extname as extname3, isAbsolute, join as join11, relative as relative3, resolve as resolve4 } from "node:path";
69638
69614
  import { promisify as promisify3 } from "node:util";
69639
69615
  import {
69640
- CopilotClient as CopilotClient3,
69641
- approveAll as approveAll3,
69616
+ CopilotClient as CopilotClient2,
69617
+ approveAll as approveAll2,
69642
69618
  defineTool
69643
69619
  } from "@github/copilot-sdk";
69644
69620
  function createEmptyUsage() {
@@ -69897,15 +69873,15 @@ async function executeAgentTask(member, task, worktreePath, options2) {
69897
69873
  const mcpServerNote = options2?.mcpServers?.length ? `Available MCP server labels: ${options2.mcpServers.join(", ")}.` : "No additional MCP servers were configured for this run.";
69898
69874
  let client2 = null;
69899
69875
  try {
69900
- client2 = new CopilotClient3({ workingDirectory: worktreePath });
69876
+ client2 = new CopilotClient2({ workingDirectory: worktreePath });
69901
69877
  await client2.start();
69902
69878
  const model = member.model ? stripVendorPrefix(member.model) : await selectModelForTask(task.description);
69903
- const session = await client2.createSession({
69879
+ const sessionPromise = client2.createSession({
69904
69880
  model,
69905
69881
  workingDirectory: worktreePath,
69906
69882
  tools,
69907
69883
  availableTools: ["custom:*"],
69908
- onPermissionRequest: approveAll3,
69884
+ onPermissionRequest: approveAll2,
69909
69885
  systemMessage: {
69910
69886
  content: `${member.systemPrompt}
69911
69887
 
@@ -69915,6 +69891,15 @@ ${historyContext}
69915
69891
  ${mcpServerNote}${options2?.instancePromptSuffix ?? ""}`
69916
69892
  }
69917
69893
  });
69894
+ const session = await Promise.race([
69895
+ sessionPromise,
69896
+ new Promise(
69897
+ (_, reject) => setTimeout(
69898
+ () => reject(new Error(`Session creation timed out after ${SESSION_CREATE_TIMEOUT_MS}ms`)),
69899
+ SESSION_CREATE_TIMEOUT_MS
69900
+ )
69901
+ )
69902
+ ]);
69918
69903
  session.on("assistant.usage", (event) => {
69919
69904
  usageEvents.push(event.data);
69920
69905
  mergeUsage(usage, event.data);
@@ -69953,7 +69938,7 @@ Work only inside the current worktree. Summarize the concrete changes you made,
69953
69938
  }
69954
69939
  }
69955
69940
  }
69956
- var execAsync3, MAX_FILE_SIZE, MAX_LIST_RESULTS, MAX_SEARCH_RESULTS;
69941
+ var execAsync3, MAX_FILE_SIZE, MAX_LIST_RESULTS, MAX_SEARCH_RESULTS, SESSION_CREATE_TIMEOUT_MS;
69957
69942
  var init_agent = __esm({
69958
69943
  "packages/daemon/src/execution/agent.ts"() {
69959
69944
  "use strict";
@@ -69965,6 +69950,7 @@ var init_agent = __esm({
69965
69950
  MAX_FILE_SIZE = 2e5;
69966
69951
  MAX_LIST_RESULTS = 200;
69967
69952
  MAX_SEARCH_RESULTS = 100;
69953
+ SESSION_CREATE_TIMEOUT_MS = 3e4;
69968
69954
  }
69969
69955
  });
69970
69956
 
@@ -70056,7 +70042,7 @@ import { exec as exec4 } from "node:child_process";
70056
70042
  import { access, readFile as readFile8 } from "node:fs/promises";
70057
70043
  import { join as join12 } from "node:path";
70058
70044
  import { promisify as promisify4 } from "node:util";
70059
- import { CopilotClient as CopilotClient4, approveAll as approveAll4 } from "@github/copilot-sdk";
70045
+ import { CopilotClient as CopilotClient3, approveAll as approveAll3 } from "@github/copilot-sdk";
70060
70046
  async function fileExists(path) {
70061
70047
  try {
70062
70048
  await access(path);
@@ -70150,13 +70136,13 @@ Return strict JSON in this shape:
70150
70136
  }`;
70151
70137
  let client2 = null;
70152
70138
  try {
70153
- client2 = new CopilotClient4({ workingDirectory: repoPath });
70139
+ client2 = new CopilotClient3({ workingDirectory: repoPath });
70154
70140
  await client2.start();
70155
70141
  const model = await selectModelForTask(`Create implementation plan: ${objective.description}`);
70156
70142
  const session = await client2.createSession({
70157
70143
  model,
70158
70144
  workingDirectory: repoPath,
70159
- onPermissionRequest: approveAll4,
70145
+ onPermissionRequest: approveAll3,
70160
70146
  systemMessage: {
70161
70147
  content: `${TEAM_LEAD_PROMPT}
70162
70148
 
@@ -70276,7 +70262,7 @@ var init_pr = __esm({
70276
70262
  // packages/daemon/src/execution/qa.ts
70277
70263
  import { exec as exec6 } from "node:child_process";
70278
70264
  import { promisify as promisify6 } from "node:util";
70279
- import { CopilotClient as CopilotClient5, approveAll as approveAll5 } from "@github/copilot-sdk";
70265
+ import { CopilotClient as CopilotClient4, approveAll as approveAll4 } from "@github/copilot-sdk";
70280
70266
  function extractJsonObject2(content) {
70281
70267
  const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/i);
70282
70268
  if (fenced?.[1]) {
@@ -70314,13 +70300,13 @@ Return strict JSON:
70314
70300
  }`;
70315
70301
  let client2 = null;
70316
70302
  try {
70317
- client2 = new CopilotClient5({ workingDirectory: worktreePath });
70303
+ client2 = new CopilotClient4({ workingDirectory: worktreePath });
70318
70304
  await client2.start();
70319
70305
  const model = qaMember.model ? stripVendorPrefix(qaMember.model) : await selectModelForTask(`QA review: ${objective.description}`);
70320
70306
  const session = await client2.createSession({
70321
70307
  model,
70322
70308
  workingDirectory: worktreePath,
70323
- onPermissionRequest: approveAll5,
70309
+ onPermissionRequest: approveAll4,
70324
70310
  systemMessage: {
70325
70311
  content: QA_PROMPT
70326
70312
  }
@@ -70404,7 +70390,7 @@ var init_qa = __esm({
70404
70390
  });
70405
70391
 
70406
70392
  // packages/daemon/src/execution/review.ts
70407
- import { CopilotClient as CopilotClient6, approveAll as approveAll6 } from "@github/copilot-sdk";
70393
+ import { CopilotClient as CopilotClient5, approveAll as approveAll5 } from "@github/copilot-sdk";
70408
70394
  function extractJsonObject3(content) {
70409
70395
  const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/i);
70410
70396
  if (fenced?.[1]) {
@@ -70449,12 +70435,12 @@ Return strict JSON:
70449
70435
  }`;
70450
70436
  let client2 = null;
70451
70437
  try {
70452
- client2 = new CopilotClient6();
70438
+ client2 = new CopilotClient5();
70453
70439
  await client2.start();
70454
70440
  const model = teamLead.model ? stripVendorPrefix(teamLead.model) : await selectModelForTask(`Code review: ${objective.description}`);
70455
70441
  const session = await client2.createSession({
70456
70442
  model,
70457
- onPermissionRequest: approveAll6,
70443
+ onPermissionRequest: approveAll5,
70458
70444
  systemMessage: {
70459
70445
  content: `${TEAM_LEAD_PROMPT}
70460
70446
 
@@ -70616,60 +70602,49 @@ async function executePendingTasks(objective, members, worktreePath, mcpServers,
70616
70602
  if (pendingTasks.length === 0) {
70617
70603
  return getTasksForObjective(objective.id);
70618
70604
  }
70619
- const results = await Promise.allSettled(
70620
- pendingTasks.map(async (task) => {
70621
- const member = members.find((candidate) => candidate.id === task.assigneeId);
70622
- if (!member) {
70623
- const failedTask = await markTaskFailed(
70624
- task.id,
70625
- "No squad member matched the task assignee."
70626
- );
70627
- eventBus.emit(EVENT_NAMES.TASK_FAILED, {
70628
- task: failedTask,
70629
- agentName: "unassigned",
70630
- reason: failedTask.result ?? "No assignee"
70631
- });
70632
- throw new Error(`Task ${task.id} has no matching assignee`);
70633
- }
70634
- const inProgressTask = await updateTaskStatus(
70605
+ for (const task of pendingTasks) {
70606
+ const member = members.find((candidate) => candidate.id === task.assigneeId);
70607
+ if (!member) {
70608
+ const failedTask = await markTaskFailed(
70635
70609
  task.id,
70636
- "in_progress",
70637
- task.result ?? void 0
70610
+ "No squad member matched the task assignee."
70638
70611
  );
70639
- const startedTask = inProgressTask ?? task;
70640
- eventBus.emit(EVENT_NAMES.TASK_STARTED, { task: startedTask, agentName: member.name });
70641
- eventBus.emit(EVENT_NAMES.AGENT_EXECUTING, {
70642
- squadId: objective.squadId,
70643
- agentId: member.id,
70644
- taskId: task.id
70645
- });
70646
- const execution = await executeAgentTask(member, task, worktreePath, {
70647
- mcpServers,
70648
- instancePromptSuffix
70612
+ eventBus.emit(EVENT_NAMES.TASK_FAILED, {
70613
+ task: failedTask,
70614
+ agentName: "unassigned",
70615
+ reason: failedTask.result ?? "No assignee"
70649
70616
  });
70650
- if (!execution.success) {
70651
- const failedTask = await markTaskFailed(task.id, execution.result);
70652
- eventBus.emit(EVENT_NAMES.TASK_FAILED, {
70653
- task: failedTask,
70654
- agentName: member.name,
70655
- reason: execution.result
70656
- });
70657
- throw new Error(execution.result);
70658
- }
70659
- const completedTask = await markTaskComplete(task.id, execution.result);
70660
- await extractLearnings(member.id, member.squadId, execution.result);
70661
- eventBus.emit(EVENT_NAMES.TASK_COMPLETED, { task: completedTask, agentName: member.name });
70662
- eventBus.emit(EVENT_NAMES.AGENT_COMPLETED, {
70663
- squadId: objective.squadId,
70664
- agentId: member.id,
70665
- taskId: task.id
70617
+ throw new Error(`Task ${task.id} has no matching assignee`);
70618
+ }
70619
+ const inProgressTask = await updateTaskStatus(task.id, "in_progress", task.result ?? void 0);
70620
+ const startedTask = inProgressTask ?? task;
70621
+ eventBus.emit(EVENT_NAMES.TASK_STARTED, { task: startedTask, agentName: member.name });
70622
+ eventBus.emit(EVENT_NAMES.AGENT_EXECUTING, {
70623
+ squadId: objective.squadId,
70624
+ agentId: member.id,
70625
+ taskId: task.id
70626
+ });
70627
+ const execution = await executeAgentTask(member, task, worktreePath, {
70628
+ mcpServers,
70629
+ instancePromptSuffix
70630
+ });
70631
+ if (!execution.success) {
70632
+ const failedTask = await markTaskFailed(task.id, execution.result);
70633
+ eventBus.emit(EVENT_NAMES.TASK_FAILED, {
70634
+ task: failedTask,
70635
+ agentName: member.name,
70636
+ reason: execution.result
70666
70637
  });
70667
- return completedTask;
70668
- })
70669
- );
70670
- const failed = results.find((result) => result.status === "rejected");
70671
- if (failed && failed.status === "rejected") {
70672
- throw failed.reason instanceof Error ? failed.reason : new Error(String(failed.reason));
70638
+ throw new Error(execution.result);
70639
+ }
70640
+ const completedTask = await markTaskComplete(task.id, execution.result);
70641
+ await extractLearnings(member.id, member.squadId, execution.result);
70642
+ eventBus.emit(EVENT_NAMES.TASK_COMPLETED, { task: completedTask, agentName: member.name });
70643
+ eventBus.emit(EVENT_NAMES.AGENT_COMPLETED, {
70644
+ squadId: objective.squadId,
70645
+ agentId: member.id,
70646
+ taskId: task.id
70647
+ });
70673
70648
  }
70674
70649
  return getTasksForObjective(objective.id);
70675
70650
  }