heyio 4.1.3 → 4.2.0

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.1.3";
83
+ APP_VERSION = "4.2.0";
84
84
  API_PORT = 7777;
85
85
  API_HOST = "0.0.0.0";
86
86
  DEFAULT_MODEL = "gpt-4o";
@@ -2112,6 +2112,18 @@ var init_db = __esm({
2112
2112
  "CREATE INDEX IF NOT EXISTS idx_squad_instances_status ON squad_instances(status)",
2113
2113
  "CREATE INDEX IF NOT EXISTS idx_squad_instances_objective_id ON squad_instances(objective_id)"
2114
2114
  ]
2115
+ },
2116
+ {
2117
+ version: 4,
2118
+ name: "denormalize-usage-names",
2119
+ statements: [
2120
+ "ALTER TABLE token_usage ADD COLUMN squad_name TEXT",
2121
+ "ALTER TABLE token_usage ADD COLUMN agent_name TEXT",
2122
+ `UPDATE token_usage SET
2123
+ squad_name = (SELECT s.name FROM squads s WHERE s.id = token_usage.squad_id),
2124
+ agent_name = (SELECT sm.name FROM squad_members sm WHERE sm.id = token_usage.agent_id)
2125
+ WHERE squad_id IS NOT NULL OR agent_id IS NOT NULL`
2126
+ ]
2115
2127
  }
2116
2128
  ];
2117
2129
  client = null;
@@ -2288,6 +2300,35 @@ async function getMembers(squadId, db) {
2288
2300
  });
2289
2301
  return result.rows.map((row) => mapMember(row));
2290
2302
  }
