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.
- package/dist/daemon/cli.js +963 -352
- package/dist/daemon/index.js +45586 -44316
- package/dist/web/assets/{index-Bp8h1aTr.js → index-C6WVcVgK.js} +45 -45
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
package/dist/daemon/cli.js
CHANGED
|
@@ -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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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
|
|
52216
|
+
const identifier = req.params.id;
|
|
52217
|
+
const removed = await removeSkill(identifier);
|
|
51979
52218
|
if (!removed) {
|
|
51980
|
-
|
|
51981
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 :
|
|
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
|
|
52302
|
-
res.status(200).json(
|
|
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
|
|
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
|
|
55814
|
-
import { basename as basename2, dirname as dirname3, extname as extname2, join as
|
|
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
|
|
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
|
|
56510
|
+
await rm4(resolvePagePath(pagePath), { force: true });
|
|
55869
56511
|
}
|
|
55870
56512
|
async function collectMarkdownFiles(directory) {
|
|
55871
56513
|
try {
|
|
55872
|
-
const entries = await
|
|
56514
|
+
const entries = await readdir2(directory, { withFileTypes: true });
|
|
55873
56515
|
const files = [];
|
|
55874
56516
|
for (const entry of entries) {
|
|
55875
|
-
const entryPath =
|
|
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
|
-
|
|
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
|
|
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(
|
|
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:
|
|
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 =
|
|
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:
|
|
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"] ||
|
|
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:
|
|
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"] ||
|
|
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"] ||
|
|
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
|
|
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
|
|
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
|
-
|
|
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 +=
|
|
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 += `${
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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 +=
|
|
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 += `${
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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 +=
|
|
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 += `${
|
|
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
|
|
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,
|
|
64623
|
+
res += stringifyTypedArray(value, join16, maximumBreadth);
|
|
63968
64624
|
keys = keys.slice(value.length);
|
|
63969
64625
|
maximumPropertiesToStringify -= value.length;
|
|
63970
|
-
separator =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
67908
|
-
import { basename as basename3, dirname as dirname5, join as
|
|
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
|
|
68572
|
+
const entries = await readdir3(directory, { withFileTypes: true });
|
|
67917
68573
|
const skillFiles = [];
|
|
67918
68574
|
for (const entry of entries) {
|
|
67919
|
-
const entryPath =
|
|
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
|
|
67963
|
-
import { basename as basename4, dirname as dirname6, join as
|
|
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 =
|
|
67974
|
-
const skillPath =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
68599
|
-
import { mkdir as
|
|
68600
|
-
import { dirname as dirname8, extname as extname3, isAbsolute, join as
|
|
68601
|
-
import { promisify as
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
69710
|
+
import { exec as exec4 } from "node:child_process";
|
|
69022
69711
|
import { access, readFile as readFile8 } from "node:fs/promises";
|
|
69023
|
-
import { join as
|
|
69024
|
-
import { promisify as
|
|
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 =
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
69298
|
-
import { join as
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
69666
|
-
|
|
69667
|
-
|
|
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(
|
|
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, {
|
|
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
|
-
|
|
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
|
-
|
|
70248
|
-
|
|
70249
|
-
|
|
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}.
|
|
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();
|