heyio 4.0.7 → 4.1.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.0.7";
83
+ APP_VERSION = "4.1.0";
84
84
  API_PORT = 7777;
85
85
  API_HOST = "0.0.0.0";
86
86
  DEFAULT_MODEL = "gpt-4o";
@@ -92,6 +92,11 @@ var init_constants = __esm({
92
92
  SQUAD_CREATED: "squad.created",
93
93
  SQUAD_DELETED: "squad.deleted",
94
94
  SQUAD_UPDATED: "squad.updated",
95
+ INSTANCE_CREATED: "instance.created",
96
+ INSTANCE_STARTED: "instance.started",
97
+ INSTANCE_COMPLETED: "instance.completed",
98
+ INSTANCE_FAILED: "instance.failed",
99
+ INSTANCE_CANCELLED: "instance.cancelled",
95
100
  OBJECTIVE_STARTED: "objective.started",
96
101
  OBJECTIVE_COMPLETED: "objective.completed",
97
102
  OBJECTIVE_FAILED: "objective.failed",
@@ -2085,6 +2090,27 @@ var init_db = __esm({
2085
2090
  "ALTER TABLE token_usage ADD COLUMN premium_request_cost REAL",
2086
2091
  "ALTER TABLE token_usage ADD COLUMN token_unit_cost REAL"
2087
2092
  ]
2093
+ },
2094
+ {
2095
+ version: 3,
2096
+ name: "add-squad-instances",
2097
+ statements: [
2098
+ `CREATE TABLE IF NOT EXISTS squad_instances (
2099
+ id TEXT PRIMARY KEY,
2100
+ squad_id TEXT NOT NULL REFERENCES squads(id) ON DELETE CASCADE,
2101
+ objective_id TEXT REFERENCES objectives(id) ON DELETE SET NULL,
2102
+ status TEXT NOT NULL DEFAULT 'queued',
2103
+ branch TEXT,
2104
+ worktree_path TEXT,
2105
+ created_at TEXT NOT NULL,
2106
+ started_at TEXT,
2107
+ completed_at TEXT,
2108
+ error TEXT
2109
+ )`,
2110
+ "CREATE INDEX IF NOT EXISTS idx_squad_instances_squad_status ON squad_instances(squad_id, status)",
2111
+ "CREATE INDEX IF NOT EXISTS idx_squad_instances_status ON squad_instances(status)",
2112
+ "CREATE INDEX IF NOT EXISTS idx_squad_instances_objective_id ON squad_instances(objective_id)"
2113
+ ]
2088
2114
  }
2089
2115
  ];
2090
2116
  client = null;
@@ -11852,87 +11878,6 @@ async function recordUsage(data, db) {
11852
11878
  });
11853
11879
  return usage;
11854
11880
  }
