heyio 4.2.5 → 4.2.7

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.2.5";
83
+ APP_VERSION = "4.2.7";
84
84
  API_PORT = 7777;
85
85
  API_HOST = "0.0.0.0";
86
86
  DEFAULT_MODEL = "gpt-4o";
@@ -2121,6 +2121,11 @@ var init_db = __esm({
2121
2121
  agent_name = (SELECT sm.name FROM squad_members sm WHERE sm.id = token_usage.agent_id)
2122
2122
  WHERE squad_id IS NOT NULL OR agent_id IS NOT NULL`
2123
2123
  ]
2124
+ },
2125
+ {
2126
+ version: 5,
2127
+ name: "add-squad-soft-delete",
2128
+ statements: ["ALTER TABLE squads ADD COLUMN deleted_at TEXT"]
2124
2129
  }
2125
2130
  ];
2126
2131
  client = null;
@@ -2144,7 +2149,8 @@ async function createSquad(data, db) {
2144
2149
  status: data.status ?? "active",
2145
2150
  config: data.config,
2146
2151
  createdAt: timestamp,
2147
- updatedAt: timestamp
2152
+ updatedAt: timestamp,
2153
+ deletedAt: null
2148
2154
  };
2149
2155
  await database.execute({
2150
2156
  sql: `INSERT INTO squads (id, name, repo_url, repo_owner, repo_name, status, config, created_at, updated_at)
@@ -2166,7 +2172,7 @@ async function createSquad(data, db) {
2166
2172
  async function getSquad(id, db) {
2167
2173
  const database = db ?? await getDatabase();
2168
2174
  const squadResult = await database.execute({
2169
- sql: "SELECT * FROM squads WHERE id = ? LIMIT 1",
2175
+ sql: "SELECT * FROM squads WHERE id = ? AND deleted_at IS NULL LIMIT 1",
2170
2176
  args: [id]
2171
2177
  });
2172
2178
  const row = squadResult.rows[0];
@@ -2182,7 +2188,7 @@ async function getSquad(id, db) {
2182
2188
  async function getSquadByName(name, db) {
2183
2189
  const database = db ?? await getDatabase();
2184
2190
  const result = await database.execute({
2185
- sql: "SELECT * FROM squads WHERE name = ? LIMIT 1",
2191
+ sql: "SELECT * FROM squads WHERE name = ? AND deleted_at IS NULL LIMIT 1",
2186
2192
  args: [name]
2187
2193
  });
2188
2194
  const row = result.rows[0];
@@ -2195,7 +2201,9 @@ async function getSquadByName(name, db) {
2195
2201
  }
2196
2202
  async function listSquads(db) {
2197
2203
  const database = db ?? await getDatabase();
2198
- const result = await database.execute("SELECT * FROM squads ORDER BY created_at DESC, id DESC");
2204
+ const result = await database.execute(
2205
+ "SELECT * FROM squads WHERE deleted_at IS NULL ORDER BY created_at DESC, id DESC"
2206
+ );
2199
2207
  return result.rows.map((row) => mapSquad(row));
2200
2208
  }
2201
2209
  async function updateSquad(id, data, db) {
@@ -2214,7 +2222,8 @@ async function updateSquad(id, data, db) {
2214
2222
  status: data.status ?? existing.status,
2215
2223
  config: data.config ?? existing.config,
2216
2224
  createdAt: existing.createdAt,
2217
- updatedAt
2225
+ updatedAt,
2226
+ deletedAt: existing.deletedAt
2218
2227
  };
2219
2228
  await database.execute({
2220
2229
  sql: `UPDATE squads
@@ -2235,16 +2244,34 @@ async function updateSquad(id, data, db) {
2235
2244
  }
2236
2245
  async function deleteSquad(id, db) {
2237
2246
  const database = db ?? await getDatabase();
2247
+ const now = nowIso();
2238
2248
  const result = await database.execute({
2239
- sql: "DELETE FROM squads WHERE id = ?",
2240
- args: [id]
2249
+ sql: "UPDATE squads SET status = 'deleted', deleted_at = ?, updated_at = ? WHERE id = ? AND deleted_at IS NULL",
2250
+ args: [now, now, id]
2241
2251
  });
2242
2252
  return result.rowsAffected > 0;
2243
2253
  }
2254
+ async function restoreSquad(id, db) {
2255
+ const database = db ?? await getDatabase();
2256
+ const now = nowIso();
2257
+ const result = await database.execute({
2258
+ sql: "UPDATE squads SET status = 'active', deleted_at = NULL, updated_at = ? WHERE id = ? AND deleted_at IS NOT NULL",
2259
+ args: [now, id]
2260
+ });
2261
+ if (result.rowsAffected === 0) return null;
2262
+ return getSquadRow(id, database);
2263
+ }
2264
+ async function listDeletedSquads(db) {
2265
+ const database = db ?? await getDatabase();
2266
+ const result = await database.execute(
2267
+ "SELECT * FROM squads WHERE deleted_at IS NOT NULL ORDER BY deleted_at DESC, id DESC"
2268
+ );
2269
+ return result.rows.map((row) => mapSquad(row));
2270
+ }
2244
2271
  async function getSquadByRepo(repoOwner, repoName, db) {
2245
2272
  const database = db ?? await getDatabase();
2246
2273
  const result = await database.execute({
2247
- sql: "SELECT * FROM squads WHERE repo_owner = ? AND repo_name = ? LIMIT 1",
2274
+ sql: "SELECT * FROM squads WHERE repo_owner = ? AND repo_name = ? AND deleted_at IS NULL LIMIT 1",
2248
2275
  args: [repoOwner, repoName]
2249
2276
  });
2250
2277
  const row = result.rows[0];
@@ -2348,7 +2375,8 @@ function mapSquad(row) {
2348
2375
  status: asString(row.status),
2349
2376
  config: parseJson(asString(row.config)),
2350
2377
  createdAt: asString(row.created_at),
2351
- updatedAt: asString(row.updated_at)
2378
+ updatedAt: asString(row.updated_at),
2379
+ deletedAt: asNullableString(row.deleted_at)
2352
2380
  };
2353
2381
  }
2354
2382
  function mapMember(row) {
@@ -52850,6 +52878,39 @@ var init_squads2 = __esm({
52850
52878
  });
52851
52879
  }
52852
52880
  });
52881
+ router7.get("/api/squads/deleted", async (_req, res) => {
52882
+ try {
52883
+ const squads = await listDeletedSquads();
52884
+ res.status(200).json({ squads });
52885
+ } catch (error51) {
52886
+ res.status(500).json({
52887
+ error: "Failed to list deleted squads",
52888
+ details: error51 instanceof Error ? error51.message : "Unknown error"
52889
+ });
52890
+ }
52891
+ });
52892
+ router7.post("/api/squads/:id/restore", async (req, res) => {
52893
+ try {
52894
+ const restored = await restoreSquad(req.params.id);
52895
+ if (!restored) {
52896
+ res.status(404).json({ error: "Squad not found or not deleted" });
52897
+ return;
52898
+ }
52899
+ await logActivity({
52900
+ squadId: restored.id,
52901
+ event: EVENT_NAMES.SQUAD_UPDATED,
52902
+ description: `Restored squad ${restored.name}`,
52903
+ metadata: { repoUrl: restored.repoUrl }
52904
+ });
52905
+ eventBus.emit(EVENT_NAMES.SQUAD_UPDATED, { squad: restored });
52906
+ res.status(200).json({ squad: restored });
52907
+ } catch (error51) {
52908
+ res.status(500).json({
52909
+ error: "Failed to restore squad",
52910
+ details: error51 instanceof Error ? error51.message : "Unknown error"
52911
+ });
52912
+ }
52913
+ });
52853
52914
  router7.get("/api/squads/:id/members", async (req, res) => {
52854
52915
  try {
52855
52916
  const squad = await resolveSquad(req.params.id);
@@ -68132,226 +68193,6 @@ var init_pricing_scraper = __esm({
68132
68193
  }
68133
68194
  });
68134
68195
 
68135
- // packages/daemon/src/models/seed.ts
68136
- var SEED_MODELS;
68137
- var init_seed = __esm({
68138
- "packages/daemon/src/models/seed.ts"() {
68139
- "use strict";
68140
- SEED_MODELS = [
68141
- {
68142
- id: "gpt-4o-mini",
68143
- displayName: "OpenAI GPT-4o mini",
68144
- premiumMultiplier: 0.33,
68145
- tokenInputMultiplier: 0.015,
68146
- tokenOutputMultiplier: 0.06,
68147
- cachedInputMultiplier: 75e-4,
68148
- tier: "trivial",
68149
- available: true
68150
- },
68151
- {
68152
- id: "gpt-4o",
68153
- displayName: "OpenAI GPT-4o",
68154
- premiumMultiplier: 0.33,
68155
- tokenInputMultiplier: 0.25,
68156
- tokenOutputMultiplier: 1,
68157
- cachedInputMultiplier: 0.125,
68158
- tier: "trivial",
68159
- available: true
68160
- },
68161
- {
68162
- id: "gpt-5-mini",
68163
- displayName: "GPT-5 mini",
68164
- premiumMultiplier: 0.33,
68165
- tokenInputMultiplier: 0.025,
68166
- tokenOutputMultiplier: 0.2,
68167
- cachedInputMultiplier: 25e-4,
68168
- tier: "trivial",
68169
- available: true
68170
- },
68171
- {
68172
- id: "gpt-5.3-codex",
68173
- displayName: "GPT-5.3-Codex",
68174
- premiumMultiplier: 6,
68175
- tokenInputMultiplier: 0.175,
68176
- tokenOutputMultiplier: 1.4,
68177
- cachedInputMultiplier: 0.0175,
68178
- tier: "premium",
68179
- available: true
68180
- },
68181
- {
68182
- id: "gpt-5.4",
68183
- displayName: "GPT-5.4",
68184
- premiumMultiplier: 6,
68185
- tokenInputMultiplier: 0.25,
68186
- tokenOutputMultiplier: 1.5,
68187
- cachedInputMultiplier: 0.025,
68188
- tier: "premium",
68189
- available: true
68190
- },
68191
- {
68192
- id: "gpt-5.4-mini",
68193
- displayName: "GPT-5.4 mini",
68194
- premiumMultiplier: 6,
68195
- tokenInputMultiplier: 0.075,
68196
- tokenOutputMultiplier: 0.45,
68197
- cachedInputMultiplier: 75e-4,
68198
- tier: "premium",
68199
- available: true
68200
- },
68201
- {
68202
- id: "gpt-5.5",
68203
- displayName: "GPT-5.5",
68204
- premiumMultiplier: 57,
68205
- tokenInputMultiplier: 0.5,
68206
- tokenOutputMultiplier: 3,
68207
- cachedInputMultiplier: 0.05,
68208
- tier: "ultra",
68209
- available: true
68210
- },
68211
- {
68212
- id: "claude-sonnet-4",
68213
- displayName: "Claude Sonnet 4",
68214
- premiumMultiplier: 6,
68215
- tokenInputMultiplier: 0.3,
68216
- tokenOutputMultiplier: 1.5,
68217
- cachedInputMultiplier: 0.03,
68218
- tier: "premium",
68219
- available: true
68220
- },
68221
- {
68222
- id: "claude-sonnet-4.5",
68223
- displayName: "Claude Sonnet 4.5",
68224
- premiumMultiplier: 6,
68225
- tokenInputMultiplier: 0.3,
68226
- tokenOutputMultiplier: 1.5,
68227
- cachedInputMultiplier: 0.03,
68228
- tier: "premium",
68229
- available: true
68230
- },
68231
- {
68232
- id: "claude-sonnet-4.6",
68233
- displayName: "Claude Sonnet 4.6",
68234
- premiumMultiplier: 9,
68235
- tokenInputMultiplier: 0.3,
68236
- tokenOutputMultiplier: 1.5,
68237
- cachedInputMultiplier: 0.03,
68238
- tier: "premium",
68239
- available: true
68240
- },
68241
- {
68242
- id: "claude-haiku-4.5",
68243
- displayName: "Claude Haiku 4.5",
68244
- premiumMultiplier: 0.33,
68245
- tokenInputMultiplier: 0.1,
68246
- tokenOutputMultiplier: 0.5,
68247
- cachedInputMultiplier: 0.01,
68248
- tier: "trivial",
68249
- available: true
68250
- },
68251
- {
68252
- id: "claude-opus-4.5",
68253
- displayName: "Claude Opus 4.5",
68254
- premiumMultiplier: 15,
68255
- tokenInputMultiplier: 0.5,
68256
- tokenOutputMultiplier: 2.5,
68257
- cachedInputMultiplier: 0.05,
68258
- tier: "premium",
68259
- available: true
68260
- },
68261
- {
68262
- id: "claude-opus-4.6",
68263
- displayName: "Claude Opus 4.6",
68264
- premiumMultiplier: 27,
68265
- tokenInputMultiplier: 0.5,
68266
- tokenOutputMultiplier: 2.5,
68267
- cachedInputMultiplier: 0.05,
68268
- tier: "ultra",
68269
- available: true
68270
- },
68271
- {
68272
- id: "claude-opus-4.7",
68273
- displayName: "Claude Opus 4.7",
68274
- premiumMultiplier: 27,
68275
- tokenInputMultiplier: 0.5,
68276
- tokenOutputMultiplier: 2.5,
68277
- cachedInputMultiplier: 0.05,
68278
- tier: "ultra",
68279
- available: true
68280
- },
68281
- {
68282
- id: "claude-opus-4.8",
68283
- displayName: "Claude Opus 4.8",
68284
- premiumMultiplier: 27,
68285
- tokenInputMultiplier: 0.5,
68286
- tokenOutputMultiplier: 2.5,
68287
- cachedInputMultiplier: 0.05,
68288
- tier: "ultra",
68289
- available: true
68290
- },
68291
- {
68292
- id: "gemini-2.5-pro",
68293
- displayName: "Gemini 2.5 Pro",
68294
- premiumMultiplier: 1,
68295
- tokenInputMultiplier: 0.125,
68296
- tokenOutputMultiplier: 1,
68297
- cachedInputMultiplier: 0.0125,
68298
- tier: "fast",
68299
- available: true
68300
- },
68301
- {
68302
- id: "gemini-3-flash",
68303
- displayName: "Gemini 3 Flash",
68304
- premiumMultiplier: 0.33,
68305
- tokenInputMultiplier: 0.05,
68306
- tokenOutputMultiplier: 0.3,
68307
- cachedInputMultiplier: 5e-3,
68308
- tier: "trivial",
68309
- available: true
68310
- },
68311
- {
68312
- id: "gemini-3.1-pro",
68313
- displayName: "Gemini 3.1 Pro",
68314
- premiumMultiplier: 6,
68315
- tokenInputMultiplier: 0.2,
68316
- tokenOutputMultiplier: 1.2,
68317
- cachedInputMultiplier: 0.02,
68318
- tier: "premium",
68319
- available: true
68320
- },
68321
- {
68322
- id: "gemini-3.5-flash",
68323
- displayName: "Gemini 3.5 Flash",
68324
- premiumMultiplier: 14,
68325
- tokenInputMultiplier: 0.15,
68326
- tokenOutputMultiplier: 0.9,
68327
- cachedInputMultiplier: 0.015,
68328
- tier: "premium",
68329
- available: true
68330
- },
68331
- {
68332
- id: "raptor-mini",
68333
- displayName: "Raptor mini",
68334
- premiumMultiplier: 0.33,
68335
- tokenInputMultiplier: 0.025,
68336
- tokenOutputMultiplier: 0.2,
68337
- cachedInputMultiplier: 25e-4,
68338
- tier: "trivial",
68339
- available: true
68340
- },
68341
- {
68342
- id: "mai-code-1-flash",
68343
- displayName: "MAI-Code-1-Flash",
68344
- premiumMultiplier: 0.33,
68345
- tokenInputMultiplier: 0.075,
68346
- tokenOutputMultiplier: 0.45,
68347
- cachedInputMultiplier: 75e-4,
68348
- tier: "trivial",
68349
- available: true
68350
- }
68351
- ];
68352
- }
68353
- });
68354
-
68355
68196
  // packages/daemon/src/models/types.ts
68356
68197
  function computeTierFromMultiplier(premiumMultiplier) {
68357
68198
  if (premiumMultiplier === null) {
@@ -68494,9 +68335,7 @@ async function refreshModelPricing(logger2) {
68494
68335
  await scrapeCopilotPricingIntoMap(modelMap, result, logger2);
68495
68336
  await scrapePremiumPricingIntoMap(modelMap, result, logger2);
68496
68337
  if (!result.catalogFetched && !result.tokenPricingScraped && !result.premiumPricingScraped && !result.copilotPricingScraped) {
68497
- logger2?.warn("All pricing sources failed, using seed data");
68498
- await seedFromFallback();
68499
- result.modelsUpdated = SEED_MODELS.length;
68338
+ logger2?.warn("All pricing sources failed, no models available");
68500
68339
  return result;
68501
68340
  }
68502
68341
  const db = await getDatabase();
@@ -68518,13 +68357,6 @@ async function refreshModelPricing(logger2) {
68518
68357
  }
68519
68358
  return result;
68520
68359
  }
68521
- async function seedFromFallback() {
68522
- const db = await getDatabase();
68523
- const now = nowIso();
68524
- for (const model of SEED_MODELS) {
68525
- await upsertModel(db, { ...model, updatedAt: now });
68526
- }
68527
- }
68528
68360
  async function getModelPricing(modelId) {
68529
68361
  const db = await getDatabase();
68530
68362
  const result = await db.execute({
@@ -68605,7 +68437,6 @@ var init_registry = __esm({
68605
68437
  init_db();
68606
68438
  init_catalog();
68607
68439
  init_pricing_scraper();
68608
- init_seed();
68609
68440
  init_types();
68610
68441
  }
68611
68442
  });
@@ -68616,7 +68447,6 @@ var init_models = __esm({
68616
68447
  "use strict";
68617
68448
  init_catalog();
68618
68449
  init_registry();
68619
- init_seed();
68620
68450
  init_types();
68621
68451
  }
68622
68452
  });
@@ -71056,7 +70886,7 @@ async function processQueue2(squadId) {
71056
70886
  const next = await getNextQueued(squadId);
71057
70887
  if (next) {
71058
70888
  const freshSquad = await getSquad(squadId);
71059
- if (freshSquad) {
70889
+ if (freshSquad && next.objectiveId) {
71060
70890
  void startAndExecuteInstance(next.id, freshSquad, next.objectiveId);
71061
70891
  }
71062
70892
  }
@@ -71191,13 +71021,28 @@ async function handleFireSquad(rawArgs) {
71191
71021
  if (activeObjectives.length > 0) {
71192
71022
  const updated = await updateSquad(squadId, { status: "inactive" });
71193
71023
  return {
71194
- message: `Squad ${squadId} was deactivated because it still has active objectives.`,
71024
+ message: `Squad ${squadId} was deactivated because it still has active objectives. Use fire_squad again after objectives complete to delete it.`,
71195
71025
  squad: updated,
71196
71026
  activeObjectives
71197
71027
  };
71198
71028
  }
71199
71029
  await deleteSquad(squadId);
71200
- return { message: `Squad ${squadId} was deleted.`, squadId };
71030
+ return {
71031
+ message: `Squad "${squad.name}" has been deleted. It can be restored with restore_squad if needed.`,
71032
+ squadId
71033
+ };
71034
+ }
71035
+ async function handleRestoreSquad(rawArgs) {
71036
+ const { squadId } = squadIdSchema.parse(rawArgs);
71037
+ const restored = await restoreSquad(squadId);
71038
+ if (!restored) {
71039
+ throw new Error(`Squad ${squadId} was not found or is not deleted.`);
71040
+ }
71041
+ eventBus.emit(EVENT_NAMES.SQUAD_UPDATED, { squad: restored });
71042
+ return {
71043
+ message: `Squad "${restored.name}" has been restored.`,
71044
+ squad: restored
71045
+ };
71201
71046
  }
71202
71047
  async function handleDelegateToSquad(rawArgs) {
71203
71048
  const { squadId, objective } = delegateToSquadSchema.parse(rawArgs);
@@ -71262,11 +71107,26 @@ function createSquadToolExecutor(_config) {
71262
71107
  return handleAnalyzeRepo(rawArgs);
71263
71108
  case "fire_squad":
71264
71109
  return handleFireSquad(rawArgs);
71110
+ case "restore_squad":
71111
+ return handleRestoreSquad(rawArgs);
71112
+ case "list_deleted_squads": {
71113
+ const deletedSquads = await listDeletedSquads();
71114
+ if (deletedSquads.length === 0) {
71115
+ return { message: "No deleted squads.", squads: [] };
71116
+ }
71117
+ const list = deletedSquads.map((s) => `${s.id}: ${s.name} (${s.repoOwner}/${s.repoName}) [deleted ${s.deletedAt}]`).join("\n");
71118
+ return { message: list, squads: deletedSquads };
71119
+ }
71265
71120
  case "list_squads": {
71266
71121
  const squads = await listSquads();
71122
+ const deletedCount = (await listDeletedSquads()).length;
71123
+ const suffix = deletedCount > 0 ? `
71124
+
71125
+ ${deletedCount} deleted squad(s) available for restore (use list_deleted_squads to view).` : "";
71267
71126
  return {
71268
- message: formatSquadList(squads),
71269
- squads
71127
+ message: formatSquadList(squads) + suffix,
71128
+ squads,
71129
+ deletedCount
71270
71130
  };
71271
71131
  }
71272
71132
  case "get_squad_status": {
@@ -71398,10 +71258,22 @@ var init_squad2 = __esm({
71398
71258
  },
71399
71259
  {
71400
71260
  name: "fire_squad",
71401
- description: "Deactivate or delete a squad.",
71261
+ description: "Soft-delete a squad. The squad can be restored later with restore_squad.",
71402
71262
  parameters: squadIdSchema,
71403
71263
  skipPermission: true
71404
71264
  },
71265
+ {
71266
+ name: "restore_squad",
71267
+ description: "Restore a previously deleted squad and all its members.",
71268
+ parameters: squadIdSchema,
71269
+ skipPermission: true
71270
+ },
71271
+ {
71272
+ name: "list_deleted_squads",
71273
+ description: "List all soft-deleted squads that can be restored.",
71274
+ parameters: external_exports.object({}),
71275
+ skipPermission: true
71276
+ },
71405
71277
  {
71406
71278
  name: "list_squads",
71407
71279
  description: "List all squads and their status.",
@@ -85514,8 +85386,7 @@ async function main() {
85514
85386
  logger2.info("Database initialized");
85515
85387
  const pricingResult = await refreshModelPricing(logger2);
85516
85388
  if (pricingResult.modelsUpdated === 0) {
85517
- logger2.warn("Model pricing refresh returned 0 models, seeding with fallback");
85518
- await seedFromFallback();
85389
+ logger2.warn("Model pricing refresh returned 0 models");
85519
85390
  }
85520
85391
  logger2.info({ modelsUpdated: pricingResult.modelsUpdated }, "Model pricing initialized");
85521
85392
  await scanSkills();