2303
+ async function getMember(memberId, db) {
2304
+ const database = db ?? await getDatabase();
2305
+ const result = await database.execute({
2306
+ sql: "SELECT * FROM squad_members WHERE id = ? LIMIT 1",
2307
+ args: [memberId]
2308
+ });
2309
+ const row = result.rows[0];
2310
+ return row ? mapMember(row) : null;
2311
+ }
2312
+ async function updateMember(memberId, data, db) {
2313
+ const database = db ?? await getDatabase();
2314
+ const sets = [];
2315
+ const args = [];
2316
+ if (data.systemPrompt !== void 0) {
2317
+ sets.push("system_prompt = ?");
2318
+ args.push(data.systemPrompt);
2319
+ }
2320
+ if (data.model !== void 0) {
2321
+ sets.push("model = ?");
2322
+ args.push(data.model || null);
2323
+ }
2324
+ if (sets.length === 0) return getMember(memberId, database);
2325
+ args.push(memberId);
2326
+ await database.execute({
2327
+ sql: `UPDATE squad_members SET ${sets.join(", ")} WHERE id = ?`,
2328
+ args
2329
+ });
2330
+ return getMember(memberId, database);
2331
+ }
2291
2332
  async function getSquadRow(id, db) {
2292
2333
  const result = await db.execute({
2293
2334
  sql: "SELECT * FROM squads WHERE id = ? LIMIT 1",
@@ -11606,8 +11647,8 @@ var require_CronFileParser = __commonJS({
11606
11647
  * @throws If file cannot be read
11607
11648
  */
11608
11649
  static async parseFile(filePath) {
11609
- const { readFile: readFile10 } = await Promise.resolve().then(() => __importStar(__require("fs/promises")));
11610
- const data = await readFile10(filePath, "utf8");
11650
+ const { readFile: readFile11 } = await Promise.resolve().then(() => __importStar(__require("fs/promises")));
11651
+ const data = await readFile11(filePath, "utf8");
11611
11652
  return _CronFileParser.#parseContent(data);
11612
11653
  }
11613
11654
  /**
@@ -11876,8 +11917,8 @@ async function recordUsage(data, db) {
11876
11917
  createdAt: data.createdAt ?? nowIso()
11877
11918
  };
11878
11919
  await database.execute({
11879
- sql: `INSERT INTO token_usage (id, squad_id, agent_id, model, input_tokens, output_tokens, cost, premium_request_cost, token_unit_cost, created_at)
11880
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
11920
+ sql: `INSERT INTO token_usage (id, squad_id, agent_id, model, input_tokens, output_tokens, cost, premium_request_cost, token_unit_cost, squad_name, agent_name, created_at)
11921
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
11881
11922
  args: [
11882
11923
  usage.id,
11883
11924
  usage.squadId,
@@ -11888,6 +11929,8 @@ async function recordUsage(data, db) {
11888
11929
  usage.cost,
11889
11930
  data.premiumRequestCost ?? null,
11890
11931
  data.tokenUnitCost ?? null,
11932
+ data.squadName ?? null,
11933
+ data.agentName ?? null,
11891
11934
  usage.createdAt
11892
11935
  ]
11893
11936
  });
@@ -11952,8 +11995,8 @@ async function getUsageRecords(params = {}, db) {
11952
11995
  const result = await database.execute({
11953
11996
  sql: `SELECT tu.model, tu.input_tokens, tu.output_tokens, tu.cost,
11954
11997
  tu.created_at, tu.squad_id, tu.agent_id,
11955
- COALESCE(s.name, '') AS squad_name,
11956
- COALESCE(sm.name, '') AS agent_name
11998
+ COALESCE(s.name, tu.squad_name, '') AS squad_name,
11999
+ COALESCE(sm.name, tu.agent_name, '') AS agent_name
11957
12000
  FROM token_usage tu
11958
12001
  LEFT JOIN squads s ON s.id = tu.squad_id
11959
12002
  LEFT JOIN squad_members sm ON sm.id = tu.agent_id
@@ -31315,7 +31358,7 @@ var require_view = __commonJS({
31315
31358
  var dirname9 = path.dirname;
31316
31359
  var basename6 = path.basename;
31317
31360
  var extname4 = path.extname;
31318
- var join16 = path.join;
31361
+ var join17 = path.join;
31319
31362
  var resolve5 = path.resolve;
31320
31363
  module2.exports = View;
31321
31364
  function View(name, options2) {
@@ -31377,14 +31420,14 @@ var require_view = __commonJS({
31377
31420
  };
31378
31421
  View.prototype.resolve = function resolve6(dir, file2) {
31379
31422
  var ext = this.ext;
31380
- var path2 = join16(dir, file2);
31381
- var stat4 = tryStat(path2);
31382
- if (stat4 && stat4.isFile()) {
31423
+ var path2 = join17(dir, file2);
31424
+ var stat5 = tryStat(path2);
31425
+ if (stat5 && stat5.isFile()) {
31383
31426
  return path2;
31384
31427
  }
31385
- path2 = join16(dir, basename6(file2, ext), "index" + ext);
31386
- stat4 = tryStat(path2);
31387
- if (stat4 && stat4.isFile()) {
31428
+ path2 = join17(dir, basename6(file2, ext), "index" + ext);
31429
+ stat5 = tryStat(path2);
31430
+ if (stat5 && stat5.isFile()) {
31388
31431
  return path2;
31389
31432
  }
31390
31433
  };
@@ -31433,9 +31476,9 @@ var require_etag = __commonJS({
31433
31476
  }
31434
31477
  return obj && typeof obj === "object" && "ctime" in obj && toString.call(obj.ctime) === "[object Date]" && "mtime" in obj && toString.call(obj.mtime) === "[object Date]" && "ino" in obj && typeof obj.ino === "number" && "size" in obj && typeof obj.size === "number";
31435
31478
  }
31436
- function stattag(stat4) {
31437
- var mtime = stat4.mtime.getTime().toString(16);
31438
- var size = stat4.size.toString(16);
31479
+ function stattag(stat5) {
31480
+ var mtime = stat5.mtime.getTime().toString(16);
31481
+ var size = stat5.size.toString(16);
31439
31482
  return '"' + size + "-" + mtime + '"';
31440
31483
  }
31441
31484
  }
@@ -35087,7 +35130,7 @@ var require_send = __commonJS({
35087
35130
  var Stream = __require("stream");
35088
35131
  var util = __require("util");
35089
35132
  var extname4 = path.extname;
35090
- var join16 = path.join;
35133
+ var join17 = path.join;
35091
35134
  var normalize = path.normalize;
35092
35135
  var resolve5 = path.resolve;
35093
35136
  var sep = path.sep;
@@ -35259,7 +35302,7 @@ var require_send = __commonJS({
35259
35302
  return res;
35260
35303
  }
35261
35304
  parts = path2.split(sep);
35262
- path2 = normalize(join16(root, path2));
35305
+ path2 = normalize(join17(root, path2));
35263
35306
  } else {
35264
35307
  if (UP_PATH_REGEXP.test(path2)) {
35265
35308
  debug('malicious path "%s"', path2);
@@ -35290,8 +35333,8 @@ var require_send = __commonJS({
35290
35333
  this.sendFile(path2);
35291
35334
  return res;
35292
35335
  };
35293
- SendStream.prototype.send = function send3(path2, stat4) {
35294
- var len = stat4.size;
35336
+ SendStream.prototype.send = function send3(path2, stat5) {
35337
+ var len = stat5.size;
35295
35338
  var options2 = this.options;
35296
35339
  var opts = {};
35297
35340
  var res = this.res;
@@ -35303,7 +35346,7 @@ var require_send = __commonJS({
35303
35346
  return;
35304
35347
  }
35305
35348
  debug('pipe "%s"', path2);
35306
- this.setHeader(path2, stat4);
35349
+ this.setHeader(path2, stat5);
35307
35350
  this.type(path2);
35308
35351
  if (this.isConditionalGET()) {
35309
35352
  if (this.isPreconditionFailure()) {
@@ -35359,16 +35402,16 @@ var require_send = __commonJS({
35359
35402
  var i = 0;
35360
35403
  var self = this;
35361
35404
  debug('stat "%s"', path2);
35362
- fs.stat(path2, function onstat(err, stat4) {
35405
+ fs.stat(path2, function onstat(err, stat5) {
35363
35406
  var pathEndsWithSep = path2[path2.length - 1] === sep;
35364
35407
  if (err && err.code === "ENOENT" && !extname4(path2) && !pathEndsWithSep) {
35365
35408
  return next(err);
35366
35409
  }
35367
35410
  if (err) return self.onStatError(err);
35368
- if (stat4.isDirectory()) return self.redirect(path2);
35411
+ if (stat5.isDirectory()) return self.redirect(path2);
35369
35412
  if (pathEndsWithSep) return self.error(404);
35370
- self.emit("file", path2, stat4);
35371
- self.send(path2, stat4);
35413
+ self.emit("file", path2, stat5);
35414
+ self.send(path2, stat5);
35372
35415
  });
35373
35416
  function next(err) {
35374
35417
  if (self._extensions.length <= i) {
@@ -35376,11 +35419,11 @@ var require_send = __commonJS({
35376
35419
  }
35377
35420
  var p = path2 + "." + self._extensions[i++];
35378
35421
  debug('stat "%s"', p);
35379
- fs.stat(p, function(err2, stat4) {
35422
+ fs.stat(p, function(err2, stat5) {
35380
35423
  if (err2) return next(err2);
35381
- if (stat4.isDirectory()) return next();
35382
- self.emit("file", p, stat4);
35383
- self.send(p, stat4);
35424
+ if (stat5.isDirectory()) return next();
35425
+ self.emit("file", p, stat5);
35426
+ self.send(p, stat5);
35384
35427
  });
35385
35428
  }
35386
35429
  };
@@ -35392,13 +35435,13 @@ var require_send = __commonJS({
35392
35435
  if (err) return self.onStatError(err);
35393
35436
  return self.error(404);
35394
35437
  }
35395
- var p = join16(path2, self._index[i]);
35438
+ var p = join17(path2, self._index[i]);
35396
35439
  debug('stat "%s"', p);
35397
- fs.stat(p, function(err2, stat4) {
35440
+ fs.stat(p, function(err2, stat5) {
35398
35441
  if (err2) return next(err2);
35399
- if (stat4.isDirectory()) return next();
35400
- self.emit("file", p, stat4);
35401
- self.send(p, stat4);
35442
+ if (stat5.isDirectory()) return next();
35443
+ self.emit("file", p, stat5);
35444
+ self.send(p, stat5);
35402
35445
  });
35403
35446
  }
35404
35447
  next();
@@ -35429,9 +35472,9 @@ var require_send = __commonJS({
35429
35472
  debug("content-type %s", type2);
35430
35473
  res.setHeader("Content-Type", type2);
35431
35474
  };
35432
- SendStream.prototype.setHeader = function setHeader(path2, stat4) {
35475
+ SendStream.prototype.setHeader = function setHeader(path2, stat5) {
35433
35476
  var res = this.res;
35434
- this.emit("headers", res, path2, stat4);
35477
+ this.emit("headers", res, path2, stat5);
35435
35478
  if (this._acceptRanges && !res.getHeader("Accept-Ranges")) {
35436
35479
  debug("accept ranges");
35437
35480
  res.setHeader("Accept-Ranges", "bytes");
@@ -35445,12 +35488,12 @@ var require_send = __commonJS({
35445
35488
  res.setHeader("Cache-Control", cacheControl);
35446
35489
  }
35447
35490
  if (this._lastModified && !res.getHeader("Last-Modified")) {
35448
- var modified = stat4.mtime.toUTCString();
35491
+ var modified = stat5.mtime.toUTCString();
35449
35492
  debug("modified %s", modified);
35450
35493
  res.setHeader("Last-Modified", modified);
35451
35494
  }
35452
35495
  if (this._etag && !res.getHeader("ETag")) {
35453
- var val = etag(stat4);
35496
+ var val = etag(stat5);
35454
35497
  debug("etag %s", val);
35455
35498
  res.setHeader("ETag", val);
35456
35499
  }
@@ -52395,10 +52438,10 @@ async function spawnInstance(input2) {
52395
52438
  async function startInstance(instanceId, repoPath, baseBranch) {
52396
52439
  const branchName = `squad/instance-${instanceId.slice(0, 8)}`;
52397
52440
  try {
52398
- const { exec: exec8 } = await import("node:child_process");
52399
- const { promisify: promisify8 } = await import("node:util");
52400
- const execAsync8 = promisify8(exec8);
52401
- await execAsync8(`git fetch origin && git pull origin ${baseBranch}`, {
52441
+ const { exec: exec9 } = await import("node:child_process");
52442
+ const { promisify: promisify9 } = await import("node:util");
52443
+ const execAsync9 = promisify9(exec9);
52444
+ await execAsync9(`git fetch origin && git pull origin ${baseBranch}`, {
52402
52445
  cwd: repoPath,
52403
52446
  maxBuffer: 10 * 1024 * 1024
52404
52447
  });
@@ -52818,6 +52861,26 @@ var init_squads2 = __esm({
52818
52861
  });
52819
52862
  }
52820
52863
  });
52864
+ router7.put("/api/squads/:id/members/:memberId", async (req, res) => {
52865
+ try {
52866
+ const member = await getMember(req.params.memberId);
52867
+ if (!member) {
52868
+ res.status(404).json({ error: "Member not found" });
52869
+ return;
52870
+ }
52871
+ const { systemPrompt, model } = req.body;
52872
+ const updated = await updateMember(member.id, {
52873
+ systemPrompt,
52874
+ model: model === "" ? null : model
52875
+ });
52876
+ res.status(200).json(updated);
52877
+ } catch (error51) {
52878
+ res.status(500).json({
52879
+ error: "Failed to update member",
52880
+ details: error51 instanceof Error ? error51.message : "Unknown error"
52881
+ });
52882
+ }
52883
+ });
52821
52884
  router7.post("/api/squads/:id/objectives", async (req, res) => {
52822
52885
  try {
52823
52886
  const squad = await resolveSquad(req.params.id);
@@ -54266,7 +54329,7 @@ var require_sonic_boom = __commonJS({
54266
54329
  if (!(this instanceof SonicBoom)) {
54267
54330
  return new SonicBoom(opts);
54268
54331
  }
54269
- let { fd, dest, minLength, maxLength, maxWrite, periodicFlush, sync, append = true, mkdir: mkdir10, retryEAGAIN, fsync, contentMode, mode } = opts || {};
54332
+ let { fd, dest, minLength, maxLength, maxWrite, periodicFlush, sync, append = true, mkdir: mkdir11, retryEAGAIN, fsync, contentMode, mode } = opts || {};
54270
54333
  fd = fd || dest;
54271
54334
  this._len = 0;
54272
54335
  this.fd = -1;
@@ -54291,7 +54354,7 @@ var require_sonic_boom = __commonJS({
54291
54354
  this.append = append || false;
54292
54355
  this.mode = mode;
54293
54356
  this.retryEAGAIN = retryEAGAIN || (() => true);
54294
- this.mkdir = mkdir10 || false;
54357
+ this.mkdir = mkdir11 || false;
54295
54358
  let fsWriteSync;
54296
54359
  let fsWrite;
54297
54360
  if (contentMode === kContentModeBuffer) {
@@ -55009,7 +55072,7 @@ var require_thread_stream = __commonJS({
55009
55072
  var { version: version2 } = require_package();
55010
55073
  var { EventEmitter: EventEmitter2 } = __require("events");
55011
55074
  var { Worker } = __require("worker_threads");
55012
- var { join: join16 } = __require("path");
55075
+ var { join: join17 } = __require("path");
55013
55076
  var { pathToFileURL: pathToFileURL2 } = __require("url");
55014
55077
  var { wait } = require_wait();
55015
55078
  var {
@@ -55052,7 +55115,7 @@ var require_thread_stream = __commonJS({
55052
55115
  function createWorker(stream, opts) {
55053
55116
  const { filename, workerData } = opts;
55054
55117
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
55055
- const toExecute = bundlerOverrides["thread-stream-worker"] || join16(__dirname, "lib", "worker.js");
55118
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join17(__dirname, "lib", "worker.js");
55056
55119
  const worker = new Worker(toExecute, {
55057
55120
  ...opts.workerOpts,
55058
55121
  trackUnmanagedFds: false,
@@ -55455,7 +55518,7 @@ var require_transport = __commonJS({
55455
55518
  "use strict";
55456
55519
  var { createRequire } = __require("module");
55457
55520
  var getCallers = require_caller();
55458
- var { join: join16, isAbsolute: isAbsolute2, sep } = __require("node:path");
55521
+ var { join: join17, isAbsolute: isAbsolute2, sep } = __require("node:path");
55459
55522
  var sleep = require_atomic_sleep();
55460
55523
  var onExit = require_on_exit_leak_free();
55461
55524
  var ThreadStream = require_thread_stream();
@@ -55518,7 +55581,7 @@ var require_transport = __commonJS({
55518
55581
  throw new Error("only one of target or targets can be specified");
55519
55582
  }
55520
55583
  if (targets) {
55521
- target = bundlerOverrides["pino-worker"] || join16(__dirname, "worker.js");
55584
+ target = bundlerOverrides["pino-worker"] || join17(__dirname, "worker.js");
55522
55585
  options2.targets = targets.filter((dest) => dest.target).map((dest) => {
55523
55586
  return {
55524
55587
  ...dest,
@@ -55536,7 +55599,7 @@ var require_transport = __commonJS({
55536
55599
  });
55537
55600
  });
55538
55601
  } else if (pipeline) {
55539
- target = bundlerOverrides["pino-worker"] || join16(__dirname, "worker.js");
55602
+ target = bundlerOverrides["pino-worker"] || join17(__dirname, "worker.js");
55540
55603
  options2.pipelines = [pipeline.map((dest) => {
55541
55604
  return {
55542
55605
  ...dest,
@@ -55558,7 +55621,7 @@ var require_transport = __commonJS({
55558
55621
  return origin;
55559
55622
  }
55560
55623
  if (origin === "pino/file") {
55561
- return join16(__dirname, "..", "file.js");
55624
+ return join17(__dirname, "..", "file.js");
55562
55625
  }
55563
55626
  let fixTarget2;
55564
55627
  for (const filePath of callers) {
@@ -56547,7 +56610,7 @@ var require_safe_stable_stringify = __commonJS({
56547
56610
  return circularValue;
56548
56611
  }
56549
56612
  let res = "";
56550
- let join16 = ",";
56613
+ let join17 = ",";
56551
56614
  const originalIndentation = indentation;
56552
56615
  if (Array.isArray(value)) {
56553
56616
  if (value.length === 0) {
@@ -56561,7 +56624,7 @@ var require_safe_stable_stringify = __commonJS({
56561
56624
  indentation += spacer;
56562
56625
  res += `
56563
56626
  ${indentation}`;
56564
- join16 = `,
56627
+ join17 = `,
56565
56628
  ${indentation}`;
56566
56629
  }
56567
56630
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -56569,13 +56632,13 @@ ${indentation}`;
56569
56632
  for (; i < maximumValuesToStringify - 1; i++) {
56570
56633
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
56571
56634
  res += tmp2 !== void 0 ? tmp2 : "null";
56572
- res += join16;
56635
+ res += join17;
56573
56636
  }
56574
56637
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
56575
56638
  res += tmp !== void 0 ? tmp : "null";
56576
56639
  if (value.length - 1 > maximumBreadth) {
56577
56640
  const removedKeys = value.length - maximumBreadth - 1;
56578
- res += `${join16}"... ${getItemCount(removedKeys)} not stringified"`;
56641
+ res += `${join17}"... ${getItemCount(removedKeys)} not stringified"`;
56579
56642
  }
56580
56643
  if (spacer !== "") {
56581
56644
  res += `
@@ -56596,7 +56659,7 @@ ${originalIndentation}`;
56596
56659
  let separator = "";
56597
56660
  if (spacer !== "") {
56598
56661
  indentation += spacer;
56599
- join16 = `,
56662
+ join17 = `,
56600
56663
  ${indentation}`;
56601
56664
  whitespace = " ";
56602
56665
  }
@@ -56610,13 +56673,13 @@ ${indentation}`;
56610
56673
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
56611
56674
  if (tmp !== void 0) {
56612
56675
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
56613
- separator = join16;
56676
+ separator = join17;
56614
56677
  }
56615
56678
  }
56616
56679
  if (keyLength > maximumBreadth) {
56617
56680
  const removedKeys = keyLength - maximumBreadth;
56618
56681
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
56619
- separator = join16;
56682
+ separator = join17;
56620
56683
  }
56621
56684
  if (spacer !== "" && separator.length > 1) {
56622
56685
  res = `
@@ -56657,7 +56720,7 @@ ${originalIndentation}`;
56657
56720
  }
56658
56721
  const originalIndentation = indentation;
56659
56722
  let res = "";
56660
- let join16 = ",";
56723
+ let join17 = ",";
56661
56724
  if (Array.isArray(value)) {
56662
56725
  if (value.length === 0) {
56663
56726
  return "[]";
@@ -56670,7 +56733,7 @@ ${originalIndentation}`;
56670
56733
  indentation += spacer;
56671
56734
  res += `
56672
56735
  ${indentation}`;
56673
- join16 = `,
56736
+ join17 = `,
56674
56737
  ${indentation}`;
56675
56738
  }
56676
56739
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -56678,13 +56741,13 @@ ${indentation}`;
56678
56741
  for (; i < maximumValuesToStringify - 1; i++) {
56679
56742
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
56680
56743
  res += tmp2 !== void 0 ? tmp2 : "null";
56681
- res += join16;
56744
+ res += join17;
56682
56745
  }
56683
56746
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
56684
56747
  res += tmp !== void 0 ? tmp : "null";
56685
56748
  if (value.length - 1 > maximumBreadth) {
56686
56749
  const removedKeys = value.length - maximumBreadth - 1;
56687
- res += `${join16}"... ${getItemCount(removedKeys)} not stringified"`;
56750
+ res += `${join17}"... ${getItemCount(removedKeys)} not stringified"`;
56688
56751
  }
56689
56752
  if (spacer !== "") {
56690
56753
  res += `
@@ -56697,7 +56760,7 @@ ${originalIndentation}`;
56697
56760
  let whitespace = "";
56698
56761
  if (spacer !== "") {
56699
56762
  indentation += spacer;
56700
- join16 = `,
56763
+ join17 = `,
56701
56764
  ${indentation}`;
56702
56765
  whitespace = " ";
56703
56766
  }
@@ -56706,7 +56769,7 @@ ${indentation}`;
56706
56769
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
56707
56770
  if (tmp !== void 0) {
56708
56771
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
56709
- separator = join16;
56772
+ separator = join17;
56710
56773
  }
56711
56774
  }
56712
56775
  if (spacer !== "" && separator.length > 1) {
@@ -56764,20 +56827,20 @@ ${originalIndentation}`;
56764
56827
  indentation += spacer;
56765
56828
  let res2 = `
56766
56829
  ${indentation}`;
56767
- const join17 = `,
56830
+ const join18 = `,
56768
56831
  ${indentation}`;
56769
56832
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
56770
56833
  let i = 0;
56771
56834
  for (; i < maximumValuesToStringify - 1; i++) {
56772
56835
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
56773
56836
  res2 += tmp2 !== void 0 ? tmp2 : "null";
56774
- res2 += join17;
56837
+ res2 += join18;
56775
56838
  }
56776
56839
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
56777
56840
  res2 += tmp !== void 0 ? tmp : "null";
56778
56841
  if (value.length - 1 > maximumBreadth) {
56779
56842
  const removedKeys = value.length - maximumBreadth - 1;
56780
- res2 += `${join17}"... ${getItemCount(removedKeys)} not stringified"`;
56843
+ res2 += `${join18}"... ${getItemCount(removedKeys)} not stringified"`;
56781
56844
  }
56782
56845
  res2 += `
56783
56846
  ${originalIndentation}`;
@@ -56793,16 +56856,16 @@ ${originalIndentation}`;
56793
56856
  return '"[Object]"';
56794
56857
  }
56795
56858
  indentation += spacer;
56796
- const join16 = `,
56859
+ const join17 = `,
56797
56860
  ${indentation}`;
56798
56861
  let res = "";
56799
56862
  let separator = "";
56800
56863
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
56801
56864
  if (isTypedArrayWithEntries(value)) {
56802
- res += stringifyTypedArray(value, join16, maximumBreadth);
56865
+ res += stringifyTypedArray(value, join17, maximumBreadth);
56803
56866
  keys = keys.slice(value.length);
56804
56867
  maximumPropertiesToStringify -= value.length;
56805
- separator = join16;
56868
+ separator = join17;
56806
56869
  }
56807
56870
  if (deterministic) {
56808
56871
  keys = sort(keys, comparator);
@@ -56813,13 +56876,13 @@ ${indentation}`;
56813
56876
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
56814
56877
  if (tmp !== void 0) {
56815
56878
  res += `${separator}${strEscape(key2)}: ${tmp}`;
56816
- separator = join16;
56879
+ separator = join17;
56817
56880
  }
56818
56881
  }
56819
56882
  if (keyLength > maximumBreadth) {
56820
56883
  const removedKeys = keyLength - maximumBreadth;
56821
56884
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
56822
- separator = join16;
56885
+ separator = join17;
56823
56886
  }
56824
56887
  if (separator !== "") {
56825
56888
  res = `
@@ -69429,7 +69492,8 @@ function mergeUsage(target, usage) {
69429
69492
  target.models.push(usage.model);
69430
69493
  }
69431
69494
  }
69432
- async function persistUsage(member, usageEvents) {
69495
+ async function persistUsage(member, usageEvents, squadName) {
69496
+ const resolvedSquadName = squadName ?? (member.squadId ? (await getSquad(member.squadId))?.name : null) ?? null;
69433
69497
  for (const usage of usageEvents) {
69434
69498
  const model = usage.model;
69435
69499
  const pricing = await getModelPricing(model);
@@ -69442,7 +69506,9 @@ async function persistUsage(member, usageEvents) {
69442
69506
  ) : 0;
69443
69507
  await recordUsage({
69444
69508
  squadId: member.squadId,
69509
+ squadName: resolvedSquadName,
69445
69510
  agentId: member.id,
69511
+ agentName: member.name,
69446
69512
  model,
69447
69513
  inputTokens: usage.inputTokens ?? 0,
69448
69514
  outputTokens: usage.outputTokens ?? 0,
@@ -70368,7 +70434,11 @@ async function runGit2(command, cwd) {
70368
70434
  return stdout.trim();
70369
70435
  }
70370
70436
  async function resolveRepoPath(repoUrl, repoName) {
70437
+ const urlSegments = repoUrl.replace(/\.git$/i, "").split("/").filter(Boolean);
70438
+ const owner = urlSegments.at(-2) ?? "";
70439
+ const managedDir = owner && repoName ? join15(DATA_DIR, "repos", `${owner}--${repoName}`) : null;
70371
70440
  const candidates = [
70441
+ ...managedDir ? [managedDir] : [],
70372
70442
  process.cwd(),
70373
70443
  join15(process.cwd(), repoName),
70374
70444
  join15(process.cwd(), "repos", repoName),
@@ -70635,6 +70705,7 @@ var init_runner = __esm({
70635
70705
  "packages/daemon/src/execution/runner.ts"() {
70636
70706
  "use strict";
70637
70707
  init_dist();
70708
+ init_paths();
70638
70709
  init_event_bus();
70639
70710
  init_manager2();
70640
70711
  init_store2();
@@ -70886,6 +70957,18 @@ var init_hiring = __esm({
70886
70957
  });
70887
70958
 
70888
70959
  // packages/daemon/src/orchestrator/tools/squad.ts
70960
+ import { exec as exec8 } from "node:child_process";
70961
+ import { mkdir as mkdir10, readFile as readFile9, readdir as readdir6, stat as stat4 } from "node:fs/promises";
70962
+ import { join as join16 } from "node:path";
70963
+ import { promisify as promisify8 } from "node:util";
70964
+ async function pathExists2(path) {
70965
+ try {
70966
+ await stat4(path);
70967
+ return true;
70968
+ } catch {
70969
+ return false;
70970
+ }
70971
+ }
70889
70972
  function getDefaultSquadConfig(_config) {
70890
70973
  return {
70891
70974
  prMode: "draft-pr",
@@ -70905,58 +70988,94 @@ async function buildRepoAnalysis(repoUrl) {
70905
70988
  );
70906
70989
  return lines.join("\n");
70907
70990
  }
70908
- const headers = { Accept: "application/vnd.github+json" };
70909
- if (process.env.GITHUB_TOKEN) {
70910
- headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
70991
+ const repoDir = join16(DATA_DIR, "repos", `${owner}--${name}`);
70992
+ try {
70993
+ await mkdir10(join16(DATA_DIR, "repos"), { recursive: true });
70994
+ if (await pathExists2(join16(repoDir, ".git"))) {
70995
+ await execAsync8("git pull --ff-only", { cwd: repoDir, timeout: 3e4 }).catch(
70996
+ () => void 0
70997
+ );
70998
+ } else {
70999
+ await execAsync8(`git clone --depth 50 ${normalized} "${repoDir}"`, {
71000
+ timeout: 6e4
71001
+ });
71002
+ }
71003
+ } catch {
71004
+ lines.push("Unable to clone repository locally; falling back to basic analysis.");
71005
+ lines.push("Based on the repository name, propose roles that match common project patterns.");
71006
+ return lines.join("\n");
70911
71007
  }
70912
71008
  try {
70913
- const metaRes = await fetch(`https://api.github.com/repos/${owner}/${name}`, { headers });
70914
- if (metaRes.ok) {
70915
- const meta3 = await metaRes.json();
70916
- if (meta3.description) lines.push(`Description: ${meta3.description}`);
70917
- if (meta3.language) lines.push(`Primary language: ${meta3.language}`);
70918
- if (meta3.topics?.length) lines.push(`Topics: ${meta3.topics.join(", ")}`);
70919
- }
70920
- const treeRes = await fetch(
70921
- `https://api.github.com/repos/${owner}/${name}/git/trees/HEAD?recursive=false`,
70922
- { headers }
70923
- );
70924
- if (treeRes.ok) {
70925
- const tree = await treeRes.json();
70926
- const rootFiles = (tree.tree ?? []).filter((entry) => entry.type === "blob").map((entry) => entry.path);
70927
- const rootDirs = (tree.tree ?? []).filter((entry) => entry.type === "tree").map((entry) => entry.path);
70928
- if (rootFiles.length) lines.push(`Root files: ${rootFiles.join(", ")}`);
70929
- if (rootDirs.length) lines.push(`Root directories: ${rootDirs.join(", ")}`);
70930
- }
70931
- const manifests = [
71009
+ const rootEntries = await readdir6(repoDir, { withFileTypes: true });
71010
+ const rootFiles = rootEntries.filter((e) => e.isFile()).map((e) => e.name);
71011
+ const rootDirs = rootEntries.filter((e) => e.isDirectory() && e.name !== ".git").map((e) => e.name);
71012
+ if (rootFiles.length) lines.push(`Root files: ${rootFiles.join(", ")}`);
71013
+ if (rootDirs.length) lines.push(`Root directories: ${rootDirs.join(", ")}`);
71014
+ const manifestFiles = [
70932
71015
  "package.json",
70933
71016
  "Cargo.toml",
70934
71017
  "go.mod",
70935
71018
  "requirements.txt",
70936
- "pyproject.toml"
71019
+ "pyproject.toml",
71020
+ "Gemfile",
71021
+ "pom.xml",
71022
+ "build.gradle",
71023
+ "composer.json",
71024
+ "Makefile",
71025
+ "Dockerfile",
71026
+ "docker-compose.yml",
71027
+ "docker-compose.yaml",
71028
+ ".github/workflows"
70937
71029
  ];
70938
- for (const manifest of manifests) {
71030
+ for (const manifest of manifestFiles) {
71031
+ const fullPath = join16(repoDir, manifest);
70939
71032
  try {
70940
- const fileRes = await fetch(
70941
- `https://api.github.com/repos/${owner}/${name}/contents/${manifest}`,
70942
- { headers }
70943
- );
70944
- if (fileRes.ok) {
70945
- const file2 = await fileRes.json();
70946
- if (file2.content && file2.encoding === "base64") {
70947
- const decoded = Buffer.from(file2.content, "base64").toString("utf8");
70948
- lines.push(`
71033
+ const fileStat = await stat4(fullPath);
71034
+ if (fileStat.isFile()) {
71035
+ const content = await readFile9(fullPath, "utf8");
71036
+ lines.push(`
70949
71037
  --- ${manifest} ---
70950
- ${decoded.slice(0, 2e3)}`);
70951
- }
71038
+ ${content.slice(0, 3e3)}`);
71039
+ } else if (fileStat.isDirectory()) {
71040
+ const children = await readdir6(fullPath);
71041
+ lines.push(`
71042
+ --- ${manifest}/ ---
71043
+ ${children.join(", ")}`);
70952
71044
  }
70953
71045
  } catch {
70954
71046
  }
70955
71047
  }
71048
+ const srcDirs = rootDirs.filter(
71049
+ (d) => ["src", "lib", "app", "packages", "crates", "cmd", "internal"].includes(d)
71050
+ );
71051
+ for (const srcDir of srcDirs) {
71052
+ try {
71053
+ const srcEntries = await readdir6(join16(repoDir, srcDir), { withFileTypes: true });
71054
+ const srcFiles = srcEntries.filter((e) => e.isFile()).map((e) => e.name);
71055
+ const srcSubDirs = srcEntries.filter((e) => e.isDirectory()).map((e) => e.name);
71056
+ lines.push(`
71057
+ --- ${srcDir}/ ---`);
71058
+ if (srcSubDirs.length) lines.push(` Directories: ${srcSubDirs.join(", ")}`);
71059
+ if (srcFiles.length) lines.push(` Files: ${srcFiles.slice(0, 30).join(", ")}`);
71060
+ } catch {
71061
+ }
71062
+ }
71063
+ const readmeCandidates = ["README.md", "README.rst", "README.txt", "README"];
71064
+ for (const readme of readmeCandidates) {
71065
+ try {
71066
+ const content = await readFile9(join16(repoDir, readme), "utf8");
71067
+ lines.push(`
71068
+ --- ${readme} (excerpt) ---
71069
+ ${content.slice(0, 1500)}`);
71070
+ break;
71071
+ } catch {
71072
+ }
71073
+ }
70956
71074
  } catch {
71075
+ lines.push("Filesystem scan failed; using minimal info.");
70957
71076
  }
70958
71077
  lines.push(
70959
- "\nBased on the above repository structure, propose roles that match the project's actual technology stack."
71078
+ "\nBased on the above repository structure and contents, propose roles that match the project's actual technology stack and architecture."
70960
71079
  );
70961
71080
  return lines.join("\n");
70962
71081
  }
@@ -71079,17 +71198,19 @@ function createSquadToolExecutor(config2) {
71079
71198
  }
71080
71199
  };
71081
71200
  }
71082
- var hireSquadSchema, squadIdSchema, delegateToSquadSchema, squadToolDefinitions;
71201
+ var execAsync8, hireSquadSchema, squadIdSchema, delegateToSquadSchema, squadToolDefinitions;
71083
71202
  var init_squad2 = __esm({
71084
71203
  "packages/daemon/src/orchestrator/tools/squad.ts"() {
71085
71204
  "use strict";
71086
71205
  init_dist();
71206
+ init_paths();
71087
71207
  init_zod();
71088
71208
  init_instances2();
71089
71209
  init_runner();
71090
71210
  init_hiring();
71091
71211
  init_manager2();
71092
71212
  init_store2();
71213
+ execAsync8 = promisify8(exec8);
71093
71214
  hireSquadSchema = external_exports.object({
71094
71215
  repoUrl: external_exports.string().trim().min(1)
71095
71216
  });
@@ -85259,7 +85380,7 @@ var init_index = __esm({
85259
85380
  init_dist();
85260
85381
  init_paths();
85261
85382
  init_data_dir();
85262
- import { readFile as readFile9, writeFile as writeFile8 } from "node:fs/promises";
85383
+ import { readFile as readFile10, writeFile as writeFile8 } from "node:fs/promises";
85263
85384
  import { stdin as input, stdout as output } from "node:process";
85264
85385
  import { createInterface } from "node:readline/promises";
85265
85386
  function printHelp() {
@@ -85274,7 +85395,7 @@ Usage:
85274
85395
  }
85275
85396
  async function readExistingConfig() {
85276
85397
  try {
85277
- const existingConfig = await readFile9(CONFIG_PATH, "utf8");
85398
+ const existingConfig = await readFile10(CONFIG_PATH, "utf8");
85278
85399
  const parsedConfig = JSON.parse(existingConfig);
85279
85400
  if (parsedConfig === null || typeof parsedConfig !== "object" || Array.isArray(parsedConfig)) {
85280
85401
  throw new Error(`Invalid config file at ${CONFIG_PATH}: expected a JSON object`);