11855
- async function getUsageSummary(params = {}, db) {
11856
- const database = db ?? await getDatabase();
11857
- const filter = buildUsageFilter(params);
11858
- const [totalsResult, bySquadResult, byAgentResult, byModelResult, daily] = await Promise.all([
11859
- database.execute({
11860
- sql: `SELECT COALESCE(SUM(input_tokens), 0) AS total_input_tokens,
11861
- COALESCE(SUM(output_tokens), 0) AS total_output_tokens,
11862
- COALESCE(SUM(cost), 0) AS total_cost
11863
- FROM token_usage ${filter.clause}`,
11864
- args: filter.args
11865
- }),
11866
- database.execute({
11867
- sql: `SELECT tu.squad_id,
11868
- COALESCE(s.name, tu.squad_id, 'Unknown squad') AS squad_name,
11869
- COALESCE(SUM(tu.input_tokens), 0) AS input_tokens,
11870
- COALESCE(SUM(tu.output_tokens), 0) AS output_tokens,
11871
- COALESCE(SUM(tu.cost), 0) AS cost
11872
- FROM token_usage tu
11873
- LEFT JOIN squads s ON s.id = tu.squad_id
11874
- ${filter.clause.replaceAll("created_at", "tu.created_at").replaceAll("squad_id", "tu.squad_id").replaceAll("agent_id", "tu.agent_id").replaceAll("model", "tu.model")}
11875
- AND tu.squad_id IS NOT NULL
11876
- GROUP BY tu.squad_id, squad_name
11877
- ORDER BY cost DESC, input_tokens DESC`,
11878
- args: filter.args
11879
- }),
11880
- database.execute({
11881
- sql: `SELECT tu.agent_id,
11882
- COALESCE(sm.name, tu.agent_id, 'Unknown agent') AS agent_name,
11883
- COALESCE(tu.squad_id, '') AS squad_id,
11884
- COALESCE(SUM(tu.input_tokens), 0) AS input_tokens,
11885
- COALESCE(SUM(tu.output_tokens), 0) AS output_tokens,
11886
- COALESCE(SUM(tu.cost), 0) AS cost
11887
- FROM token_usage tu
11888
- LEFT JOIN squad_members sm ON sm.id = tu.agent_id
11889
- ${filter.clause.replaceAll("created_at", "tu.created_at").replaceAll("squad_id", "tu.squad_id").replaceAll("agent_id", "tu.agent_id").replaceAll("model", "tu.model")}
11890
- AND tu.agent_id IS NOT NULL
11891
- GROUP BY tu.agent_id, agent_name, tu.squad_id
11892
- ORDER BY cost DESC, input_tokens DESC`,
11893
- args: filter.args
11894
- }),
11895
- database.execute({
11896
- sql: `SELECT model,
11897
- COALESCE(SUM(input_tokens), 0) AS input_tokens,
11898
- COALESCE(SUM(output_tokens), 0) AS output_tokens,
11899
- COALESCE(SUM(cost), 0) AS cost
11900
- FROM token_usage ${filter.clause}
11901
- GROUP BY model
11902
- ORDER BY cost DESC, input_tokens DESC`,
11903
- args: filter.args
11904
- }),
11905
- getDailyUsage(params.startDate ?? null, params.endDate ?? null, params, database)
11906
- ]);
11907
- const totals = totalsResult.rows[0];
11908
- return {
11909
- totalInputTokens: totals ? asNumber(totals.total_input_tokens) : 0,
11910
- totalOutputTokens: totals ? asNumber(totals.total_output_tokens) : 0,
11911
- totalCost: totals ? asNumber(totals.total_cost) : 0,
11912
- bySquad: bySquadResult.rows.map((row) => ({
11913
- squadId: asString(row.squad_id),
11914
- squadName: asString(row.squad_name),
11915
- inputTokens: asNumber(row.input_tokens),
11916
- outputTokens: asNumber(row.output_tokens),
11917
- cost: asNumber(row.cost)
11918
- })),
11919
- byAgent: byAgentResult.rows.map((row) => ({
11920
- agentId: asString(row.agent_id),
11921
- agentName: asString(row.agent_name),
11922
- squadId: asString(row.squad_id),
11923
- inputTokens: asNumber(row.input_tokens),
11924
- outputTokens: asNumber(row.output_tokens),
11925
- cost: asNumber(row.cost)
11926
- })),
11927
- byModel: byModelResult.rows.map((row) => ({
11928
- model: asString(row.model),
11929
- inputTokens: asNumber(row.input_tokens),
11930
- outputTokens: asNumber(row.output_tokens),
11931
- cost: asNumber(row.cost)
11932
- })),
11933
- daily
11934
- };
11935
- }
11936
11881
  async function getDailyUsage(startDate, endDate, params = {}, db) {
11937
11882
  const database = db ?? await getDatabase();
11938
11883
  const filter = buildUsageFilter({
@@ -11985,6 +11930,51 @@ function buildUsageFilter(params) {
11985
11930
  args
11986
11931
  };
11987
11932
  }
11933
+ async function getUsageRecords(params = {}, db) {
11934
+ const database = db ?? await getDatabase();
11935
+ const filter = buildUsageFilter(params);
11936
+ const aliasedClause = filter.clause.replaceAll("created_at", "tu.created_at").replaceAll("squad_id", "tu.squad_id").replaceAll("agent_id", "tu.agent_id").replaceAll("model", "tu.model");
11937
+ const result = await database.execute({
11938
+ sql: `SELECT tu.model, tu.input_tokens, tu.output_tokens, tu.cost,
11939
+ tu.created_at, tu.squad_id, tu.agent_id,
11940
+ COALESCE(s.name, '') AS squad_name,
11941
+ COALESCE(sm.name, '') AS agent_name
11942
+ FROM token_usage tu
11943
+ LEFT JOIN squads s ON s.id = tu.squad_id
11944
+ LEFT JOIN squad_members sm ON sm.id = tu.agent_id
11945
+ ${aliasedClause}
11946
+ ORDER BY tu.created_at DESC
11947
+ LIMIT 10000`,
11948
+ args: filter.args
11949
+ });
11950
+ const records = result.rows.map((row) => ({
11951
+ model: asString(row.model),
11952
+ inputTokens: asNumber(row.input_tokens),
11953
+ outputTokens: asNumber(row.output_tokens),
11954
+ estimatedCostUsd: asNumber(row.cost),
11955
+ timestamp: asString(row.created_at),
11956
+ squadId: asNullableString(row.squad_id),
11957
+ squadName: asNullableString(row.squad_name) || null,
11958
+ agentRole: asNullableString(row.agent_name) || null
11959
+ }));
11960
+ let totalInputTokens = 0;
11961
+ let totalOutputTokens = 0;
11962
+ let totalCostUsd = 0;
11963
+ for (const r of records) {
11964
+ totalInputTokens += r.inputTokens;
11965
+ totalOutputTokens += r.outputTokens;
11966
+ totalCostUsd += r.estimatedCostUsd ?? 0;
11967
+ }
11968
+ return {
11969
+ records,
11970
+ totals: {
11971
+ totalInputTokens,
11972
+ totalOutputTokens,
11973
+ totalCostUsd,
11974
+ callCount: records.length
11975
+ }
11976
+ };
11977
+ }
11988
11978
  var init_token_usage = __esm({
11989
11979
  "packages/daemon/src/store/token-usage.ts"() {
11990
11980
  "use strict";
@@ -12292,6 +12282,141 @@ var init_objectives = __esm({
12292
12282
  }
12293
12283
  });
12294
12284
 
12285
+ // packages/daemon/src/store/instances.ts
12286
+ async function createInstance(input2, db) {
12287
+ const database = db ?? await getDatabase();
12288
+ const instance = {
12289
+ id: generateId(),
12290
+ squadId: input2.squadId,
12291
+ objectiveId: input2.objectiveId ?? null,
12292
+ status: "queued",
12293
+ branch: input2.branch ?? null,
12294
+ worktreePath: null,
12295
+ createdAt: nowIso(),
12296
+ startedAt: null,
12297
+ completedAt: null,
12298
+ error: null
12299
+ };
12300
+ await database.execute({
12301
+ sql: `INSERT INTO squad_instances (id, squad_id, objective_id, status, branch, worktree_path, created_at, started_at, completed_at, error)
12302
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
12303
+ args: [
12304
+ instance.id,
12305
+ instance.squadId,
12306
+ instance.objectiveId,
12307
+ instance.status,
12308
+ instance.branch,
12309
+ instance.worktreePath,
12310
+ instance.createdAt,
12311
+ instance.startedAt,
12312
+ instance.completedAt,
12313
+ instance.error
12314
+ ]
12315
+ });
12316
+ return instance;
12317
+ }
12318
+ async function getInstance(instanceId, db) {
12319
+ const database = db ?? await getDatabase();
12320
+ const result = await database.execute({
12321
+ sql: "SELECT * FROM squad_instances WHERE id = ?",
12322
+ args: [instanceId]
12323
+ });
12324
+ return result.rows[0] ? mapRow(result.rows[0]) : null;
12325
+ }
12326
+ async function listInstancesBySquad(squadId, db) {
12327
+ const database = db ?? await getDatabase();
12328
+ const result = await database.execute({
12329
+ sql: "SELECT * FROM squad_instances WHERE squad_id = ? ORDER BY created_at DESC",
12330
+ args: [squadId]
12331
+ });
12332
+ return result.rows.map(mapRow);
12333
+ }
12334
+ async function listActiveInstances(squadId, db) {
12335
+ const database = db ?? await getDatabase();
12336
+ const result = await database.execute({
12337
+ sql: "SELECT * FROM squad_instances WHERE squad_id = ? AND status IN ('queued', 'running', 'completing') ORDER BY created_at ASC",
12338
+ args: [squadId]
12339
+ });
12340
+ return result.rows.map(mapRow);
12341
+ }
12342
+ async function countRunningInstances(squadId, db) {
12343
+ const database = db ?? await getDatabase();
12344
+ const result = await database.execute({
12345
+ sql: "SELECT COUNT(*) AS cnt FROM squad_instances WHERE squad_id = ? AND status = 'running'",
12346
+ args: [squadId]
12347
+ });
12348
+ return result.rows[0] ? asNumber(result.rows[0].cnt) : 0;
12349
+ }
12350
+ async function getNextQueued(squadId, db) {
12351
+ const database = db ?? await getDatabase();
12352
+ const result = await database.execute({
12353
+ sql: "SELECT * FROM squad_instances WHERE squad_id = ? AND status = 'queued' ORDER BY created_at ASC LIMIT 1",
12354
+ args: [squadId]
12355
+ });
12356
+ return result.rows[0] ? mapRow(result.rows[0]) : null;
12357
+ }
12358
+ async function updateInstanceStatus(instanceId, status, updates, db) {
12359
+ const database = db ?? await getDatabase();
12360
+ const now = nowIso();
12361
+ const sets = ["status = ?"];
12362
+ const args = [status];
12363
+ if (status === "running") {
12364
+ sets.push("started_at = ?");
12365
+ args.push(now);
12366
+ }
12367
+ if (status === "completed" || status === "failed" || status === "cancelled") {
12368
+ sets.push("completed_at = ?");
12369
+ args.push(now);
12370
+ }
12371
+ if (updates?.branch) {
12372
+ sets.push("branch = ?");
12373
+ args.push(updates.branch);
12374
+ }
12375
+ if (updates?.worktreePath) {
12376
+ sets.push("worktree_path = ?");
12377
+ args.push(updates.worktreePath);
12378
+ }
12379
+ if (updates?.error) {
12380
+ sets.push("error = ?");
12381
+ args.push(updates.error);
12382
+ }
12383
+ args.push(instanceId);
12384
+ await database.execute({
12385
+ sql: `UPDATE squad_instances SET ${sets.join(", ")} WHERE id = ?`,
12386
+ args
12387
+ });
12388
+ return getInstance(instanceId, database);
12389
+ }
12390
+ async function findStaleInstances(db) {
12391
+ const database = db ?? await getDatabase();
12392
+ const cutoff = new Date(Date.now() - 6 * 60 * 60 * 1e3).toISOString();
12393
+ const result = await database.execute({
12394
+ sql: "SELECT * FROM squad_instances WHERE status = 'running' AND started_at < ?",
12395
+ args: [cutoff]
12396
+ });
12397
+ return result.rows.map(mapRow);
12398
+ }
12399
+ function mapRow(row) {
12400
+ return {
12401
+ id: asString(row.id),
12402
+ squadId: asString(row.squad_id),
12403
+ objectiveId: asNullableString(row.objective_id),
12404
+ status: asString(row.status),
12405
+ branch: asNullableString(row.branch),
12406
+ worktreePath: asNullableString(row.worktree_path),
12407
+ createdAt: asString(row.created_at),
12408
+ startedAt: asNullableString(row.started_at),
12409
+ completedAt: asNullableString(row.completed_at),
12410
+ error: asNullableString(row.error)
12411
+ };
12412
+ }
12413
+ var init_instances = __esm({
12414
+ "packages/daemon/src/store/instances.ts"() {
12415
+ "use strict";
12416
+ init_db();
12417
+ }
12418
+ });
12419
+
12295
12420
  // packages/daemon/src/store/index.ts
12296
12421
  var init_store2 = __esm({
12297
12422
  "packages/daemon/src/store/index.ts"() {
@@ -12305,6 +12430,7 @@ var init_store2 = __esm({
12305
12430
  init_activity();
12306
12431
  init_agent_history();
12307
12432
  init_objectives();
12433
+ init_instances();
12308
12434
  }
12309
12435
  });
12310
12436
 
@@ -31174,7 +31300,7 @@ var require_view = __commonJS({
31174
31300
  var dirname9 = path.dirname;
31175
31301
  var basename6 = path.basename;
31176
31302
  var extname4 = path.extname;
31177
- var join15 = path.join;
31303
+ var join16 = path.join;
31178
31304
  var resolve5 = path.resolve;
31179
31305
  module2.exports = View;
31180
31306
  function View(name, options2) {
@@ -31236,12 +31362,12 @@ var require_view = __commonJS({
31236
31362
  };
31237
31363
  View.prototype.resolve = function resolve6(dir, file2) {
31238
31364
  var ext = this.ext;
31239
- var path2 = join15(dir, file2);
31365
+ var path2 = join16(dir, file2);
31240
31366
  var stat4 = tryStat(path2);
31241
31367
  if (stat4 && stat4.isFile()) {
31242
31368
  return path2;
31243
31369
  }
31244
- path2 = join15(dir, basename6(file2, ext), "index" + ext);
31370
+ path2 = join16(dir, basename6(file2, ext), "index" + ext);
31245
31371
  stat4 = tryStat(path2);
31246
31372
  if (stat4 && stat4.isFile()) {
31247
31373
  return path2;
@@ -34946,7 +35072,7 @@ var require_send = __commonJS({
34946
35072
  var Stream = __require("stream");
34947
35073
  var util = __require("util");
34948
35074
  var extname4 = path.extname;
34949
- var join15 = path.join;
35075
+ var join16 = path.join;
34950
35076
  var normalize = path.normalize;
34951
35077
  var resolve5 = path.resolve;
34952
35078
  var sep = path.sep;
@@ -35118,7 +35244,7 @@ var require_send = __commonJS({
35118
35244
  return res;
35119
35245
  }
35120
35246
  parts = path2.split(sep);
35121
- path2 = normalize(join15(root, path2));
35247
+ path2 = normalize(join16(root, path2));
35122
35248
  } else {
35123
35249
  if (UP_PATH_REGEXP.test(path2)) {
35124
35250
  debug('malicious path "%s"', path2);
@@ -35251,7 +35377,7 @@ var require_send = __commonJS({
35251
35377
  if (err) return self.onStatError(err);
35252
35378
  return self.error(404);
35253
35379
  }
35254
- var p = join15(path2, self._index[i]);
35380
+ var p = join16(path2, self._index[i]);
35255
35381
  debug('stat "%s"', p);
35256
35382
  fs.stat(p, function(err2, stat4) {
35257
35383
  if (err2) return next(err2);
@@ -51511,6 +51637,10 @@ var init_zod = __esm({
51511
51637
  });
51512
51638
 
51513
51639
  // packages/daemon/src/config.ts
51640
+ var config_exports = {};
51641
+ __export(config_exports, {
51642
+ loadConfig: () => loadConfig
51643
+ });
51514
51644
  import { existsSync, readFileSync } from "node:fs";
51515
51645
  function parseConfigFile() {
51516
51646
  if (!existsSync(CONFIG_PATH)) {
@@ -51593,7 +51723,8 @@ var init_config = __esm({
51593
51723
  supabaseUrl: external_exports.string().trim().min(1).nullable().default(null),
51594
51724
  supabaseAnonKey: external_exports.string().trim().min(1).nullable().default(null),
51595
51725
  sessionResetThreshold: external_exports.coerce.number().int().positive().default(SESSION_RESET_THRESHOLD),
51596
- pricingRefreshHours: external_exports.coerce.number().positive().default(24)
51726
+ pricingRefreshHours: external_exports.coerce.number().positive().default(24),
51727
+ maxInstancesPerSquad: external_exports.coerce.number().int().positive().default(3)
51597
51728
  });
51598
51729
  }
51599
51730
  });
@@ -51717,6 +51848,36 @@ var init_settings = __esm({
51717
51848
  // packages/daemon/src/api/routes/skills.ts
51718
51849
  import { mkdir as mkdir3, readFile as readFile2, rm, writeFile as writeFile2 } from "node:fs/promises";
51719
51850
  import { basename, extname, join as join3 } from "node:path";
51851
+ async function getSkillContent(skill) {
51852
+ if (!skill.entryFile) return "";
51853
+ const filePath = join3(SKILLS_DIR, skill.directory, skill.entryFile);
51854
+ try {
51855
+ return await readFile2(filePath, "utf8");
51856
+ } catch {
51857
+ return "";
51858
+ }
51859
+ }
51860
+ function extractDescription(content) {
51861
+ const lines = content.split("\n").filter((l) => l.trim() && !l.startsWith("#"));
51862
+ return lines[0]?.trim().slice(0, 200) ?? "";
51863
+ }
51864
+ function extractPreview(content) {
51865
+ return content.slice(0, 300);
51866
+ }
51867
+ async function buildSkillSummaries(skills) {
51868
+ return Promise.all(
51869
+ skills.map(async (skill) => {
51870
+ const content = await getSkillContent(skill);
51871
+ return {
51872
+ name: skill.slug,
51873
+ activatedForOrchestrator: true,
51874
+ preview: extractPreview(content),
51875
+ description: extractDescription(content),
51876
+ filePath: skill.entryFile ? join3(SKILLS_DIR, skill.directory, skill.entryFile) : join3(SKILLS_DIR, skill.directory)
51877
+ };
51878
+ })
51879
+ );
51880
+ }
51720
51881
  async function installSkill(request) {
51721
51882
  await mkdir3(SKILLS_DIR, { recursive: true });
51722
51883
  const installedSkills = await readInstalledSkills();
@@ -51774,6 +51935,16 @@ async function removeSkill(skillId) {
51774
51935
  await writeSkillsLock(installedSkills.filter((entry) => entry.id !== skillId));
51775
51936
  return true;
51776
51937
  }
51938
+ async function removeSkillBySlug(slug) {
51939
+ const installedSkills = await readInstalledSkills();
51940
+ const skill = installedSkills.find((entry) => entry.slug === slug);
51941
+ if (!skill) {
51942
+ return false;
51943
+ }
51944
+ await rm(skill.directory, { recursive: true, force: true });
51945
+ await writeSkillsLock(installedSkills.filter((entry) => entry.slug !== slug));
51946
+ return true;
51947
+ }
51777
51948
  async function readInstalledSkills() {
51778
51949
  try {
51779
51950
  const raw = await readFile2(SKILLS_LOCK_PATH, "utf8");
@@ -51943,7 +52114,9 @@ var init_skills = __esm({
51943
52114
  router6 = (0, import_express6.Router)();
51944
52115
  router6.get("/api/skills", async (_req, res) => {
51945
52116
  try {
51946
- res.status(200).json(await readInstalledSkills());
52117
+ const skills = await readInstalledSkills();
52118
+ const summaries = await buildSkillSummaries(skills);
52119
+ res.status(200).json({ skills: summaries });
51947
52120
  } catch (error51) {
51948
52121
  res.status(500).json({
51949
52122
  error: "Failed to list skills",
@@ -51951,6 +52124,71 @@ var init_skills = __esm({
51951
52124
  });
51952
52125
  }
51953
52126
  });
52127
+ router6.get("/api/skills/discover", async (req, res) => {
52128
+ try {
52129
+ const source = typeof req.query.source === "string" ? req.query.source : "";
52130
+ const query = typeof req.query.q === "string" ? req.query.q.trim() : "";
52131
+ if (source === "skillssh") {
52132
+ const skills = await discoverSkillsSh(query);
52133
+ res.status(200).json({ skills });
52134
+ } else if (source === "awesome-copilot") {
52135
+ const skills = await discoverAwesomeCopilot(query);
52136
+ res.status(200).json({ skills });
52137
+ } else {
52138
+ res.status(400).json({ error: `Unknown source: ${source}` });
52139
+ }
52140
+ } catch (error51) {
52141
+ res.status(500).json({
52142
+ error: "Failed to discover skills",
52143
+ details: error51 instanceof Error ? error51.message : "Unknown error"
52144
+ });
52145
+ }
52146
+ });
52147
+ router6.get("/api/skills/:name", async (req, res) => {
52148
+ try {
52149
+ const skills = await readInstalledSkills();
52150
+ const skill = skills.find((s) => s.slug === req.params.name);
52151
+ if (!skill) {
52152
+ res.status(404).json({ error: "Skill not found" });
52153
+ return;
52154
+ }
52155
+ const content = await getSkillContent(skill);
52156
+ const filePath = skill.entryFile ? join3(SKILLS_DIR, skill.directory, skill.entryFile) : join3(SKILLS_DIR, skill.directory);
52157
+ res.status(200).json({ name: skill.slug, content, filePath });
52158
+ } catch (error51) {
52159
+ res.status(500).json({
52160
+ error: "Failed to get skill",
52161
+ details: error51 instanceof Error ? error51.message : "Unknown error"
52162
+ });
52163
+ }
52164
+ });
52165
+ router6.put("/api/skills/:name", async (req, res) => {
52166
+ try {
52167
+ const skills = await readInstalledSkills();
52168
+ const skill = skills.find((s) => s.slug === req.params.name);
52169
+ if (!skill) {
52170
+ res.status(404).json({ error: "Skill not found" });
52171
+ return;
52172
+ }
52173
+ if (!skill.entryFile) {
52174
+ res.status(400).json({ error: "Skill has no entry file to update" });
52175
+ return;
52176
+ }
52177
+ const { content } = req.body;
52178
+ if (typeof content !== "string") {
52179
+ res.status(400).json({ error: "content is required" });
52180
+ return;
52181
+ }
52182
+ const filePath = join3(SKILLS_DIR, skill.directory, skill.entryFile);
52183
+ await writeFile2(filePath, content, "utf8");
52184
+ res.status(200).json({ name: skill.slug, content, filePath });
52185
+ } catch (error51) {
52186
+ res.status(500).json({
52187
+ error: "Failed to update skill",
52188
+ details: error51 instanceof Error ? error51.message : "Unknown error"
52189
+ });
52190
+ }
52191
+ });
51954
52192
  router6.post("/api/skills/install", async (req, res) => {
51955
52193
  try {
51956
52194
  const body = req.body;
@@ -51975,10 +52213,14 @@ var init_skills = __esm({
51975
52213
  });
51976
52214
  router6.delete("/api/skills/:id", async (req, res) => {
51977
52215
  try {
51978
- const removed = await removeSkill(req.params.id);
52216
+ const identifier = req.params.id;
52217
+ const removed = await removeSkill(identifier);
51979
52218
  if (!removed) {
51980
- res.status(404).json({ error: "Skill not found" });
51981
- return;
52219
+ const removedBySlug = await removeSkillBySlug(identifier);
52220
+ if (!removedBySlug) {
52221
+ res.status(404).json({ error: "Skill not found" });
52222
+ return;
52223
+ }
51982
52224
  }
51983
52225
  res.status(200).json({ deleted: true });
51984
52226
  } catch (error51) {
@@ -51988,31 +52230,311 @@ var init_skills = __esm({
51988
52230
  });
51989
52231
  }
51990
52232
  });
51991
- router6.get("/api/skills/discover", async (req, res) => {
51992
- try {
51993
- const source = typeof req.query.source === "string" ? req.query.source : "";
51994
- const query = typeof req.query.q === "string" ? req.query.q.trim() : "";
51995
- if (source === "skillssh") {
51996
- const skills = await discoverSkillsSh(query);
51997
- res.status(200).json(skills);
51998
- } else if (source === "awesome-copilot") {
51999
- const skills = await discoverAwesomeCopilot(query);
52000
- res.status(200).json(skills);
52001
- } else {
52002
- res.status(400).json({ error: `Unknown source: ${source}` });
52003
- }
52004
- } catch (error51) {
52005
- res.status(500).json({
52006
- error: "Failed to discover skills",
52007
- details: error51 instanceof Error ? error51.message : "Unknown error"
52008
- });
52009
- }
52010
- });
52011
52233
  awesomeCopilotCache = null;
52012
52234
  AWESOME_COPILOT_CACHE_TTL = 60 * 60 * 1e3;
52013
52235
  }
52014
52236
  });
52015
52237
 
52238
+ // packages/daemon/src/execution/worktree.ts
52239
+ import { exec } from "node:child_process";
52240
+ import { mkdir as mkdir4, rm as rm2 } from "node:fs/promises";
52241
+ import { join as join4 } from "node:path";
52242
+ import { promisify } from "node:util";
52243
+ function sanitizeBranchName(branchName) {
52244
+ return branchName.replace(/[^a-zA-Z0-9._-]+/g, "-");
52245
+ }
52246
+ async function runGit(command, cwd) {
52247
+ const { stdout } = await execAsync(command, {
52248
+ cwd,
52249
+ ...EXEC_OPTIONS
52250
+ });
52251
+ return stdout.trim();
52252
+ }
52253
+ async function branchExists(repoPath, branchName) {
52254
+ const output2 = await runGit(`git branch --list ${JSON.stringify(branchName)}`, repoPath);
52255
+ return output2.length > 0;
52256
+ }
52257
+ function getWorktreePath(repoPath, branchName) {
52258
+ return join4(repoPath, ".worktrees", sanitizeBranchName(branchName));
52259
+ }
52260
+ async function listWorktrees(repoPath) {
52261
+ const output2 = await runGit("git worktree list --porcelain", repoPath);
52262
+ if (!output2) {
52263
+ return [];
52264
+ }
52265
+ const blocks = output2.split(/\r?\n\r?\n/).filter(Boolean);
52266
+ return blocks.map((block) => {
52267
+ const info = {
52268
+ path: "",
52269
+ branch: null,
52270
+ head: null,
52271
+ bare: false,
52272
+ detached: false,
52273
+ locked: false,
52274
+ prunable: false
52275
+ };
52276
+ for (const line of block.split(/\r?\n/)) {
52277
+ const [key, ...rest] = line.split(" ");
52278
+ const value = rest.join(" ").trim();
52279
+ switch (key) {
52280
+ case "worktree":
52281
+ info.path = value;
52282
+ break;
52283
+ case "branch":
52284
+ info.branch = value.replace(/^refs\/heads\//, "");
52285
+ break;
52286
+ case "HEAD":
52287
+ info.head = value;
52288
+ break;
52289
+ case "bare":
52290
+ info.bare = true;
52291
+ break;
52292
+ case "detached":
52293
+ info.detached = true;
52294
+ break;
52295
+ case "locked":
52296
+ info.locked = true;
52297
+ break;
52298
+ case "prunable":
52299
+ info.prunable = true;
52300
+ break;
52301
+ }
52302
+ }
52303
+ return info;
52304
+ });
52305
+ }
52306
+ async function createWorktree(repoPath, branchName, baseBranch) {
52307
+ const worktreePath = getWorktreePath(repoPath, branchName);
52308
+ await mkdir4(join4(repoPath, ".worktrees"), { recursive: true });
52309
+ const existing = (await listWorktrees(repoPath)).find(
52310
+ (worktree) => worktree.path === worktreePath
52311
+ );
52312
+ if (existing) {
52313
+ return worktreePath;
52314
+ }
52315
+ const startPoint = baseBranch?.trim();
52316
+ const createNewBranch = !await branchExists(repoPath, branchName);
52317
+ const command = createNewBranch ? `git worktree add ${JSON.stringify(worktreePath)} -b ${JSON.stringify(branchName)}${startPoint ? ` ${JSON.stringify(startPoint)}` : ""}` : `git worktree add ${JSON.stringify(worktreePath)} ${JSON.stringify(branchName)}`;
52318
+ try {
52319
+ await runGit(command, repoPath);
52320
+ return worktreePath;
52321
+ } catch (error51) {
52322
+ const message2 = error51 instanceof Error ? error51.message : String(error51);
52323
+ if (/already exists/i.test(message2)) {
52324
+ return worktreePath;
52325
+ }
52326
+ throw new Error(`Failed to create worktree for ${branchName}: ${message2}`);
52327
+ }
52328
+ }
52329
+ async function cleanupWorktree(worktreePath) {
52330
+ const parentRepoPath = join4(worktreePath, "..", "..");
52331
+ try {
52332
+ await runGit(`git worktree remove ${JSON.stringify(worktreePath)}`, parentRepoPath);
52333
+ } catch (error51) {
52334
+ const message2 = error51 instanceof Error ? error51.message : String(error51);
52335
+ if (!/not a working tree/i.test(message2) && !/does not exist/i.test(message2)) {
52336
+ await runGit(
52337
+ `git worktree remove --force ${JSON.stringify(worktreePath)}`,
52338
+ parentRepoPath
52339
+ ).catch(() => void 0);
52340
+ }
52341
+ }
52342
+ await runGit("git worktree prune", parentRepoPath).catch(() => void 0);
52343
+ await rm2(worktreePath, { recursive: true, force: true }).catch(() => void 0);
52344
+ }
52345
+ async function pushBranch(worktreePath, remote = DEFAULT_REMOTE) {
52346
+ const branchName = await runGit("git branch --show-current", worktreePath);
52347
+ if (!branchName) {
52348
+ throw new Error(`Unable to determine branch for worktree ${worktreePath}`);
52349
+ }
52350
+ const output2 = await runGit(
52351
+ `git push --set-upstream ${JSON.stringify(remote)} ${JSON.stringify(branchName)}`,
52352
+ worktreePath
52353
+ );
52354
+ return { branchName, remote, output: output2 };
52355
+ }
52356
+ var execAsync, DEFAULT_REMOTE, EXEC_OPTIONS;
52357
+ var init_worktree = __esm({
52358
+ "packages/daemon/src/execution/worktree.ts"() {
52359
+ "use strict";
52360
+ execAsync = promisify(exec);
52361
+ DEFAULT_REMOTE = "origin";
52362
+ EXEC_OPTIONS = { maxBuffer: 10 * 1024 * 1024 };
52363
+ }
52364
+ });
52365
+
52366
+ // packages/daemon/src/execution/instances.ts
52367
+ import { mkdir as mkdir5, readdir, rename, rm as rm3 } from "node:fs/promises";
52368
+ import { join as join5 } from "node:path";
52369
+ async function spawnInstance(input2) {
52370
+ const config2 = loadConfig();
52371
+ const instance = await createInstance(input2);
52372
+ emitInstanceEvent(EVENT_NAMES.INSTANCE_CREATED, instance);
52373
+ await cleanStaleInstances();
52374
+ const running = await countRunningInstances(input2.squadId);
52375
+ if (running < config2.maxInstancesPerSquad) {
52376
+ return { instance, queued: false };
52377
+ }
52378
+ return { instance, queued: true };
52379
+ }
52380
+ async function startInstance(instanceId, repoPath, baseBranch) {
52381
+ const branchName = `squad/instance-${instanceId.slice(0, 8)}`;
52382
+ try {
52383
+ const { exec: exec8 } = await import("node:child_process");
52384
+ const { promisify: promisify8 } = await import("node:util");
52385
+ const execAsync8 = promisify8(exec8);
52386
+ await execAsync8(`git fetch origin && git pull origin ${baseBranch}`, {
52387
+ cwd: repoPath,
52388
+ maxBuffer: 10 * 1024 * 1024
52389
+ });
52390
+ } catch {
52391
+ }
52392
+ const worktreePath = await createWorktree(repoPath, branchName, baseBranch);
52393
+ const updated = await updateInstanceStatus(instanceId, "running", {
52394
+ branch: branchName,
52395
+ worktreePath
52396
+ });
52397
+ if (!updated) {
52398
+ throw new Error(`Instance ${instanceId} not found during start`);
52399
+ }
52400
+ emitInstanceEvent(EVENT_NAMES.INSTANCE_STARTED, updated);
52401
+ return updated;
52402
+ }
52403
+ async function completeInstance(instanceId) {
52404
+ const instance = await getInstance(instanceId);
52405
+ if (!instance) {
52406
+ throw new Error(`Instance ${instanceId} not found`);
52407
+ }
52408
+ await mergeWikiPages(instance);
52409
+ if (instance.worktreePath) {
52410
+ await cleanupWorktree(instance.worktreePath).catch(() => {
52411
+ });
52412
+ }
52413
+ const updated = await updateInstanceStatus(instanceId, "completed");
52414
+ if (!updated) {
52415
+ throw new Error(`Instance ${instanceId} not found during completion`);
52416
+ }
52417
+ emitInstanceEvent(EVENT_NAMES.INSTANCE_COMPLETED, updated);
52418
+ await processQueue(instance.squadId);
52419
+ return updated;
52420
+ }
52421
+ async function failInstance(instanceId, error51) {
52422
+ const instance = await getInstance(instanceId);
52423
+ if (!instance) {
52424
+ throw new Error(`Instance ${instanceId} not found`);
52425
+ }
52426
+ await cleanupPendingWiki(instance);
52427
+ if (instance.worktreePath) {
52428
+ await cleanupWorktree(instance.worktreePath).catch(() => {
52429
+ });
52430
+ }
52431
+ const updated = await updateInstanceStatus(instanceId, "failed", { error: error51 });
52432
+ if (!updated) {
52433
+ throw new Error(`Instance ${instanceId} not found during failure`);
52434
+ }
52435
+ emitInstanceEvent(EVENT_NAMES.INSTANCE_FAILED, updated);
52436
+ await processQueue(instance.squadId);
52437
+ return updated;
52438
+ }
52439
+ async function cancelInstance(instanceId) {
52440
+ const instance = await getInstance(instanceId);
52441
+ if (!instance) {
52442
+ throw new Error(`Instance ${instanceId} not found`);
52443
+ }
52444
+ await cleanupPendingWiki(instance);
52445
+ if (instance.worktreePath) {
52446
+ await cleanupWorktree(instance.worktreePath).catch(() => {
52447
+ });
52448
+ }
52449
+ const updated = await updateInstanceStatus(instanceId, "cancelled");
52450
+ if (!updated) {
52451
+ throw new Error(`Instance ${instanceId} not found during cancellation`);
52452
+ }
52453
+ emitInstanceEvent(EVENT_NAMES.INSTANCE_CANCELLED, updated);
52454
+ await processQueue(instance.squadId);
52455
+ return updated;
52456
+ }
52457
+ async function processQueue(squadId) {
52458
+ const config2 = loadConfig();
52459
+ await cleanStaleInstances();
52460
+ const running = await countRunningInstances(squadId);
52461
+ if (running >= config2.maxInstancesPerSquad) {
52462
+ return;
52463
+ }
52464
+ const next = await getNextQueued(squadId);
52465
+ if (!next) {
52466
+ return;
52467
+ }
52468
+ emitInstanceEvent(EVENT_NAMES.INSTANCE_STARTED, next);
52469
+ }
52470
+ async function cleanStaleInstances() {
52471
+ const stale = await findStaleInstances();
52472
+ for (const instance of stale) {
52473
+ if (instance.worktreePath) {
52474
+ await cleanupWorktree(instance.worktreePath).catch(() => {
52475
+ });
52476
+ }
52477
+ await cleanupPendingWiki(instance);
52478
+ await updateInstanceStatus(instance.id, "failed", {
52479
+ error: "Instance timed out (stale detection)"
52480
+ });
52481
+ emitInstanceEvent(EVENT_NAMES.INSTANCE_FAILED, instance);
52482
+ }
52483
+ }
52484
+ function getWikiPendingDir(instance) {
52485
+ return join5(WIKI_DIR, ".pending", instance.id);
52486
+ }
52487
+ async function mergeWikiPages(instance) {
52488
+ const pendingDir = getWikiPendingDir(instance);
52489
+ try {
52490
+ const entries = await readdir(pendingDir, { withFileTypes: true });
52491
+ if (entries.length === 0) {
52492
+ await rm3(pendingDir, { recursive: true, force: true });
52493
+ return;
52494
+ }
52495
+ await mkdir5(WIKI_DIR, { recursive: true });
52496
+ for (const entry of entries) {
52497
+ const source = join5(pendingDir, entry.name);
52498
+ const dest = join5(WIKI_DIR, entry.name);
52499
+ await rename(source, dest).catch(async () => {
52500
+ const { cp } = await import("node:fs/promises");
52501
+ await cp(source, dest, { recursive: true });
52502
+ await rm3(source, { recursive: true, force: true });
52503
+ });
52504
+ }
52505
+ await rm3(pendingDir, { recursive: true, force: true });
52506
+ } catch (error51) {
52507
+ if (error51.code === "ENOENT") {
52508
+ return;
52509
+ }
52510
+ throw error51;
52511
+ }
52512
+ }
52513
+ async function cleanupPendingWiki(instance) {
52514
+ const pendingDir = getWikiPendingDir(instance);
52515
+ await rm3(pendingDir, { recursive: true, force: true });
52516
+ }
52517
+ function emitInstanceEvent(event, instance) {
52518
+ eventBus.emit(event, {
52519
+ squadId: instance.squadId,
52520
+ instanceId: instance.id,
52521
+ status: instance.status,
52522
+ branch: instance.branch,
52523
+ objectiveId: instance.objectiveId
52524
+ });
52525
+ }
52526
+ var init_instances2 = __esm({
52527
+ "packages/daemon/src/execution/instances.ts"() {
52528
+ "use strict";
52529
+ init_dist();
52530
+ init_paths();
52531
+ init_config();
52532
+ init_event_bus();
52533
+ init_store2();
52534
+ init_worktree();
52535
+ }
52536
+ });
52537
+
52016
52538
  // packages/daemon/src/api/routes/squads.ts
52017
52539
  async function listObjectivesForSquad(squadId) {
52018
52540
  const database = await getDatabase();
@@ -52070,13 +52592,28 @@ function parseRepoInfo(repoUrl, repoOwner, repoName) {
52070
52592
  function isValidationError2(error51) {
52071
52593
  return error51 instanceof Error && /repoUrl|config|Invalid URL/i.test(error51.message);
52072
52594
  }
52595
+ async function getTasksForInstance(objectiveId) {
52596
+ const database = await getDatabase();
52597
+ const result = await database.execute({
52598
+ sql: "SELECT id, title, assignee_id, status FROM tasks WHERE objective_id = ? ORDER BY created_at ASC",
52599
+ args: [objectiveId]
52600
+ });
52601
+ return result.rows.map((row) => ({
52602
+ id: asString(row.id),
52603
+ description: asString(row.title),
52604
+ assignedTo: asNullableString(row.assignee_id) ?? "unassigned",
52605
+ status: asString(row.status)
52606
+ }));
52607
+ }
52073
52608
  var import_express7, router7, DEFAULT_CONFIG;
52074
52609
  var init_squads2 = __esm({
52075
52610
  "packages/daemon/src/api/routes/squads.ts"() {
52076
52611
  "use strict";
52077
52612
  init_dist();
52078
52613
  import_express7 = __toESM(require_express2(), 1);
52614
+ init_config();
52079
52615
  init_event_bus();
52616
+ init_instances2();
52080
52617
  init_db();
52081
52618
  init_store2();
52082
52619
  router7 = (0, import_express7.Router)();
@@ -52087,7 +52624,23 @@ var init_squads2 = __esm({
52087
52624
  };
52088
52625
  router7.get("/api/squads", async (_req, res) => {
52089
52626
  try {
52090
- res.status(200).json(await listSquads());
52627
+ const squads = await listSquads();
52628
+ const config2 = loadConfig();
52629
+ const enriched = await Promise.all(
52630
+ squads.map(async (squad) => {
52631
+ const instances = await listActiveInstances(squad.id);
52632
+ const allInstances = await listInstancesBySquad(squad.id);
52633
+ const members = await getMembers(squad.id);
52634
+ return {
52635
+ ...squad,
52636
+ memberCount: members.length,
52637
+ activeInstances: instances.filter((i) => i.status === "running").length,
52638
+ totalInstances: allInstances.length,
52639
+ recentActivity: []
52640
+ };
52641
+ })
52642
+ );
52643
+ res.status(200).json({ squads: enriched, config: { maxInstancesPerSquad: config2.maxInstancesPerSquad } });
52091
52644
  } catch (error51) {
52092
52645
  res.status(500).json({
52093
52646
  error: "Failed to list squads",
@@ -52102,7 +52655,21 @@ var init_squads2 = __esm({
52102
52655
  res.status(404).json({ error: "Squad not found" });
52103
52656
  return;
52104
52657
  }
52105
- res.status(200).json(squad);
52658
+ const members = await getMembers(squad.id);
52659
+ const instances = await listActiveInstances(squad.id);
52660
+ const instanceSummaries = instances.map((inst) => ({
52661
+ id: inst.id,
52662
+ status: inst.status,
52663
+ issueRef: null,
52664
+ branch: inst.branch,
52665
+ taskCount: 0,
52666
+ tasksComplete: 0
52667
+ }));
52668
+ res.status(200).json({
52669
+ squad,
52670
+ members,
52671
+ instances: instanceSummaries
52672
+ });
52106
52673
  } catch (error51) {
52107
52674
  res.status(500).json({
52108
52675
  error: "Failed to fetch squad",
@@ -52275,13 +52842,65 @@ var init_squads2 = __esm({
52275
52842
  });
52276
52843
  }
52277
52844
  });
52845
+ router7.get("/api/squads/:name/instances/:instanceId", async (req, res) => {
52846
+ try {
52847
+ const instance = await getInstance(req.params.instanceId);
52848
+ if (!instance) {
52849
+ res.status(404).json({ error: "Instance not found" });
52850
+ return;
52851
+ }
52852
+ const squad = await getSquad(instance.squadId);
52853
+ const members = squad ? await getMembers(squad.id) : [];
52854
+ const tasks = instance.objectiveId ? await getTasksForInstance(instance.objectiveId) : [];
52855
+ res.status(200).json({
52856
+ squadColor: squad?.color ?? void 0,
52857
+ instance: {
52858
+ id: instance.id,
52859
+ status: instance.status,
52860
+ branch: instance.branch,
52861
+ issueRef: null,
52862
+ taskCount: tasks.length,
52863
+ tasksComplete: tasks.filter((t) => t.status === "completed").length,
52864
+ tasks,
52865
+ meetingLog: []
52866
+ },
52867
+ members: members.map((m) => ({
52868
+ id: m.id,
52869
+ name: m.name,
52870
+ role: m.role,
52871
+ displayName: m.name,
52872
+ veto: false,
52873
+ status: "idle",
52874
+ currentTask: null
52875
+ })),
52876
+ activity: []
52877
+ });
52878
+ } catch (error51) {
52879
+ res.status(500).json({
52880
+ error: "Failed to get instance",
52881
+ details: error51 instanceof Error ? error51.message : "Unknown error"
52882
+ });
52883
+ }
52884
+ });
52885
+ router7.post("/api/squads/:name/instances/:instanceId/cancel", async (req, res) => {
52886
+ try {
52887
+ const instance = await cancelInstance(req.params.instanceId);
52888
+ res.status(200).json({ instance });
52889
+ } catch (error51) {
52890
+ res.status(500).json({
52891
+ error: "Failed to cancel instance",
52892
+ details: error51 instanceof Error ? error51.message : "Unknown error"
52893
+ });
52894
+ }
52895
+ });
52278
52896
  }
52279
52897
  });
52280
52898
 
52281
52899
  // packages/daemon/src/api/routes/usage.ts
52282
52900
  function getUsageParams(query) {
52901
+ const since = typeof query.since === "string" ? query.since : void 0;
52283
52902
  return {
52284
- startDate: typeof query.startDate === "string" ? query.startDate : void 0,
52903
+ startDate: typeof query.startDate === "string" ? query.startDate : since,
52285
52904
  endDate: typeof query.endDate === "string" ? query.endDate : void 0,
52286
52905
  squadId: typeof query.squadId === "string" ? query.squadId : void 0,
52287
52906
  agentId: typeof query.agentId === "string" ? query.agentId : void 0,
@@ -52298,11 +52917,11 @@ var init_usage = __esm({
52298
52917
  router8.get("/api/usage", async (req, res) => {
52299
52918
  try {
52300
52919
  const params = getUsageParams(req.query);
52301
- const summary = await getUsageSummary(params);
52302
- res.status(200).json(summary);
52920
+ const result = await getUsageRecords(params);
52921
+ res.status(200).json(result);
52303
52922
  } catch (error51) {
52304
52923
  res.status(500).json({
52305
- error: "Failed to fetch usage summary",
52924
+ error: "Failed to fetch usage",
52306
52925
  details: error51 instanceof Error ? error51.message : "Unknown error"
52307
52926
  });
52308
52927
  }
@@ -55810,8 +56429,8 @@ var require_gray_matter = __commonJS({
55810
56429
  });
55811
56430
 
55812
56431
  // packages/daemon/src/wiki/wiki.ts
55813
- import { mkdir as mkdir4, readFile as readFile3, readdir, rm as rm2, stat, writeFile as writeFile3 } from "node:fs/promises";
55814
- import { basename as basename2, dirname as dirname3, extname as extname2, join as join4, relative, resolve } from "node:path";
56432
+ import { mkdir as mkdir6, readFile as readFile3, readdir as readdir2, rm as rm4, stat, writeFile as writeFile3 } from "node:fs/promises";
56433
+ import { basename as basename2, dirname as dirname3, extname as extname2, join as join6, relative, resolve } from "node:path";
55815
56434
  function getWikiPagesDir() {
55816
56435
  return wikiDirectoryOverride ?? process.env.WIKI_DIR ?? WIKI_DIR;
55817
56436
  }
@@ -55820,6 +56439,29 @@ async function listPages() {
55820
56439
  const pages = await Promise.all(markdownFiles.map((filePath) => readWikiPageFromFile(filePath)));
55821
56440
  return pages.sort((left, right) => left.path.localeCompare(right.path));
55822
56441
  }
56442
+ async function listDirectories() {
56443
+ const directories = await collectDirectories(getWikiPagesDir());
56444
+ return directories.map((dirPath) => ({ path: relative(getWikiPagesDir(), dirPath).replace(/\\/g, "/") })).sort((left, right) => left.path.localeCompare(right.path));
56445
+ }
56446
+ async function collectDirectories(directory) {
56447
+ try {
56448
+ const entries = await readdir2(directory, { withFileTypes: true });
56449
+ const dirs = [];
56450
+ for (const entry of entries) {
56451
+ if (entry.isDirectory()) {
56452
+ const entryPath = join6(directory, entry.name);
56453
+ dirs.push(entryPath);
56454
+ dirs.push(...await collectDirectories(entryPath));
56455
+ }
56456
+ }
56457
+ return dirs;
56458
+ } catch (error51) {
56459
+ if (isMissingFileError3(error51)) {
56460
+ return [];
56461
+ }
56462
+ throw error51;
56463
+ }
56464
+ }
55823
56465
  async function getPage(pagePath) {
55824
56466
  try {
55825
56467
  return await readWikiPageFromFile(resolvePagePath(pagePath));
@@ -55833,7 +56475,7 @@ async function getPage(pagePath) {
55833
56475
  async function createPage(pagePath, title, content, tags = []) {
55834
56476
  const filePath = resolvePagePath(pagePath);
55835
56477
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
55836
- await mkdir4(dirname3(filePath), { recursive: true });
56478
+ await mkdir6(dirname3(filePath), { recursive: true });
55837
56479
  await writeFile3(filePath, serializeWikiPage({ title, tags, updatedAt }, content), { flag: "wx" });
55838
56480
  return {
55839
56481
  path: toRelativePagePath(filePath),
@@ -55865,14 +56507,14 @@ async function updatePage(pagePath, updates) {
55865
56507
  return nextPage;
55866
56508
  }
55867
56509
  async function deletePage(pagePath) {
55868
- await rm2(resolvePagePath(pagePath), { force: true });
56510
+ await rm4(resolvePagePath(pagePath), { force: true });
55869
56511
  }
55870
56512
  async function collectMarkdownFiles(directory) {
55871
56513
  try {
55872
- const entries = await readdir(directory, { withFileTypes: true });
56514
+ const entries = await readdir2(directory, { withFileTypes: true });
55873
56515
  const files = [];
55874
56516
  for (const entry of entries) {
55875
- const entryPath = join4(directory, entry.name);
56517
+ const entryPath = join6(directory, entry.name);
55876
56518
  if (entry.isDirectory()) {
55877
56519
  files.push(...await collectMarkdownFiles(entryPath));
55878
56520
  continue;
@@ -56100,8 +56742,16 @@ var init_wiki3 = __esm({
56100
56742
  router9 = (0, import_express9.Router)();
56101
56743
  router9.get("/api/wiki/pages", async (_req, res) => {
56102
56744
  try {
56103
- const pages = await listPages();
56104
- res.status(200).json(pages);
56745
+ const [pages, directories] = await Promise.all([listPages(), listDirectories()]);
56746
+ const dirEntries = directories.map((d) => ({
56747
+ path: d.path,
56748
+ title: d.path.split("/").pop() ?? d.path,
56749
+ tags: [],
56750
+ content: "",
56751
+ updatedAt: "",
56752
+ isDir: true
56753
+ }));
56754
+ res.status(200).json([...dirEntries, ...pages]);
56105
56755
  } catch (error51) {
56106
56756
  res.status(500).json({
56107
56757
  error: "Failed to list wiki pages",
@@ -60051,7 +60701,7 @@ var init_websocket = __esm({
60051
60701
  // packages/daemon/src/api/server.ts
60052
60702
  import { existsSync as existsSync2 } from "node:fs";
60053
60703
  import { createServer } from "node:http";
60054
- import { dirname as dirname4, join as join5, resolve as resolve2 } from "node:path";
60704
+ import { dirname as dirname4, join as join7, resolve as resolve2 } from "node:path";
60055
60705
  import { fileURLToPath } from "node:url";
60056
60706
  function createApiServer(config2) {
60057
60707
  const app = (0, import_express10.default)();
@@ -60074,6 +60724,9 @@ function createApiServer(config2) {
60074
60724
  supabaseAnonKey: config2.supabaseAnonKey ?? null
60075
60725
  });
60076
60726
  });
60727
+ app.get("/api/version", (_req, res) => {
60728
+ res.json({ version: APP_VERSION });
60729
+ });
60077
60730
  app.use("/api", createAuthMiddleware(config2));
60078
60731
  app.use(router2);
60079
60732
  app.use(router7);
@@ -60084,13 +60737,16 @@ function createApiServer(config2) {
60084
60737
  app.use(router8);
60085
60738
  app.use(router5);
60086
60739
  app.use(router);
60740
+ app.get("/api/config", (_req, res) => {
60741
+ res.json({ config: { maxInstancesPerSquad: config2.maxInstancesPerSquad } });
60742
+ });
60087
60743
  app.use("/api", (_req, res) => {
60088
60744
  res.status(404).json({ error: "API route not found" });
60089
60745
  });
60090
60746
  if (existsSync2(webDirectory)) {
60091
60747
  app.use(import_express10.default.static(webDirectory));
60092
60748
  app.use((_req, res) => {
60093
- res.sendFile(join5(webDirectory, "index.html"));
60749
+ res.sendFile(join7(webDirectory, "index.html"));
60094
60750
  });
60095
60751
  }
60096
60752
  app.use((error51, _req, res, next) => {
@@ -61431,7 +62087,7 @@ var require_sonic_boom = __commonJS({
61431
62087
  if (!(this instanceof SonicBoom)) {
61432
62088
  return new SonicBoom(opts);
61433
62089
  }
61434
- let { fd, dest, minLength, maxLength, maxWrite, periodicFlush, sync, append = true, mkdir: mkdir9, retryEAGAIN, fsync, contentMode, mode } = opts || {};
62090
+ let { fd, dest, minLength, maxLength, maxWrite, periodicFlush, sync, append = true, mkdir: mkdir10, retryEAGAIN, fsync, contentMode, mode } = opts || {};
61435
62091
  fd = fd || dest;
61436
62092
  this._len = 0;
61437
62093
  this.fd = -1;
@@ -61456,7 +62112,7 @@ var require_sonic_boom = __commonJS({
61456
62112
  this.append = append || false;
61457
62113
  this.mode = mode;
61458
62114
  this.retryEAGAIN = retryEAGAIN || (() => true);
61459
- this.mkdir = mkdir9 || false;
62115
+ this.mkdir = mkdir10 || false;
61460
62116
  let fsWriteSync;
61461
62117
  let fsWrite;
61462
62118
  if (contentMode === kContentModeBuffer) {
@@ -62174,7 +62830,7 @@ var require_thread_stream = __commonJS({
62174
62830
  var { version: version2 } = require_package();
62175
62831
  var { EventEmitter: EventEmitter2 } = __require("events");
62176
62832
  var { Worker } = __require("worker_threads");
62177
- var { join: join15 } = __require("path");
62833
+ var { join: join16 } = __require("path");
62178
62834
  var { pathToFileURL: pathToFileURL2 } = __require("url");
62179
62835
  var { wait } = require_wait();
62180
62836
  var {
@@ -62217,7 +62873,7 @@ var require_thread_stream = __commonJS({
62217
62873
  function createWorker(stream, opts) {
62218
62874
  const { filename, workerData } = opts;
62219
62875
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
62220
- const toExecute = bundlerOverrides["thread-stream-worker"] || join15(__dirname, "lib", "worker.js");
62876
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join16(__dirname, "lib", "worker.js");
62221
62877
  const worker = new Worker(toExecute, {
62222
62878
  ...opts.workerOpts,
62223
62879
  trackUnmanagedFds: false,
@@ -62620,7 +63276,7 @@ var require_transport = __commonJS({
62620
63276
  "use strict";
62621
63277
  var { createRequire } = __require("module");
62622
63278
  var getCallers = require_caller();
62623
- var { join: join15, isAbsolute: isAbsolute2, sep } = __require("node:path");
63279
+ var { join: join16, isAbsolute: isAbsolute2, sep } = __require("node:path");
62624
63280
  var sleep = require_atomic_sleep();
62625
63281
  var onExit = require_on_exit_leak_free();
62626
63282
  var ThreadStream = require_thread_stream();
@@ -62683,7 +63339,7 @@ var require_transport = __commonJS({
62683
63339
  throw new Error("only one of target or targets can be specified");
62684
63340
  }
62685
63341
  if (targets) {
62686
- target = bundlerOverrides["pino-worker"] || join15(__dirname, "worker.js");
63342
+ target = bundlerOverrides["pino-worker"] || join16(__dirname, "worker.js");
62687
63343
  options2.targets = targets.filter((dest) => dest.target).map((dest) => {
62688
63344
  return {
62689
63345
  ...dest,
@@ -62701,7 +63357,7 @@ var require_transport = __commonJS({
62701
63357
  });
62702
63358
  });
62703
63359
  } else if (pipeline) {
62704
- target = bundlerOverrides["pino-worker"] || join15(__dirname, "worker.js");
63360
+ target = bundlerOverrides["pino-worker"] || join16(__dirname, "worker.js");
62705
63361
  options2.pipelines = [pipeline.map((dest) => {
62706
63362
  return {
62707
63363
  ...dest,
@@ -62723,7 +63379,7 @@ var require_transport = __commonJS({
62723
63379
  return origin;
62724
63380
  }
62725
63381
  if (origin === "pino/file") {
62726
- return join15(__dirname, "..", "file.js");
63382
+ return join16(__dirname, "..", "file.js");
62727
63383
  }
62728
63384
  let fixTarget2;
62729
63385
  for (const filePath of callers) {
@@ -63712,7 +64368,7 @@ var require_safe_stable_stringify = __commonJS({
63712
64368
  return circularValue;
63713
64369
  }
63714
64370
  let res = "";
63715
- let join15 = ",";
64371
+ let join16 = ",";
63716
64372
  const originalIndentation = indentation;
63717
64373
  if (Array.isArray(value)) {
63718
64374
  if (value.length === 0) {
@@ -63726,7 +64382,7 @@ var require_safe_stable_stringify = __commonJS({
63726
64382
  indentation += spacer;
63727
64383
  res += `
63728
64384
  ${indentation}`;
63729
- join15 = `,
64385
+ join16 = `,
63730
64386
  ${indentation}`;
63731
64387
  }
63732
64388
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -63734,13 +64390,13 @@ ${indentation}`;
63734
64390
  for (; i < maximumValuesToStringify - 1; i++) {
63735
64391
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
63736
64392
  res += tmp2 !== void 0 ? tmp2 : "null";
63737
- res += join15;
64393
+ res += join16;
63738
64394
  }
63739
64395
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
63740
64396
  res += tmp !== void 0 ? tmp : "null";
63741
64397
  if (value.length - 1 > maximumBreadth) {
63742
64398
  const removedKeys = value.length - maximumBreadth - 1;
63743
- res += `${join15}"... ${getItemCount(removedKeys)} not stringified"`;
64399
+ res += `${join16}"... ${getItemCount(removedKeys)} not stringified"`;
63744
64400
  }
63745
64401
  if (spacer !== "") {
63746
64402
  res += `
@@ -63761,7 +64417,7 @@ ${originalIndentation}`;
63761
64417
  let separator = "";
63762
64418
  if (spacer !== "") {
63763
64419
  indentation += spacer;
63764
- join15 = `,
64420
+ join16 = `,
63765
64421
  ${indentation}`;
63766
64422
  whitespace = " ";
63767
64423
  }
@@ -63775,13 +64431,13 @@ ${indentation}`;
63775
64431
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
63776
64432
  if (tmp !== void 0) {
63777
64433
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
63778
- separator = join15;
64434
+ separator = join16;
63779
64435
  }
63780
64436
  }
63781
64437
  if (keyLength > maximumBreadth) {
63782
64438
  const removedKeys = keyLength - maximumBreadth;
63783
64439
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
63784
- separator = join15;
64440
+ separator = join16;
63785
64441
  }
63786
64442
  if (spacer !== "" && separator.length > 1) {
63787
64443
  res = `
@@ -63822,7 +64478,7 @@ ${originalIndentation}`;
63822
64478
  }
63823
64479
  const originalIndentation = indentation;
63824
64480
  let res = "";
63825
- let join15 = ",";
64481
+ let join16 = ",";
63826
64482
  if (Array.isArray(value)) {
63827
64483
  if (value.length === 0) {
63828
64484
  return "[]";
@@ -63835,7 +64491,7 @@ ${originalIndentation}`;
63835
64491
  indentation += spacer;
63836
64492
  res += `
63837
64493
  ${indentation}`;
63838
- join15 = `,
64494
+ join16 = `,
63839
64495
  ${indentation}`;
63840
64496
  }
63841
64497
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -63843,13 +64499,13 @@ ${indentation}`;
63843
64499
  for (; i < maximumValuesToStringify - 1; i++) {
63844
64500
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
63845
64501
  res += tmp2 !== void 0 ? tmp2 : "null";
63846
- res += join15;
64502
+ res += join16;
63847
64503
  }
63848
64504
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
63849
64505
  res += tmp !== void 0 ? tmp : "null";
63850
64506
  if (value.length - 1 > maximumBreadth) {
63851
64507
  const removedKeys = value.length - maximumBreadth - 1;
63852
- res += `${join15}"... ${getItemCount(removedKeys)} not stringified"`;
64508
+ res += `${join16}"... ${getItemCount(removedKeys)} not stringified"`;
63853
64509
  }
63854
64510
  if (spacer !== "") {
63855
64511
  res += `
@@ -63862,7 +64518,7 @@ ${originalIndentation}`;
63862
64518
  let whitespace = "";
63863
64519
  if (spacer !== "") {
63864
64520
  indentation += spacer;
63865
- join15 = `,
64521
+ join16 = `,
63866
64522
  ${indentation}`;
63867
64523
  whitespace = " ";
63868
64524
  }
@@ -63871,7 +64527,7 @@ ${indentation}`;
63871
64527
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
63872
64528
  if (tmp !== void 0) {
63873
64529
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
63874
- separator = join15;
64530
+ separator = join16;
63875
64531
  }
63876
64532
  }
63877
64533
  if (spacer !== "" && separator.length > 1) {
@@ -63929,20 +64585,20 @@ ${originalIndentation}`;
63929
64585
  indentation += spacer;
63930
64586
  let res2 = `
63931
64587
  ${indentation}`;
63932
- const join16 = `,
64588
+ const join17 = `,
63933
64589
  ${indentation}`;
63934
64590
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
63935
64591
  let i = 0;
63936
64592
  for (; i < maximumValuesToStringify - 1; i++) {
63937
64593
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
63938
64594
  res2 += tmp2 !== void 0 ? tmp2 : "null";
63939
- res2 += join16;
64595
+ res2 += join17;
63940
64596
  }
63941
64597
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
63942
64598
  res2 += tmp !== void 0 ? tmp : "null";
63943
64599
  if (value.length - 1 > maximumBreadth) {
63944
64600
  const removedKeys = value.length - maximumBreadth - 1;
63945
- res2 += `${join16}"... ${getItemCount(removedKeys)} not stringified"`;
64601
+ res2 += `${join17}"... ${getItemCount(removedKeys)} not stringified"`;
63946
64602
  }
63947
64603
  res2 += `
63948
64604
  ${originalIndentation}`;
@@ -63958,16 +64614,16 @@ ${originalIndentation}`;
63958
64614
  return '"[Object]"';
63959
64615
  }
63960
64616
  indentation += spacer;
63961
- const join15 = `,
64617
+ const join16 = `,
63962
64618
  ${indentation}`;
63963
64619
  let res = "";
63964
64620
  let separator = "";
63965
64621
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
63966
64622
  if (isTypedArrayWithEntries(value)) {
63967
- res += stringifyTypedArray(value, join15, maximumBreadth);
64623
+ res += stringifyTypedArray(value, join16, maximumBreadth);
63968
64624
  keys = keys.slice(value.length);
63969
64625
  maximumPropertiesToStringify -= value.length;
63970
- separator = join15;
64626
+ separator = join16;
63971
64627
  }
63972
64628
  if (deterministic) {
63973
64629
  keys = sort(keys, comparator);
@@ -63978,13 +64634,13 @@ ${indentation}`;
63978
64634
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
63979
64635
  if (tmp !== void 0) {
63980
64636
  res += `${separator}${strEscape(key2)}: ${tmp}`;
63981
- separator = join15;
64637
+ separator = join16;
63982
64638
  }
63983
64639
  }
63984
64640
  if (keyLength > maximumBreadth) {
63985
64641
  const removedKeys = keyLength - maximumBreadth;
63986
64642
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
63987
- separator = join15;
64643
+ separator = join16;
63988
64644
  }
63989
64645
  if (separator !== "") {
63990
64646
  res = `
@@ -67014,7 +67670,7 @@ var require_pino_pretty = __commonJS({
67014
67670
  });
67015
67671
 
67016
67672
  // packages/daemon/src/logging/logger.ts
67017
- import { join as join6 } from "node:path";
67673
+ import { join as join8 } from "node:path";
67018
67674
  function shouldPrettyPrint(logLevel) {
67019
67675
  return process.env.NODE_ENV !== "production" || process.env.LOG_LEVEL === "debug" || logLevel === "debug" || logLevel === "trace";
67020
67676
  }
@@ -67061,7 +67717,7 @@ var init_logger = __esm({
67061
67717
  init_paths();
67062
67718
  import_pino = __toESM(require_pino(), 1);
67063
67719
  import_pino_pretty = __toESM(require_pino_pretty(), 1);
67064
- LOG_FILE_PATH = join6(LOGS_DIR, "io.log");
67720
+ LOG_FILE_PATH = join8(LOGS_DIR, "io.log");
67065
67721
  rootLogger = null;
67066
67722
  }
67067
67723
  });
@@ -67659,7 +68315,7 @@ var init_reset = __esm({
67659
68315
  // packages/daemon/src/copilot/client.ts
67660
68316
  import { execFileSync as execFileSync2 } from "node:child_process";
67661
68317
  import { mkdirSync as mkdirSync2 } from "node:fs";
67662
- import { join as join7 } from "node:path";
68318
+ import { join as join9 } from "node:path";
67663
68319
  import { CopilotClient } from "@github/copilot-sdk";
67664
68320
  function readTokenFromEnvironment() {
67665
68321
  const token = process.env.GITHUB_TOKEN?.trim();
@@ -67745,7 +68401,7 @@ var init_client = __esm({
67745
68401
  "use strict";
67746
68402
  init_paths();
67747
68403
  COPILOT_AUTH_ERROR_HINT = "Set GITHUB_TOKEN or authenticate with the GitHub CLI (`gh auth login`) so `gh auth token` returns a valid token.";
67748
- COPILOT_BASE_DIRECTORY = join7(DATA_DIR, "copilot-sdk");
68404
+ COPILOT_BASE_DIRECTORY = join9(DATA_DIR, "copilot-sdk");
67749
68405
  copilotClientSingleton = null;
67750
68406
  copilotClientInitPromise = null;
67751
68407
  }
@@ -67904,8 +68560,8 @@ var init_session = __esm({
67904
68560
  });
67905
68561
 
67906
68562
  // packages/daemon/src/skills/loader.ts
67907
- import { readFile as readFile4, readdir as readdir2 } from "node:fs/promises";
67908
- import { basename as basename3, dirname as dirname5, join as join8 } from "node:path";
68563
+ import { readFile as readFile4, readdir as readdir3 } from "node:fs/promises";
68564
+ import { basename as basename3, dirname as dirname5, join as join10 } from "node:path";
67909
68565
  async function scanSkills() {
67910
68566
  const skillFilePaths = await collectSkillFiles(SKILLS_DIR);
67911
68567
  const skills = await Promise.all(skillFilePaths.map((filePath) => readSkillFromFile(filePath)));
@@ -67913,10 +68569,10 @@ async function scanSkills() {
67913
68569
  }
67914
68570
  async function collectSkillFiles(directory) {
67915
68571
  try {
67916
- const entries = await readdir2(directory, { withFileTypes: true });
68572
+ const entries = await readdir3(directory, { withFileTypes: true });
67917
68573
  const skillFiles = [];
67918
68574
  for (const entry of entries) {
67919
- const entryPath = join8(directory, entry.name);
68575
+ const entryPath = join10(directory, entry.name);
67920
68576
  if (entry.isDirectory()) {
67921
68577
  skillFiles.push(...await collectSkillFiles(entryPath));
67922
68578
  continue;
@@ -67959,8 +68615,8 @@ var init_loader = __esm({
67959
68615
  });
67960
68616
 
67961
68617
  // packages/daemon/src/skills/manager.ts
67962
- import { mkdir as mkdir5, readFile as readFile5, rm as rm3, writeFile as writeFile4 } from "node:fs/promises";
67963
- import { basename as basename4, dirname as dirname6, join as join9 } from "node:path";
68618
+ import { mkdir as mkdir7, readFile as readFile5, rm as rm5, writeFile as writeFile4 } from "node:fs/promises";
68619
+ import { basename as basename4, dirname as dirname6, join as join11 } from "node:path";
67964
68620
  async function installSkill2(url2) {
67965
68621
  const response = await fetch(url2);
67966
68622
  if (!response.ok) {
@@ -67970,8 +68626,8 @@ async function installSkill2(url2) {
67970
68626
  }
67971
68627
  const skillMarkdown = await response.text();
67972
68628
  const skillId = getSkillIdFromUrl(url2);
67973
- const skillDirectory = join9(SKILLS_DIR, skillId);
67974
- const skillPath = join9(skillDirectory, "SKILL.md");
68629
+ const skillDirectory = join11(SKILLS_DIR, skillId);
68630
+ const skillPath = join11(skillDirectory, "SKILL.md");
67975
68631
  const parsed = (0, import_gray_matter3.default)(skillMarkdown);
67976
68632
  const installedSkill = {
67977
68633
  id: skillId,
@@ -67979,13 +68635,13 @@ async function installSkill2(url2) {
67979
68635
  url: url2,
67980
68636
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
67981
68637
  };
67982
- await mkdir5(skillDirectory, { recursive: true });
68638
+ await mkdir7(skillDirectory, { recursive: true });
67983
68639
  await writeFile4(skillPath, skillMarkdown, "utf8");
67984
68640
  await upsertInstalledSkill(installedSkill);
67985
68641
  return installedSkill;
67986
68642
  }
67987
68643
  async function removeSkill2(id) {
67988
- await rm3(join9(SKILLS_DIR, id), { recursive: true, force: true });
68644
+ await rm5(join11(SKILLS_DIR, id), { recursive: true, force: true });
67989
68645
  const lockFile = await readSkillsLock();
67990
68646
  lockFile.skills = lockFile.skills.filter((skill) => skill.id !== id);
67991
68647
  await writeSkillsLock2(lockFile);
@@ -68014,7 +68670,7 @@ async function readSkillsLock() {
68014
68670
  }
68015
68671
  }
68016
68672
  async function writeSkillsLock2(lockFile) {
68017
- await mkdir5(dirname6(SKILLS_LOCK_PATH), { recursive: true });
68673
+ await mkdir7(dirname6(SKILLS_LOCK_PATH), { recursive: true });
68018
68674
  await writeFile4(SKILLS_LOCK_PATH, `${JSON.stringify(lockFile, null, 2)}
68019
68675
  `, "utf8");
68020
68676
  }
@@ -68104,10 +68760,10 @@ var init_skills2 = __esm({
68104
68760
  });
68105
68761
 
68106
68762
  // packages/daemon/src/orchestrator/tools/coding.ts
68107
- import { exec } from "node:child_process";
68108
- import { mkdir as mkdir6, readFile as readFile6, readdir as readdir3, stat as stat2, writeFile as writeFile5 } from "node:fs/promises";
68763
+ import { exec as exec2 } from "node:child_process";
68764
+ import { mkdir as mkdir8, readFile as readFile6, readdir as readdir4, stat as stat2, writeFile as writeFile5 } from "node:fs/promises";
68109
68765
  import { dirname as dirname7, relative as relative2, resolve as resolve3 } from "node:path";
68110
- import { promisify } from "node:util";
68766
+ import { promisify as promisify2 } from "node:util";
68111
68767
  function resolveWorkspacePath(inputPath = ".") {
68112
68768
  const resolvedPath = resolve3(DEFAULT_ROOT, inputPath);
68113
68769
  const relativePath = relative2(DEFAULT_ROOT, resolvedPath);
@@ -68121,7 +68777,7 @@ function globToRegExp(pattern) {
68121
68777
  return new RegExp(`^${source}$`, "iu");
68122
68778
  }
68123
68779
  async function walkFiles(directory) {
68124
- const entries = await readdir3(directory, { withFileTypes: true });
68780
+ const entries = await readdir4(directory, { withFileTypes: true });
68125
68781
  const files = [];
68126
68782
  for (const entry of entries) {
68127
68783
  const entryPath = resolve3(directory, entry.name);
@@ -68145,12 +68801,12 @@ async function collectMatchingFiles(basePath, pattern) {
68145
68801
  (filePath) => matcher.test(relative2(basePath, filePath).replace(/\\/gu, "/"))
68146
68802
  );
68147
68803
  }
68148
- var execAsync, DEFAULT_ROOT, readFileSchema, editFileSchema, runCommandSchema, searchCodeSchema, listFilesSchema, codingToolDefinitions, executeCodingToolCall;
68804
+ var execAsync2, DEFAULT_ROOT, readFileSchema, editFileSchema, runCommandSchema, searchCodeSchema, listFilesSchema, codingToolDefinitions, executeCodingToolCall;
68149
68805
  var init_coding = __esm({
68150
68806
  "packages/daemon/src/orchestrator/tools/coding.ts"() {
68151
68807
  "use strict";
68152
68808
  init_zod();
68153
- execAsync = promisify(exec);
68809
+ execAsync2 = promisify2(exec2);
68154
68810
  DEFAULT_ROOT = process.cwd();
68155
68811
  readFileSchema = external_exports.object({
68156
68812
  path: external_exports.string().trim().min(1)
@@ -68215,14 +68871,14 @@ var init_coding = __esm({
68215
68871
  case "edit_file": {
68216
68872
  const { path, content } = editFileSchema.parse(rawArgs);
68217
68873
  const filePath = resolveWorkspacePath(path);
68218
- await mkdir6(dirname7(filePath), { recursive: true });
68874
+ await mkdir8(dirname7(filePath), { recursive: true });
68219
68875
  await writeFile5(filePath, content, "utf8");
68220
68876
  return { message: `Wrote ${filePath}.`, path: filePath };
68221
68877
  }
68222
68878
  case "run_command": {
68223
68879
  const { command, cwd } = runCommandSchema.parse(rawArgs);
68224
68880
  const workingDirectory = cwd ? resolveWorkspacePath(cwd) : DEFAULT_ROOT;
68225
- const { stdout, stderr } = await execAsync(command, {
68881
+ const { stdout, stderr } = await execAsync2(command, {
68226
68882
  cwd: workingDirectory,
68227
68883
  maxBuffer: 1024 * 1024 * 4,
68228
68884
  timeout: 12e4
@@ -68241,7 +68897,7 @@ var init_coding = __esm({
68241
68897
  if (glob) {
68242
68898
  args.unshift("--glob", glob);
68243
68899
  }
68244
- const { stdout } = await execAsync(
68900
+ const { stdout } = await execAsync2(
68245
68901
  `rg ${args.map((value) => JSON.stringify(value)).join(" ")}`,
68246
68902
  {
68247
68903
  cwd: DEFAULT_ROOT,
@@ -68595,10 +69251,10 @@ var init_history = __esm({
68595
69251
  });
68596
69252
 
68597
69253
  // packages/daemon/src/execution/agent.ts
68598
- import { exec as exec2 } from "node:child_process";
68599
- import { mkdir as mkdir7, readFile as readFile7, readdir as readdir4, stat as stat3, writeFile as writeFile6 } from "node:fs/promises";
68600
- import { dirname as dirname8, extname as extname3, isAbsolute, join as join10, relative as relative3, resolve as resolve4 } from "node:path";
68601
- import { promisify as promisify2 } from "node:util";
69254
+ import { exec as exec3 } from "node:child_process";
69255
+ import { mkdir as mkdir9, readFile as readFile7, readdir as readdir5, stat as stat3, writeFile as writeFile6 } from "node:fs/promises";
69256
+ import { dirname as dirname8, extname as extname3, isAbsolute, join as join12, relative as relative3, resolve as resolve4 } from "node:path";
69257
+ import { promisify as promisify3 } from "node:util";
68602
69258
  import {
68603
69259
  CopilotClient as CopilotClient2,
68604
69260
  approveAll as approveAll2,
@@ -68658,12 +69314,12 @@ function ensureWithinWorktree(worktreePath, requestedPath) {
68658
69314
  return candidate;
68659
69315
  }
68660
69316
  async function collectFiles(directory, recursive, output2) {
68661
- const entries = await readdir4(directory, { withFileTypes: true });
69317
+ const entries = await readdir5(directory, { withFileTypes: true });
68662
69318
  for (const entry of entries) {
68663
69319
  if (output2.length >= MAX_LIST_RESULTS) {
68664
69320
  return;
68665
69321
  }
68666
- const fullPath = join10(directory, entry.name);
69322
+ const fullPath = join12(directory, entry.name);
68667
69323
  output2.push(fullPath);
68668
69324
  if (recursive && entry.isDirectory()) {
68669
69325
  await collectFiles(fullPath, recursive, output2);
@@ -68723,7 +69379,7 @@ function createAgentToolSet(worktreePath) {
68723
69379
  skipPermission: true,
68724
69380
  handler: async (args) => {
68725
69381
  const targetPath = ensureWithinWorktree(worktreePath, args.path);
68726
- await mkdir7(dirname8(targetPath), { recursive: true });
69382
+ await mkdir9(dirname8(targetPath), { recursive: true });
68727
69383
  let nextContent = args.content ?? "";
68728
69384
  let previousContent = "";
68729
69385
  try {
@@ -68759,7 +69415,7 @@ function createAgentToolSet(worktreePath) {
68759
69415
  },
68760
69416
  skipPermission: true,
68761
69417
  handler: async (args) => {
68762
- const { stdout, stderr } = await execAsync2(args.command, {
69418
+ const { stdout, stderr } = await execAsync3(args.command, {
68763
69419
  cwd: worktreePath,
68764
69420
  timeout: Math.max(1e3, Math.min(args.timeoutMs ?? 6e4, 3e5)),
68765
69421
  maxBuffer: 10 * 1024 * 1024
@@ -68874,7 +69530,7 @@ async function executeAgentTask(member, task, worktreePath, options2) {
68874
69530
  Recent agent history:
68875
69531
  ${historyContext}
68876
69532
 
68877
- ${mcpServerNote}`
69533
+ ${mcpServerNote}${options2?.instancePromptSuffix ?? ""}`
68878
69534
  }
68879
69535
  });
68880
69536
  session.on("assistant.usage", (event) => {
@@ -68915,7 +69571,7 @@ Work only inside the current worktree. Summarize the concrete changes you made,
68915
69571
  }
68916
69572
  }
68917
69573
  }
68918
- var execAsync2, MAX_FILE_SIZE, MAX_LIST_RESULTS, MAX_SEARCH_RESULTS;
69574
+ var execAsync3, MAX_FILE_SIZE, MAX_LIST_RESULTS, MAX_SEARCH_RESULTS;
68919
69575
  var init_agent = __esm({
68920
69576
  "packages/daemon/src/execution/agent.ts"() {
68921
69577
  "use strict";
@@ -68923,13 +69579,46 @@ var init_agent = __esm({
68923
69579
  init_registry();
68924
69580
  init_store2();
68925
69581
  init_history();
68926
- execAsync2 = promisify2(exec2);
69582
+ execAsync3 = promisify3(exec3);
68927
69583
  MAX_FILE_SIZE = 2e5;
68928
69584
  MAX_LIST_RESULTS = 200;
68929
69585
  MAX_SEARCH_RESULTS = 100;
68930
69586
  }
68931
69587
  });
68932
69588
 
69589
+ // packages/daemon/src/execution/instance-context.ts
69590
+ async function buildWikiContext(_squadId) {
69591
+ const pages = await listPages().catch(() => []);
69592
+ if (pages.length === 0) {
69593
+ return "No wiki pages available.";
69594
+ }
69595
+ const entries = pages.map((page) => {
69596
+ const summary = page.content.slice(0, 150).replace(/\n/g, " ").trim();
69597
+ const truncated = summary.length < page.content.length ? `${summary}...` : summary;
69598
+ return `- **${page.title}** (${page.path}): ${truncated}`;
69599
+ });
69600
+ return `## Squad Wiki Knowledge (${pages.length} pages)
69601
+
69602
+ ${entries.join("\n")}`;
69603
+ }
69604
+ async function buildInstanceSystemPromptSuffix(squadId, instanceId) {
69605
+ const wikiContext = await buildWikiContext(squadId);
69606
+ return [
69607
+ "\n\n--- Instance Context ---",
69608
+ `Instance ID: ${instanceId}`,
69609
+ "You are working within an isolated instance. Your changes will be reviewed before merging.",
69610
+ "Wiki pages written during this instance go to a pending area and merge on successful completion.",
69611
+ "",
69612
+ wikiContext
69613
+ ].join("\n");
69614
+ }
69615
+ var init_instance_context = __esm({
69616
+ "packages/daemon/src/execution/instance-context.ts"() {
69617
+ "use strict";
69618
+ init_wiki();
69619
+ }
69620
+ });
69621
+
68933
69622
  // packages/daemon/src/squad/roles.ts
68934
69623
  function generateRolePrompt(role, repoContext) {
68935
69624
  const normalizedRole = role.trim() || "specialist";
@@ -69018,10 +69707,10 @@ Return strict JSON in this shape:
69018
69707
  });
69019
69708
 
69020
69709
  // packages/daemon/src/execution/planning.ts
69021
- import { exec as exec3 } from "node:child_process";
69710
+ import { exec as exec4 } from "node:child_process";
69022
69711
  import { access, readFile as readFile8 } from "node:fs/promises";
69023
- import { join as join11 } from "node:path";
69024
- import { promisify as promisify3 } from "node:util";
69712
+ import { join as join13 } from "node:path";
69713
+ import { promisify as promisify4 } from "node:util";
69025
69714
  import { CopilotClient as CopilotClient3, approveAll as approveAll3 } from "@github/copilot-sdk";
69026
69715
  async function fileExists(path) {
69027
69716
  try {
@@ -69033,13 +69722,13 @@ async function fileExists(path) {
69033
69722
  }
69034
69723
  async function buildRepoContext(repoPath) {
69035
69724
  for (const candidate of README_CANDIDATES) {
69036
- const readmePath = join11(repoPath, candidate);
69725
+ const readmePath = join13(repoPath, candidate);
69037
69726
  if (await fileExists(readmePath)) {
69038
69727
  const content = await readFile8(readmePath, "utf8");
69039
69728
  return content.slice(0, MAX_REPO_CONTEXT_LENGTH);
69040
69729
  }
69041
69730
  }
69042
- const { stdout } = await execAsync3("git ls-files", {
69731
+ const { stdout } = await execAsync4("git ls-files", {
69043
69732
  cwd: repoPath,
69044
69733
  maxBuffer: 5 * 1024 * 1024
69045
69734
  });
@@ -69152,150 +69841,22 @@ ${repoContext}`
69152
69841
  }
69153
69842
  }
69154
69843
  }
69155
- var execAsync3, README_CANDIDATES, MAX_REPO_CONTEXT_LENGTH;
69844
+ var execAsync4, README_CANDIDATES, MAX_REPO_CONTEXT_LENGTH;
69156
69845
  var init_planning = __esm({
69157
69846
  "packages/daemon/src/execution/planning.ts"() {
69158
69847
  "use strict";
69159
69848
  init_dist();
69160
69849
  init_roles();
69161
- execAsync3 = promisify3(exec3);
69850
+ execAsync4 = promisify4(exec4);
69162
69851
  README_CANDIDATES = ["README.md", "readme.md"];
69163
69852
  MAX_REPO_CONTEXT_LENGTH = 8e3;
69164
69853
  }
69165
69854
  });
69166
69855
 
69167
- // packages/daemon/src/execution/worktree.ts
69168
- import { exec as exec4 } from "node:child_process";
69169
- import { mkdir as mkdir8, rm as rm4 } from "node:fs/promises";
69170
- import { join as join12 } from "node:path";
69171
- import { promisify as promisify4 } from "node:util";
69172
- function sanitizeBranchName(branchName) {
69173
- return branchName.replace(/[^a-zA-Z0-9._-]+/g, "-");
69174
- }
69175
- async function runGit(command, cwd) {
69176
- const { stdout } = await execAsync4(command, {
69177
- cwd,
69178
- ...EXEC_OPTIONS
69179
- });
69180
- return stdout.trim();
69181
- }
69182
- async function branchExists(repoPath, branchName) {
69183
- const output2 = await runGit(`git branch --list ${JSON.stringify(branchName)}`, repoPath);
69184
- return output2.length > 0;
69185
- }
69186
- function getWorktreePath(repoPath, branchName) {
69187
- return join12(repoPath, ".worktrees", sanitizeBranchName(branchName));
69188
- }
69189
- async function listWorktrees(repoPath) {
69190
- const output2 = await runGit("git worktree list --porcelain", repoPath);
69191
- if (!output2) {
69192
- return [];
69193
- }
69194
- const blocks = output2.split(/\r?\n\r?\n/).filter(Boolean);
69195
- return blocks.map((block) => {
69196
- const info = {
69197
- path: "",
69198
- branch: null,
69199
- head: null,
69200
- bare: false,
69201
- detached: false,
69202
- locked: false,
69203
- prunable: false
69204
- };
69205
- for (const line of block.split(/\r?\n/)) {
69206
- const [key, ...rest] = line.split(" ");
69207
- const value = rest.join(" ").trim();
69208
- switch (key) {
69209
- case "worktree":
69210
- info.path = value;
69211
- break;
69212
- case "branch":
69213
- info.branch = value.replace(/^refs\/heads\//, "");
69214
- break;
69215
- case "HEAD":
69216
- info.head = value;
69217
- break;
69218
- case "bare":
69219
- info.bare = true;
69220
- break;
69221
- case "detached":
69222
- info.detached = true;
69223
- break;
69224
- case "locked":
69225
- info.locked = true;
69226
- break;
69227
- case "prunable":
69228
- info.prunable = true;
69229
- break;
69230
- }
69231
- }
69232
- return info;
69233
- });
69234
- }
69235
- async function createWorktree(repoPath, branchName, baseBranch) {
69236
- const worktreePath = getWorktreePath(repoPath, branchName);
69237
- await mkdir8(join12(repoPath, ".worktrees"), { recursive: true });
69238
- const existing = (await listWorktrees(repoPath)).find(
69239
- (worktree) => worktree.path === worktreePath
69240
- );
69241
- if (existing) {
69242
- return worktreePath;
69243
- }
69244
- const startPoint = baseBranch?.trim();
69245
- const createNewBranch = !await branchExists(repoPath, branchName);
69246
- const command = createNewBranch ? `git worktree add ${JSON.stringify(worktreePath)} -b ${JSON.stringify(branchName)}${startPoint ? ` ${JSON.stringify(startPoint)}` : ""}` : `git worktree add ${JSON.stringify(worktreePath)} ${JSON.stringify(branchName)}`;
69247
- try {
69248
- await runGit(command, repoPath);
69249
- return worktreePath;
69250
- } catch (error51) {
69251
- const message2 = error51 instanceof Error ? error51.message : String(error51);
69252
- if (/already exists/i.test(message2)) {
69253
- return worktreePath;
69254
- }
69255
- throw new Error(`Failed to create worktree for ${branchName}: ${message2}`);
69256
- }
69257
- }
69258
- async function cleanupWorktree(worktreePath) {
69259
- const parentRepoPath = join12(worktreePath, "..", "..");
69260
- try {
69261
- await runGit(`git worktree remove ${JSON.stringify(worktreePath)}`, parentRepoPath);
69262
- } catch (error51) {
69263
- const message2 = error51 instanceof Error ? error51.message : String(error51);
69264
- if (!/not a working tree/i.test(message2) && !/does not exist/i.test(message2)) {
69265
- await runGit(
69266
- `git worktree remove --force ${JSON.stringify(worktreePath)}`,
69267
- parentRepoPath
69268
- ).catch(() => void 0);
69269
- }
69270
- }
69271
- await runGit("git worktree prune", parentRepoPath).catch(() => void 0);
69272
- await rm4(worktreePath, { recursive: true, force: true }).catch(() => void 0);
69273
- }
69274
- async function pushBranch(worktreePath, remote = DEFAULT_REMOTE) {
69275
- const branchName = await runGit("git branch --show-current", worktreePath);
69276
- if (!branchName) {
69277
- throw new Error(`Unable to determine branch for worktree ${worktreePath}`);
69278
- }
69279
- const output2 = await runGit(
69280
- `git push --set-upstream ${JSON.stringify(remote)} ${JSON.stringify(branchName)}`,
69281
- worktreePath
69282
- );
69283
- return { branchName, remote, output: output2 };
69284
- }
69285
- var execAsync4, DEFAULT_REMOTE, EXEC_OPTIONS;
69286
- var init_worktree = __esm({
69287
- "packages/daemon/src/execution/worktree.ts"() {
69288
- "use strict";
69289
- execAsync4 = promisify4(exec4);
69290
- DEFAULT_REMOTE = "origin";
69291
- EXEC_OPTIONS = { maxBuffer: 10 * 1024 * 1024 };
69292
- }
69293
- });
69294
-
69295
69856
  // packages/daemon/src/execution/pr.ts
69296
69857
  import { exec as exec5 } from "node:child_process";
69297
- import { rm as rm5, writeFile as writeFile7 } from "node:fs/promises";
69298
- import { join as join13 } from "node:path";
69858
+ import { rm as rm6, writeFile as writeFile7 } from "node:fs/promises";
69859
+ import { join as join14 } from "node:path";
69299
69860
  import { promisify as promisify5 } from "node:util";
69300
69861
  async function runCommand(command, cwd) {
69301
69862
  const { stdout } = await execAsync5(command, {
@@ -69309,7 +69870,7 @@ function extractUrl(output2) {
69309
69870
  }
69310
69871
  function buildBodyFilePath(repoPath, branchName) {
69311
69872
  const safeBranchName = branchName.replace(/[^a-zA-Z0-9._-]+/g, "-");
69312
- return join13(repoPath, `.io-pr-body-${safeBranchName}.md`);
69873
+ return join14(repoPath, `.io-pr-body-${safeBranchName}.md`);
69313
69874
  }
69314
69875
  function buildPrBody(objective, plan, taskSummaries, qaOutcome) {
69315
69876
  const tasks = taskSummaries.map((summary) => `- ${summary}`).join("\n") || "- No task summaries recorded.";
@@ -69344,7 +69905,7 @@ async function createPullRequest(options2) {
69344
69905
  options2.repoPath
69345
69906
  );
69346
69907
  } finally {
69347
- await rm5(bodyFilePath, { force: true }).catch(() => void 0);
69908
+ await rm6(bodyFilePath, { force: true }).catch(() => void 0);
69348
69909
  }
69349
69910
  const prUrl = extractUrl(createOutput);
69350
69911
  if (!prUrl) {
@@ -69642,7 +70203,7 @@ var init_tasks = __esm({
69642
70203
  // packages/daemon/src/execution/runner.ts
69643
70204
  import { exec as exec7 } from "node:child_process";
69644
70205
  import { access as access2 } from "node:fs/promises";
69645
- import { basename as basename5, join as join14 } from "node:path";
70206
+ import { basename as basename5, join as join15 } from "node:path";
69646
70207
  import { promisify as promisify7 } from "node:util";
69647
70208
  async function pathExists(path) {
69648
70209
  try {
@@ -69662,12 +70223,12 @@ async function runGit2(command, cwd) {
69662
70223
  async function resolveRepoPath(repoUrl, repoName) {
69663
70224
  const candidates = [
69664
70225
  process.cwd(),
69665
- join14(process.cwd(), repoName),
69666
- join14(process.cwd(), "repos", repoName),
69667
- join14(process.cwd(), "..", repoName)
70226
+ join15(process.cwd(), repoName),
70227
+ join15(process.cwd(), "repos", repoName),
70228
+ join15(process.cwd(), "..", repoName)
69668
70229
  ];
69669
70230
  for (const candidate of candidates) {
69670
- if (!await pathExists(join14(candidate, ".git"))) {
70231
+ if (!await pathExists(join15(candidate, ".git"))) {
69671
70232
  continue;
69672
70233
  }
69673
70234
  const remoteUrl = await runGit2("git remote get-url origin", candidate).catch(() => "");
@@ -69695,7 +70256,7 @@ function summarizeTask(task, member) {
69695
70256
  const owner = member ? `${member.name} (${member.role})` : task.assigneeId ?? "unassigned";
69696
70257
  return `${task.title} \u2014 ${owner}: ${task.result ?? "No result recorded."}`;
69697
70258
  }
69698
- async function executePendingTasks(objective, members, worktreePath, mcpServers) {
70259
+ async function executePendingTasks(objective, members, worktreePath, mcpServers, instancePromptSuffix) {
69699
70260
  const pendingTasks = await getNextPendingTasks(objective.id);
69700
70261
  if (pendingTasks.length === 0) {
69701
70262
  return getTasksForObjective(objective.id);
@@ -69727,7 +70288,10 @@ async function executePendingTasks(objective, members, worktreePath, mcpServers)
69727
70288
  agentId: member.id,
69728
70289
  taskId: task.id
69729
70290
  });
69730
- const execution = await executeAgentTask(member, task, worktreePath, { mcpServers });
70291
+ const execution = await executeAgentTask(member, task, worktreePath, {
70292
+ mcpServers,
70293
+ instancePromptSuffix
70294
+ });
69731
70295
  if (!execution.success) {
69732
70296
  const failedTask = await markTaskFailed(task.id, execution.result);
69733
70297
  eventBus.emit(EVENT_NAMES.TASK_FAILED, {
@@ -69762,7 +70326,7 @@ async function createFeedbackTask(objectiveId, teamLead, title, description) {
69762
70326
  status: "pending"
69763
70327
  });
69764
70328
  }
69765
- async function executeObjective(squadId, objectiveId) {
70329
+ async function executeObjective(squadId, objectiveId, instanceContext) {
69766
70330
  const squadRecord = await getSquad(squadId);
69767
70331
  if (!squadRecord) {
69768
70332
  return { success: false, error: `Squad ${squadId} was not found.` };
@@ -69780,10 +70344,11 @@ async function executeObjective(squadId, objectiveId) {
69780
70344
  const teamLead = requireMemberByRole(squadRecord.members, "team-lead");
69781
70345
  const qaMember = requireMemberByRole(squadRecord.members, "qa");
69782
70346
  const repoPath = await resolveRepoPath(squadRecord.repoUrl, squadRecord.repoName);
69783
- const baseBranch = await runGit2("git branch --show-current", repoPath) || "main";
69784
- const branchName = buildBranchName(objectiveId);
69785
- let worktreePath = null;
70347
+ const baseBranch = instanceContext ? instanceContext.branch.replace(/^squad\//, "") : await runGit2("git branch --show-current", repoPath) || "main";
70348
+ const branchName = instanceContext?.branch ?? buildBranchName(objectiveId);
70349
+ let worktreePath = instanceContext?.worktreePath ?? null;
69786
70350
  let currentObjective = objectiveRecord;
70351
+ const ownsWorktree = !instanceContext;
69787
70352
  try {
69788
70353
  await updateSquad(squadId, { status: "executing" });
69789
70354
  const startedObjective = await updateObjectiveStatus(objectiveId, "planning");
@@ -69791,7 +70356,9 @@ async function executeObjective(squadId, objectiveId) {
69791
70356
  currentObjective = startedObjective;
69792
70357
  }
69793
70358
  eventBus.emit(EVENT_NAMES.OBJECTIVE_STARTED, { objective: currentObjective });
69794
- worktreePath = await createWorktree(repoPath, branchName, baseBranch);
70359
+ if (!worktreePath) {
70360
+ worktreePath = await createWorktree(repoPath, branchName, baseBranch);
70361
+ }
69795
70362
  const objectiveWithBranch = await updateObjectiveBranch(objectiveId, branchName);
69796
70363
  if (objectiveWithBranch) {
69797
70364
  currentObjective = objectiveWithBranch;
@@ -69803,6 +70370,7 @@ async function executeObjective(squadId, objectiveId) {
69803
70370
  }
69804
70371
  await updateObjectiveStatus(objectiveId, "executing");
69805
70372
  await createTasksFromPlan(objectiveId, planned.tasks, squadRecord.members);
70373
+ const instancePromptSuffix = instanceContext ? await buildInstanceSystemPromptSuffix(squadId, instanceContext.instanceId).catch(() => "") : void 0;
69806
70374
  let qaOutcome = null;
69807
70375
  while (true) {
69808
70376
  currentObjective = await getObjective(objectiveId) ?? currentObjective;
@@ -69810,7 +70378,8 @@ async function executeObjective(squadId, objectiveId) {
69810
70378
  currentObjective,
69811
70379
  squadRecord.members,
69812
70380
  worktreePath,
69813
- squadRecord.config.mcpServers
70381
+ squadRecord.config.mcpServers,
70382
+ instancePromptSuffix
69814
70383
  );
69815
70384
  const tasksAfterExecution = await getTasksForObjective(objectiveId);
69816
70385
  eventBus.emit(EVENT_NAMES.REVIEW_STARTED, { objectiveId });
@@ -69908,7 +70477,7 @@ ${reviewOutcome.issues?.join("\n") ?? "Resolve the review feedback and re-valida
69908
70477
  });
69909
70478
  return { success: false, error: message2 };
69910
70479
  } finally {
69911
- if (worktreePath) {
70480
+ if (ownsWorktree && worktreePath) {
69912
70481
  await cleanupWorktree(worktreePath).catch(() => void 0);
69913
70482
  }
69914
70483
  await updateSquad(squadId, { status: "active" }).catch(() => null);
@@ -69924,6 +70493,7 @@ var init_runner = __esm({
69924
70493
  init_store2();
69925
70494
  init_agent();
69926
70495
  init_history();
70496
+ init_instance_context();
69927
70497
  init_planning();
69928
70498
  init_pr();
69929
70499
  init_qa();
@@ -70191,6 +70761,42 @@ function formatSquadList(squads) {
70191
70761
  (squad) => `${squad.id}: ${squad.name} (${squad.repoOwner}/${squad.repoName}) [${squad.status}]`
70192
70762
  ).join("\n");
70193
70763
  }
70764
+ async function startAndExecuteInstance(instanceId, squad, objectiveId) {
70765
+ try {
70766
+ const repoPath = await resolveRepoPath(squad.repoUrl, squad.repoName);
70767
+ const baseBranch = "main";
70768
+ const started = await startInstance(instanceId, repoPath, baseBranch);
70769
+ const result = await executeObjective(squad.id, objectiveId, {
70770
+ instanceId: started.id,
70771
+ worktreePath: started.worktreePath ?? "",
70772
+ branch: started.branch ?? ""
70773
+ });
70774
+ if (result.success) {
70775
+ await completeInstance(instanceId);
70776
+ } else {
70777
+ await failInstance(instanceId, result.error ?? "Unknown execution failure");
70778
+ }
70779
+ } catch (error51) {
70780
+ const message2 = error51 instanceof Error ? error51.message : String(error51);
70781
+ await failInstance(instanceId, message2).catch(() => {
70782
+ });
70783
+ } finally {
70784
+ try {
70785
+ const running = await countRunningInstances(squad.id);
70786
+ const config2 = (await Promise.resolve().then(() => (init_config(), config_exports))).loadConfig();
70787
+ if (running < config2.maxInstancesPerSquad) {
70788
+ const next = await getNextQueued(squad.id);
70789
+ if (next) {
70790
+ const freshSquad = await getSquad(squad.id);
70791
+ if (freshSquad) {
70792
+ void startAndExecuteInstance(next.id, freshSquad, next.objectiveId);
70793
+ }
70794
+ }
70795
+ }
70796
+ } catch {
70797
+ }
70798
+ }
70799
+ }
70194
70800
  function createSquadToolExecutor(config2) {
70195
70801
  return async (toolName, rawArgs) => {
70196
70802
  switch (toolName) {
@@ -70244,14 +70850,18 @@ function createSquadToolExecutor(config2) {
70244
70850
  throw new Error(`Squad ${squadId} was not found.`);
70245
70851
  }
70246
70852
  const createdObjective = await createObjective(squadId, objective);
70247
- void executeObjective(squadId, createdObjective.id).catch(async (error51) => {
70248
- const message2 = error51 instanceof Error ? error51.message : String(error51);
70249
- await updateSquad(squadId, { status: "active" }).catch(() => void 0);
70250
- console.error(`Failed to execute objective ${createdObjective.id}: ${message2}`);
70853
+ const { instance, queued } = await spawnInstance({
70854
+ squadId,
70855
+ objectiveId: createdObjective.id
70251
70856
  });
70857
+ if (!queued) {
70858
+ void startAndExecuteInstance(instance.id, squad, createdObjective.id);
70859
+ }
70252
70860
  return {
70253
- message: `Delegated objective to squad ${squad.name}. Execution started in the background.`,
70254
- objective: createdObjective
70861
+ message: queued ? `Objective queued for squad ${squad.name} (at capacity). Instance ${instance.id} will start when a slot opens.` : `Delegated objective to squad ${squad.name}. Instance ${instance.id} started.`,
70862
+ objective: createdObjective,
70863
+ instanceId: instance.id,
70864
+ queued
70255
70865
  };
70256
70866
  }
70257
70867
  default:
@@ -70265,6 +70875,7 @@ var init_squad2 = __esm({
70265
70875
  "use strict";
70266
70876
  init_dist();
70267
70877
  init_zod();
70878
+ init_instances2();
70268
70879
  init_runner();
70269
70880
  init_hiring();
70270
70881
  init_manager2();