@runfusion/fusion 0.3.0 → 0.4.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/bin.js +51800 -49478
- package/dist/client/assets/{AgentDetailView-CJIxNRq-.js → AgentDetailView-DJwWfkpv.js} +3 -3
- package/dist/client/assets/{AgentsView-BS17exn3.js → AgentsView-DegK8aw-.js} +3 -3
- package/dist/client/assets/ChatView-CYpEShLS.js +1 -0
- package/dist/client/assets/{DevServerView-qMPpnXRb.js → DevServerView-DfCTA9fx.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-CTwgv9LY.js → DirectoryPicker-B0qNpfLW.js} +1 -1
- package/dist/client/assets/{DocumentsView-DOz1KFGN.js → DocumentsView-CsQxuyz3.js} +1 -1
- package/dist/client/assets/{InsightsView-CHZTJUic.js → InsightsView-Bzs7A2jv.js} +1 -1
- package/dist/client/assets/MemoryView-Cl5ASqjW.js +2 -0
- package/dist/client/assets/MemoryView-DiajLXby.css +1 -0
- package/dist/client/assets/{NodesView-BtGNRj2z.js → NodesView-BpiqRlvc.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-D9Ye2Vak.js → PiExtensionsManager-Cr6EoC7S.js} +3 -3
- package/dist/client/assets/{PluginManager-LeHp0jJ_.js → PluginManager-DXtQdfns.js} +1 -1
- package/dist/client/assets/{RoadmapsView-C413ISVU.js → RoadmapsView-CYPLTTB0.js} +1 -1
- package/dist/client/assets/{SettingsModal-olTBmYJs.js → SettingsModal-CNdVTVqD.js} +1 -1
- package/dist/client/assets/SettingsModal-CyCC7MzL.js +31 -0
- package/dist/client/assets/SettingsModal-G0ESQXRD.css +1 -0
- package/dist/client/assets/{SetupWizardModal-WdaR2eQQ.js → SetupWizardModal-BLiljNn7.js} +1 -1
- package/dist/client/assets/{SkillsView-BcE57w8i.js → SkillsView-Dlpw5LKI.js} +1 -1
- package/dist/client/assets/{folder-open-Ec4hU1xL.js → folder-open-B_38R5AA.js} +1 -1
- package/dist/client/assets/index-DQKtk17v.js +616 -0
- package/dist/client/assets/index-DjOxzdj3.css +1 -0
- package/dist/client/assets/{upload-BksRDuGJ.js → upload-DNQF7XCK.js} +1 -1
- package/dist/client/assets/{users-EFU4n9Qr.js → users-CG2_rCdk.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -0
- package/dist/extension.js +2101 -877
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/pi-claude-cli/src/provider.ts +0 -1
- package/package.json +17 -17
- package/LICENSE +0 -21
- package/dist/client/assets/ChatView-BUlq3WNJ.js +0 -1
- package/dist/client/assets/MemoryView-DhinauGs.css +0 -1
- package/dist/client/assets/MemoryView-V0QdeO3e.js +0 -2
- package/dist/client/assets/SettingsModal--vWmKBpT.css +0 -1
- package/dist/client/assets/SettingsModal-BZLL2xAP.js +0 -31
- package/dist/client/assets/index-CCYdhck-.js +0 -616
- package/dist/client/assets/index-lJ5WOmO9.css +0 -1
package/dist/extension.js
CHANGED
|
@@ -193,6 +193,39 @@ var init_settings_schema = __esm({
|
|
|
193
193
|
missionHealthCheckIntervalMs: 3e5,
|
|
194
194
|
agentPrompts: void 0,
|
|
195
195
|
promptOverrides: void 0,
|
|
196
|
+
remoteAccess: {
|
|
197
|
+
activeProvider: null,
|
|
198
|
+
providers: {
|
|
199
|
+
tailscale: {
|
|
200
|
+
enabled: false,
|
|
201
|
+
hostname: "",
|
|
202
|
+
targetPort: 0,
|
|
203
|
+
acceptRoutes: false
|
|
204
|
+
},
|
|
205
|
+
cloudflare: {
|
|
206
|
+
enabled: false,
|
|
207
|
+
tunnelName: "",
|
|
208
|
+
tunnelToken: null,
|
|
209
|
+
ingressUrl: ""
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
tokenStrategy: {
|
|
213
|
+
persistent: {
|
|
214
|
+
enabled: true,
|
|
215
|
+
token: null
|
|
216
|
+
},
|
|
217
|
+
shortLived: {
|
|
218
|
+
enabled: false,
|
|
219
|
+
ttlMs: 9e5,
|
|
220
|
+
maxTtlMs: 864e5
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
lifecycle: {
|
|
224
|
+
rememberLastRunning: false,
|
|
225
|
+
wasRunningOnShutdown: false,
|
|
226
|
+
lastRunningProvider: null
|
|
227
|
+
}
|
|
228
|
+
},
|
|
196
229
|
reflectionEnabled: false,
|
|
197
230
|
reflectionIntervalMs: 36e5,
|
|
198
231
|
reflectionAfterTask: true,
|
|
@@ -17106,10 +17139,10 @@ var init_central_core = __esm({
|
|
|
17106
17139
|
*/
|
|
17107
17140
|
async generateProjectName(projectPath) {
|
|
17108
17141
|
try {
|
|
17109
|
-
const { execFile:
|
|
17110
|
-
const { promisify:
|
|
17111
|
-
const
|
|
17112
|
-
const { stdout } = await
|
|
17142
|
+
const { execFile: execFile6 } = await import("node:child_process");
|
|
17143
|
+
const { promisify: promisify13 } = await import("node:util");
|
|
17144
|
+
const execFileAsync4 = promisify13(execFile6);
|
|
17145
|
+
const { stdout } = await execFileAsync4(
|
|
17113
17146
|
"git",
|
|
17114
17147
|
["remote", "get-url", "origin"],
|
|
17115
17148
|
{ cwd: projectPath, timeout: 5e3 }
|
|
@@ -17594,8 +17627,8 @@ function hasProjectDbFile(dir, folderName, dbName) {
|
|
|
17594
17627
|
if (!existsSync8(projectDir)) return false;
|
|
17595
17628
|
if (!existsSync8(dbPath)) return false;
|
|
17596
17629
|
try {
|
|
17597
|
-
const
|
|
17598
|
-
return
|
|
17630
|
+
const stat8 = statSync2(dbPath);
|
|
17631
|
+
return stat8.isFile() && stat8.size > 0;
|
|
17599
17632
|
} catch {
|
|
17600
17633
|
return false;
|
|
17601
17634
|
}
|
|
@@ -17722,10 +17755,10 @@ var init_migration = __esm({
|
|
|
17722
17755
|
return basename3(projectPath);
|
|
17723
17756
|
}
|
|
17724
17757
|
try {
|
|
17725
|
-
const { execFile:
|
|
17726
|
-
const { promisify:
|
|
17727
|
-
const
|
|
17728
|
-
const { stdout } = await
|
|
17758
|
+
const { execFile: execFile6 } = await import("node:child_process");
|
|
17759
|
+
const { promisify: promisify13 } = await import("node:util");
|
|
17760
|
+
const execFileAsync4 = promisify13(execFile6);
|
|
17761
|
+
const { stdout } = await execFileAsync4(
|
|
17729
17762
|
"git",
|
|
17730
17763
|
["remote", "get-url", "origin"],
|
|
17731
17764
|
{ cwd: projectPath, timeout: 1e3 }
|
|
@@ -28431,13 +28464,13 @@ async function searchWithQmd(rootDir, options) {
|
|
|
28431
28464
|
const command = "qmd";
|
|
28432
28465
|
const limit = Math.max(1, Math.min(options.limit ?? 5, 20));
|
|
28433
28466
|
try {
|
|
28434
|
-
const { execFile:
|
|
28435
|
-
const { promisify:
|
|
28436
|
-
const
|
|
28437
|
-
await ensureQmdProjectMemoryCollection(rootDir,
|
|
28467
|
+
const { execFile: execFile6 } = await import("node:child_process");
|
|
28468
|
+
const { promisify: promisify13 } = await import("node:util");
|
|
28469
|
+
const execFileAsync4 = promisify13(execFile6);
|
|
28470
|
+
await ensureQmdProjectMemoryCollection(rootDir, execFileAsync4);
|
|
28438
28471
|
scheduleQmdProjectMemoryRefresh(rootDir);
|
|
28439
28472
|
const args = buildQmdSearchArgs(rootDir, options);
|
|
28440
|
-
const { stdout } = await
|
|
28473
|
+
const { stdout } = await execFileAsync4(command, args, {
|
|
28441
28474
|
cwd: rootDir,
|
|
28442
28475
|
timeout: 4e3,
|
|
28443
28476
|
maxBuffer: 1024 * 1024
|
|
@@ -28462,12 +28495,12 @@ async function searchWithQmd(rootDir, options) {
|
|
|
28462
28495
|
return [];
|
|
28463
28496
|
}
|
|
28464
28497
|
}
|
|
28465
|
-
async function ensureQmdProjectMemoryCollection(rootDir,
|
|
28498
|
+
async function ensureQmdProjectMemoryCollection(rootDir, execFileAsync4) {
|
|
28466
28499
|
const collectionName = qmdMemoryCollectionName(rootDir);
|
|
28467
28500
|
const memoryDir = memoryWorkspacePath(rootDir);
|
|
28468
28501
|
await mkdir6(memoryDir, { recursive: true });
|
|
28469
28502
|
try {
|
|
28470
|
-
await
|
|
28503
|
+
await execFileAsync4("qmd", buildQmdCollectionAddArgs(rootDir), {
|
|
28471
28504
|
cwd: rootDir,
|
|
28472
28505
|
timeout: 4e3,
|
|
28473
28506
|
maxBuffer: 512 * 1024
|
|
@@ -28483,9 +28516,9 @@ ${stderr}`)) {
|
|
|
28483
28516
|
return collectionName;
|
|
28484
28517
|
}
|
|
28485
28518
|
async function getDefaultExecFileAsync() {
|
|
28486
|
-
const { execFile:
|
|
28487
|
-
const { promisify:
|
|
28488
|
-
return
|
|
28519
|
+
const { execFile: execFile6 } = await import("node:child_process");
|
|
28520
|
+
const { promisify: promisify13 } = await import("node:util");
|
|
28521
|
+
return promisify13(execFile6);
|
|
28489
28522
|
}
|
|
28490
28523
|
async function refreshQmdProjectMemoryIndex(rootDir, options) {
|
|
28491
28524
|
const key = resolve5(rootDir);
|
|
@@ -28500,14 +28533,14 @@ async function refreshQmdProjectMemoryIndex(rootDir, options) {
|
|
|
28500
28533
|
}
|
|
28501
28534
|
}
|
|
28502
28535
|
const promise = (async () => {
|
|
28503
|
-
const
|
|
28504
|
-
await ensureQmdProjectMemoryCollection(rootDir,
|
|
28505
|
-
await
|
|
28536
|
+
const execFileAsync4 = options?.execFileAsync ?? await getDefaultExecFileAsync();
|
|
28537
|
+
await ensureQmdProjectMemoryCollection(rootDir, execFileAsync4);
|
|
28538
|
+
await execFileAsync4("qmd", ["update"], {
|
|
28506
28539
|
cwd: rootDir,
|
|
28507
28540
|
timeout: 3e4,
|
|
28508
28541
|
maxBuffer: 1024 * 1024
|
|
28509
28542
|
});
|
|
28510
|
-
await
|
|
28543
|
+
await execFileAsync4("qmd", ["embed"], {
|
|
28511
28544
|
cwd: rootDir,
|
|
28512
28545
|
timeout: 12e4,
|
|
28513
28546
|
maxBuffer: 1024 * 1024
|
|
@@ -28532,8 +28565,8 @@ function scheduleQmdProjectMemoryRefresh(rootDir) {
|
|
|
28532
28565
|
}
|
|
28533
28566
|
async function isQmdAvailable() {
|
|
28534
28567
|
try {
|
|
28535
|
-
const
|
|
28536
|
-
await
|
|
28568
|
+
const execFileAsync4 = await getDefaultExecFileAsync();
|
|
28569
|
+
await execFileAsync4("qmd", ["--help"], {
|
|
28537
28570
|
timeout: 3e3,
|
|
28538
28571
|
maxBuffer: 128 * 1024
|
|
28539
28572
|
});
|
|
@@ -28543,12 +28576,12 @@ async function isQmdAvailable() {
|
|
|
28543
28576
|
}
|
|
28544
28577
|
}
|
|
28545
28578
|
async function installQmd(options) {
|
|
28546
|
-
const
|
|
28579
|
+
const execFileAsync4 = options?.execFileAsync ?? await getDefaultExecFileAsync();
|
|
28547
28580
|
const [command, ...args] = QMD_INSTALL_COMMAND.split(" ");
|
|
28548
28581
|
if (!command || args.length === 0) {
|
|
28549
28582
|
throw new MemoryBackendError("BACKEND_UNAVAILABLE", "qmd install command is not configured", "qmd");
|
|
28550
28583
|
}
|
|
28551
|
-
await
|
|
28584
|
+
await execFileAsync4(command, args, {
|
|
28552
28585
|
timeout: 12e4,
|
|
28553
28586
|
maxBuffer: 1024 * 1024
|
|
28554
28587
|
});
|
|
@@ -29354,6 +29387,29 @@ function canonicalizeSettings(settings) {
|
|
|
29354
29387
|
}
|
|
29355
29388
|
return base;
|
|
29356
29389
|
}
|
|
29390
|
+
function isPlainObject(value) {
|
|
29391
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
29392
|
+
}
|
|
29393
|
+
function deepMergeWithNullDelete(existingValue, patchValue) {
|
|
29394
|
+
const merged = isPlainObject(existingValue) ? { ...existingValue } : {};
|
|
29395
|
+
for (const [key, value] of Object.entries(patchValue)) {
|
|
29396
|
+
if (value === null) {
|
|
29397
|
+
delete merged[key];
|
|
29398
|
+
continue;
|
|
29399
|
+
}
|
|
29400
|
+
if (isPlainObject(value)) {
|
|
29401
|
+
const nested = deepMergeWithNullDelete(merged[key], value);
|
|
29402
|
+
if (nested === void 0) {
|
|
29403
|
+
delete merged[key];
|
|
29404
|
+
} else {
|
|
29405
|
+
merged[key] = nested;
|
|
29406
|
+
}
|
|
29407
|
+
continue;
|
|
29408
|
+
}
|
|
29409
|
+
merged[key] = value;
|
|
29410
|
+
}
|
|
29411
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
29412
|
+
}
|
|
29357
29413
|
var TASK_ACTIVITY_LOG_ENTRY_LIMIT, TASK_ACTIVITY_LOG_OUTCOME_LIMIT, ARCHIVE_AGENT_LOG_SNAPSHOT_LIMIT, ARCHIVE_AGENT_LOG_SNIPPET_LIMIT, storeLog, TaskHasDependentsError, TaskStore;
|
|
29358
29414
|
var init_store = __esm({
|
|
29359
29415
|
"../core/src/store.ts"() {
|
|
@@ -30524,6 +30580,21 @@ ${recentText}` : void 0
|
|
|
30524
30580
|
projectPatch["promptOverrides"] = mergedMap;
|
|
30525
30581
|
}
|
|
30526
30582
|
}
|
|
30583
|
+
const incomingRemoteAccess = projectPatch["remoteAccess"];
|
|
30584
|
+
if (incomingRemoteAccess === null) {
|
|
30585
|
+
delete config.settings["remoteAccess"];
|
|
30586
|
+
delete projectPatch["remoteAccess"];
|
|
30587
|
+
} else if (isPlainObject(incomingRemoteAccess)) {
|
|
30588
|
+
const existingRemoteAccess = config.settings["remoteAccess"];
|
|
30589
|
+
const mergedRemoteAccess = deepMergeWithNullDelete(existingRemoteAccess, incomingRemoteAccess);
|
|
30590
|
+
if (mergedRemoteAccess === void 0) {
|
|
30591
|
+
delete config.settings["remoteAccess"];
|
|
30592
|
+
delete projectPatch["remoteAccess"];
|
|
30593
|
+
} else {
|
|
30594
|
+
config.settings["remoteAccess"] = mergedRemoteAccess;
|
|
30595
|
+
projectPatch["remoteAccess"] = mergedRemoteAccess;
|
|
30596
|
+
}
|
|
30597
|
+
}
|
|
30527
30598
|
for (const key of Object.keys(projectPatch)) {
|
|
30528
30599
|
if (projectPatch[key] === null) {
|
|
30529
30600
|
delete config.settings[key];
|
|
@@ -31914,8 +31985,8 @@ ${task.description}
|
|
|
31914
31985
|
if (this.isWatching) this.taskCache.delete(id);
|
|
31915
31986
|
const dir = this.taskDir(id);
|
|
31916
31987
|
if (existsSync12(dir)) {
|
|
31917
|
-
const { rm:
|
|
31918
|
-
await
|
|
31988
|
+
const { rm: rm4 } = await import("node:fs/promises");
|
|
31989
|
+
await rm4(dir, { recursive: true });
|
|
31919
31990
|
}
|
|
31920
31991
|
for (const dependentTask of rewrittenDependents) {
|
|
31921
31992
|
this.emit("task:updated", dependentTask);
|
|
@@ -32250,8 +32321,8 @@ ${task.description}
|
|
|
32250
32321
|
this.archiveDb.upsert(entry);
|
|
32251
32322
|
this.db.prepare("DELETE FROM tasks WHERE id = ?").run(id);
|
|
32252
32323
|
this.db.bumpLastModified();
|
|
32253
|
-
const { rm:
|
|
32254
|
-
await
|
|
32324
|
+
const { rm: rm4 } = await import("node:fs/promises");
|
|
32325
|
+
await rm4(dir, { recursive: true, force: true });
|
|
32255
32326
|
if (this.isWatching) {
|
|
32256
32327
|
this.taskCache.delete(id);
|
|
32257
32328
|
}
|
|
@@ -33203,14 +33274,14 @@ ${task.description}
|
|
|
33203
33274
|
if (rows.length === 0) {
|
|
33204
33275
|
return;
|
|
33205
33276
|
}
|
|
33206
|
-
const { rm:
|
|
33277
|
+
const { rm: rm4 } = await import("node:fs/promises");
|
|
33207
33278
|
for (const row of rows) {
|
|
33208
33279
|
const task = this.rowToTask(row);
|
|
33209
33280
|
const archivedAt = task.columnMovedAt ?? task.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
33210
33281
|
const entry = await this.taskToArchiveEntry(task, archivedAt);
|
|
33211
33282
|
this.archiveDb.upsert(entry);
|
|
33212
33283
|
this.db.prepare("DELETE FROM tasks WHERE id = ?").run(task.id);
|
|
33213
|
-
await
|
|
33284
|
+
await rm4(this.taskDir(task.id), { recursive: true, force: true });
|
|
33214
33285
|
if (this.isWatching) {
|
|
33215
33286
|
this.taskCache.delete(task.id);
|
|
33216
33287
|
}
|
|
@@ -33233,8 +33304,8 @@ ${task.description}
|
|
|
33233
33304
|
this.archiveDb.upsert(entry);
|
|
33234
33305
|
this.db.prepare("DELETE FROM tasks WHERE id = ?").run(task.id);
|
|
33235
33306
|
this.db.bumpLastModified();
|
|
33236
|
-
const { rm:
|
|
33237
|
-
await
|
|
33307
|
+
const { rm: rm4 } = await import("node:fs/promises");
|
|
33308
|
+
await rm4(dir, { recursive: true, force: true });
|
|
33238
33309
|
if (this.isWatching) {
|
|
33239
33310
|
this.taskCache.delete(task.id);
|
|
33240
33311
|
}
|
|
@@ -36345,6 +36416,47 @@ async function writeMemoryAudit(rootDir, content) {
|
|
|
36345
36416
|
}
|
|
36346
36417
|
await writeFile8(filePath, content, "utf-8");
|
|
36347
36418
|
}
|
|
36419
|
+
async function readMemoryAuditState(rootDir) {
|
|
36420
|
+
const filePath = join18(rootDir, MEMORY_AUDIT_STATE_PATH);
|
|
36421
|
+
if (!existsSync15(filePath)) {
|
|
36422
|
+
return null;
|
|
36423
|
+
}
|
|
36424
|
+
try {
|
|
36425
|
+
const raw = await readFile10(filePath, "utf-8");
|
|
36426
|
+
const parsed = JSON.parse(raw);
|
|
36427
|
+
const extraction = isValidExtractionMetadata(parsed.extraction) ? parsed.extraction : void 0;
|
|
36428
|
+
const pruning = isValidPruneOutcome(parsed.pruning) ? parsed.pruning : void 0;
|
|
36429
|
+
return {
|
|
36430
|
+
extraction,
|
|
36431
|
+
pruning,
|
|
36432
|
+
updatedAt: typeof parsed.updatedAt === "string" && parsed.updatedAt.trim() ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
36433
|
+
};
|
|
36434
|
+
} catch {
|
|
36435
|
+
return null;
|
|
36436
|
+
}
|
|
36437
|
+
}
|
|
36438
|
+
async function writeMemoryAuditState(rootDir, state) {
|
|
36439
|
+
const filePath = join18(rootDir, MEMORY_AUDIT_STATE_PATH);
|
|
36440
|
+
const dir = join18(rootDir, ".fusion");
|
|
36441
|
+
if (!existsSync15(dir)) {
|
|
36442
|
+
await mkdir9(dir, { recursive: true });
|
|
36443
|
+
}
|
|
36444
|
+
await writeFile8(filePath, JSON.stringify(state, null, 2), "utf-8");
|
|
36445
|
+
}
|
|
36446
|
+
function isValidExtractionMetadata(value) {
|
|
36447
|
+
if (!value || typeof value !== "object") {
|
|
36448
|
+
return false;
|
|
36449
|
+
}
|
|
36450
|
+
const candidate = value;
|
|
36451
|
+
return typeof candidate.runAt === "string" && typeof candidate.success === "boolean" && typeof candidate.insightCount === "number" && typeof candidate.duplicateCount === "number" && typeof candidate.skippedCount === "number" && typeof candidate.summary === "string" && (candidate.error === void 0 || typeof candidate.error === "string");
|
|
36452
|
+
}
|
|
36453
|
+
function isValidPruneOutcome(value) {
|
|
36454
|
+
if (!value || typeof value !== "object") {
|
|
36455
|
+
return false;
|
|
36456
|
+
}
|
|
36457
|
+
const candidate = value;
|
|
36458
|
+
return typeof candidate.applied === "boolean" && typeof candidate.reason === "string" && typeof candidate.sizeDelta === "number" && typeof candidate.originalSize === "number" && typeof candidate.newSize === "number";
|
|
36459
|
+
}
|
|
36348
36460
|
function buildInsightExtractionPrompt(workingMemory, existingInsights) {
|
|
36349
36461
|
const existingSection = existingInsights ? `
|
|
36350
36462
|
## Existing Insights (already captured \u2014 do not duplicate)
|
|
@@ -36799,6 +36911,9 @@ function countInsightsInMarkdown(markdown) {
|
|
|
36799
36911
|
async function generateMemoryAudit(rootDir, lastExtraction, pruningOutcome) {
|
|
36800
36912
|
const checks = [];
|
|
36801
36913
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
36914
|
+
const persistedState = lastExtraction === void 0 || pruningOutcome === void 0 ? await readMemoryAuditState(rootDir) : null;
|
|
36915
|
+
const effectiveExtraction = lastExtraction ?? persistedState?.extraction;
|
|
36916
|
+
const effectivePruning = pruningOutcome ?? persistedState?.pruning;
|
|
36802
36917
|
const workingMemoryPath = join18(rootDir, MEMORY_WORKING_PATH);
|
|
36803
36918
|
const workingMemoryExists = existsSync15(workingMemoryPath);
|
|
36804
36919
|
let workingMemorySize = 0;
|
|
@@ -36917,20 +37032,20 @@ async function generateMemoryAudit(rootDir, lastExtraction, pruningOutcome) {
|
|
|
36917
37032
|
details: totalInsights > 0 ? `Contains ${totalInsights} insights across categories: patterns=${categoryCounts.pattern}, principles=${categoryCounts.principle}, conventions=${categoryCounts.convention}, pitfalls=${categoryCounts.pitfall}, context=${categoryCounts.context}` : "No insights extracted yet"
|
|
36918
37033
|
});
|
|
36919
37034
|
}
|
|
36920
|
-
if (
|
|
36921
|
-
const extractionAge = Date.now() - new Date(
|
|
37035
|
+
if (effectiveExtraction) {
|
|
37036
|
+
const extractionAge = Date.now() - new Date(effectiveExtraction.runAt).getTime();
|
|
36922
37037
|
const oneWeekMs = 7 * 24 * 60 * 60 * 1e3;
|
|
36923
37038
|
checks.push({
|
|
36924
37039
|
id: "recent-extraction",
|
|
36925
37040
|
name: "Recent extraction activity",
|
|
36926
|
-
passed:
|
|
36927
|
-
details:
|
|
37041
|
+
passed: effectiveExtraction.success && extractionAge < oneWeekMs,
|
|
37042
|
+
details: effectiveExtraction.success ? `Last successful extraction ${formatTimeAgo(effectiveExtraction.runAt)} (${effectiveExtraction.insightCount} insights, ${effectiveExtraction.duplicateCount} duplicates skipped)` : `Last extraction failed: ${effectiveExtraction.error || "Unknown error"}`
|
|
36928
37043
|
});
|
|
36929
37044
|
checks.push({
|
|
36930
37045
|
id: "extraction-summary",
|
|
36931
37046
|
name: "Extraction produces meaningful summaries",
|
|
36932
|
-
passed:
|
|
36933
|
-
details:
|
|
37047
|
+
passed: effectiveExtraction.success && effectiveExtraction.summary.length > 10,
|
|
37048
|
+
details: effectiveExtraction.success ? `Summary: "${effectiveExtraction.summary.slice(0, 100)}${effectiveExtraction.summary.length > 100 ? "..." : ""}"` : "No meaningful summary available"
|
|
36934
37049
|
});
|
|
36935
37050
|
} else {
|
|
36936
37051
|
checks.push({
|
|
@@ -36940,12 +37055,12 @@ async function generateMemoryAudit(rootDir, lastExtraction, pruningOutcome) {
|
|
|
36940
37055
|
details: "No extraction runs recorded"
|
|
36941
37056
|
});
|
|
36942
37057
|
}
|
|
36943
|
-
if (
|
|
37058
|
+
if (effectivePruning) {
|
|
36944
37059
|
checks.push({
|
|
36945
37060
|
id: "pruning-applied",
|
|
36946
37061
|
name: "Memory pruning outcome",
|
|
36947
|
-
passed:
|
|
36948
|
-
details:
|
|
37062
|
+
passed: effectivePruning.applied,
|
|
37063
|
+
details: effectivePruning.applied ? `Pruning applied: ${effectivePruning.originalSize} \u2192 ${effectivePruning.newSize} chars (${effectivePruning.sizeDelta >= 0 ? "+" : ""}${effectivePruning.sizeDelta} chars)` : `Pruning skipped: ${effectivePruning.reason}`
|
|
36949
37064
|
});
|
|
36950
37065
|
}
|
|
36951
37066
|
const failedChecks = checks.filter((c) => !c.passed);
|
|
@@ -36972,14 +37087,14 @@ async function generateMemoryAudit(rootDir, lastExtraction, pruningOutcome) {
|
|
|
36972
37087
|
categories: categoryCounts,
|
|
36973
37088
|
lastUpdated
|
|
36974
37089
|
},
|
|
36975
|
-
extraction:
|
|
36976
|
-
runAt:
|
|
36977
|
-
success:
|
|
36978
|
-
insightCount:
|
|
36979
|
-
duplicateCount:
|
|
36980
|
-
skippedCount:
|
|
36981
|
-
summary:
|
|
36982
|
-
error:
|
|
37090
|
+
extraction: effectiveExtraction ? {
|
|
37091
|
+
runAt: effectiveExtraction.runAt,
|
|
37092
|
+
success: effectiveExtraction.success,
|
|
37093
|
+
insightCount: effectiveExtraction.insightCount,
|
|
37094
|
+
duplicateCount: effectiveExtraction.duplicateCount,
|
|
37095
|
+
skippedCount: effectiveExtraction.skippedCount,
|
|
37096
|
+
summary: effectiveExtraction.summary,
|
|
37097
|
+
error: effectiveExtraction.error
|
|
36983
37098
|
} : {
|
|
36984
37099
|
runAt: "",
|
|
36985
37100
|
success: false,
|
|
@@ -36988,7 +37103,7 @@ async function generateMemoryAudit(rootDir, lastExtraction, pruningOutcome) {
|
|
|
36988
37103
|
skippedCount: 0,
|
|
36989
37104
|
summary: "No extraction runs recorded"
|
|
36990
37105
|
},
|
|
36991
|
-
pruning:
|
|
37106
|
+
pruning: effectivePruning ?? {
|
|
36992
37107
|
applied: false,
|
|
36993
37108
|
reason: "No pruning run recorded",
|
|
36994
37109
|
sizeDelta: 0,
|
|
@@ -37129,6 +37244,17 @@ async function processAndAuditInsightExtraction(rootDir, input) {
|
|
|
37129
37244
|
newSize: currentMemory.length
|
|
37130
37245
|
};
|
|
37131
37246
|
}
|
|
37247
|
+
try {
|
|
37248
|
+
await writeMemoryAuditState(rootDir, {
|
|
37249
|
+
extraction: extractionInfo,
|
|
37250
|
+
pruning: pruneOutcome,
|
|
37251
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
37252
|
+
});
|
|
37253
|
+
} catch (err) {
|
|
37254
|
+
console.error(
|
|
37255
|
+
`[memory-audit] Failed to persist audit state: ${err instanceof Error ? err.message : String(err)}`
|
|
37256
|
+
);
|
|
37257
|
+
}
|
|
37132
37258
|
const auditReport = await generateMemoryAudit(rootDir, extractionInfo, pruneOutcome);
|
|
37133
37259
|
try {
|
|
37134
37260
|
const auditMarkdown = renderMemoryAuditMarkdown(auditReport);
|
|
@@ -37140,13 +37266,14 @@ async function processAndAuditInsightExtraction(rootDir, input) {
|
|
|
37140
37266
|
}
|
|
37141
37267
|
return auditReport;
|
|
37142
37268
|
}
|
|
37143
|
-
var MEMORY_WORKING_PATH, MEMORY_INSIGHTS_PATH, MEMORY_AUDIT_PATH, DEFAULT_INSIGHT_SCHEDULE, DEFAULT_MIN_INTERVAL_MS, MIN_INSIGHT_GROWTH_CHARS, INSIGHT_EXTRACTION_SCHEDULE_NAME, REQUIRED_MEMORY_SECTIONS;
|
|
37269
|
+
var MEMORY_WORKING_PATH, MEMORY_INSIGHTS_PATH, MEMORY_AUDIT_PATH, MEMORY_AUDIT_STATE_PATH, DEFAULT_INSIGHT_SCHEDULE, DEFAULT_MIN_INTERVAL_MS, MIN_INSIGHT_GROWTH_CHARS, INSIGHT_EXTRACTION_SCHEDULE_NAME, REQUIRED_MEMORY_SECTIONS;
|
|
37144
37270
|
var init_memory_insights = __esm({
|
|
37145
37271
|
"../core/src/memory-insights.ts"() {
|
|
37146
37272
|
"use strict";
|
|
37147
37273
|
MEMORY_WORKING_PATH = ".fusion/memory/MEMORY.md";
|
|
37148
37274
|
MEMORY_INSIGHTS_PATH = ".fusion/memory-insights.md";
|
|
37149
37275
|
MEMORY_AUDIT_PATH = ".fusion/memory-audit.md";
|
|
37276
|
+
MEMORY_AUDIT_STATE_PATH = ".fusion/memory-audit-state.json";
|
|
37150
37277
|
DEFAULT_INSIGHT_SCHEDULE = "0 2 * * *";
|
|
37151
37278
|
DEFAULT_MIN_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
37152
37279
|
MIN_INSIGHT_GROWTH_CHARS = 1e3;
|
|
@@ -38324,15 +38451,15 @@ var require_fd_slicer = __commonJS({
|
|
|
38324
38451
|
var Writable = stream.Writable;
|
|
38325
38452
|
var PassThrough = stream.PassThrough;
|
|
38326
38453
|
var Pend = require_pend();
|
|
38327
|
-
var
|
|
38454
|
+
var EventEmitter26 = __require("events").EventEmitter;
|
|
38328
38455
|
exports.createFromBuffer = createFromBuffer;
|
|
38329
38456
|
exports.createFromFd = createFromFd;
|
|
38330
38457
|
exports.BufferSlicer = BufferSlicer;
|
|
38331
38458
|
exports.FdSlicer = FdSlicer;
|
|
38332
|
-
util.inherits(FdSlicer,
|
|
38459
|
+
util.inherits(FdSlicer, EventEmitter26);
|
|
38333
38460
|
function FdSlicer(fd, options) {
|
|
38334
38461
|
options = options || {};
|
|
38335
|
-
|
|
38462
|
+
EventEmitter26.call(this);
|
|
38336
38463
|
this.fd = fd;
|
|
38337
38464
|
this.pend = new Pend();
|
|
38338
38465
|
this.pend.max = 1;
|
|
@@ -38476,9 +38603,9 @@ var require_fd_slicer = __commonJS({
|
|
|
38476
38603
|
this.destroyed = true;
|
|
38477
38604
|
this.context.unref();
|
|
38478
38605
|
};
|
|
38479
|
-
util.inherits(BufferSlicer,
|
|
38606
|
+
util.inherits(BufferSlicer, EventEmitter26);
|
|
38480
38607
|
function BufferSlicer(buffer, options) {
|
|
38481
|
-
|
|
38608
|
+
EventEmitter26.call(this);
|
|
38482
38609
|
options = options || {};
|
|
38483
38610
|
this.refCount = 0;
|
|
38484
38611
|
this.buffer = buffer;
|
|
@@ -38890,7 +39017,7 @@ var require_yauzl = __commonJS({
|
|
|
38890
39017
|
var fd_slicer = require_fd_slicer();
|
|
38891
39018
|
var crc32 = require_buffer_crc32();
|
|
38892
39019
|
var util = __require("util");
|
|
38893
|
-
var
|
|
39020
|
+
var EventEmitter26 = __require("events").EventEmitter;
|
|
38894
39021
|
var Transform = __require("stream").Transform;
|
|
38895
39022
|
var PassThrough = __require("stream").PassThrough;
|
|
38896
39023
|
var Writable = __require("stream").Writable;
|
|
@@ -39022,10 +39149,10 @@ var require_yauzl = __commonJS({
|
|
|
39022
39149
|
callback(new Error("end of central directory record signature not found"));
|
|
39023
39150
|
});
|
|
39024
39151
|
}
|
|
39025
|
-
util.inherits(ZipFile,
|
|
39152
|
+
util.inherits(ZipFile, EventEmitter26);
|
|
39026
39153
|
function ZipFile(reader, centralDirectoryOffset, fileSize, entryCount, comment, autoClose, lazyEntries, decodeStrings, validateEntrySizes, strictFileNames) {
|
|
39027
39154
|
var self = this;
|
|
39028
|
-
|
|
39155
|
+
EventEmitter26.call(self);
|
|
39029
39156
|
self.reader = reader;
|
|
39030
39157
|
self.reader.on("error", function(err) {
|
|
39031
39158
|
emitError(self, err);
|
|
@@ -39386,9 +39513,9 @@ var require_yauzl = __commonJS({
|
|
|
39386
39513
|
}
|
|
39387
39514
|
cb();
|
|
39388
39515
|
};
|
|
39389
|
-
util.inherits(RandomAccessReader,
|
|
39516
|
+
util.inherits(RandomAccessReader, EventEmitter26);
|
|
39390
39517
|
function RandomAccessReader() {
|
|
39391
|
-
|
|
39518
|
+
EventEmitter26.call(this);
|
|
39392
39519
|
this.refCount = 0;
|
|
39393
39520
|
}
|
|
39394
39521
|
RandomAccessReader.prototype.ref = function() {
|
|
@@ -39519,11 +39646,11 @@ var require_extract_zip = __commonJS({
|
|
|
39519
39646
|
var { createWriteStream, promises: fs } = __require("fs");
|
|
39520
39647
|
var getStream = require_get_stream();
|
|
39521
39648
|
var path = __require("path");
|
|
39522
|
-
var { promisify:
|
|
39649
|
+
var { promisify: promisify13 } = __require("util");
|
|
39523
39650
|
var stream = __require("stream");
|
|
39524
39651
|
var yauzl = require_yauzl();
|
|
39525
|
-
var openZip =
|
|
39526
|
-
var pipeline =
|
|
39652
|
+
var openZip = promisify13(yauzl.open);
|
|
39653
|
+
var pipeline = promisify13(stream.pipeline);
|
|
39527
39654
|
var Extractor = class {
|
|
39528
39655
|
constructor(zipPath, opts) {
|
|
39529
39656
|
this.zipPath = zipPath;
|
|
@@ -39605,7 +39732,7 @@ var require_extract_zip = __commonJS({
|
|
|
39605
39732
|
await fs.mkdir(destDir, mkdirOptions);
|
|
39606
39733
|
if (isDir) return;
|
|
39607
39734
|
debug("opening read stream", dest);
|
|
39608
|
-
const readStream = await
|
|
39735
|
+
const readStream = await promisify13(this.zipfile.openReadStream.bind(this.zipfile))(entry);
|
|
39609
39736
|
if (symlink) {
|
|
39610
39737
|
const link = await getStream(readStream);
|
|
39611
39738
|
debug("creating symlink", link, dest);
|
|
@@ -47266,12 +47393,12 @@ function resolveExtractionRoot(tempDir) {
|
|
|
47266
47393
|
return tempDir;
|
|
47267
47394
|
}
|
|
47268
47395
|
async function extractTarArchive(archivePath, outputDir) {
|
|
47269
|
-
const [{ execFile:
|
|
47396
|
+
const [{ execFile: execFile6 }, { promisify: promisify13 }] = await Promise.all([
|
|
47270
47397
|
import("node:child_process"),
|
|
47271
47398
|
import("node:util")
|
|
47272
47399
|
]);
|
|
47273
|
-
const
|
|
47274
|
-
await
|
|
47400
|
+
const execFileAsync4 = promisify13(execFile6);
|
|
47401
|
+
await execFileAsync4("tar", ["xzf", archivePath, "-C", outputDir]);
|
|
47275
47402
|
}
|
|
47276
47403
|
async function parseCompanyArchive(archivePath) {
|
|
47277
47404
|
const resolvedArchivePath = resolve8(archivePath);
|
|
@@ -48451,7 +48578,7 @@ ${stack}` : message2;
|
|
|
48451
48578
|
}
|
|
48452
48579
|
return { message, detail: message };
|
|
48453
48580
|
}
|
|
48454
|
-
var LOG_LEVEL_MARKER_PREFIX2, LOG_LEVEL_MARKER_SUFFIX2, schedulerLog, executorLog, triageLog, piLog, extensionsLog, mergerLog, worktreePoolLog, reviewerLog, prMonitorLog, runtimeLog, ipcLog, projectManagerLog, hybridExecutorLog, autopilotLog, heartbeatLog, remoteNodeLog, nodeHealthMonitorLog, peerExchangeLog;
|
|
48581
|
+
var LOG_LEVEL_MARKER_PREFIX2, LOG_LEVEL_MARKER_SUFFIX2, schedulerLog, executorLog, triageLog, piLog, extensionsLog, mergerLog, worktreePoolLog, reviewerLog, prMonitorLog, runtimeLog, ipcLog, projectManagerLog, hybridExecutorLog, autopilotLog, heartbeatLog, remoteNodeLog, remoteTunnelLog, nodeHealthMonitorLog, peerExchangeLog;
|
|
48455
48582
|
var init_logger2 = __esm({
|
|
48456
48583
|
"../engine/src/logger.ts"() {
|
|
48457
48584
|
"use strict";
|
|
@@ -48473,6 +48600,7 @@ var init_logger2 = __esm({
|
|
|
48473
48600
|
autopilotLog = createLogger2("autopilot");
|
|
48474
48601
|
heartbeatLog = createLogger2("heartbeat");
|
|
48475
48602
|
remoteNodeLog = createLogger2("remote-node");
|
|
48603
|
+
remoteTunnelLog = createLogger2("remote-tunnel");
|
|
48476
48604
|
nodeHealthMonitorLog = createLogger2("node-health-monitor");
|
|
48477
48605
|
peerExchangeLog = createLogger2("peer-exchange");
|
|
48478
48606
|
}
|
|
@@ -48809,11 +48937,11 @@ async function refreshAgentMemoryQmdIndex(rootDir, agentMemory) {
|
|
|
48809
48937
|
return;
|
|
48810
48938
|
}
|
|
48811
48939
|
const promise = (async () => {
|
|
48812
|
-
const { execFile:
|
|
48813
|
-
const { promisify:
|
|
48814
|
-
const
|
|
48940
|
+
const { execFile: execFile6 } = await import("node:child_process");
|
|
48941
|
+
const { promisify: promisify13 } = await import("node:util");
|
|
48942
|
+
const execFileAsync4 = promisify13(execFile6);
|
|
48815
48943
|
try {
|
|
48816
|
-
await
|
|
48944
|
+
await execFileAsync4("qmd", buildQmdAgentMemoryCollectionAddArgs(rootDir, agentMemory.agentId), {
|
|
48817
48945
|
cwd: rootDir,
|
|
48818
48946
|
timeout: 4e3,
|
|
48819
48947
|
maxBuffer: 512 * 1024
|
|
@@ -48826,8 +48954,8 @@ ${stderr}`)) {
|
|
|
48826
48954
|
throw error;
|
|
48827
48955
|
}
|
|
48828
48956
|
}
|
|
48829
|
-
await
|
|
48830
|
-
await
|
|
48957
|
+
await execFileAsync4("qmd", ["update"], { cwd: rootDir, timeout: 3e4, maxBuffer: 1024 * 1024 });
|
|
48958
|
+
await execFileAsync4("qmd", ["embed"], { cwd: rootDir, timeout: 12e4, maxBuffer: 1024 * 1024 });
|
|
48831
48959
|
})();
|
|
48832
48960
|
agentQmdRefreshState.set(key, { lastStartedAt: now, inFlight: promise });
|
|
48833
48961
|
try {
|
|
@@ -48848,10 +48976,10 @@ async function searchAgentMemoryWithQmd(rootDir, agentMemory, query, limit) {
|
|
|
48848
48976
|
}
|
|
48849
48977
|
try {
|
|
48850
48978
|
await refreshAgentMemoryQmdIndex(rootDir, agentMemory);
|
|
48851
|
-
const { execFile:
|
|
48852
|
-
const { promisify:
|
|
48853
|
-
const
|
|
48854
|
-
const { stdout } = await
|
|
48979
|
+
const { execFile: execFile6 } = await import("node:child_process");
|
|
48980
|
+
const { promisify: promisify13 } = await import("node:util");
|
|
48981
|
+
const execFileAsync4 = promisify13(execFile6);
|
|
48982
|
+
const { stdout } = await execFileAsync4("qmd", buildQmdAgentMemorySearchArgs(rootDir, agentMemory.agentId, query, limit), {
|
|
48855
48983
|
cwd: rootDir,
|
|
48856
48984
|
timeout: 4e3,
|
|
48857
48985
|
maxBuffer: 1024 * 1024
|
|
@@ -54044,14 +54172,14 @@ function rethrowIfMergeAborted(error) {
|
|
|
54044
54172
|
throw error;
|
|
54045
54173
|
}
|
|
54046
54174
|
}
|
|
54047
|
-
async function runDeterministicVerification(store, rootDir, taskId, testCommand,
|
|
54175
|
+
async function runDeterministicVerification(store, rootDir, taskId, testCommand, buildCommand2, testSource, buildSource, signal) {
|
|
54048
54176
|
const result = { allPassed: true };
|
|
54049
|
-
if (!testCommand && !
|
|
54177
|
+
if (!testCommand && !buildCommand2) {
|
|
54050
54178
|
mergerLog.log(`${taskId}: no verification commands configured \u2014 skipping`);
|
|
54051
54179
|
return result;
|
|
54052
54180
|
}
|
|
54053
54181
|
const normalizedTestCommand = testCommand?.trim();
|
|
54054
|
-
const normalizedBuildCommand =
|
|
54182
|
+
const normalizedBuildCommand = buildCommand2?.trim();
|
|
54055
54183
|
const hasTestCommand = !!normalizedTestCommand;
|
|
54056
54184
|
const hasBuildCommand = !!normalizedBuildCommand;
|
|
54057
54185
|
const testSourceLabel = testSource === "inferred" ? " [inferred]" : "";
|
|
@@ -55545,7 +55673,7 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
55545
55673
|
result,
|
|
55546
55674
|
settings,
|
|
55547
55675
|
testCommand,
|
|
55548
|
-
buildCommand,
|
|
55676
|
+
buildCommand: buildCommand2,
|
|
55549
55677
|
testSource,
|
|
55550
55678
|
buildSource
|
|
55551
55679
|
} = params;
|
|
@@ -55614,14 +55742,14 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
55614
55742
|
);
|
|
55615
55743
|
mergerLog.log(`${taskId}: committed after auto-resolving all conflicts`);
|
|
55616
55744
|
}
|
|
55617
|
-
if (testCommand ||
|
|
55745
|
+
if (testCommand || buildCommand2) {
|
|
55618
55746
|
throwIfAborted(options.signal, taskId);
|
|
55619
55747
|
await runDeterministicVerification(
|
|
55620
55748
|
store,
|
|
55621
55749
|
rootDir,
|
|
55622
55750
|
taskId,
|
|
55623
55751
|
testCommand,
|
|
55624
|
-
|
|
55752
|
+
buildCommand2,
|
|
55625
55753
|
testSource,
|
|
55626
55754
|
buildSource,
|
|
55627
55755
|
options.signal
|
|
@@ -55637,14 +55765,14 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
55637
55765
|
).trim() === "0";
|
|
55638
55766
|
if (squashIsEmpty) {
|
|
55639
55767
|
mergerLog.log(`${taskId}: squash merge staged nothing \u2014 already merged`);
|
|
55640
|
-
if (testCommand ||
|
|
55768
|
+
if (testCommand || buildCommand2) {
|
|
55641
55769
|
throwIfAborted(options.signal, taskId);
|
|
55642
55770
|
await runDeterministicVerification(
|
|
55643
55771
|
store,
|
|
55644
55772
|
rootDir,
|
|
55645
55773
|
taskId,
|
|
55646
55774
|
testCommand,
|
|
55647
|
-
|
|
55775
|
+
buildCommand2,
|
|
55648
55776
|
testSource,
|
|
55649
55777
|
buildSource,
|
|
55650
55778
|
options.signal
|
|
@@ -55664,14 +55792,14 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
55664
55792
|
).trim() === "0";
|
|
55665
55793
|
if (squashIsEmpty) {
|
|
55666
55794
|
mergerLog.log(`${taskId}: squash merge staged nothing \u2014 already merged`);
|
|
55667
|
-
if (testCommand ||
|
|
55795
|
+
if (testCommand || buildCommand2) {
|
|
55668
55796
|
throwIfAborted(options.signal, taskId);
|
|
55669
55797
|
await runDeterministicVerification(
|
|
55670
55798
|
store,
|
|
55671
55799
|
rootDir,
|
|
55672
55800
|
taskId,
|
|
55673
55801
|
testCommand,
|
|
55674
|
-
|
|
55802
|
+
buildCommand2,
|
|
55675
55803
|
testSource,
|
|
55676
55804
|
buildSource,
|
|
55677
55805
|
options.signal
|
|
@@ -55691,7 +55819,7 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
55691
55819
|
return false;
|
|
55692
55820
|
}
|
|
55693
55821
|
}
|
|
55694
|
-
if (
|
|
55822
|
+
if (buildCommand2) {
|
|
55695
55823
|
throwIfAborted(options.signal, taskId);
|
|
55696
55824
|
const stagedFiles = await getStagedFiles(rootDir);
|
|
55697
55825
|
if (shouldSyncDependenciesForMerge(stagedFiles, hasInstallState(rootDir))) {
|
|
@@ -55712,7 +55840,7 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
55712
55840
|
simplifiedContext: attemptNum === 2,
|
|
55713
55841
|
options,
|
|
55714
55842
|
testCommand,
|
|
55715
|
-
buildCommand
|
|
55843
|
+
buildCommand: buildCommand2
|
|
55716
55844
|
});
|
|
55717
55845
|
if (!agentResult.success) {
|
|
55718
55846
|
const errorMessage = agentResult.error || "Build verification failed";
|
|
@@ -55727,14 +55855,14 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
55727
55855
|
}
|
|
55728
55856
|
throw new Error(`Build verification failed for ${taskId}: ${errorMessage}`);
|
|
55729
55857
|
}
|
|
55730
|
-
if (testCommand ||
|
|
55858
|
+
if (testCommand || buildCommand2) {
|
|
55731
55859
|
throwIfAborted(options.signal, taskId);
|
|
55732
55860
|
await runDeterministicVerification(
|
|
55733
55861
|
store,
|
|
55734
55862
|
rootDir,
|
|
55735
55863
|
taskId,
|
|
55736
55864
|
testCommand,
|
|
55737
|
-
|
|
55865
|
+
buildCommand2,
|
|
55738
55866
|
testSource,
|
|
55739
55867
|
buildSource,
|
|
55740
55868
|
options.signal
|
|
@@ -55762,7 +55890,7 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
55762
55890
|
}
|
|
55763
55891
|
}
|
|
55764
55892
|
async function attemptWithTheirsStrategy(params) {
|
|
55765
|
-
const { rootDir, branch, commitLog, includeTaskId, taskId, store, settings, testCommand, buildCommand, testSource, buildSource } = params;
|
|
55893
|
+
const { rootDir, branch, commitLog, includeTaskId, taskId, store, settings, testCommand, buildCommand: buildCommand2, testSource, buildSource } = params;
|
|
55766
55894
|
mergerLog.log(`${taskId}: attempting merge with -X theirs strategy`);
|
|
55767
55895
|
try {
|
|
55768
55896
|
throwIfAborted(params.options.signal, taskId);
|
|
@@ -55782,14 +55910,14 @@ async function attemptWithTheirsStrategy(params) {
|
|
|
55782
55910
|
encoding: "utf-8"
|
|
55783
55911
|
}).trim();
|
|
55784
55912
|
if (staged === "0") {
|
|
55785
|
-
if (testCommand ||
|
|
55913
|
+
if (testCommand || buildCommand2) {
|
|
55786
55914
|
throwIfAborted(params.options.signal, taskId);
|
|
55787
55915
|
await runDeterministicVerification(
|
|
55788
55916
|
store,
|
|
55789
55917
|
rootDir,
|
|
55790
55918
|
taskId,
|
|
55791
55919
|
testCommand,
|
|
55792
|
-
|
|
55920
|
+
buildCommand2,
|
|
55793
55921
|
testSource,
|
|
55794
55922
|
buildSource,
|
|
55795
55923
|
params.options.signal
|
|
@@ -55806,14 +55934,14 @@ async function attemptWithTheirsStrategy(params) {
|
|
|
55806
55934
|
{ cwd: rootDir }
|
|
55807
55935
|
);
|
|
55808
55936
|
mergerLog.log(`${taskId}: committed with -X theirs auto-resolution`);
|
|
55809
|
-
if (testCommand ||
|
|
55937
|
+
if (testCommand || buildCommand2) {
|
|
55810
55938
|
throwIfAborted(params.options.signal, taskId);
|
|
55811
55939
|
await runDeterministicVerification(
|
|
55812
55940
|
store,
|
|
55813
55941
|
rootDir,
|
|
55814
55942
|
taskId,
|
|
55815
55943
|
testCommand,
|
|
55816
|
-
|
|
55944
|
+
buildCommand2,
|
|
55817
55945
|
testSource,
|
|
55818
55946
|
buildSource,
|
|
55819
55947
|
params.options.signal
|
|
@@ -55841,7 +55969,7 @@ async function runAiAgentForCommit(params) {
|
|
|
55841
55969
|
simplifiedContext,
|
|
55842
55970
|
options,
|
|
55843
55971
|
testCommand,
|
|
55844
|
-
buildCommand
|
|
55972
|
+
buildCommand: buildCommand2
|
|
55845
55973
|
} = params;
|
|
55846
55974
|
const settings = await store.getSettings();
|
|
55847
55975
|
let buildFailed = false;
|
|
@@ -55930,7 +56058,7 @@ async function runAiAgentForCommit(params) {
|
|
|
55930
56058
|
hasConflicts,
|
|
55931
56059
|
simplifiedContext,
|
|
55932
56060
|
testCommand,
|
|
55933
|
-
buildCommand,
|
|
56061
|
+
buildCommand: buildCommand2,
|
|
55934
56062
|
authorArg
|
|
55935
56063
|
});
|
|
55936
56064
|
mergerLog.log(`${taskId}: starting fresh merge agent session`);
|
|
@@ -55962,7 +56090,7 @@ async function runAiAgentForCommit(params) {
|
|
|
55962
56090
|
simplifiedContext: true,
|
|
55963
56091
|
// Also skip detailed context
|
|
55964
56092
|
testCommand,
|
|
55965
|
-
buildCommand,
|
|
56093
|
+
buildCommand: buildCommand2,
|
|
55966
56094
|
authorArg
|
|
55967
56095
|
});
|
|
55968
56096
|
try {
|
|
@@ -55998,7 +56126,7 @@ async function runAiAgentForCommit(params) {
|
|
|
55998
56126
|
encoding: "utf-8"
|
|
55999
56127
|
}).trim();
|
|
56000
56128
|
if (staged !== "0") {
|
|
56001
|
-
if (!
|
|
56129
|
+
if (!buildCommand2) {
|
|
56002
56130
|
throwIfAborted(options.signal, taskId);
|
|
56003
56131
|
mergerLog.log("Agent didn't commit \u2014 committing with fallback message");
|
|
56004
56132
|
const escapedLog = commitLog.replace(/"/g, '\\"');
|
|
@@ -56025,7 +56153,7 @@ async function runAiAgentForCommit(params) {
|
|
|
56025
56153
|
}
|
|
56026
56154
|
}
|
|
56027
56155
|
function buildMergePrompt(params) {
|
|
56028
|
-
const { taskId, branch, commitLog, diffStat, hasConflicts, simplifiedContext, testCommand, buildCommand, authorArg } = params;
|
|
56156
|
+
const { taskId, branch, commitLog, diffStat, hasConflicts, simplifiedContext, testCommand, buildCommand: buildCommand2, authorArg } = params;
|
|
56029
56157
|
const truncatedCommitLog = truncateWithEllipsis(commitLog, MERGE_COMMIT_LOG_MAX_CHARS);
|
|
56030
56158
|
const truncatedDiffStat = truncateWithEllipsis(diffStat, MERGE_DIFF_STAT_MAX_CHARS);
|
|
56031
56159
|
const parts = [
|
|
@@ -56073,11 +56201,11 @@ function buildMergePrompt(params) {
|
|
|
56073
56201
|
"If it exits non-zero, call `fn_report_build_failure` with the concrete error output and stop without committing."
|
|
56074
56202
|
);
|
|
56075
56203
|
}
|
|
56076
|
-
if (
|
|
56204
|
+
if (buildCommand2) {
|
|
56077
56205
|
parts.push(
|
|
56078
56206
|
"",
|
|
56079
56207
|
"## Build command",
|
|
56080
|
-
`Build command: \`${
|
|
56208
|
+
`Build command: \`${buildCommand2}\``,
|
|
56081
56209
|
"",
|
|
56082
56210
|
"This command is mandatory before commit.",
|
|
56083
56211
|
"Run it with the bash tool in the current worktree and inspect the actual exit code.",
|
|
@@ -58487,6 +58615,8 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
58487
58615
|
loopRecoveryState = /* @__PURE__ */ new Map();
|
|
58488
58616
|
/** Spawned child agent IDs per parent task ID. Used for lifecycle tracking. */
|
|
58489
58617
|
spawnedAgents = /* @__PURE__ */ new Map();
|
|
58618
|
+
/** Per-task baseline of agent cumulative token counters used for delta persistence. */
|
|
58619
|
+
tokenUsageBaselines = /* @__PURE__ */ new Map();
|
|
58490
58620
|
async finalizeAlreadyReviewedTask(taskId) {
|
|
58491
58621
|
const latestTask = await this.store.getTask(taskId);
|
|
58492
58622
|
if (!latestTask || latestTask.column !== "in-review") {
|
|
@@ -58602,6 +58732,65 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
58602
58732
|
async getTaskCompletionBlocker(task) {
|
|
58603
58733
|
return getTaskCompletionBlockerForStore(this.store, task);
|
|
58604
58734
|
}
|
|
58735
|
+
async initializeTokenUsageBaseline(taskId, task) {
|
|
58736
|
+
if (!this.options.agentStore) return;
|
|
58737
|
+
const currentTask = task ?? await this.store.getTask(taskId);
|
|
58738
|
+
const assignedAgentId = currentTask.assignedAgentId?.trim();
|
|
58739
|
+
if (!assignedAgentId) return;
|
|
58740
|
+
const existing = this.tokenUsageBaselines.get(taskId);
|
|
58741
|
+
if (existing?.agentId === assignedAgentId) return;
|
|
58742
|
+
const agent = await this.options.agentStore.getAgent(assignedAgentId);
|
|
58743
|
+
if (!agent) return;
|
|
58744
|
+
this.tokenUsageBaselines.set(taskId, {
|
|
58745
|
+
agentId: assignedAgentId,
|
|
58746
|
+
inputTokens: agent.totalInputTokens ?? 0,
|
|
58747
|
+
outputTokens: agent.totalOutputTokens ?? 0
|
|
58748
|
+
});
|
|
58749
|
+
}
|
|
58750
|
+
async persistTokenUsage(taskId) {
|
|
58751
|
+
if (!this.options.agentStore) return;
|
|
58752
|
+
const task = await this.store.getTask(taskId);
|
|
58753
|
+
const assignedAgentId = task.assignedAgentId?.trim();
|
|
58754
|
+
if (!assignedAgentId) return;
|
|
58755
|
+
const agent = await this.options.agentStore.getAgent(assignedAgentId);
|
|
58756
|
+
if (!agent) return;
|
|
58757
|
+
const currentInputTokens = agent.totalInputTokens ?? 0;
|
|
58758
|
+
const currentOutputTokens = agent.totalOutputTokens ?? 0;
|
|
58759
|
+
const baseline = this.tokenUsageBaselines.get(taskId);
|
|
58760
|
+
if (!baseline || baseline.agentId !== assignedAgentId) {
|
|
58761
|
+
this.tokenUsageBaselines.set(taskId, {
|
|
58762
|
+
agentId: assignedAgentId,
|
|
58763
|
+
inputTokens: currentInputTokens,
|
|
58764
|
+
outputTokens: currentOutputTokens
|
|
58765
|
+
});
|
|
58766
|
+
return;
|
|
58767
|
+
}
|
|
58768
|
+
const inputDelta = Math.max(0, currentInputTokens - baseline.inputTokens);
|
|
58769
|
+
const outputDelta = Math.max(0, currentOutputTokens - baseline.outputTokens);
|
|
58770
|
+
this.tokenUsageBaselines.set(taskId, {
|
|
58771
|
+
agentId: assignedAgentId,
|
|
58772
|
+
inputTokens: currentInputTokens,
|
|
58773
|
+
outputTokens: currentOutputTokens
|
|
58774
|
+
});
|
|
58775
|
+
if (inputDelta === 0 && outputDelta === 0 && !task.tokenUsage) {
|
|
58776
|
+
return;
|
|
58777
|
+
}
|
|
58778
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
58779
|
+
const mergedInputTokens = (task.tokenUsage?.inputTokens ?? 0) + inputDelta;
|
|
58780
|
+
const mergedOutputTokens = (task.tokenUsage?.outputTokens ?? 0) + outputDelta;
|
|
58781
|
+
const cachedTokens = task.tokenUsage?.cachedTokens ?? 0;
|
|
58782
|
+
const totalTokens = mergedInputTokens + mergedOutputTokens + cachedTokens;
|
|
58783
|
+
await this.store.updateTask(taskId, {
|
|
58784
|
+
tokenUsage: {
|
|
58785
|
+
inputTokens: mergedInputTokens,
|
|
58786
|
+
outputTokens: mergedOutputTokens,
|
|
58787
|
+
cachedTokens,
|
|
58788
|
+
totalTokens,
|
|
58789
|
+
firstUsedAt: task.tokenUsage?.firstUsedAt ?? now,
|
|
58790
|
+
lastUsedAt: now
|
|
58791
|
+
}
|
|
58792
|
+
});
|
|
58793
|
+
}
|
|
58605
58794
|
/**
|
|
58606
58795
|
* Execute a review handoff: move the task to in-review column with
|
|
58607
58796
|
* awaiting-user-review status, assign the requesting user, and dispose
|
|
@@ -58624,6 +58813,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
58624
58813
|
},
|
|
58625
58814
|
this.currentRunContext
|
|
58626
58815
|
);
|
|
58816
|
+
await this.persistTokenUsage(task.id);
|
|
58627
58817
|
await this.store.moveTask(task.id, "in-review");
|
|
58628
58818
|
if (this.activeSessions.has(task.id)) {
|
|
58629
58819
|
const { session: activeSession } = this.activeSessions.get(task.id);
|
|
@@ -58662,6 +58852,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
58662
58852
|
executorLog.log(`${task.id}: fast mode \u2014 skipping workflow steps on auto-recovery`);
|
|
58663
58853
|
}
|
|
58664
58854
|
}
|
|
58855
|
+
await this.persistTokenUsage(task.id);
|
|
58665
58856
|
await this.store.moveTask(task.id, "in-review");
|
|
58666
58857
|
await this.store.logEntry(task.id, "Auto-recovered: task work was complete but stuck in in-progress \u2014 moved to in-review");
|
|
58667
58858
|
executorLog.log(`\u2713 ${task.id} auto-recovered completed task \u2192 in-review`);
|
|
@@ -59041,6 +59232,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59041
59232
|
this.options.onStart?.(task, worktreePath);
|
|
59042
59233
|
const detail = await this.store.getTask(task.id);
|
|
59043
59234
|
executorLog.log(`${task.id}: fetched task detail (${detail.steps.length} steps, prompt length=${detail.prompt?.length ?? 0})`);
|
|
59235
|
+
await this.initializeTokenUsageBaseline(task.id, detail);
|
|
59044
59236
|
if (detail.steps.length === 0) {
|
|
59045
59237
|
const steps = await this.store.parseStepsFromPrompt(task.id);
|
|
59046
59238
|
if (steps.length > 0) {
|
|
@@ -59088,6 +59280,9 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59088
59280
|
} catch (err) {
|
|
59089
59281
|
executorLog.warn(`${task.id}: failed to update step ${stepIndex} status: ${err}`);
|
|
59090
59282
|
}
|
|
59283
|
+
this.persistTokenUsage(task.id).catch((err) => {
|
|
59284
|
+
executorLog.warn(`${task.id}: failed to persist token usage on step ${stepIndex} complete: ${err}`);
|
|
59285
|
+
});
|
|
59091
59286
|
}
|
|
59092
59287
|
});
|
|
59093
59288
|
this.activeStepExecutors.set(task.id, stepExecutor);
|
|
@@ -59137,6 +59332,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59137
59332
|
await this.store.logEntry(task.id, "Fast mode \u2014 pre-merge workflow steps skipped", void 0, this.currentRunContext);
|
|
59138
59333
|
}
|
|
59139
59334
|
await this.store.updateTask(task.id, { workflowStepRetries: void 0, taskDoneRetryCount: null });
|
|
59335
|
+
await this.persistTokenUsage(task.id);
|
|
59140
59336
|
await this.store.moveTask(task.id, "in-review");
|
|
59141
59337
|
await audit.database({ type: "task:move", target: task.id, metadata: { to: "in-review" } });
|
|
59142
59338
|
executorLog.log(`\u2713 ${task.id} completed (step-session) \u2192 in-review`);
|
|
@@ -59145,6 +59341,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59145
59341
|
const failedSteps = results.filter((r) => !r.success);
|
|
59146
59342
|
const errorSummary = failedSteps.map((r) => `Step ${r.stepIndex}: ${r.error || "unknown error"}`).join("; ");
|
|
59147
59343
|
await this.store.updateTask(task.id, { status: "failed", error: errorSummary });
|
|
59344
|
+
await this.persistTokenUsage(task.id);
|
|
59148
59345
|
await this.store.moveTask(task.id, "in-review");
|
|
59149
59346
|
executorLog.log(`\u2717 ${task.id} step-session failed \u2192 in-review: ${errorSummary}`);
|
|
59150
59347
|
this.options.onError?.(task, new Error(errorSummary));
|
|
@@ -59221,6 +59418,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59221
59418
|
recoveryRetryCount: null,
|
|
59222
59419
|
nextRecoveryAt: null
|
|
59223
59420
|
});
|
|
59421
|
+
await this.persistTokenUsage(task.id);
|
|
59224
59422
|
await this.store.moveTask(task.id, "in-review");
|
|
59225
59423
|
executorLog.log(`\u2717 ${task.id} transient retries exhausted \u2192 in-review`);
|
|
59226
59424
|
this.options.onError?.(task, err instanceof Error ? err : new Error(errorMessage));
|
|
@@ -59228,6 +59426,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59228
59426
|
executorLog.error(`\u2717 ${task.id} step-session execution failed:`, errorDetail);
|
|
59229
59427
|
await this.store.logEntry(task.id, `Step-session execution failed: ${errorMessage}`, errorStack ?? errorDetail, this.currentRunContext);
|
|
59230
59428
|
await this.store.updateTask(task.id, { status: "failed", error: errorMessage });
|
|
59429
|
+
await this.persistTokenUsage(task.id);
|
|
59231
59430
|
await this.store.moveTask(task.id, "in-review");
|
|
59232
59431
|
executorLog.log(`\u2717 ${task.id} step-session execution failed \u2192 in-review`);
|
|
59233
59432
|
this.options.onError?.(task, err instanceof Error ? err : new Error(errorMessage));
|
|
@@ -59462,6 +59661,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59462
59661
|
if (await this.shouldFinalizeCompletedTask(task.id, taskDone)) {
|
|
59463
59662
|
executorLog.log(`${task.id} paused after completion (graceful session exit) \u2014 finalizing to in-review`);
|
|
59464
59663
|
await this.store.logEntry(task.id, "Execution paused after completion \u2014 finalizing to in-review");
|
|
59664
|
+
await this.persistTokenUsage(task.id);
|
|
59465
59665
|
await this.store.moveTask(task.id, "in-review");
|
|
59466
59666
|
this.options.onComplete?.(task);
|
|
59467
59667
|
} else {
|
|
@@ -59511,6 +59711,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59511
59711
|
await this.store.logEntry(task.id, "Fast mode \u2014 pre-merge workflow steps skipped", void 0, this.currentRunContext);
|
|
59512
59712
|
}
|
|
59513
59713
|
await this.store.updateTask(task.id, { workflowStepRetries: void 0, taskDoneRetryCount: null });
|
|
59714
|
+
await this.persistTokenUsage(task.id);
|
|
59514
59715
|
await this.store.moveTask(task.id, "in-review");
|
|
59515
59716
|
executorLog.log(`\u2713 ${task.id} completed \u2192 in-review`);
|
|
59516
59717
|
this.options.onComplete?.(task);
|
|
@@ -59607,6 +59808,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59607
59808
|
await this.store.logEntry(task.id, "Fast mode \u2014 pre-merge workflow steps skipped", void 0, this.currentRunContext);
|
|
59608
59809
|
}
|
|
59609
59810
|
await this.store.updateTask(task.id, { workflowStepRetries: void 0, taskDoneRetryCount: null });
|
|
59811
|
+
await this.persistTokenUsage(task.id);
|
|
59610
59812
|
await this.store.moveTask(task.id, "in-review");
|
|
59611
59813
|
executorLog.log(`\u2713 ${task.id} completed on retry \u2192 in-review`);
|
|
59612
59814
|
this.options.onComplete?.(task);
|
|
@@ -59631,6 +59833,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59631
59833
|
} else {
|
|
59632
59834
|
await this.store.updateTask(task.id, { status: "failed", error: errorMessage });
|
|
59633
59835
|
await this.store.logEntry(task.id, `${errorMessage} \u2014 moved to in-review for inspection`, void 0, this.currentRunContext);
|
|
59836
|
+
await this.persistTokenUsage(task.id);
|
|
59634
59837
|
await this.store.moveTask(task.id, "in-review");
|
|
59635
59838
|
executorLog.log(`\u2717 ${task.id} failed after ${MAX_TASK_DONE_SESSION_RETRIES} retries \u2014 no fn_task_done \u2192 in-review`);
|
|
59636
59839
|
}
|
|
@@ -59694,6 +59897,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59694
59897
|
if (await this.shouldFinalizeCompletedTask(task.id, taskDone)) {
|
|
59695
59898
|
executorLog.log(`${task.id} paused after completion \u2014 finalizing to in-review`);
|
|
59696
59899
|
await this.store.logEntry(task.id, "Execution paused after completion \u2014 finalizing to in-review", void 0, this.currentRunContext);
|
|
59900
|
+
await this.persistTokenUsage(task.id);
|
|
59697
59901
|
await this.store.moveTask(task.id, "in-review");
|
|
59698
59902
|
this.options.onComplete?.(task);
|
|
59699
59903
|
} else {
|
|
@@ -59819,6 +60023,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59819
60023
|
recoveryRetryCount: null,
|
|
59820
60024
|
nextRecoveryAt: null
|
|
59821
60025
|
});
|
|
60026
|
+
await this.persistTokenUsage(task.id);
|
|
59822
60027
|
await this.store.moveTask(task.id, "in-review");
|
|
59823
60028
|
executorLog.log(`\u2717 ${task.id} transient retries exhausted \u2192 in-review`);
|
|
59824
60029
|
this.options.onError?.(task, err instanceof Error ? err : new Error(errorMessage));
|
|
@@ -59827,6 +60032,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59827
60032
|
executorLog.error(`\u2717 ${task.id} execution failed:`, errorDetail);
|
|
59828
60033
|
await this.store.logEntry(task.id, `Execution failed: ${errorMessage}`, errorStack ?? errorDetail, this.currentRunContext);
|
|
59829
60034
|
await this.store.updateTask(task.id, { status: "failed", error: errorMessage });
|
|
60035
|
+
await this.persistTokenUsage(task.id);
|
|
59830
60036
|
await this.store.moveTask(task.id, "in-review");
|
|
59831
60037
|
executorLog.log(`\u2717 ${task.id} execution failed \u2192 in-review`);
|
|
59832
60038
|
this.options.onError?.(task, err instanceof Error ? err : new Error(errorMessage));
|
|
@@ -59840,6 +60046,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
59840
60046
|
executorLog.warn(`terminateAllChildren failed for ${task.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
59841
60047
|
}
|
|
59842
60048
|
this.loopRecoveryState.delete(task.id);
|
|
60049
|
+
this.tokenUsageBaselines.delete(task.id);
|
|
59843
60050
|
if (stuckRequeue === true) {
|
|
59844
60051
|
try {
|
|
59845
60052
|
const latestTask = await this.store.getTask(task.id);
|
|
@@ -70580,8 +70787,568 @@ var init_project_manager = __esm({
|
|
|
70580
70787
|
}
|
|
70581
70788
|
});
|
|
70582
70789
|
|
|
70790
|
+
// ../engine/src/remote-access/provider-adapters.ts
|
|
70791
|
+
import { accessSync, constants as fsConstants } from "node:fs";
|
|
70792
|
+
function isAbsoluteOrPathLike(input) {
|
|
70793
|
+
return input.startsWith("/") || input.startsWith("./") || input.startsWith("../");
|
|
70794
|
+
}
|
|
70795
|
+
function assertNonEmpty(value, label) {
|
|
70796
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
70797
|
+
throw new Error(`invalid_config:${label} must be a non-empty string`);
|
|
70798
|
+
}
|
|
70799
|
+
}
|
|
70800
|
+
function ensureNumberInRange(value, label) {
|
|
70801
|
+
if (value === void 0) {
|
|
70802
|
+
return void 0;
|
|
70803
|
+
}
|
|
70804
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
70805
|
+
throw new Error(`invalid_config:${label} must be a positive number`);
|
|
70806
|
+
}
|
|
70807
|
+
return Math.floor(value);
|
|
70808
|
+
}
|
|
70809
|
+
function collectSensitiveValues(config) {
|
|
70810
|
+
const values = /* @__PURE__ */ new Set();
|
|
70811
|
+
const env = config.env ?? {};
|
|
70812
|
+
const tokenEnvVar = config.tokenEnvVar;
|
|
70813
|
+
if (typeof tokenEnvVar === "string" && tokenEnvVar.trim().length > 0) {
|
|
70814
|
+
const tokenValue = env[tokenEnvVar] ?? process.env[tokenEnvVar];
|
|
70815
|
+
if (!tokenValue) {
|
|
70816
|
+
throw new Error(`invalid_config:missing credential in env var ${tokenEnvVar}`);
|
|
70817
|
+
}
|
|
70818
|
+
values.add(tokenValue);
|
|
70819
|
+
}
|
|
70820
|
+
for (const envName of config.sensitiveEnvVars ?? []) {
|
|
70821
|
+
const envValue = env[envName] ?? process.env[envName];
|
|
70822
|
+
if (envValue) {
|
|
70823
|
+
values.add(envValue);
|
|
70824
|
+
}
|
|
70825
|
+
}
|
|
70826
|
+
return [...values].sort((a, b) => b.length - a.length);
|
|
70827
|
+
}
|
|
70828
|
+
function redactValue(input, sensitiveValues) {
|
|
70829
|
+
let redacted = input;
|
|
70830
|
+
for (const value of sensitiveValues) {
|
|
70831
|
+
redacted = redacted.split(value).join("[REDACTED]");
|
|
70832
|
+
}
|
|
70833
|
+
return redacted;
|
|
70834
|
+
}
|
|
70835
|
+
function redactArgs(args, sensitiveValues) {
|
|
70836
|
+
return args.map((arg) => redactValue(arg, sensitiveValues));
|
|
70837
|
+
}
|
|
70838
|
+
function buildCommand(config) {
|
|
70839
|
+
const command = config.executablePath.trim();
|
|
70840
|
+
const args = [...config.args];
|
|
70841
|
+
const env = {
|
|
70842
|
+
...process.env,
|
|
70843
|
+
...config.env ?? {}
|
|
70844
|
+
};
|
|
70845
|
+
const sensitiveValues = collectSensitiveValues(config);
|
|
70846
|
+
const redactedPreview = [command, ...redactArgs(args, sensitiveValues)].join(" ").trim();
|
|
70847
|
+
return {
|
|
70848
|
+
provider: config.provider,
|
|
70849
|
+
command,
|
|
70850
|
+
args,
|
|
70851
|
+
cwd: config.cwd,
|
|
70852
|
+
env,
|
|
70853
|
+
redactedPreview,
|
|
70854
|
+
sensitiveValues,
|
|
70855
|
+
readinessTimeoutMs: config.readinessTimeoutMs ?? DEFAULT_READINESS_TIMEOUT_MS,
|
|
70856
|
+
stopTimeoutMs: config.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS
|
|
70857
|
+
};
|
|
70858
|
+
}
|
|
70859
|
+
function parseCommonReadiness(line) {
|
|
70860
|
+
const normalized = line.trim();
|
|
70861
|
+
if (!normalized) {
|
|
70862
|
+
return null;
|
|
70863
|
+
}
|
|
70864
|
+
const urlMatch = normalized.match(URL_PATTERN);
|
|
70865
|
+
const url = urlMatch?.[1];
|
|
70866
|
+
if (/\b(connected|ready|available|started|serving)\b/i.test(normalized)) {
|
|
70867
|
+
return { ready: true, url };
|
|
70868
|
+
}
|
|
70869
|
+
if (url && /\b(trycloudflare|tailscale|ts\.net|serve|funnel)\b/i.test(normalized)) {
|
|
70870
|
+
return { ready: true, url };
|
|
70871
|
+
}
|
|
70872
|
+
return null;
|
|
70873
|
+
}
|
|
70874
|
+
function validateBaseConfig(config, provider) {
|
|
70875
|
+
if (config.provider !== provider) {
|
|
70876
|
+
throw new Error(`invalid_config:config provider ${config.provider} does not match ${provider}`);
|
|
70877
|
+
}
|
|
70878
|
+
assertNonEmpty(config.executablePath, "executablePath");
|
|
70879
|
+
if (!Array.isArray(config.args)) {
|
|
70880
|
+
throw new Error("invalid_config:args must be an array");
|
|
70881
|
+
}
|
|
70882
|
+
for (const [index, arg] of config.args.entries()) {
|
|
70883
|
+
assertNonEmpty(arg, `args[${index}]`);
|
|
70884
|
+
}
|
|
70885
|
+
if (config.cwd !== void 0) {
|
|
70886
|
+
assertNonEmpty(config.cwd, "cwd");
|
|
70887
|
+
}
|
|
70888
|
+
if (config.tokenEnvVar !== void 0) {
|
|
70889
|
+
assertNonEmpty(config.tokenEnvVar, "tokenEnvVar");
|
|
70890
|
+
}
|
|
70891
|
+
ensureNumberInRange(config.readinessTimeoutMs, "readinessTimeoutMs");
|
|
70892
|
+
ensureNumberInRange(config.stopTimeoutMs, "stopTimeoutMs");
|
|
70893
|
+
}
|
|
70894
|
+
function getTunnelProviderAdapter(provider) {
|
|
70895
|
+
return ADAPTERS[provider];
|
|
70896
|
+
}
|
|
70897
|
+
function redactTunnelText(input, sensitiveValues) {
|
|
70898
|
+
return redactValue(input, sensitiveValues);
|
|
70899
|
+
}
|
|
70900
|
+
var DEFAULT_READINESS_TIMEOUT_MS, DEFAULT_STOP_TIMEOUT_MS, URL_PATTERN, tailscaleAdapter, cloudflareAdapter, ADAPTERS;
|
|
70901
|
+
var init_provider_adapters = __esm({
|
|
70902
|
+
"../engine/src/remote-access/provider-adapters.ts"() {
|
|
70903
|
+
"use strict";
|
|
70904
|
+
DEFAULT_READINESS_TIMEOUT_MS = 2e4;
|
|
70905
|
+
DEFAULT_STOP_TIMEOUT_MS = 5e3;
|
|
70906
|
+
URL_PATTERN = /(https?:\/\/[^\s]+)/i;
|
|
70907
|
+
tailscaleAdapter = {
|
|
70908
|
+
provider: "tailscale",
|
|
70909
|
+
validateConfig(config) {
|
|
70910
|
+
validateBaseConfig(config, "tailscale");
|
|
70911
|
+
},
|
|
70912
|
+
buildCommand(config) {
|
|
70913
|
+
this.validateConfig(config);
|
|
70914
|
+
return buildCommand(config);
|
|
70915
|
+
},
|
|
70916
|
+
parseReadiness(line, _stream) {
|
|
70917
|
+
return parseCommonReadiness(line);
|
|
70918
|
+
}
|
|
70919
|
+
};
|
|
70920
|
+
cloudflareAdapter = {
|
|
70921
|
+
provider: "cloudflare",
|
|
70922
|
+
validateConfig(config) {
|
|
70923
|
+
validateBaseConfig(config, "cloudflare");
|
|
70924
|
+
if ("credentialsPath" in config && config.credentialsPath !== void 0) {
|
|
70925
|
+
assertNonEmpty(config.credentialsPath, "credentialsPath");
|
|
70926
|
+
if (isAbsoluteOrPathLike(config.credentialsPath)) {
|
|
70927
|
+
accessSync(config.credentialsPath, fsConstants.R_OK);
|
|
70928
|
+
}
|
|
70929
|
+
}
|
|
70930
|
+
},
|
|
70931
|
+
buildCommand(config) {
|
|
70932
|
+
this.validateConfig(config);
|
|
70933
|
+
return buildCommand(config);
|
|
70934
|
+
},
|
|
70935
|
+
parseReadiness(line, _stream) {
|
|
70936
|
+
return parseCommonReadiness(line);
|
|
70937
|
+
}
|
|
70938
|
+
};
|
|
70939
|
+
ADAPTERS = {
|
|
70940
|
+
tailscale: tailscaleAdapter,
|
|
70941
|
+
cloudflare: cloudflareAdapter
|
|
70942
|
+
};
|
|
70943
|
+
}
|
|
70944
|
+
});
|
|
70945
|
+
|
|
70946
|
+
// ../engine/src/remote-access/tunnel-process-manager.ts
|
|
70947
|
+
import { EventEmitter as EventEmitter18 } from "node:events";
|
|
70948
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
70949
|
+
function nowIso() {
|
|
70950
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
70951
|
+
}
|
|
70952
|
+
function normalizeError(input) {
|
|
70953
|
+
if (input instanceof Error) {
|
|
70954
|
+
return input;
|
|
70955
|
+
}
|
|
70956
|
+
return new Error(String(input));
|
|
70957
|
+
}
|
|
70958
|
+
function maskSensitive(message, processHandle) {
|
|
70959
|
+
if (!processHandle) {
|
|
70960
|
+
return message;
|
|
70961
|
+
}
|
|
70962
|
+
return redactTunnelText(message, processHandle.command.sensitiveValues);
|
|
70963
|
+
}
|
|
70964
|
+
function killManagedProcess(child, signal) {
|
|
70965
|
+
if (typeof child.pid !== "number") {
|
|
70966
|
+
return;
|
|
70967
|
+
}
|
|
70968
|
+
if (process.platform !== "win32") {
|
|
70969
|
+
try {
|
|
70970
|
+
process.kill(-child.pid, signal);
|
|
70971
|
+
return;
|
|
70972
|
+
} catch {
|
|
70973
|
+
}
|
|
70974
|
+
}
|
|
70975
|
+
try {
|
|
70976
|
+
process.kill(child.pid, signal);
|
|
70977
|
+
} catch {
|
|
70978
|
+
}
|
|
70979
|
+
}
|
|
70980
|
+
function toStateError(code, err) {
|
|
70981
|
+
const normalized = normalizeError(err);
|
|
70982
|
+
return {
|
|
70983
|
+
code,
|
|
70984
|
+
message: normalized.message,
|
|
70985
|
+
at: nowIso()
|
|
70986
|
+
};
|
|
70987
|
+
}
|
|
70988
|
+
var DEFAULT_MAX_LOG_ENTRIES, DEFAULT_STOP_TIMEOUT_MS2, LineBuffer, TunnelProcessManager;
|
|
70989
|
+
var init_tunnel_process_manager = __esm({
|
|
70990
|
+
"../engine/src/remote-access/tunnel-process-manager.ts"() {
|
|
70991
|
+
"use strict";
|
|
70992
|
+
init_logger2();
|
|
70993
|
+
init_provider_adapters();
|
|
70994
|
+
DEFAULT_MAX_LOG_ENTRIES = 400;
|
|
70995
|
+
DEFAULT_STOP_TIMEOUT_MS2 = 5e3;
|
|
70996
|
+
LineBuffer = class {
|
|
70997
|
+
pending = "";
|
|
70998
|
+
push(chunk) {
|
|
70999
|
+
this.pending += chunk;
|
|
71000
|
+
const lines = this.pending.split(/\r?\n/);
|
|
71001
|
+
this.pending = lines.pop() ?? "";
|
|
71002
|
+
return lines.map((line) => line.trim()).filter(Boolean);
|
|
71003
|
+
}
|
|
71004
|
+
flush() {
|
|
71005
|
+
const tail = this.pending.trim();
|
|
71006
|
+
this.pending = "";
|
|
71007
|
+
return tail ? [tail] : [];
|
|
71008
|
+
}
|
|
71009
|
+
};
|
|
71010
|
+
TunnelProcessManager = class extends EventEmitter18 {
|
|
71011
|
+
maxLogEntries;
|
|
71012
|
+
defaultStopTimeoutMs;
|
|
71013
|
+
spawnImpl;
|
|
71014
|
+
status = {
|
|
71015
|
+
provider: null,
|
|
71016
|
+
state: "stopped",
|
|
71017
|
+
pid: null,
|
|
71018
|
+
startedAt: null,
|
|
71019
|
+
stoppedAt: null,
|
|
71020
|
+
url: null,
|
|
71021
|
+
lastError: null
|
|
71022
|
+
};
|
|
71023
|
+
logs = [];
|
|
71024
|
+
statusListeners = /* @__PURE__ */ new Set();
|
|
71025
|
+
logListeners = /* @__PURE__ */ new Set();
|
|
71026
|
+
processHandle = null;
|
|
71027
|
+
readinessTimer = null;
|
|
71028
|
+
stopTimer = null;
|
|
71029
|
+
operationChain = Promise.resolve();
|
|
71030
|
+
expectedStop = false;
|
|
71031
|
+
activeStopPromise = null;
|
|
71032
|
+
constructor(options = {}) {
|
|
71033
|
+
super();
|
|
71034
|
+
this.maxLogEntries = options.maxLogEntries ?? DEFAULT_MAX_LOG_ENTRIES;
|
|
71035
|
+
this.defaultStopTimeoutMs = options.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS2;
|
|
71036
|
+
this.spawnImpl = options.spawnImpl ?? spawn2;
|
|
71037
|
+
}
|
|
71038
|
+
getStatus() {
|
|
71039
|
+
return { ...this.status, lastError: this.status.lastError ? { ...this.status.lastError } : null };
|
|
71040
|
+
}
|
|
71041
|
+
subscribeStatus(listener) {
|
|
71042
|
+
this.statusListeners.add(listener);
|
|
71043
|
+
listener(this.getStatus());
|
|
71044
|
+
return () => {
|
|
71045
|
+
this.statusListeners.delete(listener);
|
|
71046
|
+
};
|
|
71047
|
+
}
|
|
71048
|
+
subscribeLogs(listener) {
|
|
71049
|
+
this.logListeners.add(listener);
|
|
71050
|
+
return () => {
|
|
71051
|
+
this.logListeners.delete(listener);
|
|
71052
|
+
};
|
|
71053
|
+
}
|
|
71054
|
+
async start(provider, config) {
|
|
71055
|
+
return this.runExclusive(async () => {
|
|
71056
|
+
if (this.processHandle || this.status.state === "starting" || this.status.state === "running") {
|
|
71057
|
+
throw new Error("already_running:tunnel process is already active");
|
|
71058
|
+
}
|
|
71059
|
+
await this.startInternal(provider, config);
|
|
71060
|
+
});
|
|
71061
|
+
}
|
|
71062
|
+
async stop() {
|
|
71063
|
+
return this.runExclusive(async () => {
|
|
71064
|
+
await this.stopInternal();
|
|
71065
|
+
});
|
|
71066
|
+
}
|
|
71067
|
+
async switchProvider(target, config) {
|
|
71068
|
+
return this.runExclusive(async () => {
|
|
71069
|
+
const previousProvider = this.status.provider;
|
|
71070
|
+
if (this.processHandle) {
|
|
71071
|
+
await this.stopInternal();
|
|
71072
|
+
}
|
|
71073
|
+
try {
|
|
71074
|
+
await this.startInternal(target, config);
|
|
71075
|
+
} catch (error) {
|
|
71076
|
+
const stateError = toStateError("switch_failed", error);
|
|
71077
|
+
const redactedMessage = this.redactForProviderConfig(target, config, stateError.message);
|
|
71078
|
+
this.updateStatus({
|
|
71079
|
+
provider: target,
|
|
71080
|
+
state: "failed",
|
|
71081
|
+
pid: null,
|
|
71082
|
+
startedAt: null,
|
|
71083
|
+
stoppedAt: nowIso(),
|
|
71084
|
+
url: null,
|
|
71085
|
+
lastError: {
|
|
71086
|
+
...stateError,
|
|
71087
|
+
message: redactedMessage
|
|
71088
|
+
}
|
|
71089
|
+
});
|
|
71090
|
+
this.emitLog("error", "manager", `Provider switch failed (${previousProvider ?? "none"} -> ${target}): ${redactedMessage}`);
|
|
71091
|
+
throw error;
|
|
71092
|
+
}
|
|
71093
|
+
});
|
|
71094
|
+
}
|
|
71095
|
+
redactForProviderConfig(provider, config, message) {
|
|
71096
|
+
try {
|
|
71097
|
+
const adapter = getTunnelProviderAdapter(provider);
|
|
71098
|
+
const command = adapter.buildCommand(config);
|
|
71099
|
+
return redactTunnelText(message, command.sensitiveValues);
|
|
71100
|
+
} catch {
|
|
71101
|
+
return message;
|
|
71102
|
+
}
|
|
71103
|
+
}
|
|
71104
|
+
async runExclusive(operation) {
|
|
71105
|
+
const next = this.operationChain.then(operation);
|
|
71106
|
+
this.operationChain = next.catch(() => void 0);
|
|
71107
|
+
return next;
|
|
71108
|
+
}
|
|
71109
|
+
async startInternal(provider, config) {
|
|
71110
|
+
const adapter = getTunnelProviderAdapter(provider);
|
|
71111
|
+
if (config.provider !== provider) {
|
|
71112
|
+
throw new Error(`invalid_config:provider mismatch (${config.provider} vs ${provider})`);
|
|
71113
|
+
}
|
|
71114
|
+
try {
|
|
71115
|
+
adapter.validateConfig(config);
|
|
71116
|
+
} catch (error) {
|
|
71117
|
+
const stateError = toStateError("invalid_config", error);
|
|
71118
|
+
this.updateStatus({
|
|
71119
|
+
provider,
|
|
71120
|
+
state: "failed",
|
|
71121
|
+
pid: null,
|
|
71122
|
+
startedAt: null,
|
|
71123
|
+
stoppedAt: nowIso(),
|
|
71124
|
+
url: null,
|
|
71125
|
+
lastError: stateError
|
|
71126
|
+
});
|
|
71127
|
+
this.emitLog("error", "manager", `Configuration validation failed for ${provider}: ${stateError.message}`);
|
|
71128
|
+
throw error;
|
|
71129
|
+
}
|
|
71130
|
+
const command = adapter.buildCommand(config);
|
|
71131
|
+
this.updateStatus({
|
|
71132
|
+
provider,
|
|
71133
|
+
state: "starting",
|
|
71134
|
+
pid: null,
|
|
71135
|
+
startedAt: nowIso(),
|
|
71136
|
+
stoppedAt: null,
|
|
71137
|
+
url: null,
|
|
71138
|
+
lastError: null
|
|
71139
|
+
});
|
|
71140
|
+
this.emitLog("info", "manager", `Starting ${provider} tunnel: ${command.redactedPreview}`);
|
|
71141
|
+
const child = this.spawnImpl(command.command, command.args, {
|
|
71142
|
+
cwd: command.cwd,
|
|
71143
|
+
env: command.env,
|
|
71144
|
+
detached: process.platform !== "win32",
|
|
71145
|
+
shell: false,
|
|
71146
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
71147
|
+
});
|
|
71148
|
+
this.processHandle = {
|
|
71149
|
+
provider,
|
|
71150
|
+
child,
|
|
71151
|
+
command
|
|
71152
|
+
};
|
|
71153
|
+
this.expectedStop = false;
|
|
71154
|
+
this.updateStatus({ pid: child.pid ?? null });
|
|
71155
|
+
const stdoutBuffer = new LineBuffer();
|
|
71156
|
+
const stderrBuffer = new LineBuffer();
|
|
71157
|
+
const attachStream = (stream, source, buffer) => {
|
|
71158
|
+
stream?.on("data", (chunk) => {
|
|
71159
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
71160
|
+
for (const line of buffer.push(text)) {
|
|
71161
|
+
this.handleOutputLine(source, line);
|
|
71162
|
+
}
|
|
71163
|
+
});
|
|
71164
|
+
};
|
|
71165
|
+
attachStream(child.stdout, "stdout", stdoutBuffer);
|
|
71166
|
+
attachStream(child.stderr, "stderr", stderrBuffer);
|
|
71167
|
+
child.once("error", (error) => {
|
|
71168
|
+
const maskedMessage = maskSensitive(normalizeError(error).message, this.processHandle);
|
|
71169
|
+
this.emitLog("error", "manager", `Spawn failure for ${provider}: ${maskedMessage}`);
|
|
71170
|
+
this.handleUnexpectedExit("start_failed", `Spawn failure: ${maskedMessage}`);
|
|
71171
|
+
});
|
|
71172
|
+
child.once("close", (code, signal) => {
|
|
71173
|
+
for (const line of stdoutBuffer.flush()) {
|
|
71174
|
+
this.handleOutputLine("stdout", line);
|
|
71175
|
+
}
|
|
71176
|
+
for (const line of stderrBuffer.flush()) {
|
|
71177
|
+
this.handleOutputLine("stderr", line);
|
|
71178
|
+
}
|
|
71179
|
+
const reason = signal ? `signal ${signal}` : `exit code ${code ?? 0}`;
|
|
71180
|
+
if (this.expectedStop) {
|
|
71181
|
+
this.emitLog("info", "manager", `Tunnel process stopped (${reason})`);
|
|
71182
|
+
this.finalizeStoppedState();
|
|
71183
|
+
return;
|
|
71184
|
+
}
|
|
71185
|
+
this.emitLog("error", "manager", `Tunnel process exited unexpectedly (${reason})`);
|
|
71186
|
+
this.handleUnexpectedExit("process_exit", `Process exited unexpectedly (${reason})`);
|
|
71187
|
+
});
|
|
71188
|
+
this.readinessTimer = setTimeout(() => {
|
|
71189
|
+
if (this.status.state === "starting" && this.processHandle?.provider === provider) {
|
|
71190
|
+
this.emitLog("error", "manager", `Readiness timed out after ${command.readinessTimeoutMs}ms`);
|
|
71191
|
+
this.handleUnexpectedExit("readiness_timeout", `Tunnel readiness timeout after ${command.readinessTimeoutMs}ms`);
|
|
71192
|
+
}
|
|
71193
|
+
}, command.readinessTimeoutMs);
|
|
71194
|
+
this.readinessTimer.unref?.();
|
|
71195
|
+
}
|
|
71196
|
+
async stopInternal() {
|
|
71197
|
+
if (!this.processHandle) {
|
|
71198
|
+
this.updateStatus({
|
|
71199
|
+
provider: null,
|
|
71200
|
+
state: "stopped",
|
|
71201
|
+
pid: null,
|
|
71202
|
+
stoppedAt: nowIso(),
|
|
71203
|
+
url: null
|
|
71204
|
+
});
|
|
71205
|
+
return;
|
|
71206
|
+
}
|
|
71207
|
+
if (this.activeStopPromise) {
|
|
71208
|
+
await this.activeStopPromise;
|
|
71209
|
+
return;
|
|
71210
|
+
}
|
|
71211
|
+
const currentHandle = this.processHandle;
|
|
71212
|
+
const stopTimeoutMs = currentHandle.command.stopTimeoutMs || this.defaultStopTimeoutMs;
|
|
71213
|
+
this.expectedStop = true;
|
|
71214
|
+
this.updateStatus({
|
|
71215
|
+
state: "stopping",
|
|
71216
|
+
provider: currentHandle.provider,
|
|
71217
|
+
pid: currentHandle.child.pid ?? null,
|
|
71218
|
+
lastError: null
|
|
71219
|
+
});
|
|
71220
|
+
this.emitLog("info", "manager", `Stopping ${currentHandle.provider} tunnel (pid=${currentHandle.child.pid ?? "n/a"})`);
|
|
71221
|
+
this.activeStopPromise = new Promise((resolve16) => {
|
|
71222
|
+
const onClose = () => {
|
|
71223
|
+
currentHandle.child.removeListener("close", onClose);
|
|
71224
|
+
resolve16();
|
|
71225
|
+
};
|
|
71226
|
+
currentHandle.child.once("close", onClose);
|
|
71227
|
+
killManagedProcess(currentHandle.child, "SIGTERM");
|
|
71228
|
+
this.stopTimer = setTimeout(() => {
|
|
71229
|
+
if (this.processHandle === currentHandle) {
|
|
71230
|
+
this.emitLog("warn", "manager", `Graceful stop timed out after ${stopTimeoutMs}ms, sending SIGKILL`);
|
|
71231
|
+
killManagedProcess(currentHandle.child, "SIGKILL");
|
|
71232
|
+
}
|
|
71233
|
+
}, stopTimeoutMs);
|
|
71234
|
+
this.stopTimer.unref?.();
|
|
71235
|
+
}).finally(() => {
|
|
71236
|
+
this.activeStopPromise = null;
|
|
71237
|
+
if (this.stopTimer) {
|
|
71238
|
+
clearTimeout(this.stopTimer);
|
|
71239
|
+
this.stopTimer = null;
|
|
71240
|
+
}
|
|
71241
|
+
});
|
|
71242
|
+
await this.activeStopPromise;
|
|
71243
|
+
}
|
|
71244
|
+
handleOutputLine(source, rawLine) {
|
|
71245
|
+
const processHandle = this.processHandle;
|
|
71246
|
+
const maskedLine = maskSensitive(rawLine, processHandle);
|
|
71247
|
+
this.emitLog("info", source, maskedLine);
|
|
71248
|
+
if (!processHandle || this.status.state !== "starting") {
|
|
71249
|
+
return;
|
|
71250
|
+
}
|
|
71251
|
+
const adapter = getTunnelProviderAdapter(processHandle.provider);
|
|
71252
|
+
const readiness = adapter.parseReadiness(maskedLine, source);
|
|
71253
|
+
if (!readiness?.ready) {
|
|
71254
|
+
return;
|
|
71255
|
+
}
|
|
71256
|
+
this.clearReadinessTimer();
|
|
71257
|
+
this.updateStatus({
|
|
71258
|
+
state: "running",
|
|
71259
|
+
provider: processHandle.provider,
|
|
71260
|
+
pid: processHandle.child.pid ?? null,
|
|
71261
|
+
url: readiness.url ?? this.status.url,
|
|
71262
|
+
startedAt: this.status.startedAt ?? nowIso(),
|
|
71263
|
+
lastError: null
|
|
71264
|
+
});
|
|
71265
|
+
this.emitLog("info", "manager", `${processHandle.provider} tunnel is running`);
|
|
71266
|
+
}
|
|
71267
|
+
handleUnexpectedExit(code, message) {
|
|
71268
|
+
this.clearReadinessTimer();
|
|
71269
|
+
if (this.stopTimer) {
|
|
71270
|
+
clearTimeout(this.stopTimer);
|
|
71271
|
+
this.stopTimer = null;
|
|
71272
|
+
}
|
|
71273
|
+
this.expectedStop = false;
|
|
71274
|
+
const provider = this.processHandle?.provider ?? this.status.provider;
|
|
71275
|
+
this.processHandle = null;
|
|
71276
|
+
this.updateStatus({
|
|
71277
|
+
provider,
|
|
71278
|
+
state: "failed",
|
|
71279
|
+
pid: null,
|
|
71280
|
+
stoppedAt: nowIso(),
|
|
71281
|
+
url: null,
|
|
71282
|
+
lastError: {
|
|
71283
|
+
code,
|
|
71284
|
+
message,
|
|
71285
|
+
at: nowIso()
|
|
71286
|
+
}
|
|
71287
|
+
});
|
|
71288
|
+
}
|
|
71289
|
+
finalizeStoppedState() {
|
|
71290
|
+
this.clearReadinessTimer();
|
|
71291
|
+
if (this.stopTimer) {
|
|
71292
|
+
clearTimeout(this.stopTimer);
|
|
71293
|
+
this.stopTimer = null;
|
|
71294
|
+
}
|
|
71295
|
+
this.expectedStop = false;
|
|
71296
|
+
this.processHandle = null;
|
|
71297
|
+
this.updateStatus({
|
|
71298
|
+
provider: null,
|
|
71299
|
+
state: "stopped",
|
|
71300
|
+
pid: null,
|
|
71301
|
+
stoppedAt: nowIso(),
|
|
71302
|
+
url: null,
|
|
71303
|
+
lastError: null
|
|
71304
|
+
});
|
|
71305
|
+
}
|
|
71306
|
+
clearReadinessTimer() {
|
|
71307
|
+
if (this.readinessTimer) {
|
|
71308
|
+
clearTimeout(this.readinessTimer);
|
|
71309
|
+
this.readinessTimer = null;
|
|
71310
|
+
}
|
|
71311
|
+
}
|
|
71312
|
+
updateStatus(patch) {
|
|
71313
|
+
this.status = {
|
|
71314
|
+
...this.status,
|
|
71315
|
+
...patch,
|
|
71316
|
+
lastError: patch.lastError === void 0 ? this.status.lastError : patch.lastError
|
|
71317
|
+
};
|
|
71318
|
+
const snapshot = this.getStatus();
|
|
71319
|
+
for (const listener of this.statusListeners) {
|
|
71320
|
+
listener(snapshot);
|
|
71321
|
+
}
|
|
71322
|
+
this.emit("status", snapshot);
|
|
71323
|
+
}
|
|
71324
|
+
emitLog(level, source, message) {
|
|
71325
|
+
const safeMessage = maskSensitive(message, this.processHandle);
|
|
71326
|
+
const entry = {
|
|
71327
|
+
timestamp: nowIso(),
|
|
71328
|
+
provider: this.status.provider,
|
|
71329
|
+
level,
|
|
71330
|
+
source,
|
|
71331
|
+
message: safeMessage
|
|
71332
|
+
};
|
|
71333
|
+
this.logs.push(entry);
|
|
71334
|
+
if (this.logs.length > this.maxLogEntries) {
|
|
71335
|
+
this.logs.splice(0, this.logs.length - this.maxLogEntries);
|
|
71336
|
+
}
|
|
71337
|
+
const logMethod = level === "error" ? "error" : level === "warn" ? "warn" : "log";
|
|
71338
|
+
remoteTunnelLog[logMethod](safeMessage);
|
|
71339
|
+
for (const listener of this.logListeners) {
|
|
71340
|
+
listener(entry);
|
|
71341
|
+
}
|
|
71342
|
+
this.emit("log", entry);
|
|
71343
|
+
}
|
|
71344
|
+
};
|
|
71345
|
+
}
|
|
71346
|
+
});
|
|
71347
|
+
|
|
70583
71348
|
// ../engine/src/project-engine.ts
|
|
70584
|
-
|
|
71349
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
71350
|
+
import { promisify as promisify10 } from "node:util";
|
|
71351
|
+
var execFileAsync, isRemoteActive, ProjectEngine;
|
|
70585
71352
|
var init_project_engine = __esm({
|
|
70586
71353
|
"../engine/src/project-engine.ts"() {
|
|
70587
71354
|
"use strict";
|
|
@@ -70593,6 +71360,9 @@ var init_project_engine = __esm({
|
|
|
70593
71360
|
init_merger();
|
|
70594
71361
|
init_concurrency();
|
|
70595
71362
|
init_logger2();
|
|
71363
|
+
init_tunnel_process_manager();
|
|
71364
|
+
execFileAsync = promisify10(execFile3);
|
|
71365
|
+
isRemoteActive = (ra) => ra?.activeProvider != null && (ra.providers[ra.activeProvider]?.enabled ?? false);
|
|
70596
71366
|
ProjectEngine = class _ProjectEngine {
|
|
70597
71367
|
constructor(config, centralCore, options = {}) {
|
|
70598
71368
|
this.config = config;
|
|
@@ -70606,6 +71376,13 @@ var init_project_engine = __esm({
|
|
|
70606
71376
|
notifier;
|
|
70607
71377
|
cronRunner;
|
|
70608
71378
|
automationStore;
|
|
71379
|
+
remoteTunnelManager;
|
|
71380
|
+
remoteTunnelRestoreDiagnostics = {
|
|
71381
|
+
outcome: "skipped",
|
|
71382
|
+
reason: "not_attempted",
|
|
71383
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
71384
|
+
provider: null
|
|
71385
|
+
};
|
|
70609
71386
|
// ── Auto-merge state ──
|
|
70610
71387
|
mergeQueue = [];
|
|
70611
71388
|
mergeActive = /* @__PURE__ */ new Set();
|
|
@@ -70633,6 +71410,14 @@ var init_project_engine = __esm({
|
|
|
70633
71410
|
await this.runtime.start();
|
|
70634
71411
|
const store = this.runtime.getTaskStore();
|
|
70635
71412
|
const cwd = this.config.workingDirectory;
|
|
71413
|
+
this.remoteTunnelManager = new TunnelProcessManager();
|
|
71414
|
+
try {
|
|
71415
|
+
await this.restoreRemoteTunnelIfNeeded(store);
|
|
71416
|
+
} catch (error) {
|
|
71417
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
71418
|
+
this.setRestoreDiagnostics("failed", "restore_start_failed", null, message);
|
|
71419
|
+
runtimeLog.warn(`Remote tunnel restore evaluation failed (continuing startup): ${message}`);
|
|
71420
|
+
}
|
|
70636
71421
|
this.prMonitor = new PrMonitor();
|
|
70637
71422
|
this.prCommentHandler = new PrCommentHandler(store);
|
|
70638
71423
|
this.prMonitor.onNewComments(
|
|
@@ -70732,6 +71517,30 @@ var init_project_engine = __esm({
|
|
|
70732
71517
|
}
|
|
70733
71518
|
this.notifier?.stop();
|
|
70734
71519
|
this.cronRunner?.stop();
|
|
71520
|
+
const tunnelManager = this.remoteTunnelManager;
|
|
71521
|
+
this.remoteTunnelManager = void 0;
|
|
71522
|
+
if (tunnelManager) {
|
|
71523
|
+
let shutdownStore = null;
|
|
71524
|
+
try {
|
|
71525
|
+
shutdownStore = this.runtime.getTaskStore();
|
|
71526
|
+
} catch {
|
|
71527
|
+
shutdownStore = null;
|
|
71528
|
+
}
|
|
71529
|
+
if (shutdownStore) {
|
|
71530
|
+
try {
|
|
71531
|
+
await this.persistShutdownRemoteLifecycle(shutdownStore, tunnelManager.getStatus());
|
|
71532
|
+
} catch (error) {
|
|
71533
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
71534
|
+
runtimeLog.warn(`Failed to persist remote lifecycle shutdown markers: ${message}`);
|
|
71535
|
+
}
|
|
71536
|
+
}
|
|
71537
|
+
try {
|
|
71538
|
+
await tunnelManager.stop();
|
|
71539
|
+
} catch (error) {
|
|
71540
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
71541
|
+
runtimeLog.warn(`Tunnel process manager stop failed (continuing shutdown): ${message}`);
|
|
71542
|
+
}
|
|
71543
|
+
}
|
|
70735
71544
|
await this.runtime.stop();
|
|
70736
71545
|
runtimeLog.log(`ProjectEngine stopped for ${this.config.projectId}`);
|
|
70737
71546
|
}
|
|
@@ -70776,6 +71585,71 @@ var init_project_engine = __esm({
|
|
|
70776
71585
|
getRoutineStore() {
|
|
70777
71586
|
return this.runtime.getRoutineStore();
|
|
70778
71587
|
}
|
|
71588
|
+
/** Get the remote tunnel manager (available after start()). */
|
|
71589
|
+
getRemoteTunnelManager() {
|
|
71590
|
+
return this.remoteTunnelManager;
|
|
71591
|
+
}
|
|
71592
|
+
getRemoteTunnelRestoreDiagnostics() {
|
|
71593
|
+
return { ...this.remoteTunnelRestoreDiagnostics };
|
|
71594
|
+
}
|
|
71595
|
+
async startRemoteTunnel() {
|
|
71596
|
+
const manager = this.remoteTunnelManager;
|
|
71597
|
+
if (!manager) {
|
|
71598
|
+
throw new Error("remote_tunnel_unavailable:remote tunnel manager is not initialized");
|
|
71599
|
+
}
|
|
71600
|
+
const store = this.runtime.getTaskStore();
|
|
71601
|
+
const settings = await store.getSettings();
|
|
71602
|
+
const remoteAccess = settings.remoteAccess;
|
|
71603
|
+
if (!remoteAccess || !isRemoteActive(remoteAccess)) {
|
|
71604
|
+
throw new Error("invalid_config:no remote access provider enabled");
|
|
71605
|
+
}
|
|
71606
|
+
const provider = remoteAccess.activeProvider;
|
|
71607
|
+
if (!provider) {
|
|
71608
|
+
throw new Error("invalid_config:no active remote provider configured");
|
|
71609
|
+
}
|
|
71610
|
+
const lifecycle = await this.evaluateRemoteLifecycle(settings, provider);
|
|
71611
|
+
if (!lifecycle.config) {
|
|
71612
|
+
throw new Error(`${lifecycle.reason ?? "invalid_config"}:${lifecycle.message ?? "remote provider prerequisites are not met"}`);
|
|
71613
|
+
}
|
|
71614
|
+
const current = manager.getStatus();
|
|
71615
|
+
if (current.state === "running" && current.provider === provider) {
|
|
71616
|
+
await this.writeRemoteLifecycleState(store, remoteAccess, {
|
|
71617
|
+
...remoteAccess.lifecycle,
|
|
71618
|
+
wasRunningOnShutdown: true,
|
|
71619
|
+
lastRunningProvider: provider
|
|
71620
|
+
});
|
|
71621
|
+
return manager.getStatus();
|
|
71622
|
+
}
|
|
71623
|
+
if (current.state === "running" && current.provider && current.provider !== provider) {
|
|
71624
|
+
await manager.switchProvider(provider, lifecycle.config);
|
|
71625
|
+
} else {
|
|
71626
|
+
await manager.start(provider, lifecycle.config);
|
|
71627
|
+
}
|
|
71628
|
+
await this.writeRemoteLifecycleState(store, remoteAccess, {
|
|
71629
|
+
...remoteAccess.lifecycle,
|
|
71630
|
+
wasRunningOnShutdown: true,
|
|
71631
|
+
lastRunningProvider: provider
|
|
71632
|
+
});
|
|
71633
|
+
return manager.getStatus();
|
|
71634
|
+
}
|
|
71635
|
+
async stopRemoteTunnel() {
|
|
71636
|
+
const manager = this.remoteTunnelManager;
|
|
71637
|
+
if (!manager) {
|
|
71638
|
+
throw new Error("remote_tunnel_unavailable:remote tunnel manager is not initialized");
|
|
71639
|
+
}
|
|
71640
|
+
await manager.stop();
|
|
71641
|
+
const store = this.runtime.getTaskStore();
|
|
71642
|
+
const settings = await store.getSettings();
|
|
71643
|
+
const remoteAccess = settings.remoteAccess;
|
|
71644
|
+
if (remoteAccess) {
|
|
71645
|
+
await this.writeRemoteLifecycleState(store, remoteAccess, {
|
|
71646
|
+
...remoteAccess.lifecycle,
|
|
71647
|
+
wasRunningOnShutdown: false,
|
|
71648
|
+
lastRunningProvider: null
|
|
71649
|
+
});
|
|
71650
|
+
}
|
|
71651
|
+
return manager.getStatus();
|
|
71652
|
+
}
|
|
70779
71653
|
/** Get the RoutineRunner (if initialized). */
|
|
70780
71654
|
getRoutineRunner() {
|
|
70781
71655
|
return this.runtime.getRoutineRunner();
|
|
@@ -70810,6 +71684,168 @@ var init_project_engine = __esm({
|
|
|
70810
71684
|
this.internalEnqueueMerge(taskId);
|
|
70811
71685
|
});
|
|
70812
71686
|
}
|
|
71687
|
+
setRestoreDiagnostics(outcome, reason, provider, message) {
|
|
71688
|
+
this.remoteTunnelRestoreDiagnostics = {
|
|
71689
|
+
outcome,
|
|
71690
|
+
reason,
|
|
71691
|
+
provider,
|
|
71692
|
+
message,
|
|
71693
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
71694
|
+
};
|
|
71695
|
+
}
|
|
71696
|
+
async restoreRemoteTunnelIfNeeded(store) {
|
|
71697
|
+
const manager = this.remoteTunnelManager;
|
|
71698
|
+
if (!manager) {
|
|
71699
|
+
return;
|
|
71700
|
+
}
|
|
71701
|
+
const settings = await store.getSettings();
|
|
71702
|
+
const remoteAccess = settings.remoteAccess;
|
|
71703
|
+
if (!remoteAccess || !isRemoteActive(remoteAccess)) {
|
|
71704
|
+
this.setRestoreDiagnostics("skipped", "remote_access_disabled", null);
|
|
71705
|
+
return;
|
|
71706
|
+
}
|
|
71707
|
+
const lifecycle = remoteAccess.lifecycle;
|
|
71708
|
+
if (!lifecycle.rememberLastRunning) {
|
|
71709
|
+
this.setRestoreDiagnostics("skipped", "remember_last_running_disabled", null);
|
|
71710
|
+
if (lifecycle.wasRunningOnShutdown || lifecycle.lastRunningProvider) {
|
|
71711
|
+
await this.writeRemoteLifecycleState(store, remoteAccess, {
|
|
71712
|
+
...lifecycle,
|
|
71713
|
+
wasRunningOnShutdown: false,
|
|
71714
|
+
lastRunningProvider: null
|
|
71715
|
+
});
|
|
71716
|
+
}
|
|
71717
|
+
return;
|
|
71718
|
+
}
|
|
71719
|
+
if (!lifecycle.wasRunningOnShutdown) {
|
|
71720
|
+
this.setRestoreDiagnostics("skipped", "no_prior_running_marker", null);
|
|
71721
|
+
return;
|
|
71722
|
+
}
|
|
71723
|
+
const provider = lifecycle.lastRunningProvider ?? remoteAccess.activeProvider;
|
|
71724
|
+
if (!provider) {
|
|
71725
|
+
this.setRestoreDiagnostics("skipped", "provider_missing", null);
|
|
71726
|
+
await this.writeRemoteLifecycleState(store, remoteAccess, {
|
|
71727
|
+
...lifecycle,
|
|
71728
|
+
wasRunningOnShutdown: false,
|
|
71729
|
+
lastRunningProvider: null
|
|
71730
|
+
});
|
|
71731
|
+
return;
|
|
71732
|
+
}
|
|
71733
|
+
const evaluation = await this.evaluateRemoteLifecycle(settings, provider);
|
|
71734
|
+
if (!evaluation.config) {
|
|
71735
|
+
this.setRestoreDiagnostics("skipped", evaluation.reason ?? "provider_not_configured", provider, evaluation.message);
|
|
71736
|
+
await this.writeRemoteLifecycleState(store, remoteAccess, {
|
|
71737
|
+
...lifecycle,
|
|
71738
|
+
wasRunningOnShutdown: false,
|
|
71739
|
+
lastRunningProvider: null
|
|
71740
|
+
});
|
|
71741
|
+
return;
|
|
71742
|
+
}
|
|
71743
|
+
try {
|
|
71744
|
+
await manager.start(provider, evaluation.config);
|
|
71745
|
+
this.setRestoreDiagnostics("applied", "restore_started", provider);
|
|
71746
|
+
await this.writeRemoteLifecycleState(store, remoteAccess, {
|
|
71747
|
+
...lifecycle,
|
|
71748
|
+
wasRunningOnShutdown: true,
|
|
71749
|
+
lastRunningProvider: provider
|
|
71750
|
+
}, provider);
|
|
71751
|
+
} catch (error) {
|
|
71752
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
71753
|
+
this.setRestoreDiagnostics("failed", "restore_start_failed", provider, message);
|
|
71754
|
+
runtimeLog.warn(`Remote tunnel restore failed for ${provider}: ${message}`);
|
|
71755
|
+
await this.writeRemoteLifecycleState(store, remoteAccess, {
|
|
71756
|
+
...lifecycle,
|
|
71757
|
+
wasRunningOnShutdown: false,
|
|
71758
|
+
lastRunningProvider: null
|
|
71759
|
+
});
|
|
71760
|
+
}
|
|
71761
|
+
}
|
|
71762
|
+
async persistShutdownRemoteLifecycle(store, status) {
|
|
71763
|
+
const settings = await store.getSettings();
|
|
71764
|
+
const remoteAccess = settings.remoteAccess;
|
|
71765
|
+
if (!remoteAccess) {
|
|
71766
|
+
return;
|
|
71767
|
+
}
|
|
71768
|
+
const shouldRememberRunning = (status.state === "running" || status.state === "starting" || status.state === "stopping") && status.provider !== null;
|
|
71769
|
+
await this.writeRemoteLifecycleState(store, remoteAccess, {
|
|
71770
|
+
...remoteAccess.lifecycle,
|
|
71771
|
+
wasRunningOnShutdown: shouldRememberRunning,
|
|
71772
|
+
lastRunningProvider: shouldRememberRunning ? status.provider : null
|
|
71773
|
+
}, shouldRememberRunning ? status.provider : remoteAccess.activeProvider);
|
|
71774
|
+
}
|
|
71775
|
+
async writeRemoteLifecycleState(store, remoteAccess, lifecycle, activeProviderOverride) {
|
|
71776
|
+
await store.updateSettings({
|
|
71777
|
+
remoteAccess: {
|
|
71778
|
+
...remoteAccess,
|
|
71779
|
+
activeProvider: activeProviderOverride === void 0 ? remoteAccess.activeProvider : activeProviderOverride,
|
|
71780
|
+
lifecycle
|
|
71781
|
+
}
|
|
71782
|
+
});
|
|
71783
|
+
}
|
|
71784
|
+
async evaluateRemoteLifecycle(settings, provider) {
|
|
71785
|
+
const remoteAccess = settings.remoteAccess;
|
|
71786
|
+
if (!remoteAccess || !isRemoteActive(remoteAccess)) {
|
|
71787
|
+
return { provider, reason: "remote_access_disabled", message: "No remote provider is enabled" };
|
|
71788
|
+
}
|
|
71789
|
+
if (provider === "tailscale") {
|
|
71790
|
+
const tailscale = remoteAccess.providers.tailscale;
|
|
71791
|
+
if (!tailscale.enabled) {
|
|
71792
|
+
return { provider, reason: "provider_not_enabled", message: "Tailscale provider is disabled" };
|
|
71793
|
+
}
|
|
71794
|
+
if (!tailscale.hostname?.trim() || !Number.isFinite(tailscale.targetPort) || tailscale.targetPort <= 0) {
|
|
71795
|
+
return { provider, reason: "provider_not_configured", message: "Tailscale hostname and target port must be configured" };
|
|
71796
|
+
}
|
|
71797
|
+
const executable2 = await this.checkExecutableAvailable("tailscale");
|
|
71798
|
+
if (!executable2.available) {
|
|
71799
|
+
return { provider, reason: "runtime_prerequisite_missing", message: executable2.message };
|
|
71800
|
+
}
|
|
71801
|
+
return {
|
|
71802
|
+
provider,
|
|
71803
|
+
config: {
|
|
71804
|
+
provider: "tailscale",
|
|
71805
|
+
executablePath: "tailscale",
|
|
71806
|
+
args: ["funnel", String(Math.floor(tailscale.targetPort))]
|
|
71807
|
+
}
|
|
71808
|
+
};
|
|
71809
|
+
}
|
|
71810
|
+
const cloudflare = remoteAccess.providers.cloudflare;
|
|
71811
|
+
if (!cloudflare.enabled) {
|
|
71812
|
+
return { provider, reason: "provider_not_enabled", message: "Cloudflare provider is disabled" };
|
|
71813
|
+
}
|
|
71814
|
+
if (!cloudflare.tunnelName?.trim() || !cloudflare.ingressUrl?.trim()) {
|
|
71815
|
+
return { provider, reason: "provider_not_configured", message: "Cloudflare tunnel name and ingress URL must be configured" };
|
|
71816
|
+
}
|
|
71817
|
+
if (!cloudflare.tunnelToken?.trim()) {
|
|
71818
|
+
return { provider, reason: "provider_not_configured", message: "Cloudflare tunnel token is required" };
|
|
71819
|
+
}
|
|
71820
|
+
const executable = await this.checkExecutableAvailable("cloudflared");
|
|
71821
|
+
if (!executable.available) {
|
|
71822
|
+
return { provider, reason: "runtime_prerequisite_missing", message: executable.message };
|
|
71823
|
+
}
|
|
71824
|
+
return {
|
|
71825
|
+
provider,
|
|
71826
|
+
config: {
|
|
71827
|
+
provider: "cloudflare",
|
|
71828
|
+
executablePath: "cloudflared",
|
|
71829
|
+
args: ["tunnel", "--no-autoupdate", "run", cloudflare.tunnelName.trim()],
|
|
71830
|
+
tokenEnvVar: "TUNNEL_TOKEN",
|
|
71831
|
+
env: {
|
|
71832
|
+
TUNNEL_TOKEN: cloudflare.tunnelToken
|
|
71833
|
+
}
|
|
71834
|
+
}
|
|
71835
|
+
};
|
|
71836
|
+
}
|
|
71837
|
+
async checkExecutableAvailable(command) {
|
|
71838
|
+
const checker = process.platform === "win32" ? "where" : "which";
|
|
71839
|
+
try {
|
|
71840
|
+
await execFileAsync(checker, [command]);
|
|
71841
|
+
return { available: true };
|
|
71842
|
+
} catch {
|
|
71843
|
+
return {
|
|
71844
|
+
available: false,
|
|
71845
|
+
message: `${command} is not available on PATH`
|
|
71846
|
+
};
|
|
71847
|
+
}
|
|
71848
|
+
}
|
|
70813
71849
|
// ── Merge eligibility helpers (richer logic from dashboard.ts) ──
|
|
70814
71850
|
/**
|
|
70815
71851
|
* True when a retry-exhausted task in "in-review" has a verification buffer
|
|
@@ -71422,6 +72458,15 @@ var init_peer_exchange_service = __esm({
|
|
|
71422
72458
|
}
|
|
71423
72459
|
});
|
|
71424
72460
|
|
|
72461
|
+
// ../engine/src/remote-access/index.ts
|
|
72462
|
+
var init_remote_access = __esm({
|
|
72463
|
+
"../engine/src/remote-access/index.ts"() {
|
|
72464
|
+
"use strict";
|
|
72465
|
+
init_provider_adapters();
|
|
72466
|
+
init_tunnel_process_manager();
|
|
72467
|
+
}
|
|
72468
|
+
});
|
|
72469
|
+
|
|
71425
72470
|
// ../engine/src/index.ts
|
|
71426
72471
|
var init_src2 = __esm({
|
|
71427
72472
|
"../engine/src/index.ts"() {
|
|
@@ -71462,6 +72507,7 @@ var init_src2 = __esm({
|
|
|
71462
72507
|
init_project_engine_manager();
|
|
71463
72508
|
init_node_health_monitor();
|
|
71464
72509
|
init_peer_exchange_service();
|
|
72510
|
+
init_remote_access();
|
|
71465
72511
|
init_remote_node_client();
|
|
71466
72512
|
init_remote_node_runtime();
|
|
71467
72513
|
init_step_session_executor();
|
|
@@ -71615,7 +72661,7 @@ var init_ai_session_diagnostics = __esm({
|
|
|
71615
72661
|
|
|
71616
72662
|
// ../dashboard/src/planning.ts
|
|
71617
72663
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
71618
|
-
import { EventEmitter as
|
|
72664
|
+
import { EventEmitter as EventEmitter19 } from "node:events";
|
|
71619
72665
|
async function initEngine2() {
|
|
71620
72666
|
try {
|
|
71621
72667
|
const engineModule = "@fusion/engine";
|
|
@@ -72449,7 +73495,7 @@ For completion:
|
|
|
72449
73495
|
process.on("beforeExit", () => {
|
|
72450
73496
|
clearInterval(cleanupInterval2);
|
|
72451
73497
|
});
|
|
72452
|
-
PlanningStreamManager = class extends
|
|
73498
|
+
PlanningStreamManager = class extends EventEmitter19 {
|
|
72453
73499
|
constructor(bufferSize = 100) {
|
|
72454
73500
|
super();
|
|
72455
73501
|
this.bufferSize = bufferSize;
|
|
@@ -72561,10 +73607,756 @@ For completion:
|
|
|
72561
73607
|
}
|
|
72562
73608
|
});
|
|
72563
73609
|
|
|
72564
|
-
// ../dashboard/src/
|
|
72565
|
-
|
|
72566
|
-
|
|
73610
|
+
// ../dashboard/src/terminal.ts
|
|
73611
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
73612
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
73613
|
+
import { EventEmitter as EventEmitter20 } from "node:events";
|
|
73614
|
+
function extractBaseCommand(command) {
|
|
73615
|
+
let trimmed = command.trim();
|
|
73616
|
+
while (/^[A-Za-z_][A-Za-z0-9_]*=/.test(trimmed)) {
|
|
73617
|
+
const match2 = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*=(?:[^\s]*|"[^"]*"|'[^']*'))\s*/);
|
|
73618
|
+
if (match2) {
|
|
73619
|
+
trimmed = trimmed.slice(match2[0].length).trim();
|
|
73620
|
+
} else {
|
|
73621
|
+
break;
|
|
73622
|
+
}
|
|
73623
|
+
}
|
|
73624
|
+
if (trimmed.startsWith("sudo ")) {
|
|
73625
|
+
trimmed = trimmed.slice(5).trim();
|
|
73626
|
+
}
|
|
73627
|
+
const match = trimmed.match(/^([A-Za-z0-9._-]+)/);
|
|
73628
|
+
return match ? match[1].toLowerCase() : null;
|
|
73629
|
+
}
|
|
73630
|
+
function validateCommand(command) {
|
|
73631
|
+
for (const pattern of SUBSTITUTION_PATTERNS) {
|
|
73632
|
+
if (pattern.test(command)) {
|
|
73633
|
+
return { valid: false, error: "Command substitution is not allowed" };
|
|
73634
|
+
}
|
|
73635
|
+
}
|
|
73636
|
+
if (/[\0\r\n]/.test(command)) {
|
|
73637
|
+
return { valid: false, error: "Command contains invalid control characters" };
|
|
73638
|
+
}
|
|
73639
|
+
for (const pattern of BLOCKED_PATTERNS) {
|
|
73640
|
+
if (pattern.test(command)) {
|
|
73641
|
+
return { valid: false, error: "Command contains dangerous patterns and is not allowed" };
|
|
73642
|
+
}
|
|
73643
|
+
}
|
|
73644
|
+
const segments = command.split(CHAIN_OPERATORS);
|
|
73645
|
+
for (const raw of segments) {
|
|
73646
|
+
const segment = raw.trim();
|
|
73647
|
+
if (segment.length === 0) continue;
|
|
73648
|
+
const baseCommand = extractBaseCommand(segment);
|
|
73649
|
+
if (!baseCommand) {
|
|
73650
|
+
return { valid: false, error: "Could not parse command" };
|
|
73651
|
+
}
|
|
73652
|
+
if (!ALLOWED_COMMANDS.has(baseCommand)) {
|
|
73653
|
+
return {
|
|
73654
|
+
valid: false,
|
|
73655
|
+
error: `Command '${baseCommand}' is not in the allowed command list. Allowed commands: ${Array.from(ALLOWED_COMMANDS).sort().join(", ")}`
|
|
73656
|
+
};
|
|
73657
|
+
}
|
|
73658
|
+
}
|
|
73659
|
+
return { valid: true };
|
|
73660
|
+
}
|
|
73661
|
+
var ALLOWED_COMMANDS, BLOCKED_PATTERNS, SUBSTITUTION_PATTERNS, CHAIN_OPERATORS, TerminalSessionManager, terminalSessionManager;
|
|
73662
|
+
var init_terminal = __esm({
|
|
73663
|
+
"../dashboard/src/terminal.ts"() {
|
|
73664
|
+
"use strict";
|
|
73665
|
+
ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
73666
|
+
// Version control
|
|
73667
|
+
"git",
|
|
73668
|
+
// Package managers
|
|
73669
|
+
"npm",
|
|
73670
|
+
"pnpm",
|
|
73671
|
+
"yarn",
|
|
73672
|
+
"bun",
|
|
73673
|
+
// File operations
|
|
73674
|
+
"ls",
|
|
73675
|
+
"cat",
|
|
73676
|
+
"echo",
|
|
73677
|
+
"pwd",
|
|
73678
|
+
"cd",
|
|
73679
|
+
"mkdir",
|
|
73680
|
+
"touch",
|
|
73681
|
+
"cp",
|
|
73682
|
+
"mv",
|
|
73683
|
+
"rm",
|
|
73684
|
+
"head",
|
|
73685
|
+
"tail",
|
|
73686
|
+
"less",
|
|
73687
|
+
"more",
|
|
73688
|
+
"find",
|
|
73689
|
+
"grep",
|
|
73690
|
+
// System info
|
|
73691
|
+
"clear",
|
|
73692
|
+
"which",
|
|
73693
|
+
"whoami",
|
|
73694
|
+
"uname",
|
|
73695
|
+
"date",
|
|
73696
|
+
// Node/JS
|
|
73697
|
+
"node",
|
|
73698
|
+
"npx",
|
|
73699
|
+
"tsx",
|
|
73700
|
+
// Python
|
|
73701
|
+
"python",
|
|
73702
|
+
"python3",
|
|
73703
|
+
"pip",
|
|
73704
|
+
"pip3",
|
|
73705
|
+
// Network
|
|
73706
|
+
"curl",
|
|
73707
|
+
"wget",
|
|
73708
|
+
// Build tools
|
|
73709
|
+
"make",
|
|
73710
|
+
"cmake",
|
|
73711
|
+
// Process management
|
|
73712
|
+
"ps",
|
|
73713
|
+
"top",
|
|
73714
|
+
"htop",
|
|
73715
|
+
"kill",
|
|
73716
|
+
"pkill",
|
|
73717
|
+
// Shell builtins that are safe
|
|
73718
|
+
"source",
|
|
73719
|
+
".",
|
|
73720
|
+
"export",
|
|
73721
|
+
"env",
|
|
73722
|
+
"printenv",
|
|
73723
|
+
"alias",
|
|
73724
|
+
// Editors (for viewing)
|
|
73725
|
+
"code",
|
|
73726
|
+
// VS Code CLI
|
|
73727
|
+
"vim",
|
|
73728
|
+
"vi",
|
|
73729
|
+
"nano"
|
|
73730
|
+
]);
|
|
73731
|
+
BLOCKED_PATTERNS = [
|
|
73732
|
+
// System destruction
|
|
73733
|
+
/rm\s+(-[rf]+\s+)?\/\s*$/i,
|
|
73734
|
+
// rm -rf / or rm /
|
|
73735
|
+
/rm\s+(-[rf]+\s+)?\/\*/i,
|
|
73736
|
+
// rm -rf /*
|
|
73737
|
+
/>\s*\/dev\/sda/i,
|
|
73738
|
+
// Direct disk write
|
|
73739
|
+
/:\(\)\s*\{\s*:\s*\|:\s*&\s*\};\s*:/i,
|
|
73740
|
+
// Fork bomb
|
|
73741
|
+
/mkfs\.\w+\s+/i,
|
|
73742
|
+
// Filesystem formatting
|
|
73743
|
+
/dd\s+if=/i,
|
|
73744
|
+
// dd with input file
|
|
73745
|
+
/\.\s*\/dev\/null/i
|
|
73746
|
+
// Sourcing /dev/null tricks
|
|
73747
|
+
];
|
|
73748
|
+
SUBSTITUTION_PATTERNS = [
|
|
73749
|
+
/\$\(/,
|
|
73750
|
+
// $(...) — command substitution
|
|
73751
|
+
/`/,
|
|
73752
|
+
// `...` — backtick command substitution
|
|
73753
|
+
/<\(/,
|
|
73754
|
+
// <(...) — process substitution (bash)
|
|
73755
|
+
/>\(/
|
|
73756
|
+
// >(...) — process substitution (bash)
|
|
73757
|
+
];
|
|
73758
|
+
CHAIN_OPERATORS = /&&|\|\||;|(?<!\|)\|(?!\|)/;
|
|
73759
|
+
TerminalSessionManager = class extends EventEmitter20 {
|
|
73760
|
+
sessions = /* @__PURE__ */ new Map();
|
|
73761
|
+
defaultTimeout = 3e4;
|
|
73762
|
+
// 30 seconds
|
|
73763
|
+
/**
|
|
73764
|
+
* Creates a new terminal session and spawns the command.
|
|
73765
|
+
* Returns the session ID for tracking.
|
|
73766
|
+
*/
|
|
73767
|
+
createSession(command, cwd) {
|
|
73768
|
+
const validation = validateCommand(command);
|
|
73769
|
+
if (!validation.valid) {
|
|
73770
|
+
return { sessionId: "", error: validation.error };
|
|
73771
|
+
}
|
|
73772
|
+
const sessionId = randomUUID11();
|
|
73773
|
+
const childProcess = spawn3(command, [], {
|
|
73774
|
+
cwd,
|
|
73775
|
+
shell: true,
|
|
73776
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
73777
|
+
env: { ...process.env, FORCE_COLOR: "1", TERM: "xterm-256color" }
|
|
73778
|
+
});
|
|
73779
|
+
const session = {
|
|
73780
|
+
id: sessionId,
|
|
73781
|
+
command,
|
|
73782
|
+
process: childProcess,
|
|
73783
|
+
startTime: /* @__PURE__ */ new Date(),
|
|
73784
|
+
output: [],
|
|
73785
|
+
exitCode: null,
|
|
73786
|
+
killed: false
|
|
73787
|
+
};
|
|
73788
|
+
this.sessions.set(sessionId, session);
|
|
73789
|
+
childProcess.stdout?.on("data", (data) => {
|
|
73790
|
+
const chunk = data.toString("utf-8");
|
|
73791
|
+
session.output.push(chunk);
|
|
73792
|
+
this.emit("output", { sessionId, type: "stdout", data: chunk });
|
|
73793
|
+
});
|
|
73794
|
+
childProcess.stderr?.on("data", (data) => {
|
|
73795
|
+
const chunk = data.toString("utf-8");
|
|
73796
|
+
session.output.push(chunk);
|
|
73797
|
+
this.emit("output", { sessionId, type: "stderr", data: chunk });
|
|
73798
|
+
});
|
|
73799
|
+
childProcess.on("exit", (code) => {
|
|
73800
|
+
session.exitCode = code ?? 0;
|
|
73801
|
+
this.emit("output", {
|
|
73802
|
+
sessionId,
|
|
73803
|
+
type: "exit",
|
|
73804
|
+
data: `Process exited with code ${code ?? 0}`,
|
|
73805
|
+
exitCode: code ?? 0
|
|
73806
|
+
});
|
|
73807
|
+
setTimeout(() => this.cleanupSession(sessionId), 5e3);
|
|
73808
|
+
});
|
|
73809
|
+
childProcess.on("error", (err) => {
|
|
73810
|
+
const errorMsg = err.message;
|
|
73811
|
+
session.output.push(errorMsg);
|
|
73812
|
+
session.exitCode = 127;
|
|
73813
|
+
this.emit("output", { sessionId, type: "stderr", data: errorMsg });
|
|
73814
|
+
this.emit("output", {
|
|
73815
|
+
sessionId,
|
|
73816
|
+
type: "exit",
|
|
73817
|
+
data: `Process failed: ${errorMsg}`,
|
|
73818
|
+
exitCode: 127
|
|
73819
|
+
});
|
|
73820
|
+
setTimeout(() => this.cleanupSession(sessionId), 5e3);
|
|
73821
|
+
});
|
|
73822
|
+
const timeout = setTimeout(() => {
|
|
73823
|
+
if (!session.exitCode && !session.killed) {
|
|
73824
|
+
this.killSession(sessionId, "SIGTERM");
|
|
73825
|
+
this.emit("output", {
|
|
73826
|
+
sessionId,
|
|
73827
|
+
type: "stderr",
|
|
73828
|
+
data: "\n[Command timed out after 30 seconds]\n"
|
|
73829
|
+
});
|
|
73830
|
+
}
|
|
73831
|
+
}, this.defaultTimeout);
|
|
73832
|
+
childProcess.on("exit", () => clearTimeout(timeout));
|
|
73833
|
+
return { sessionId };
|
|
73834
|
+
}
|
|
73835
|
+
/**
|
|
73836
|
+
* Gets a session by ID.
|
|
73837
|
+
*/
|
|
73838
|
+
getSession(sessionId) {
|
|
73839
|
+
return this.sessions.get(sessionId);
|
|
73840
|
+
}
|
|
73841
|
+
/**
|
|
73842
|
+
* Kills a running session's process.
|
|
73843
|
+
* Returns true if killed, false if not found or already exited.
|
|
73844
|
+
*/
|
|
73845
|
+
killSession(sessionId, signal = "SIGTERM") {
|
|
73846
|
+
const session = this.sessions.get(sessionId);
|
|
73847
|
+
if (!session || session.exitCode !== null || session.killed) {
|
|
73848
|
+
return false;
|
|
73849
|
+
}
|
|
73850
|
+
session.killed = true;
|
|
73851
|
+
try {
|
|
73852
|
+
if (session.process.pid) {
|
|
73853
|
+
process.kill(-session.process.pid, signal);
|
|
73854
|
+
}
|
|
73855
|
+
} catch {
|
|
73856
|
+
session.process.kill(signal);
|
|
73857
|
+
}
|
|
73858
|
+
return true;
|
|
73859
|
+
}
|
|
73860
|
+
/**
|
|
73861
|
+
* Cleans up a session from memory.
|
|
73862
|
+
*/
|
|
73863
|
+
cleanupSession(sessionId) {
|
|
73864
|
+
const session = this.sessions.get(sessionId);
|
|
73865
|
+
if (!session) return false;
|
|
73866
|
+
if (session.exitCode === null && !session.killed) {
|
|
73867
|
+
this.killSession(sessionId, "SIGKILL");
|
|
73868
|
+
}
|
|
73869
|
+
this.sessions.delete(sessionId);
|
|
73870
|
+
return true;
|
|
73871
|
+
}
|
|
73872
|
+
/**
|
|
73873
|
+
* Lists all active sessions.
|
|
73874
|
+
*/
|
|
73875
|
+
listSessions() {
|
|
73876
|
+
return Array.from(this.sessions.values()).map((s) => ({
|
|
73877
|
+
id: s.id,
|
|
73878
|
+
command: s.command,
|
|
73879
|
+
running: s.exitCode === null && !s.killed,
|
|
73880
|
+
startTime: s.startTime
|
|
73881
|
+
}));
|
|
73882
|
+
}
|
|
73883
|
+
/**
|
|
73884
|
+
* Cleans up all sessions (useful for shutdown).
|
|
73885
|
+
*/
|
|
73886
|
+
cleanupAll() {
|
|
73887
|
+
for (const [sessionId] of this.sessions) {
|
|
73888
|
+
this.cleanupSession(sessionId);
|
|
73889
|
+
}
|
|
73890
|
+
}
|
|
73891
|
+
};
|
|
73892
|
+
terminalSessionManager = new TerminalSessionManager();
|
|
73893
|
+
}
|
|
73894
|
+
});
|
|
73895
|
+
|
|
73896
|
+
// ../dashboard/src/terminal-service.ts
|
|
73897
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
73898
|
+
var isBunBinary, require2;
|
|
73899
|
+
var init_terminal_service = __esm({
|
|
73900
|
+
"../dashboard/src/terminal-service.ts"() {
|
|
73901
|
+
"use strict";
|
|
73902
|
+
isBunBinary = typeof Bun !== "undefined" && !!Bun.embeddedFiles;
|
|
73903
|
+
require2 = createRequire2(import.meta.url);
|
|
73904
|
+
}
|
|
73905
|
+
});
|
|
73906
|
+
|
|
73907
|
+
// ../dashboard/src/github-webhooks.ts
|
|
73908
|
+
var init_github_webhooks = __esm({
|
|
73909
|
+
"../dashboard/src/github-webhooks.ts"() {
|
|
73910
|
+
"use strict";
|
|
73911
|
+
}
|
|
73912
|
+
});
|
|
73913
|
+
|
|
73914
|
+
// ../dashboard/src/ai-session-store.ts
|
|
73915
|
+
var MAX_THINKING_BYTES, SESSION_CLEANUP_DEFAULT_MAX_AGE_MS, SESSION_CLEANUP_INTERVAL_MS, diagnostics2;
|
|
73916
|
+
var init_ai_session_store = __esm({
|
|
73917
|
+
"../dashboard/src/ai-session-store.ts"() {
|
|
73918
|
+
"use strict";
|
|
73919
|
+
init_ai_session_diagnostics();
|
|
73920
|
+
MAX_THINKING_BYTES = 50 * 1024;
|
|
73921
|
+
SESSION_CLEANUP_DEFAULT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
73922
|
+
SESSION_CLEANUP_INTERVAL_MS = 6 * 60 * 60 * 1e3;
|
|
73923
|
+
diagnostics2 = createSessionDiagnostics("ai-session-store");
|
|
73924
|
+
}
|
|
73925
|
+
});
|
|
73926
|
+
|
|
73927
|
+
// ../dashboard/src/subtask-breakdown.ts
|
|
73928
|
+
import { EventEmitter as EventEmitter21 } from "node:events";
|
|
73929
|
+
function cleanupInMemorySubtaskSession(sessionId) {
|
|
73930
|
+
const session = sessions2.get(sessionId);
|
|
73931
|
+
if (!session) {
|
|
73932
|
+
return false;
|
|
73933
|
+
}
|
|
73934
|
+
try {
|
|
73935
|
+
session.agent?.session?.dispose?.();
|
|
73936
|
+
} catch {
|
|
73937
|
+
}
|
|
73938
|
+
subtaskStreamManager.cleanupSession(sessionId);
|
|
73939
|
+
sessions2.delete(sessionId);
|
|
73940
|
+
return true;
|
|
73941
|
+
}
|
|
73942
|
+
function cleanupExpiredSessions2() {
|
|
73943
|
+
const now = Date.now();
|
|
73944
|
+
for (const [id, session] of sessions2) {
|
|
73945
|
+
if (now - session.updatedAt.getTime() > SESSION_TTL_MS2) {
|
|
73946
|
+
cleanupInMemorySubtaskSession(id);
|
|
73947
|
+
}
|
|
73948
|
+
}
|
|
73949
|
+
}
|
|
73950
|
+
var diagnostics3, SESSION_TTL_MS2, CLEANUP_INTERVAL_MS3, sessions2, cleanupInterval3, SubtaskStreamManager, subtaskStreamManager;
|
|
73951
|
+
var init_subtask_breakdown = __esm({
|
|
73952
|
+
"../dashboard/src/subtask-breakdown.ts"() {
|
|
72567
73953
|
"use strict";
|
|
73954
|
+
init_src();
|
|
73955
|
+
init_sse_buffer();
|
|
73956
|
+
init_ai_session_diagnostics();
|
|
73957
|
+
diagnostics3 = createSessionDiagnostics("subtask-breakdown");
|
|
73958
|
+
SESSION_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
|
|
73959
|
+
CLEANUP_INTERVAL_MS3 = 5 * 60 * 1e3;
|
|
73960
|
+
sessions2 = /* @__PURE__ */ new Map();
|
|
73961
|
+
cleanupInterval3 = setInterval(cleanupExpiredSessions2, CLEANUP_INTERVAL_MS3);
|
|
73962
|
+
cleanupInterval3.unref?.();
|
|
73963
|
+
process.on("beforeExit", () => {
|
|
73964
|
+
clearInterval(cleanupInterval3);
|
|
73965
|
+
});
|
|
73966
|
+
SubtaskStreamManager = class extends EventEmitter21 {
|
|
73967
|
+
constructor(bufferSize = 100) {
|
|
73968
|
+
super();
|
|
73969
|
+
this.bufferSize = bufferSize;
|
|
73970
|
+
}
|
|
73971
|
+
sessions = /* @__PURE__ */ new Map();
|
|
73972
|
+
buffers = /* @__PURE__ */ new Map();
|
|
73973
|
+
subscribe(sessionId, callback) {
|
|
73974
|
+
if (!this.sessions.has(sessionId)) {
|
|
73975
|
+
this.sessions.set(sessionId, /* @__PURE__ */ new Set());
|
|
73976
|
+
}
|
|
73977
|
+
const callbacks = this.sessions.get(sessionId);
|
|
73978
|
+
callbacks.add(callback);
|
|
73979
|
+
return () => {
|
|
73980
|
+
callbacks.delete(callback);
|
|
73981
|
+
if (callbacks.size === 0) {
|
|
73982
|
+
this.sessions.delete(sessionId);
|
|
73983
|
+
}
|
|
73984
|
+
};
|
|
73985
|
+
}
|
|
73986
|
+
getBuffer(sessionId) {
|
|
73987
|
+
let buffer = this.buffers.get(sessionId);
|
|
73988
|
+
if (!buffer) {
|
|
73989
|
+
buffer = new SessionEventBuffer(this.bufferSize);
|
|
73990
|
+
this.buffers.set(sessionId, buffer);
|
|
73991
|
+
}
|
|
73992
|
+
return buffer;
|
|
73993
|
+
}
|
|
73994
|
+
broadcast(sessionId, event) {
|
|
73995
|
+
const serialized = JSON.stringify(event.data ?? {});
|
|
73996
|
+
const eventData = typeof serialized === "string" ? serialized : "{}";
|
|
73997
|
+
const eventId = this.getBuffer(sessionId).push(event.type, eventData);
|
|
73998
|
+
const callbacks = this.sessions.get(sessionId);
|
|
73999
|
+
if (!callbacks) return eventId;
|
|
74000
|
+
for (const callback of callbacks) {
|
|
74001
|
+
try {
|
|
74002
|
+
callback(event, eventId);
|
|
74003
|
+
} catch {
|
|
74004
|
+
}
|
|
74005
|
+
}
|
|
74006
|
+
return eventId;
|
|
74007
|
+
}
|
|
74008
|
+
getBufferedEvents(sessionId, sinceId) {
|
|
74009
|
+
const buffer = this.buffers.get(sessionId);
|
|
74010
|
+
if (!buffer) return [];
|
|
74011
|
+
return buffer.getEventsSince(sinceId);
|
|
74012
|
+
}
|
|
74013
|
+
cleanupSession(sessionId) {
|
|
74014
|
+
this.sessions.delete(sessionId);
|
|
74015
|
+
this.buffers.delete(sessionId);
|
|
74016
|
+
}
|
|
74017
|
+
reset() {
|
|
74018
|
+
this.sessions.clear();
|
|
74019
|
+
this.buffers.clear();
|
|
74020
|
+
this.removeAllListeners();
|
|
74021
|
+
}
|
|
74022
|
+
};
|
|
74023
|
+
subtaskStreamManager = new SubtaskStreamManager();
|
|
74024
|
+
}
|
|
74025
|
+
});
|
|
74026
|
+
|
|
74027
|
+
// ../dashboard/src/mission-interview.ts
|
|
74028
|
+
import { EventEmitter as EventEmitter22 } from "node:events";
|
|
74029
|
+
function cleanupInMemoryMissionSession(sessionId) {
|
|
74030
|
+
const session = sessions3.get(sessionId);
|
|
74031
|
+
if (!session) {
|
|
74032
|
+
return false;
|
|
74033
|
+
}
|
|
74034
|
+
if (session.agent) {
|
|
74035
|
+
try {
|
|
74036
|
+
session.agent.session.dispose?.();
|
|
74037
|
+
} catch {
|
|
74038
|
+
}
|
|
74039
|
+
session.agent = void 0;
|
|
74040
|
+
}
|
|
74041
|
+
missionInterviewStreamManager.cleanupSession(sessionId);
|
|
74042
|
+
sessions3.delete(sessionId);
|
|
74043
|
+
return true;
|
|
74044
|
+
}
|
|
74045
|
+
function cleanupExpiredSessions3() {
|
|
74046
|
+
const now = Date.now();
|
|
74047
|
+
for (const [id, session] of sessions3) {
|
|
74048
|
+
if (now - session.updatedAt.getTime() > SESSION_TTL_MS3) {
|
|
74049
|
+
cleanupInMemoryMissionSession(id);
|
|
74050
|
+
}
|
|
74051
|
+
}
|
|
74052
|
+
for (const [ip, entry] of rateLimits3) {
|
|
74053
|
+
if (now - entry.firstRequestAt.getTime() > RATE_LIMIT_WINDOW_MS3) {
|
|
74054
|
+
rateLimits3.delete(ip);
|
|
74055
|
+
}
|
|
74056
|
+
}
|
|
74057
|
+
}
|
|
74058
|
+
var diagnostics4, SESSION_TTL_MS3, CLEANUP_INTERVAL_MS4, RATE_LIMIT_WINDOW_MS3, sessions3, rateLimits3, cleanupInterval4, MissionInterviewStreamManager, missionInterviewStreamManager;
|
|
74059
|
+
var init_mission_interview = __esm({
|
|
74060
|
+
"../dashboard/src/mission-interview.ts"() {
|
|
74061
|
+
"use strict";
|
|
74062
|
+
init_src();
|
|
74063
|
+
init_sse_buffer();
|
|
74064
|
+
init_ai_session_diagnostics();
|
|
74065
|
+
diagnostics4 = createSessionDiagnostics("mission-interview");
|
|
74066
|
+
SESSION_TTL_MS3 = 7 * 24 * 60 * 60 * 1e3;
|
|
74067
|
+
CLEANUP_INTERVAL_MS4 = 5 * 60 * 1e3;
|
|
74068
|
+
RATE_LIMIT_WINDOW_MS3 = 60 * 60 * 1e3;
|
|
74069
|
+
sessions3 = /* @__PURE__ */ new Map();
|
|
74070
|
+
rateLimits3 = /* @__PURE__ */ new Map();
|
|
74071
|
+
cleanupInterval4 = setInterval(cleanupExpiredSessions3, CLEANUP_INTERVAL_MS4);
|
|
74072
|
+
cleanupInterval4.unref?.();
|
|
74073
|
+
process.on("beforeExit", () => clearInterval(cleanupInterval4));
|
|
74074
|
+
MissionInterviewStreamManager = class extends EventEmitter22 {
|
|
74075
|
+
constructor(bufferSize = 100) {
|
|
74076
|
+
super();
|
|
74077
|
+
this.bufferSize = bufferSize;
|
|
74078
|
+
}
|
|
74079
|
+
sessions = /* @__PURE__ */ new Map();
|
|
74080
|
+
buffers = /* @__PURE__ */ new Map();
|
|
74081
|
+
subscribe(sessionId, callback) {
|
|
74082
|
+
if (!this.sessions.has(sessionId)) {
|
|
74083
|
+
this.sessions.set(sessionId, /* @__PURE__ */ new Set());
|
|
74084
|
+
}
|
|
74085
|
+
const callbacks = this.sessions.get(sessionId);
|
|
74086
|
+
callbacks.add(callback);
|
|
74087
|
+
return () => {
|
|
74088
|
+
callbacks.delete(callback);
|
|
74089
|
+
if (callbacks.size === 0) {
|
|
74090
|
+
this.sessions.delete(sessionId);
|
|
74091
|
+
}
|
|
74092
|
+
};
|
|
74093
|
+
}
|
|
74094
|
+
getBuffer(sessionId) {
|
|
74095
|
+
let buffer = this.buffers.get(sessionId);
|
|
74096
|
+
if (!buffer) {
|
|
74097
|
+
buffer = new SessionEventBuffer(this.bufferSize);
|
|
74098
|
+
this.buffers.set(sessionId, buffer);
|
|
74099
|
+
}
|
|
74100
|
+
return buffer;
|
|
74101
|
+
}
|
|
74102
|
+
broadcast(sessionId, event) {
|
|
74103
|
+
const serialized = JSON.stringify(event.data ?? {});
|
|
74104
|
+
const eventData = typeof serialized === "string" ? serialized : "{}";
|
|
74105
|
+
const eventId = this.getBuffer(sessionId).push(event.type, eventData);
|
|
74106
|
+
const callbacks = this.sessions.get(sessionId);
|
|
74107
|
+
if (!callbacks) return eventId;
|
|
74108
|
+
for (const callback of callbacks) {
|
|
74109
|
+
nonfatal(
|
|
74110
|
+
() => callback(event, eventId),
|
|
74111
|
+
diagnostics4,
|
|
74112
|
+
"Error broadcasting to client",
|
|
74113
|
+
{ sessionId, operation: "broadcast" }
|
|
74114
|
+
);
|
|
74115
|
+
}
|
|
74116
|
+
return eventId;
|
|
74117
|
+
}
|
|
74118
|
+
getBufferedEvents(sessionId, sinceId) {
|
|
74119
|
+
const buffer = this.buffers.get(sessionId);
|
|
74120
|
+
if (!buffer) return [];
|
|
74121
|
+
return buffer.getEventsSince(sinceId);
|
|
74122
|
+
}
|
|
74123
|
+
hasSubscribers(sessionId) {
|
|
74124
|
+
const callbacks = this.sessions.get(sessionId);
|
|
74125
|
+
return callbacks !== void 0 && callbacks.size > 0;
|
|
74126
|
+
}
|
|
74127
|
+
cleanupSession(sessionId) {
|
|
74128
|
+
this.sessions.delete(sessionId);
|
|
74129
|
+
this.buffers.delete(sessionId);
|
|
74130
|
+
}
|
|
74131
|
+
reset() {
|
|
74132
|
+
this.sessions.clear();
|
|
74133
|
+
this.buffers.clear();
|
|
74134
|
+
this.removeAllListeners();
|
|
74135
|
+
}
|
|
74136
|
+
};
|
|
74137
|
+
missionInterviewStreamManager = new MissionInterviewStreamManager();
|
|
74138
|
+
}
|
|
74139
|
+
});
|
|
74140
|
+
|
|
74141
|
+
// ../dashboard/src/milestone-slice-interview.ts
|
|
74142
|
+
import { EventEmitter as EventEmitter23 } from "node:events";
|
|
74143
|
+
function cleanupInMemorySession2(sessionId) {
|
|
74144
|
+
const session = sessions4.get(sessionId);
|
|
74145
|
+
if (!session) {
|
|
74146
|
+
return false;
|
|
74147
|
+
}
|
|
74148
|
+
if (session.agent) {
|
|
74149
|
+
try {
|
|
74150
|
+
session.agent.session.dispose?.();
|
|
74151
|
+
} catch {
|
|
74152
|
+
}
|
|
74153
|
+
session.agent = void 0;
|
|
74154
|
+
}
|
|
74155
|
+
milestoneSliceInterviewStreamManager.cleanupSession(sessionId);
|
|
74156
|
+
sessions4.delete(sessionId);
|
|
74157
|
+
return true;
|
|
74158
|
+
}
|
|
74159
|
+
function cleanupExpiredSessions4() {
|
|
74160
|
+
const now = Date.now();
|
|
74161
|
+
for (const [id, session] of sessions4) {
|
|
74162
|
+
if (now - session.updatedAt.getTime() > SESSION_TTL_MS4) {
|
|
74163
|
+
cleanupInMemorySession2(id);
|
|
74164
|
+
}
|
|
74165
|
+
}
|
|
74166
|
+
for (const [ip, entry] of rateLimits4) {
|
|
74167
|
+
if (now - entry.firstRequestAt.getTime() > RATE_LIMIT_WINDOW_MS4) {
|
|
74168
|
+
rateLimits4.delete(ip);
|
|
74169
|
+
}
|
|
74170
|
+
}
|
|
74171
|
+
}
|
|
74172
|
+
var diagnostics5, SESSION_TTL_MS4, CLEANUP_INTERVAL_MS5, RATE_LIMIT_WINDOW_MS4, sessions4, rateLimits4, cleanupInterval5, MilestoneSliceInterviewStreamManager, milestoneSliceInterviewStreamManager;
|
|
74173
|
+
var init_milestone_slice_interview = __esm({
|
|
74174
|
+
"../dashboard/src/milestone-slice-interview.ts"() {
|
|
74175
|
+
"use strict";
|
|
74176
|
+
init_sse_buffer();
|
|
74177
|
+
init_mission_interview();
|
|
74178
|
+
init_ai_session_diagnostics();
|
|
74179
|
+
init_mission_interview();
|
|
74180
|
+
diagnostics5 = createSessionDiagnostics("milestone-slice-interview");
|
|
74181
|
+
SESSION_TTL_MS4 = 7 * 24 * 60 * 60 * 1e3;
|
|
74182
|
+
CLEANUP_INTERVAL_MS5 = 5 * 60 * 1e3;
|
|
74183
|
+
RATE_LIMIT_WINDOW_MS4 = 60 * 60 * 1e3;
|
|
74184
|
+
sessions4 = /* @__PURE__ */ new Map();
|
|
74185
|
+
rateLimits4 = /* @__PURE__ */ new Map();
|
|
74186
|
+
cleanupInterval5 = setInterval(cleanupExpiredSessions4, CLEANUP_INTERVAL_MS5);
|
|
74187
|
+
cleanupInterval5.unref?.();
|
|
74188
|
+
process.on("beforeExit", () => clearInterval(cleanupInterval5));
|
|
74189
|
+
MilestoneSliceInterviewStreamManager = class extends EventEmitter23 {
|
|
74190
|
+
constructor(bufferSize = 100) {
|
|
74191
|
+
super();
|
|
74192
|
+
this.bufferSize = bufferSize;
|
|
74193
|
+
}
|
|
74194
|
+
sessions = /* @__PURE__ */ new Map();
|
|
74195
|
+
buffers = /* @__PURE__ */ new Map();
|
|
74196
|
+
subscribe(sessionId, callback) {
|
|
74197
|
+
if (!this.sessions.has(sessionId)) {
|
|
74198
|
+
this.sessions.set(sessionId, /* @__PURE__ */ new Set());
|
|
74199
|
+
}
|
|
74200
|
+
const callbacks = this.sessions.get(sessionId);
|
|
74201
|
+
callbacks.add(callback);
|
|
74202
|
+
return () => {
|
|
74203
|
+
callbacks.delete(callback);
|
|
74204
|
+
if (callbacks.size === 0) {
|
|
74205
|
+
this.sessions.delete(sessionId);
|
|
74206
|
+
}
|
|
74207
|
+
};
|
|
74208
|
+
}
|
|
74209
|
+
getBuffer(sessionId) {
|
|
74210
|
+
let buffer = this.buffers.get(sessionId);
|
|
74211
|
+
if (!buffer) {
|
|
74212
|
+
buffer = new SessionEventBuffer(this.bufferSize);
|
|
74213
|
+
this.buffers.set(sessionId, buffer);
|
|
74214
|
+
}
|
|
74215
|
+
return buffer;
|
|
74216
|
+
}
|
|
74217
|
+
broadcast(sessionId, event) {
|
|
74218
|
+
const serialized = JSON.stringify(event.data ?? {});
|
|
74219
|
+
const eventData = typeof serialized === "string" ? serialized : "{}";
|
|
74220
|
+
const eventId = this.getBuffer(sessionId).push(event.type, eventData);
|
|
74221
|
+
const callbacks = this.sessions.get(sessionId);
|
|
74222
|
+
if (!callbacks) return eventId;
|
|
74223
|
+
for (const callback of callbacks) {
|
|
74224
|
+
nonfatal(
|
|
74225
|
+
() => callback(event, eventId),
|
|
74226
|
+
diagnostics5,
|
|
74227
|
+
"Error broadcasting to client",
|
|
74228
|
+
{ sessionId, operation: "broadcast" }
|
|
74229
|
+
);
|
|
74230
|
+
}
|
|
74231
|
+
return eventId;
|
|
74232
|
+
}
|
|
74233
|
+
getBufferedEvents(sessionId, sinceId) {
|
|
74234
|
+
const buffer = this.buffers.get(sessionId);
|
|
74235
|
+
if (!buffer) return [];
|
|
74236
|
+
return buffer.getEventsSince(sinceId);
|
|
74237
|
+
}
|
|
74238
|
+
hasSubscribers(sessionId) {
|
|
74239
|
+
const callbacks = this.sessions.get(sessionId);
|
|
74240
|
+
return callbacks !== void 0 && callbacks.size > 0;
|
|
74241
|
+
}
|
|
74242
|
+
cleanupSession(sessionId) {
|
|
74243
|
+
this.sessions.delete(sessionId);
|
|
74244
|
+
this.buffers.delete(sessionId);
|
|
74245
|
+
}
|
|
74246
|
+
reset() {
|
|
74247
|
+
this.sessions.clear();
|
|
74248
|
+
this.buffers.clear();
|
|
74249
|
+
this.removeAllListeners();
|
|
74250
|
+
}
|
|
74251
|
+
};
|
|
74252
|
+
milestoneSliceInterviewStreamManager = new MilestoneSliceInterviewStreamManager();
|
|
74253
|
+
}
|
|
74254
|
+
});
|
|
74255
|
+
|
|
74256
|
+
// ../dashboard/src/runtime-logger.ts
|
|
74257
|
+
var init_runtime_logger = __esm({
|
|
74258
|
+
"../dashboard/src/runtime-logger.ts"() {
|
|
74259
|
+
"use strict";
|
|
74260
|
+
}
|
|
74261
|
+
});
|
|
74262
|
+
|
|
74263
|
+
// ../dashboard/src/api-error.ts
|
|
74264
|
+
var init_api_error = __esm({
|
|
74265
|
+
"../dashboard/src/api-error.ts"() {
|
|
74266
|
+
"use strict";
|
|
74267
|
+
init_runtime_logger();
|
|
74268
|
+
}
|
|
74269
|
+
});
|
|
74270
|
+
|
|
74271
|
+
// ../dashboard/src/plugin-routes.ts
|
|
74272
|
+
import { Router } from "express";
|
|
74273
|
+
var init_plugin_routes = __esm({
|
|
74274
|
+
"../dashboard/src/plugin-routes.ts"() {
|
|
74275
|
+
"use strict";
|
|
74276
|
+
init_src();
|
|
74277
|
+
init_api_error();
|
|
74278
|
+
}
|
|
74279
|
+
});
|
|
74280
|
+
|
|
74281
|
+
// ../dashboard/src/project-store-resolver.ts
|
|
74282
|
+
var init_project_store_resolver = __esm({
|
|
74283
|
+
"../dashboard/src/project-store-resolver.ts"() {
|
|
74284
|
+
"use strict";
|
|
74285
|
+
}
|
|
74286
|
+
});
|
|
74287
|
+
|
|
74288
|
+
// ../dashboard/src/routes/context.ts
|
|
74289
|
+
import { Router as Router2 } from "express";
|
|
74290
|
+
var init_context = __esm({
|
|
74291
|
+
"../dashboard/src/routes/context.ts"() {
|
|
74292
|
+
"use strict";
|
|
74293
|
+
init_api_error();
|
|
74294
|
+
init_project_store_resolver();
|
|
74295
|
+
init_runtime_logger();
|
|
74296
|
+
}
|
|
74297
|
+
});
|
|
74298
|
+
|
|
74299
|
+
// ../dashboard/src/routes/register-task-workflow-routes.ts
|
|
74300
|
+
var init_register_task_workflow_routes = __esm({
|
|
74301
|
+
"../dashboard/src/routes/register-task-workflow-routes.ts"() {
|
|
74302
|
+
"use strict";
|
|
74303
|
+
init_src();
|
|
74304
|
+
init_api_error();
|
|
74305
|
+
}
|
|
74306
|
+
});
|
|
74307
|
+
|
|
74308
|
+
// ../dashboard/src/routes/register-planning-subtask-routes.ts
|
|
74309
|
+
var init_register_planning_subtask_routes = __esm({
|
|
74310
|
+
"../dashboard/src/routes/register-planning-subtask-routes.ts"() {
|
|
74311
|
+
"use strict";
|
|
74312
|
+
init_api_error();
|
|
74313
|
+
init_sse_buffer();
|
|
74314
|
+
}
|
|
74315
|
+
});
|
|
74316
|
+
|
|
74317
|
+
// ../dashboard/src/rate-limit.ts
|
|
74318
|
+
var init_rate_limit = __esm({
|
|
74319
|
+
"../dashboard/src/rate-limit.ts"() {
|
|
74320
|
+
"use strict";
|
|
74321
|
+
init_api_error();
|
|
74322
|
+
}
|
|
74323
|
+
});
|
|
74324
|
+
|
|
74325
|
+
// ../dashboard/src/routes/register-chat-routes.ts
|
|
74326
|
+
var init_register_chat_routes = __esm({
|
|
74327
|
+
"../dashboard/src/routes/register-chat-routes.ts"() {
|
|
74328
|
+
"use strict";
|
|
74329
|
+
init_api_error();
|
|
74330
|
+
init_rate_limit();
|
|
74331
|
+
init_sse_buffer();
|
|
74332
|
+
}
|
|
74333
|
+
});
|
|
74334
|
+
|
|
74335
|
+
// ../dashboard/src/remote-auth.ts
|
|
74336
|
+
var init_remote_auth = __esm({
|
|
74337
|
+
"../dashboard/src/remote-auth.ts"() {
|
|
74338
|
+
"use strict";
|
|
74339
|
+
}
|
|
74340
|
+
});
|
|
74341
|
+
|
|
74342
|
+
// ../dashboard/src/routes/register-settings-memory-routes.ts
|
|
74343
|
+
var init_register_settings_memory_routes = __esm({
|
|
74344
|
+
"../dashboard/src/routes/register-settings-memory-routes.ts"() {
|
|
74345
|
+
"use strict";
|
|
74346
|
+
init_src();
|
|
74347
|
+
init_api_error();
|
|
74348
|
+
init_remote_auth();
|
|
74349
|
+
init_project_store_resolver();
|
|
74350
|
+
}
|
|
74351
|
+
});
|
|
74352
|
+
|
|
74353
|
+
// ../dashboard/src/routes/register-messaging-scripts.ts
|
|
74354
|
+
var init_register_messaging_scripts = __esm({
|
|
74355
|
+
"../dashboard/src/routes/register-messaging-scripts.ts"() {
|
|
74356
|
+
"use strict";
|
|
74357
|
+
init_src();
|
|
74358
|
+
init_api_error();
|
|
74359
|
+
init_terminal_service();
|
|
72568
74360
|
}
|
|
72569
74361
|
});
|
|
72570
74362
|
|
|
@@ -74048,7 +75840,7 @@ var init_github = __esm({
|
|
|
74048
75840
|
});
|
|
74049
75841
|
|
|
74050
75842
|
// ../dashboard/src/github-poll.ts
|
|
74051
|
-
import { EventEmitter as
|
|
75843
|
+
import { EventEmitter as EventEmitter24 } from "node:events";
|
|
74052
75844
|
function toAlias(type, number) {
|
|
74053
75845
|
return `${type}_${number}`;
|
|
74054
75846
|
}
|
|
@@ -74094,7 +75886,7 @@ var init_github_poll = __esm({
|
|
|
74094
75886
|
}
|
|
74095
75887
|
};
|
|
74096
75888
|
githubRateLimiter = new GitHubRateLimiter();
|
|
74097
|
-
GitHubPollingService = class extends
|
|
75889
|
+
GitHubPollingService = class extends EventEmitter24 {
|
|
74098
75890
|
watches = /* @__PURE__ */ new Map();
|
|
74099
75891
|
rateLimiter;
|
|
74100
75892
|
pollingIntervalMs;
|
|
@@ -74338,300 +76130,19 @@ var init_github_poll = __esm({
|
|
|
74338
76130
|
}
|
|
74339
76131
|
});
|
|
74340
76132
|
|
|
74341
|
-
// ../dashboard/src/
|
|
74342
|
-
import {
|
|
74343
|
-
import {
|
|
74344
|
-
|
|
74345
|
-
|
|
74346
|
-
|
|
74347
|
-
while (/^[A-Za-z_][A-Za-z0-9_]*=/.test(trimmed)) {
|
|
74348
|
-
const match2 = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*=(?:[^\s]*|"[^"]*"|'[^']*'))\s*/);
|
|
74349
|
-
if (match2) {
|
|
74350
|
-
trimmed = trimmed.slice(match2[0].length).trim();
|
|
74351
|
-
} else {
|
|
74352
|
-
break;
|
|
74353
|
-
}
|
|
74354
|
-
}
|
|
74355
|
-
if (trimmed.startsWith("sudo ")) {
|
|
74356
|
-
trimmed = trimmed.slice(5).trim();
|
|
74357
|
-
}
|
|
74358
|
-
const match = trimmed.match(/^([A-Za-z0-9._-]+)/);
|
|
74359
|
-
return match ? match[1].toLowerCase() : null;
|
|
74360
|
-
}
|
|
74361
|
-
function validateCommand(command) {
|
|
74362
|
-
for (const pattern of SUBSTITUTION_PATTERNS) {
|
|
74363
|
-
if (pattern.test(command)) {
|
|
74364
|
-
return { valid: false, error: "Command substitution is not allowed" };
|
|
74365
|
-
}
|
|
74366
|
-
}
|
|
74367
|
-
if (/[\0\r\n]/.test(command)) {
|
|
74368
|
-
return { valid: false, error: "Command contains invalid control characters" };
|
|
74369
|
-
}
|
|
74370
|
-
for (const pattern of BLOCKED_PATTERNS) {
|
|
74371
|
-
if (pattern.test(command)) {
|
|
74372
|
-
return { valid: false, error: "Command contains dangerous patterns and is not allowed" };
|
|
74373
|
-
}
|
|
74374
|
-
}
|
|
74375
|
-
const segments = command.split(CHAIN_OPERATORS);
|
|
74376
|
-
for (const raw of segments) {
|
|
74377
|
-
const segment = raw.trim();
|
|
74378
|
-
if (segment.length === 0) continue;
|
|
74379
|
-
const baseCommand = extractBaseCommand(segment);
|
|
74380
|
-
if (!baseCommand) {
|
|
74381
|
-
return { valid: false, error: "Could not parse command" };
|
|
74382
|
-
}
|
|
74383
|
-
if (!ALLOWED_COMMANDS.has(baseCommand)) {
|
|
74384
|
-
return {
|
|
74385
|
-
valid: false,
|
|
74386
|
-
error: `Command '${baseCommand}' is not in the allowed command list. Allowed commands: ${Array.from(ALLOWED_COMMANDS).sort().join(", ")}`
|
|
74387
|
-
};
|
|
74388
|
-
}
|
|
74389
|
-
}
|
|
74390
|
-
return { valid: true };
|
|
74391
|
-
}
|
|
74392
|
-
var ALLOWED_COMMANDS, BLOCKED_PATTERNS, SUBSTITUTION_PATTERNS, CHAIN_OPERATORS, TerminalSessionManager, terminalSessionManager;
|
|
74393
|
-
var init_terminal = __esm({
|
|
74394
|
-
"../dashboard/src/terminal.ts"() {
|
|
74395
|
-
"use strict";
|
|
74396
|
-
ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
74397
|
-
// Version control
|
|
74398
|
-
"git",
|
|
74399
|
-
// Package managers
|
|
74400
|
-
"npm",
|
|
74401
|
-
"pnpm",
|
|
74402
|
-
"yarn",
|
|
74403
|
-
"bun",
|
|
74404
|
-
// File operations
|
|
74405
|
-
"ls",
|
|
74406
|
-
"cat",
|
|
74407
|
-
"echo",
|
|
74408
|
-
"pwd",
|
|
74409
|
-
"cd",
|
|
74410
|
-
"mkdir",
|
|
74411
|
-
"touch",
|
|
74412
|
-
"cp",
|
|
74413
|
-
"mv",
|
|
74414
|
-
"rm",
|
|
74415
|
-
"head",
|
|
74416
|
-
"tail",
|
|
74417
|
-
"less",
|
|
74418
|
-
"more",
|
|
74419
|
-
"find",
|
|
74420
|
-
"grep",
|
|
74421
|
-
// System info
|
|
74422
|
-
"clear",
|
|
74423
|
-
"which",
|
|
74424
|
-
"whoami",
|
|
74425
|
-
"uname",
|
|
74426
|
-
"date",
|
|
74427
|
-
// Node/JS
|
|
74428
|
-
"node",
|
|
74429
|
-
"npx",
|
|
74430
|
-
"tsx",
|
|
74431
|
-
// Python
|
|
74432
|
-
"python",
|
|
74433
|
-
"python3",
|
|
74434
|
-
"pip",
|
|
74435
|
-
"pip3",
|
|
74436
|
-
// Network
|
|
74437
|
-
"curl",
|
|
74438
|
-
"wget",
|
|
74439
|
-
// Build tools
|
|
74440
|
-
"make",
|
|
74441
|
-
"cmake",
|
|
74442
|
-
// Process management
|
|
74443
|
-
"ps",
|
|
74444
|
-
"top",
|
|
74445
|
-
"htop",
|
|
74446
|
-
"kill",
|
|
74447
|
-
"pkill",
|
|
74448
|
-
// Shell builtins that are safe
|
|
74449
|
-
"source",
|
|
74450
|
-
".",
|
|
74451
|
-
"export",
|
|
74452
|
-
"env",
|
|
74453
|
-
"printenv",
|
|
74454
|
-
"alias",
|
|
74455
|
-
// Editors (for viewing)
|
|
74456
|
-
"code",
|
|
74457
|
-
// VS Code CLI
|
|
74458
|
-
"vim",
|
|
74459
|
-
"vi",
|
|
74460
|
-
"nano"
|
|
74461
|
-
]);
|
|
74462
|
-
BLOCKED_PATTERNS = [
|
|
74463
|
-
// System destruction
|
|
74464
|
-
/rm\s+(-[rf]+\s+)?\/\s*$/i,
|
|
74465
|
-
// rm -rf / or rm /
|
|
74466
|
-
/rm\s+(-[rf]+\s+)?\/\*/i,
|
|
74467
|
-
// rm -rf /*
|
|
74468
|
-
/>\s*\/dev\/sda/i,
|
|
74469
|
-
// Direct disk write
|
|
74470
|
-
/:\(\)\s*\{\s*:\s*\|:\s*&\s*\};\s*:/i,
|
|
74471
|
-
// Fork bomb
|
|
74472
|
-
/mkfs\.\w+\s+/i,
|
|
74473
|
-
// Filesystem formatting
|
|
74474
|
-
/dd\s+if=/i,
|
|
74475
|
-
// dd with input file
|
|
74476
|
-
/\.\s*\/dev\/null/i
|
|
74477
|
-
// Sourcing /dev/null tricks
|
|
74478
|
-
];
|
|
74479
|
-
SUBSTITUTION_PATTERNS = [
|
|
74480
|
-
/\$\(/,
|
|
74481
|
-
// $(...) — command substitution
|
|
74482
|
-
/`/,
|
|
74483
|
-
// `...` — backtick command substitution
|
|
74484
|
-
/<\(/,
|
|
74485
|
-
// <(...) — process substitution (bash)
|
|
74486
|
-
/>\(/
|
|
74487
|
-
// >(...) — process substitution (bash)
|
|
74488
|
-
];
|
|
74489
|
-
CHAIN_OPERATORS = /&&|\|\||;|(?<!\|)\|(?!\|)/;
|
|
74490
|
-
TerminalSessionManager = class extends EventEmitter20 {
|
|
74491
|
-
sessions = /* @__PURE__ */ new Map();
|
|
74492
|
-
defaultTimeout = 3e4;
|
|
74493
|
-
// 30 seconds
|
|
74494
|
-
/**
|
|
74495
|
-
* Creates a new terminal session and spawns the command.
|
|
74496
|
-
* Returns the session ID for tracking.
|
|
74497
|
-
*/
|
|
74498
|
-
createSession(command, cwd) {
|
|
74499
|
-
const validation = validateCommand(command);
|
|
74500
|
-
if (!validation.valid) {
|
|
74501
|
-
return { sessionId: "", error: validation.error };
|
|
74502
|
-
}
|
|
74503
|
-
const sessionId = randomUUID11();
|
|
74504
|
-
const childProcess = spawn2(command, [], {
|
|
74505
|
-
cwd,
|
|
74506
|
-
shell: true,
|
|
74507
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
74508
|
-
env: { ...process.env, FORCE_COLOR: "1", TERM: "xterm-256color" }
|
|
74509
|
-
});
|
|
74510
|
-
const session = {
|
|
74511
|
-
id: sessionId,
|
|
74512
|
-
command,
|
|
74513
|
-
process: childProcess,
|
|
74514
|
-
startTime: /* @__PURE__ */ new Date(),
|
|
74515
|
-
output: [],
|
|
74516
|
-
exitCode: null,
|
|
74517
|
-
killed: false
|
|
74518
|
-
};
|
|
74519
|
-
this.sessions.set(sessionId, session);
|
|
74520
|
-
childProcess.stdout?.on("data", (data) => {
|
|
74521
|
-
const chunk = data.toString("utf-8");
|
|
74522
|
-
session.output.push(chunk);
|
|
74523
|
-
this.emit("output", { sessionId, type: "stdout", data: chunk });
|
|
74524
|
-
});
|
|
74525
|
-
childProcess.stderr?.on("data", (data) => {
|
|
74526
|
-
const chunk = data.toString("utf-8");
|
|
74527
|
-
session.output.push(chunk);
|
|
74528
|
-
this.emit("output", { sessionId, type: "stderr", data: chunk });
|
|
74529
|
-
});
|
|
74530
|
-
childProcess.on("exit", (code) => {
|
|
74531
|
-
session.exitCode = code ?? 0;
|
|
74532
|
-
this.emit("output", {
|
|
74533
|
-
sessionId,
|
|
74534
|
-
type: "exit",
|
|
74535
|
-
data: `Process exited with code ${code ?? 0}`,
|
|
74536
|
-
exitCode: code ?? 0
|
|
74537
|
-
});
|
|
74538
|
-
setTimeout(() => this.cleanupSession(sessionId), 5e3);
|
|
74539
|
-
});
|
|
74540
|
-
childProcess.on("error", (err) => {
|
|
74541
|
-
const errorMsg = err.message;
|
|
74542
|
-
session.output.push(errorMsg);
|
|
74543
|
-
session.exitCode = 127;
|
|
74544
|
-
this.emit("output", { sessionId, type: "stderr", data: errorMsg });
|
|
74545
|
-
this.emit("output", {
|
|
74546
|
-
sessionId,
|
|
74547
|
-
type: "exit",
|
|
74548
|
-
data: `Process failed: ${errorMsg}`,
|
|
74549
|
-
exitCode: 127
|
|
74550
|
-
});
|
|
74551
|
-
setTimeout(() => this.cleanupSession(sessionId), 5e3);
|
|
74552
|
-
});
|
|
74553
|
-
const timeout = setTimeout(() => {
|
|
74554
|
-
if (!session.exitCode && !session.killed) {
|
|
74555
|
-
this.killSession(sessionId, "SIGTERM");
|
|
74556
|
-
this.emit("output", {
|
|
74557
|
-
sessionId,
|
|
74558
|
-
type: "stderr",
|
|
74559
|
-
data: "\n[Command timed out after 30 seconds]\n"
|
|
74560
|
-
});
|
|
74561
|
-
}
|
|
74562
|
-
}, this.defaultTimeout);
|
|
74563
|
-
childProcess.on("exit", () => clearTimeout(timeout));
|
|
74564
|
-
return { sessionId };
|
|
74565
|
-
}
|
|
74566
|
-
/**
|
|
74567
|
-
* Gets a session by ID.
|
|
74568
|
-
*/
|
|
74569
|
-
getSession(sessionId) {
|
|
74570
|
-
return this.sessions.get(sessionId);
|
|
74571
|
-
}
|
|
74572
|
-
/**
|
|
74573
|
-
* Kills a running session's process.
|
|
74574
|
-
* Returns true if killed, false if not found or already exited.
|
|
74575
|
-
*/
|
|
74576
|
-
killSession(sessionId, signal = "SIGTERM") {
|
|
74577
|
-
const session = this.sessions.get(sessionId);
|
|
74578
|
-
if (!session || session.exitCode !== null || session.killed) {
|
|
74579
|
-
return false;
|
|
74580
|
-
}
|
|
74581
|
-
session.killed = true;
|
|
74582
|
-
try {
|
|
74583
|
-
if (session.process.pid) {
|
|
74584
|
-
process.kill(-session.process.pid, signal);
|
|
74585
|
-
}
|
|
74586
|
-
} catch {
|
|
74587
|
-
session.process.kill(signal);
|
|
74588
|
-
}
|
|
74589
|
-
return true;
|
|
74590
|
-
}
|
|
74591
|
-
/**
|
|
74592
|
-
* Cleans up a session from memory.
|
|
74593
|
-
*/
|
|
74594
|
-
cleanupSession(sessionId) {
|
|
74595
|
-
const session = this.sessions.get(sessionId);
|
|
74596
|
-
if (!session) return false;
|
|
74597
|
-
if (session.exitCode === null && !session.killed) {
|
|
74598
|
-
this.killSession(sessionId, "SIGKILL");
|
|
74599
|
-
}
|
|
74600
|
-
this.sessions.delete(sessionId);
|
|
74601
|
-
return true;
|
|
74602
|
-
}
|
|
74603
|
-
/**
|
|
74604
|
-
* Lists all active sessions.
|
|
74605
|
-
*/
|
|
74606
|
-
listSessions() {
|
|
74607
|
-
return Array.from(this.sessions.values()).map((s) => ({
|
|
74608
|
-
id: s.id,
|
|
74609
|
-
command: s.command,
|
|
74610
|
-
running: s.exitCode === null && !s.killed,
|
|
74611
|
-
startTime: s.startTime
|
|
74612
|
-
}));
|
|
74613
|
-
}
|
|
74614
|
-
/**
|
|
74615
|
-
* Cleans up all sessions (useful for shutdown).
|
|
74616
|
-
*/
|
|
74617
|
-
cleanupAll() {
|
|
74618
|
-
for (const [sessionId] of this.sessions) {
|
|
74619
|
-
this.cleanupSession(sessionId);
|
|
74620
|
-
}
|
|
74621
|
-
}
|
|
74622
|
-
};
|
|
74623
|
-
terminalSessionManager = new TerminalSessionManager();
|
|
74624
|
-
}
|
|
74625
|
-
});
|
|
74626
|
-
|
|
74627
|
-
// ../dashboard/src/terminal-service.ts
|
|
74628
|
-
import { createRequire as createRequire2 } from "node:module";
|
|
74629
|
-
var isBunBinary, require2;
|
|
74630
|
-
var init_terminal_service = __esm({
|
|
74631
|
-
"../dashboard/src/terminal-service.ts"() {
|
|
76133
|
+
// ../dashboard/src/routes/register-git-github.ts
|
|
76134
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
76135
|
+
import { promisify as promisify11 } from "node:util";
|
|
76136
|
+
var execFileAsync2;
|
|
76137
|
+
var init_register_git_github = __esm({
|
|
76138
|
+
"../dashboard/src/routes/register-git-github.ts"() {
|
|
74632
76139
|
"use strict";
|
|
74633
|
-
|
|
74634
|
-
|
|
76140
|
+
init_src();
|
|
76141
|
+
init_api_error();
|
|
76142
|
+
init_github();
|
|
76143
|
+
init_github_poll();
|
|
76144
|
+
init_github_webhooks();
|
|
76145
|
+
execFileAsync2 = promisify11(execFile4);
|
|
74635
76146
|
}
|
|
74636
76147
|
});
|
|
74637
76148
|
|
|
@@ -74644,6 +76155,52 @@ var init_file_service = __esm({
|
|
|
74644
76155
|
}
|
|
74645
76156
|
});
|
|
74646
76157
|
|
|
76158
|
+
// ../dashboard/src/routes/register-file-workspace-routes.ts
|
|
76159
|
+
var init_register_file_workspace_routes = __esm({
|
|
76160
|
+
"../dashboard/src/routes/register-file-workspace-routes.ts"() {
|
|
76161
|
+
"use strict";
|
|
76162
|
+
init_api_error();
|
|
76163
|
+
init_file_service();
|
|
76164
|
+
}
|
|
76165
|
+
});
|
|
76166
|
+
|
|
76167
|
+
// ../dashboard/src/routes/register-agents-projects-nodes.ts
|
|
76168
|
+
var init_register_agents_projects_nodes = __esm({
|
|
76169
|
+
"../dashboard/src/routes/register-agents-projects-nodes.ts"() {
|
|
76170
|
+
"use strict";
|
|
76171
|
+
}
|
|
76172
|
+
});
|
|
76173
|
+
|
|
76174
|
+
// ../dashboard/src/routes/register-project-routes.ts
|
|
76175
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
76176
|
+
import * as fsPromises from "node:fs/promises";
|
|
76177
|
+
import { promisify as promisify12 } from "node:util";
|
|
76178
|
+
var access3, stat6, mkdir12, readdir8, rm2, execFileAsync3;
|
|
76179
|
+
var init_register_project_routes = __esm({
|
|
76180
|
+
"../dashboard/src/routes/register-project-routes.ts"() {
|
|
76181
|
+
"use strict";
|
|
76182
|
+
init_src();
|
|
76183
|
+
init_api_error();
|
|
76184
|
+
init_project_store_resolver();
|
|
76185
|
+
({
|
|
76186
|
+
access: access3,
|
|
76187
|
+
stat: stat6,
|
|
76188
|
+
mkdir: mkdir12,
|
|
76189
|
+
readdir: readdir8,
|
|
76190
|
+
rm: rm2
|
|
76191
|
+
} = fsPromises);
|
|
76192
|
+
execFileAsync3 = promisify12(execFile5);
|
|
76193
|
+
}
|
|
76194
|
+
});
|
|
76195
|
+
|
|
76196
|
+
// ../dashboard/src/routes/register-node-routes.ts
|
|
76197
|
+
var init_register_node_routes = __esm({
|
|
76198
|
+
"../dashboard/src/routes/register-node-routes.ts"() {
|
|
76199
|
+
"use strict";
|
|
76200
|
+
init_api_error();
|
|
76201
|
+
}
|
|
76202
|
+
});
|
|
76203
|
+
|
|
74647
76204
|
// ../dashboard/src/auth-paths.ts
|
|
74648
76205
|
var init_auth_paths = __esm({
|
|
74649
76206
|
"../dashboard/src/auth-paths.ts"() {
|
|
@@ -74651,138 +76208,72 @@ var init_auth_paths = __esm({
|
|
|
74651
76208
|
}
|
|
74652
76209
|
});
|
|
74653
76210
|
|
|
74654
|
-
// ../dashboard/src/
|
|
74655
|
-
var
|
|
74656
|
-
"../dashboard/src/
|
|
76211
|
+
// ../dashboard/src/routes/register-settings-sync-helpers.ts
|
|
76212
|
+
var init_register_settings_sync_helpers = __esm({
|
|
76213
|
+
"../dashboard/src/routes/register-settings-sync-helpers.ts"() {
|
|
74657
76214
|
"use strict";
|
|
76215
|
+
init_api_error();
|
|
74658
76216
|
init_auth_paths();
|
|
74659
76217
|
}
|
|
74660
76218
|
});
|
|
74661
76219
|
|
|
74662
|
-
// ../dashboard/src/
|
|
74663
|
-
var
|
|
74664
|
-
"../dashboard/src/
|
|
76220
|
+
// ../dashboard/src/routes/register-settings-sync-routes.ts
|
|
76221
|
+
var init_register_settings_sync_routes = __esm({
|
|
76222
|
+
"../dashboard/src/routes/register-settings-sync-routes.ts"() {
|
|
74665
76223
|
"use strict";
|
|
76224
|
+
init_api_error();
|
|
76225
|
+
init_auth_paths();
|
|
76226
|
+
init_register_settings_sync_helpers();
|
|
74666
76227
|
}
|
|
74667
76228
|
});
|
|
74668
76229
|
|
|
74669
|
-
// ../dashboard/src/
|
|
74670
|
-
var
|
|
74671
|
-
"../dashboard/src/
|
|
76230
|
+
// ../dashboard/src/routes/register-mesh-routes.ts
|
|
76231
|
+
var init_register_mesh_routes = __esm({
|
|
76232
|
+
"../dashboard/src/routes/register-mesh-routes.ts"() {
|
|
74672
76233
|
"use strict";
|
|
76234
|
+
init_api_error();
|
|
74673
76235
|
}
|
|
74674
76236
|
});
|
|
74675
76237
|
|
|
74676
|
-
// ../dashboard/src/
|
|
74677
|
-
var
|
|
74678
|
-
|
|
74679
|
-
"../dashboard/src/ai-session-store.ts"() {
|
|
76238
|
+
// ../dashboard/src/routes/register-discovery-routes.ts
|
|
76239
|
+
var init_register_discovery_routes = __esm({
|
|
76240
|
+
"../dashboard/src/routes/register-discovery-routes.ts"() {
|
|
74680
76241
|
"use strict";
|
|
74681
|
-
|
|
74682
|
-
MAX_THINKING_BYTES = 50 * 1024;
|
|
74683
|
-
SESSION_CLEANUP_DEFAULT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
74684
|
-
SESSION_CLEANUP_INTERVAL_MS = 6 * 60 * 60 * 1e3;
|
|
74685
|
-
diagnostics2 = createSessionDiagnostics("ai-session-store");
|
|
76242
|
+
init_api_error();
|
|
74686
76243
|
}
|
|
74687
76244
|
});
|
|
74688
76245
|
|
|
74689
|
-
// ../dashboard/src/
|
|
74690
|
-
|
|
74691
|
-
|
|
74692
|
-
|
|
74693
|
-
|
|
74694
|
-
|
|
76246
|
+
// ../dashboard/src/routes/register-settings-sync-inbound-routes.ts
|
|
76247
|
+
var init_register_settings_sync_inbound_routes = __esm({
|
|
76248
|
+
"../dashboard/src/routes/register-settings-sync-inbound-routes.ts"() {
|
|
76249
|
+
"use strict";
|
|
76250
|
+
init_api_error();
|
|
76251
|
+
init_auth_paths();
|
|
76252
|
+
init_register_settings_sync_helpers();
|
|
74695
76253
|
}
|
|
74696
|
-
|
|
74697
|
-
|
|
74698
|
-
|
|
76254
|
+
});
|
|
76255
|
+
|
|
76256
|
+
// ../dashboard/src/routes/register-agent-core-routes.ts
|
|
76257
|
+
var init_register_agent_core_routes = __esm({
|
|
76258
|
+
"../dashboard/src/routes/register-agent-core-routes.ts"() {
|
|
76259
|
+
"use strict";
|
|
76260
|
+
init_api_error();
|
|
74699
76261
|
}
|
|
74700
|
-
|
|
74701
|
-
|
|
74702
|
-
|
|
74703
|
-
|
|
74704
|
-
|
|
74705
|
-
|
|
74706
|
-
|
|
74707
|
-
if (now - session.updatedAt.getTime() > SESSION_TTL_MS2) {
|
|
74708
|
-
cleanupInMemorySubtaskSession(id);
|
|
74709
|
-
}
|
|
76262
|
+
});
|
|
76263
|
+
|
|
76264
|
+
// ../dashboard/src/routes/register-agent-runtime-routes.ts
|
|
76265
|
+
var init_register_agent_runtime_routes = __esm({
|
|
76266
|
+
"../dashboard/src/routes/register-agent-runtime-routes.ts"() {
|
|
76267
|
+
"use strict";
|
|
76268
|
+
init_api_error();
|
|
74710
76269
|
}
|
|
74711
|
-
}
|
|
74712
|
-
|
|
74713
|
-
|
|
74714
|
-
|
|
76270
|
+
});
|
|
76271
|
+
|
|
76272
|
+
// ../dashboard/src/routes/register-agent-reflection-rating-routes.ts
|
|
76273
|
+
var init_register_agent_reflection_rating_routes = __esm({
|
|
76274
|
+
"../dashboard/src/routes/register-agent-reflection-rating-routes.ts"() {
|
|
74715
76275
|
"use strict";
|
|
74716
|
-
|
|
74717
|
-
init_sse_buffer();
|
|
74718
|
-
init_ai_session_diagnostics();
|
|
74719
|
-
diagnostics3 = createSessionDiagnostics("subtask-breakdown");
|
|
74720
|
-
SESSION_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
|
|
74721
|
-
CLEANUP_INTERVAL_MS3 = 5 * 60 * 1e3;
|
|
74722
|
-
sessions2 = /* @__PURE__ */ new Map();
|
|
74723
|
-
cleanupInterval3 = setInterval(cleanupExpiredSessions2, CLEANUP_INTERVAL_MS3);
|
|
74724
|
-
cleanupInterval3.unref?.();
|
|
74725
|
-
process.on("beforeExit", () => {
|
|
74726
|
-
clearInterval(cleanupInterval3);
|
|
74727
|
-
});
|
|
74728
|
-
SubtaskStreamManager = class extends EventEmitter21 {
|
|
74729
|
-
constructor(bufferSize = 100) {
|
|
74730
|
-
super();
|
|
74731
|
-
this.bufferSize = bufferSize;
|
|
74732
|
-
}
|
|
74733
|
-
sessions = /* @__PURE__ */ new Map();
|
|
74734
|
-
buffers = /* @__PURE__ */ new Map();
|
|
74735
|
-
subscribe(sessionId, callback) {
|
|
74736
|
-
if (!this.sessions.has(sessionId)) {
|
|
74737
|
-
this.sessions.set(sessionId, /* @__PURE__ */ new Set());
|
|
74738
|
-
}
|
|
74739
|
-
const callbacks = this.sessions.get(sessionId);
|
|
74740
|
-
callbacks.add(callback);
|
|
74741
|
-
return () => {
|
|
74742
|
-
callbacks.delete(callback);
|
|
74743
|
-
if (callbacks.size === 0) {
|
|
74744
|
-
this.sessions.delete(sessionId);
|
|
74745
|
-
}
|
|
74746
|
-
};
|
|
74747
|
-
}
|
|
74748
|
-
getBuffer(sessionId) {
|
|
74749
|
-
let buffer = this.buffers.get(sessionId);
|
|
74750
|
-
if (!buffer) {
|
|
74751
|
-
buffer = new SessionEventBuffer(this.bufferSize);
|
|
74752
|
-
this.buffers.set(sessionId, buffer);
|
|
74753
|
-
}
|
|
74754
|
-
return buffer;
|
|
74755
|
-
}
|
|
74756
|
-
broadcast(sessionId, event) {
|
|
74757
|
-
const serialized = JSON.stringify(event.data ?? {});
|
|
74758
|
-
const eventData = typeof serialized === "string" ? serialized : "{}";
|
|
74759
|
-
const eventId = this.getBuffer(sessionId).push(event.type, eventData);
|
|
74760
|
-
const callbacks = this.sessions.get(sessionId);
|
|
74761
|
-
if (!callbacks) return eventId;
|
|
74762
|
-
for (const callback of callbacks) {
|
|
74763
|
-
try {
|
|
74764
|
-
callback(event, eventId);
|
|
74765
|
-
} catch {
|
|
74766
|
-
}
|
|
74767
|
-
}
|
|
74768
|
-
return eventId;
|
|
74769
|
-
}
|
|
74770
|
-
getBufferedEvents(sessionId, sinceId) {
|
|
74771
|
-
const buffer = this.buffers.get(sessionId);
|
|
74772
|
-
if (!buffer) return [];
|
|
74773
|
-
return buffer.getEventsSince(sinceId);
|
|
74774
|
-
}
|
|
74775
|
-
cleanupSession(sessionId) {
|
|
74776
|
-
this.sessions.delete(sessionId);
|
|
74777
|
-
this.buffers.delete(sessionId);
|
|
74778
|
-
}
|
|
74779
|
-
reset() {
|
|
74780
|
-
this.sessions.clear();
|
|
74781
|
-
this.buffers.clear();
|
|
74782
|
-
this.removeAllListeners();
|
|
74783
|
-
}
|
|
74784
|
-
};
|
|
74785
|
-
subtaskStreamManager = new SubtaskStreamManager();
|
|
76276
|
+
init_api_error();
|
|
74786
76277
|
}
|
|
74787
76278
|
});
|
|
74788
76279
|
|
|
@@ -74798,33 +76289,33 @@ async function initPromptCatalog() {
|
|
|
74798
76289
|
promptCatalogReady = true;
|
|
74799
76290
|
}
|
|
74800
76291
|
}
|
|
74801
|
-
function
|
|
76292
|
+
function cleanupExpiredSessions5() {
|
|
74802
76293
|
const now = Date.now();
|
|
74803
76294
|
let cleanedSessions = 0;
|
|
74804
76295
|
let cleanedRateLimits = 0;
|
|
74805
|
-
for (const [id, session] of
|
|
74806
|
-
if (now - session.updatedAt.getTime() >
|
|
74807
|
-
|
|
76296
|
+
for (const [id, session] of sessions5) {
|
|
76297
|
+
if (now - session.updatedAt.getTime() > SESSION_TTL_MS5) {
|
|
76298
|
+
sessions5.delete(id);
|
|
74808
76299
|
cleanedSessions++;
|
|
74809
76300
|
}
|
|
74810
76301
|
}
|
|
74811
|
-
for (const [ip, entry] of
|
|
74812
|
-
if (now - entry.firstRequestAt.getTime() >
|
|
74813
|
-
|
|
76302
|
+
for (const [ip, entry] of rateLimits5) {
|
|
76303
|
+
if (now - entry.firstRequestAt.getTime() > RATE_LIMIT_WINDOW_MS5) {
|
|
76304
|
+
rateLimits5.delete(ip);
|
|
74814
76305
|
cleanedRateLimits++;
|
|
74815
76306
|
}
|
|
74816
76307
|
}
|
|
74817
76308
|
if (cleanedSessions > 0 || cleanedRateLimits > 0) {
|
|
74818
|
-
|
|
76309
|
+
diagnostics6.info("Cleanup completed", {
|
|
74819
76310
|
cleanedSessions,
|
|
74820
76311
|
cleanedRateLimits,
|
|
74821
|
-
ttlMs:
|
|
74822
|
-
rateLimitWindowMs:
|
|
76312
|
+
ttlMs: SESSION_TTL_MS5,
|
|
76313
|
+
rateLimitWindowMs: RATE_LIMIT_WINDOW_MS5,
|
|
74823
76314
|
operation: "cleanup-expired"
|
|
74824
76315
|
});
|
|
74825
76316
|
}
|
|
74826
76317
|
}
|
|
74827
|
-
var resolvePrompt2, promptCatalogReady, promptCatalogReadyPromise,
|
|
76318
|
+
var resolvePrompt2, promptCatalogReady, promptCatalogReadyPromise, SESSION_TTL_MS5, CLEANUP_INTERVAL_MS6, RATE_LIMIT_WINDOW_MS5, sessions5, rateLimits5, diagnostics6, cleanupInterval6;
|
|
74828
76319
|
var init_agent_generation = __esm({
|
|
74829
76320
|
"../dashboard/src/agent-generation.ts"() {
|
|
74830
76321
|
"use strict";
|
|
@@ -74832,357 +76323,97 @@ var init_agent_generation = __esm({
|
|
|
74832
76323
|
resolvePrompt2 = () => "";
|
|
74833
76324
|
promptCatalogReady = false;
|
|
74834
76325
|
promptCatalogReadyPromise = initPromptCatalog();
|
|
74835
|
-
|
|
74836
|
-
CLEANUP_INTERVAL_MS4 = 5 * 60 * 1e3;
|
|
74837
|
-
RATE_LIMIT_WINDOW_MS3 = 60 * 60 * 1e3;
|
|
74838
|
-
sessions3 = /* @__PURE__ */ new Map();
|
|
74839
|
-
rateLimits3 = /* @__PURE__ */ new Map();
|
|
74840
|
-
diagnostics4 = createSessionDiagnostics("agent-generation");
|
|
74841
|
-
cleanupInterval4 = setInterval(cleanupExpiredSessions3, CLEANUP_INTERVAL_MS4);
|
|
74842
|
-
cleanupInterval4.unref?.();
|
|
74843
|
-
process.on("beforeExit", () => {
|
|
74844
|
-
clearInterval(cleanupInterval4);
|
|
74845
|
-
});
|
|
74846
|
-
}
|
|
74847
|
-
});
|
|
74848
|
-
|
|
74849
|
-
// ../dashboard/src/mission-interview.ts
|
|
74850
|
-
import { EventEmitter as EventEmitter22 } from "node:events";
|
|
74851
|
-
function cleanupInMemoryMissionSession(sessionId) {
|
|
74852
|
-
const session = sessions4.get(sessionId);
|
|
74853
|
-
if (!session) {
|
|
74854
|
-
return false;
|
|
74855
|
-
}
|
|
74856
|
-
if (session.agent) {
|
|
74857
|
-
try {
|
|
74858
|
-
session.agent.session.dispose?.();
|
|
74859
|
-
} catch {
|
|
74860
|
-
}
|
|
74861
|
-
session.agent = void 0;
|
|
74862
|
-
}
|
|
74863
|
-
missionInterviewStreamManager.cleanupSession(sessionId);
|
|
74864
|
-
sessions4.delete(sessionId);
|
|
74865
|
-
return true;
|
|
74866
|
-
}
|
|
74867
|
-
function cleanupExpiredSessions4() {
|
|
74868
|
-
const now = Date.now();
|
|
74869
|
-
for (const [id, session] of sessions4) {
|
|
74870
|
-
if (now - session.updatedAt.getTime() > SESSION_TTL_MS4) {
|
|
74871
|
-
cleanupInMemoryMissionSession(id);
|
|
74872
|
-
}
|
|
74873
|
-
}
|
|
74874
|
-
for (const [ip, entry] of rateLimits4) {
|
|
74875
|
-
if (now - entry.firstRequestAt.getTime() > RATE_LIMIT_WINDOW_MS4) {
|
|
74876
|
-
rateLimits4.delete(ip);
|
|
74877
|
-
}
|
|
74878
|
-
}
|
|
74879
|
-
}
|
|
74880
|
-
var diagnostics5, SESSION_TTL_MS4, CLEANUP_INTERVAL_MS5, RATE_LIMIT_WINDOW_MS4, sessions4, rateLimits4, cleanupInterval5, MissionInterviewStreamManager, missionInterviewStreamManager;
|
|
74881
|
-
var init_mission_interview = __esm({
|
|
74882
|
-
"../dashboard/src/mission-interview.ts"() {
|
|
74883
|
-
"use strict";
|
|
74884
|
-
init_src();
|
|
74885
|
-
init_sse_buffer();
|
|
74886
|
-
init_ai_session_diagnostics();
|
|
74887
|
-
diagnostics5 = createSessionDiagnostics("mission-interview");
|
|
74888
|
-
SESSION_TTL_MS4 = 7 * 24 * 60 * 60 * 1e3;
|
|
74889
|
-
CLEANUP_INTERVAL_MS5 = 5 * 60 * 1e3;
|
|
74890
|
-
RATE_LIMIT_WINDOW_MS4 = 60 * 60 * 1e3;
|
|
74891
|
-
sessions4 = /* @__PURE__ */ new Map();
|
|
74892
|
-
rateLimits4 = /* @__PURE__ */ new Map();
|
|
74893
|
-
cleanupInterval5 = setInterval(cleanupExpiredSessions4, CLEANUP_INTERVAL_MS5);
|
|
74894
|
-
cleanupInterval5.unref?.();
|
|
74895
|
-
process.on("beforeExit", () => clearInterval(cleanupInterval5));
|
|
74896
|
-
MissionInterviewStreamManager = class extends EventEmitter22 {
|
|
74897
|
-
constructor(bufferSize = 100) {
|
|
74898
|
-
super();
|
|
74899
|
-
this.bufferSize = bufferSize;
|
|
74900
|
-
}
|
|
74901
|
-
sessions = /* @__PURE__ */ new Map();
|
|
74902
|
-
buffers = /* @__PURE__ */ new Map();
|
|
74903
|
-
subscribe(sessionId, callback) {
|
|
74904
|
-
if (!this.sessions.has(sessionId)) {
|
|
74905
|
-
this.sessions.set(sessionId, /* @__PURE__ */ new Set());
|
|
74906
|
-
}
|
|
74907
|
-
const callbacks = this.sessions.get(sessionId);
|
|
74908
|
-
callbacks.add(callback);
|
|
74909
|
-
return () => {
|
|
74910
|
-
callbacks.delete(callback);
|
|
74911
|
-
if (callbacks.size === 0) {
|
|
74912
|
-
this.sessions.delete(sessionId);
|
|
74913
|
-
}
|
|
74914
|
-
};
|
|
74915
|
-
}
|
|
74916
|
-
getBuffer(sessionId) {
|
|
74917
|
-
let buffer = this.buffers.get(sessionId);
|
|
74918
|
-
if (!buffer) {
|
|
74919
|
-
buffer = new SessionEventBuffer(this.bufferSize);
|
|
74920
|
-
this.buffers.set(sessionId, buffer);
|
|
74921
|
-
}
|
|
74922
|
-
return buffer;
|
|
74923
|
-
}
|
|
74924
|
-
broadcast(sessionId, event) {
|
|
74925
|
-
const serialized = JSON.stringify(event.data ?? {});
|
|
74926
|
-
const eventData = typeof serialized === "string" ? serialized : "{}";
|
|
74927
|
-
const eventId = this.getBuffer(sessionId).push(event.type, eventData);
|
|
74928
|
-
const callbacks = this.sessions.get(sessionId);
|
|
74929
|
-
if (!callbacks) return eventId;
|
|
74930
|
-
for (const callback of callbacks) {
|
|
74931
|
-
nonfatal(
|
|
74932
|
-
() => callback(event, eventId),
|
|
74933
|
-
diagnostics5,
|
|
74934
|
-
"Error broadcasting to client",
|
|
74935
|
-
{ sessionId, operation: "broadcast" }
|
|
74936
|
-
);
|
|
74937
|
-
}
|
|
74938
|
-
return eventId;
|
|
74939
|
-
}
|
|
74940
|
-
getBufferedEvents(sessionId, sinceId) {
|
|
74941
|
-
const buffer = this.buffers.get(sessionId);
|
|
74942
|
-
if (!buffer) return [];
|
|
74943
|
-
return buffer.getEventsSince(sinceId);
|
|
74944
|
-
}
|
|
74945
|
-
hasSubscribers(sessionId) {
|
|
74946
|
-
const callbacks = this.sessions.get(sessionId);
|
|
74947
|
-
return callbacks !== void 0 && callbacks.size > 0;
|
|
74948
|
-
}
|
|
74949
|
-
cleanupSession(sessionId) {
|
|
74950
|
-
this.sessions.delete(sessionId);
|
|
74951
|
-
this.buffers.delete(sessionId);
|
|
74952
|
-
}
|
|
74953
|
-
reset() {
|
|
74954
|
-
this.sessions.clear();
|
|
74955
|
-
this.buffers.clear();
|
|
74956
|
-
this.removeAllListeners();
|
|
74957
|
-
}
|
|
74958
|
-
};
|
|
74959
|
-
missionInterviewStreamManager = new MissionInterviewStreamManager();
|
|
74960
|
-
}
|
|
74961
|
-
});
|
|
74962
|
-
|
|
74963
|
-
// ../dashboard/src/milestone-slice-interview.ts
|
|
74964
|
-
import { EventEmitter as EventEmitter23 } from "node:events";
|
|
74965
|
-
function cleanupInMemorySession2(sessionId) {
|
|
74966
|
-
const session = sessions5.get(sessionId);
|
|
74967
|
-
if (!session) {
|
|
74968
|
-
return false;
|
|
74969
|
-
}
|
|
74970
|
-
if (session.agent) {
|
|
74971
|
-
try {
|
|
74972
|
-
session.agent.session.dispose?.();
|
|
74973
|
-
} catch {
|
|
74974
|
-
}
|
|
74975
|
-
session.agent = void 0;
|
|
74976
|
-
}
|
|
74977
|
-
milestoneSliceInterviewStreamManager.cleanupSession(sessionId);
|
|
74978
|
-
sessions5.delete(sessionId);
|
|
74979
|
-
return true;
|
|
74980
|
-
}
|
|
74981
|
-
function cleanupExpiredSessions5() {
|
|
74982
|
-
const now = Date.now();
|
|
74983
|
-
for (const [id, session] of sessions5) {
|
|
74984
|
-
if (now - session.updatedAt.getTime() > SESSION_TTL_MS5) {
|
|
74985
|
-
cleanupInMemorySession2(id);
|
|
74986
|
-
}
|
|
74987
|
-
}
|
|
74988
|
-
for (const [ip, entry] of rateLimits5) {
|
|
74989
|
-
if (now - entry.firstRequestAt.getTime() > RATE_LIMIT_WINDOW_MS5) {
|
|
74990
|
-
rateLimits5.delete(ip);
|
|
74991
|
-
}
|
|
74992
|
-
}
|
|
74993
|
-
}
|
|
74994
|
-
var diagnostics6, SESSION_TTL_MS5, CLEANUP_INTERVAL_MS6, RATE_LIMIT_WINDOW_MS5, sessions5, rateLimits5, cleanupInterval6, MilestoneSliceInterviewStreamManager, milestoneSliceInterviewStreamManager;
|
|
74995
|
-
var init_milestone_slice_interview = __esm({
|
|
74996
|
-
"../dashboard/src/milestone-slice-interview.ts"() {
|
|
74997
|
-
"use strict";
|
|
74998
|
-
init_sse_buffer();
|
|
74999
|
-
init_mission_interview();
|
|
75000
|
-
init_ai_session_diagnostics();
|
|
75001
|
-
init_mission_interview();
|
|
75002
|
-
diagnostics6 = createSessionDiagnostics("milestone-slice-interview");
|
|
75003
|
-
SESSION_TTL_MS5 = 7 * 24 * 60 * 60 * 1e3;
|
|
76326
|
+
SESSION_TTL_MS5 = 30 * 60 * 1e3;
|
|
75004
76327
|
CLEANUP_INTERVAL_MS6 = 5 * 60 * 1e3;
|
|
75005
76328
|
RATE_LIMIT_WINDOW_MS5 = 60 * 60 * 1e3;
|
|
75006
76329
|
sessions5 = /* @__PURE__ */ new Map();
|
|
75007
76330
|
rateLimits5 = /* @__PURE__ */ new Map();
|
|
76331
|
+
diagnostics6 = createSessionDiagnostics("agent-generation");
|
|
75008
76332
|
cleanupInterval6 = setInterval(cleanupExpiredSessions5, CLEANUP_INTERVAL_MS6);
|
|
75009
76333
|
cleanupInterval6.unref?.();
|
|
75010
|
-
process.on("beforeExit", () =>
|
|
75011
|
-
|
|
75012
|
-
|
|
75013
|
-
super();
|
|
75014
|
-
this.bufferSize = bufferSize;
|
|
75015
|
-
}
|
|
75016
|
-
sessions = /* @__PURE__ */ new Map();
|
|
75017
|
-
buffers = /* @__PURE__ */ new Map();
|
|
75018
|
-
subscribe(sessionId, callback) {
|
|
75019
|
-
if (!this.sessions.has(sessionId)) {
|
|
75020
|
-
this.sessions.set(sessionId, /* @__PURE__ */ new Set());
|
|
75021
|
-
}
|
|
75022
|
-
const callbacks = this.sessions.get(sessionId);
|
|
75023
|
-
callbacks.add(callback);
|
|
75024
|
-
return () => {
|
|
75025
|
-
callbacks.delete(callback);
|
|
75026
|
-
if (callbacks.size === 0) {
|
|
75027
|
-
this.sessions.delete(sessionId);
|
|
75028
|
-
}
|
|
75029
|
-
};
|
|
75030
|
-
}
|
|
75031
|
-
getBuffer(sessionId) {
|
|
75032
|
-
let buffer = this.buffers.get(sessionId);
|
|
75033
|
-
if (!buffer) {
|
|
75034
|
-
buffer = new SessionEventBuffer(this.bufferSize);
|
|
75035
|
-
this.buffers.set(sessionId, buffer);
|
|
75036
|
-
}
|
|
75037
|
-
return buffer;
|
|
75038
|
-
}
|
|
75039
|
-
broadcast(sessionId, event) {
|
|
75040
|
-
const serialized = JSON.stringify(event.data ?? {});
|
|
75041
|
-
const eventData = typeof serialized === "string" ? serialized : "{}";
|
|
75042
|
-
const eventId = this.getBuffer(sessionId).push(event.type, eventData);
|
|
75043
|
-
const callbacks = this.sessions.get(sessionId);
|
|
75044
|
-
if (!callbacks) return eventId;
|
|
75045
|
-
for (const callback of callbacks) {
|
|
75046
|
-
nonfatal(
|
|
75047
|
-
() => callback(event, eventId),
|
|
75048
|
-
diagnostics6,
|
|
75049
|
-
"Error broadcasting to client",
|
|
75050
|
-
{ sessionId, operation: "broadcast" }
|
|
75051
|
-
);
|
|
75052
|
-
}
|
|
75053
|
-
return eventId;
|
|
75054
|
-
}
|
|
75055
|
-
getBufferedEvents(sessionId, sinceId) {
|
|
75056
|
-
const buffer = this.buffers.get(sessionId);
|
|
75057
|
-
if (!buffer) return [];
|
|
75058
|
-
return buffer.getEventsSince(sinceId);
|
|
75059
|
-
}
|
|
75060
|
-
hasSubscribers(sessionId) {
|
|
75061
|
-
const callbacks = this.sessions.get(sessionId);
|
|
75062
|
-
return callbacks !== void 0 && callbacks.size > 0;
|
|
75063
|
-
}
|
|
75064
|
-
cleanupSession(sessionId) {
|
|
75065
|
-
this.sessions.delete(sessionId);
|
|
75066
|
-
this.buffers.delete(sessionId);
|
|
75067
|
-
}
|
|
75068
|
-
reset() {
|
|
75069
|
-
this.sessions.clear();
|
|
75070
|
-
this.buffers.clear();
|
|
75071
|
-
this.removeAllListeners();
|
|
75072
|
-
}
|
|
75073
|
-
};
|
|
75074
|
-
milestoneSliceInterviewStreamManager = new MilestoneSliceInterviewStreamManager();
|
|
75075
|
-
}
|
|
75076
|
-
});
|
|
75077
|
-
|
|
75078
|
-
// ../dashboard/src/runtime-logger.ts
|
|
75079
|
-
var init_runtime_logger = __esm({
|
|
75080
|
-
"../dashboard/src/runtime-logger.ts"() {
|
|
75081
|
-
"use strict";
|
|
75082
|
-
}
|
|
75083
|
-
});
|
|
75084
|
-
|
|
75085
|
-
// ../dashboard/src/api-error.ts
|
|
75086
|
-
var init_api_error = __esm({
|
|
75087
|
-
"../dashboard/src/api-error.ts"() {
|
|
75088
|
-
"use strict";
|
|
75089
|
-
init_runtime_logger();
|
|
75090
|
-
}
|
|
75091
|
-
});
|
|
75092
|
-
|
|
75093
|
-
// ../dashboard/src/rate-limit.ts
|
|
75094
|
-
var init_rate_limit = __esm({
|
|
75095
|
-
"../dashboard/src/rate-limit.ts"() {
|
|
75096
|
-
"use strict";
|
|
75097
|
-
init_api_error();
|
|
76334
|
+
process.on("beforeExit", () => {
|
|
76335
|
+
clearInterval(cleanupInterval6);
|
|
76336
|
+
});
|
|
75098
76337
|
}
|
|
75099
76338
|
});
|
|
75100
76339
|
|
|
75101
|
-
// ../dashboard/src/
|
|
75102
|
-
import
|
|
75103
|
-
var
|
|
75104
|
-
|
|
76340
|
+
// ../dashboard/src/routes/register-agent-import-export-generation-routes.ts
|
|
76341
|
+
import * as fsPromises2 from "node:fs/promises";
|
|
76342
|
+
var mkdtemp, access4, stat7, mkdir13, rm3, fsWriteFile;
|
|
76343
|
+
var init_register_agent_import_export_generation_routes = __esm({
|
|
76344
|
+
"../dashboard/src/routes/register-agent-import-export-generation-routes.ts"() {
|
|
75105
76345
|
"use strict";
|
|
75106
|
-
init_src();
|
|
75107
76346
|
init_api_error();
|
|
76347
|
+
init_ai_session_diagnostics();
|
|
76348
|
+
init_agent_generation();
|
|
76349
|
+
({ mkdtemp, access: access4, stat: stat7, mkdir: mkdir13, rm: rm3, writeFile: fsWriteFile } = fsPromises2);
|
|
75108
76350
|
}
|
|
75109
76351
|
});
|
|
75110
76352
|
|
|
75111
|
-
// ../dashboard/src/routes/
|
|
75112
|
-
|
|
75113
|
-
|
|
75114
|
-
"../dashboard/src/routes/context.ts"() {
|
|
76353
|
+
// ../dashboard/src/routes/register-agent-skills-routes.ts
|
|
76354
|
+
var init_register_agent_skills_routes = __esm({
|
|
76355
|
+
"../dashboard/src/routes/register-agent-skills-routes.ts"() {
|
|
75115
76356
|
"use strict";
|
|
75116
76357
|
init_api_error();
|
|
75117
|
-
init_project_store_resolver();
|
|
75118
|
-
init_runtime_logger();
|
|
75119
|
-
}
|
|
75120
|
-
});
|
|
75121
|
-
|
|
75122
|
-
// ../dashboard/src/routes/register-tasks.ts
|
|
75123
|
-
var init_register_tasks = __esm({
|
|
75124
|
-
"../dashboard/src/routes/register-tasks.ts"() {
|
|
75125
|
-
"use strict";
|
|
75126
|
-
}
|
|
75127
|
-
});
|
|
75128
|
-
|
|
75129
|
-
// ../dashboard/src/routes/register-planning-chat.ts
|
|
75130
|
-
var init_register_planning_chat = __esm({
|
|
75131
|
-
"../dashboard/src/routes/register-planning-chat.ts"() {
|
|
75132
|
-
"use strict";
|
|
75133
76358
|
}
|
|
75134
76359
|
});
|
|
75135
76360
|
|
|
75136
|
-
// ../dashboard/src/routes/register-
|
|
75137
|
-
var
|
|
75138
|
-
"../dashboard/src/routes/register-
|
|
76361
|
+
// ../dashboard/src/routes/register-plugins-automation.ts
|
|
76362
|
+
var init_register_plugins_automation = __esm({
|
|
76363
|
+
"../dashboard/src/routes/register-plugins-automation.ts"() {
|
|
75139
76364
|
"use strict";
|
|
75140
76365
|
}
|
|
75141
76366
|
});
|
|
75142
76367
|
|
|
75143
|
-
// ../dashboard/src/routes/register-
|
|
75144
|
-
var
|
|
75145
|
-
"../dashboard/src/routes/register-
|
|
76368
|
+
// ../dashboard/src/routes/register-proxy.ts
|
|
76369
|
+
var init_register_proxy = __esm({
|
|
76370
|
+
"../dashboard/src/routes/register-proxy.ts"() {
|
|
75146
76371
|
"use strict";
|
|
75147
|
-
init_src();
|
|
75148
76372
|
init_api_error();
|
|
75149
|
-
init_terminal_service();
|
|
75150
76373
|
}
|
|
75151
76374
|
});
|
|
75152
76375
|
|
|
75153
|
-
// ../dashboard/src/routes/register-
|
|
75154
|
-
var
|
|
75155
|
-
"../dashboard/src/routes/register-
|
|
76376
|
+
// ../dashboard/src/routes/register-model-routes.ts
|
|
76377
|
+
var init_register_model_routes = __esm({
|
|
76378
|
+
"../dashboard/src/routes/register-model-routes.ts"() {
|
|
75156
76379
|
"use strict";
|
|
76380
|
+
init_api_error();
|
|
75157
76381
|
}
|
|
75158
76382
|
});
|
|
75159
76383
|
|
|
75160
|
-
// ../dashboard/src/
|
|
75161
|
-
var
|
|
75162
|
-
"../dashboard/src/
|
|
76384
|
+
// ../dashboard/src/usage.ts
|
|
76385
|
+
var init_usage = __esm({
|
|
76386
|
+
"../dashboard/src/usage.ts"() {
|
|
75163
76387
|
"use strict";
|
|
76388
|
+
init_auth_paths();
|
|
75164
76389
|
}
|
|
75165
76390
|
});
|
|
75166
76391
|
|
|
75167
|
-
// ../dashboard/src/routes/register-
|
|
75168
|
-
var
|
|
75169
|
-
"../dashboard/src/routes/register-
|
|
76392
|
+
// ../dashboard/src/routes/register-usage-routes.ts
|
|
76393
|
+
var init_register_usage_routes = __esm({
|
|
76394
|
+
"../dashboard/src/routes/register-usage-routes.ts"() {
|
|
75170
76395
|
"use strict";
|
|
76396
|
+
init_api_error();
|
|
76397
|
+
init_usage();
|
|
75171
76398
|
}
|
|
75172
76399
|
});
|
|
75173
76400
|
|
|
75174
|
-
// ../dashboard/src/
|
|
75175
|
-
var
|
|
75176
|
-
"../dashboard/src/
|
|
76401
|
+
// ../dashboard/src/claude-cli-probe.ts
|
|
76402
|
+
var init_claude_cli_probe = __esm({
|
|
76403
|
+
"../dashboard/src/claude-cli-probe.ts"() {
|
|
75177
76404
|
"use strict";
|
|
75178
76405
|
}
|
|
75179
76406
|
});
|
|
75180
76407
|
|
|
75181
|
-
// ../dashboard/src/routes/register-
|
|
75182
|
-
var
|
|
75183
|
-
"../dashboard/src/routes/register-
|
|
76408
|
+
// ../dashboard/src/routes/register-auth-routes.ts
|
|
76409
|
+
var init_register_auth_routes = __esm({
|
|
76410
|
+
"../dashboard/src/routes/register-auth-routes.ts"() {
|
|
75184
76411
|
"use strict";
|
|
76412
|
+
init_src();
|
|
76413
|
+
init_claude_cli_probe();
|
|
75185
76414
|
init_api_error();
|
|
76415
|
+
init_usage();
|
|
76416
|
+
init_project_store_resolver();
|
|
75186
76417
|
}
|
|
75187
76418
|
});
|
|
75188
76419
|
|
|
@@ -75282,9 +76513,6 @@ var init_register_integrated_routers = __esm({
|
|
|
75282
76513
|
|
|
75283
76514
|
// ../dashboard/src/routes.ts
|
|
75284
76515
|
import multer from "multer";
|
|
75285
|
-
import * as fsPromises from "node:fs/promises";
|
|
75286
|
-
import { execFile as execFile3 } from "node:child_process";
|
|
75287
|
-
import { promisify as promisify10 } from "node:util";
|
|
75288
76516
|
async function initPromptOverrides() {
|
|
75289
76517
|
if (promptOverridesReady) return;
|
|
75290
76518
|
try {
|
|
@@ -75296,60 +76524,55 @@ async function initPromptOverrides() {
|
|
|
75296
76524
|
promptOverridesReady = true;
|
|
75297
76525
|
}
|
|
75298
76526
|
}
|
|
75299
|
-
var
|
|
76527
|
+
var upload, resolveWorkflowStepRefinePrompt, promptOverridesReady, DEFAULT_WORKFLOW_STEP_REFINE_PROMPT;
|
|
75300
76528
|
var init_routes = __esm({
|
|
75301
76529
|
"../dashboard/src/routes.ts"() {
|
|
75302
76530
|
"use strict";
|
|
75303
76531
|
init_src();
|
|
75304
|
-
init_claude_cli_probe();
|
|
75305
|
-
init_github();
|
|
75306
|
-
init_github_poll();
|
|
75307
76532
|
init_terminal();
|
|
75308
76533
|
init_terminal_service();
|
|
75309
|
-
init_file_service();
|
|
75310
|
-
init_usage();
|
|
75311
76534
|
init_github_webhooks();
|
|
75312
|
-
init_project_store_resolver();
|
|
75313
76535
|
init_ai_session_store();
|
|
75314
76536
|
init_planning();
|
|
75315
76537
|
init_subtask_breakdown();
|
|
75316
|
-
init_agent_generation();
|
|
75317
76538
|
init_mission_interview();
|
|
75318
76539
|
init_milestone_slice_interview();
|
|
75319
76540
|
init_sse_buffer();
|
|
75320
76541
|
init_api_error();
|
|
75321
|
-
init_rate_limit();
|
|
75322
76542
|
init_plugin_routes();
|
|
75323
|
-
init_auth_paths();
|
|
75324
|
-
init_runtime_logger();
|
|
75325
76543
|
init_ai_session_diagnostics();
|
|
75326
76544
|
init_context();
|
|
75327
|
-
|
|
75328
|
-
|
|
75329
|
-
|
|
76545
|
+
init_register_task_workflow_routes();
|
|
76546
|
+
init_register_planning_subtask_routes();
|
|
76547
|
+
init_register_chat_routes();
|
|
76548
|
+
init_register_settings_memory_routes();
|
|
75330
76549
|
init_register_messaging_scripts();
|
|
75331
76550
|
init_register_git_github();
|
|
75332
|
-
|
|
76551
|
+
init_register_file_workspace_routes();
|
|
75333
76552
|
init_register_agents_projects_nodes();
|
|
76553
|
+
init_register_project_routes();
|
|
76554
|
+
init_register_node_routes();
|
|
76555
|
+
init_register_settings_sync_routes();
|
|
76556
|
+
init_register_mesh_routes();
|
|
76557
|
+
init_register_discovery_routes();
|
|
76558
|
+
init_register_settings_sync_inbound_routes();
|
|
76559
|
+
init_register_agent_core_routes();
|
|
76560
|
+
init_register_agent_runtime_routes();
|
|
76561
|
+
init_register_agent_reflection_rating_routes();
|
|
76562
|
+
init_register_agent_import_export_generation_routes();
|
|
76563
|
+
init_register_agent_skills_routes();
|
|
75334
76564
|
init_register_plugins_automation();
|
|
75335
76565
|
init_register_proxy();
|
|
76566
|
+
init_register_model_routes();
|
|
76567
|
+
init_register_usage_routes();
|
|
76568
|
+
init_register_auth_routes();
|
|
75336
76569
|
init_register_integrated_routers();
|
|
75337
|
-
(
|
|
75338
|
-
mkdtemp,
|
|
75339
|
-
access: access3,
|
|
75340
|
-
stat: stat6,
|
|
75341
|
-
mkdir: mkdir12,
|
|
75342
|
-
readdir: readdir8,
|
|
75343
|
-
rm: rm2,
|
|
75344
|
-
readFile: fsReadFile,
|
|
75345
|
-
writeFile: fsWriteFile
|
|
75346
|
-
} = fsPromises);
|
|
76570
|
+
init_register_git_github();
|
|
75347
76571
|
upload = multer({
|
|
75348
76572
|
storage: multer.memoryStorage(),
|
|
75349
76573
|
limits: { fileSize: 5 * 1024 * 1024 }
|
|
75350
76574
|
// 5MB
|
|
75351
76575
|
});
|
|
75352
|
-
execFileAsync = promisify10(execFile3);
|
|
75353
76576
|
resolveWorkflowStepRefinePrompt = () => DEFAULT_WORKFLOW_STEP_REFINE_PROMPT;
|
|
75354
76577
|
promptOverridesReady = false;
|
|
75355
76578
|
initPromptOverrides();
|
|
@@ -77577,7 +78800,7 @@ var require_extension = __commonJS({
|
|
|
77577
78800
|
var require_websocket = __commonJS({
|
|
77578
78801
|
"../../node_modules/.pnpm/ws@8.20.0/node_modules/ws/lib/websocket.js"(exports, module) {
|
|
77579
78802
|
"use strict";
|
|
77580
|
-
var
|
|
78803
|
+
var EventEmitter26 = __require("events");
|
|
77581
78804
|
var https = __require("https");
|
|
77582
78805
|
var http = __require("http");
|
|
77583
78806
|
var net = __require("net");
|
|
@@ -77609,7 +78832,7 @@ var require_websocket = __commonJS({
|
|
|
77609
78832
|
var protocolVersions = [8, 13];
|
|
77610
78833
|
var readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"];
|
|
77611
78834
|
var subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
|
|
77612
|
-
var WebSocket2 = class _WebSocket extends
|
|
78835
|
+
var WebSocket2 = class _WebSocket extends EventEmitter26 {
|
|
77613
78836
|
/**
|
|
77614
78837
|
* Create a new `WebSocket`.
|
|
77615
78838
|
*
|
|
@@ -78606,7 +79829,7 @@ var require_subprotocol = __commonJS({
|
|
|
78606
79829
|
var require_websocket_server = __commonJS({
|
|
78607
79830
|
"../../node_modules/.pnpm/ws@8.20.0/node_modules/ws/lib/websocket-server.js"(exports, module) {
|
|
78608
79831
|
"use strict";
|
|
78609
|
-
var
|
|
79832
|
+
var EventEmitter26 = __require("events");
|
|
78610
79833
|
var http = __require("http");
|
|
78611
79834
|
var { Duplex } = __require("stream");
|
|
78612
79835
|
var { createHash: createHash5 } = __require("crypto");
|
|
@@ -78619,7 +79842,7 @@ var require_websocket_server = __commonJS({
|
|
|
78619
79842
|
var RUNNING = 0;
|
|
78620
79843
|
var CLOSING = 1;
|
|
78621
79844
|
var CLOSED = 2;
|
|
78622
|
-
var WebSocketServer2 = class extends
|
|
79845
|
+
var WebSocketServer2 = class extends EventEmitter26 {
|
|
78623
79846
|
/**
|
|
78624
79847
|
* Create a `WebSocketServer` instance.
|
|
78625
79848
|
*
|
|
@@ -79035,7 +80258,7 @@ var init_terminal_websocket_diagnostics = __esm({
|
|
|
79035
80258
|
});
|
|
79036
80259
|
|
|
79037
80260
|
// ../dashboard/src/chat.ts
|
|
79038
|
-
import { EventEmitter as
|
|
80261
|
+
import { EventEmitter as EventEmitter25 } from "node:events";
|
|
79039
80262
|
var defaultDiagnostics, _diagnostics, diagnostics7, RATE_LIMIT_WINDOW_MS6, MAX_REFERENCED_FILE_SIZE, ChatStreamManager, chatStreamManager;
|
|
79040
80263
|
var init_chat = __esm({
|
|
79041
80264
|
"../dashboard/src/chat.ts"() {
|
|
@@ -79067,7 +80290,7 @@ var init_chat = __esm({
|
|
|
79067
80290
|
};
|
|
79068
80291
|
RATE_LIMIT_WINDOW_MS6 = 60 * 1e3;
|
|
79069
80292
|
MAX_REFERENCED_FILE_SIZE = 50 * 1024;
|
|
79070
|
-
ChatStreamManager = class extends
|
|
80293
|
+
ChatStreamManager = class extends EventEmitter25 {
|
|
79071
80294
|
constructor(bufferSize = 100) {
|
|
79072
80295
|
super();
|
|
79073
80296
|
this.bufferSize = bufferSize;
|
|
@@ -79202,6 +80425,7 @@ var init_server = __esm({
|
|
|
79202
80425
|
init_chat();
|
|
79203
80426
|
init_dev_server_routes();
|
|
79204
80427
|
init_auth_middleware();
|
|
80428
|
+
init_remote_auth();
|
|
79205
80429
|
__dirname = dirname8(fileURLToPath2(import.meta.url));
|
|
79206
80430
|
MIN_AI_SESSION_TTL_MS = 10 * 60 * 1e3;
|
|
79207
80431
|
MAX_AI_SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -80617,7 +81841,7 @@ __export(skills_exports, {
|
|
|
80617
81841
|
runSkillsSearch: () => runSkillsSearch,
|
|
80618
81842
|
searchSkills: () => searchSkills
|
|
80619
81843
|
});
|
|
80620
|
-
import { spawn as
|
|
81844
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
80621
81845
|
async function searchSkills(query, limit = 10) {
|
|
80622
81846
|
const url = `${SKILLS_API_BASE}/api/search?q=${encodeURIComponent(query)}&limit=${limit}`;
|
|
80623
81847
|
try {
|
|
@@ -80695,7 +81919,7 @@ async function runSkillsInstall(args, options) {
|
|
|
80695
81919
|
npxArgs.push("--skill", options.skill);
|
|
80696
81920
|
}
|
|
80697
81921
|
npxArgs.push("-y", "-a", "pi");
|
|
80698
|
-
const child =
|
|
81922
|
+
const child = spawn4("npx", npxArgs, {
|
|
80699
81923
|
cwd: process.cwd(),
|
|
80700
81924
|
stdio: "inherit"
|
|
80701
81925
|
});
|
|
@@ -80731,7 +81955,7 @@ import { StringEnum } from "@mariozechner/pi-ai";
|
|
|
80731
81955
|
import { resolve as resolve15, basename as basename8, extname as extname2, join as join36 } from "node:path";
|
|
80732
81956
|
import { readFile as readFile18 } from "node:fs/promises";
|
|
80733
81957
|
import { existsSync as existsSync30 } from "node:fs";
|
|
80734
|
-
import { spawn as
|
|
81958
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
80735
81959
|
var MIME_TYPES2 = {
|
|
80736
81960
|
".png": "image/png",
|
|
80737
81961
|
".jpg": "image/jpeg",
|
|
@@ -82132,7 +83356,7 @@ Status: ${updated.status}`
|
|
|
82132
83356
|
npxArgs.push("--skill", params.skill);
|
|
82133
83357
|
}
|
|
82134
83358
|
npxArgs.push("-y", "-a", "pi");
|
|
82135
|
-
const child =
|
|
83359
|
+
const child = spawn5("npx", npxArgs, {
|
|
82136
83360
|
cwd: resolveProjectRoot(ctx.cwd),
|
|
82137
83361
|
stdio: "pipe"
|
|
82138
83362
|
});
|
|
@@ -82213,7 +83437,7 @@ Status: ${updated.status}`
|
|
|
82213
83437
|
return;
|
|
82214
83438
|
}
|
|
82215
83439
|
const port = trimmed ? parseInt(trimmed, 10) || 4040 : 4040;
|
|
82216
|
-
const child =
|
|
83440
|
+
const child = spawn5("fn", ["dashboard", "--port", String(port)], {
|
|
82217
83441
|
cwd: resolveProjectRoot(ctx.cwd),
|
|
82218
83442
|
stdio: ["ignore", "pipe", "pipe"],
|
|
82219
83443
|
detached: false,
|