@runfusion/fusion 0.5.0 → 0.6.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 +799 -430
- package/dist/client/assets/{AgentDetailView-CnedHKqd.js → AgentDetailView-PYfYi6rl.js} +1 -1
- package/dist/client/assets/{AgentsView-TCAMvB-N.js → AgentsView-CjqSko8c.js} +3 -3
- package/dist/client/assets/{ChatView-B7djAFGF.js → ChatView-CY7Mdd3y.js} +1 -1
- package/dist/client/assets/{DevServerView-B_zgnvEn.js → DevServerView-Jt4PTXWB.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-B3ejJOl0.js → DirectoryPicker-Bcoh2_ft.js} +1 -1
- package/dist/client/assets/{DocumentsView-DzmbEKrl.js → DocumentsView-B2YRSmIS.js} +1 -1
- package/dist/client/assets/{InsightsView-CoRsf8DC.js → InsightsView-C4-vGe-H.js} +1 -1
- package/dist/client/assets/{MemoryView-oFUIaoM5.js → MemoryView-Ch7agzuP.js} +1 -1
- package/dist/client/assets/{NodesView-BXUaViVf.js → NodesView-D9rm5-_6.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-DJRC5zRv.js → PiExtensionsManager-hpV1-dOB.js} +1 -1
- package/dist/client/assets/{PluginManager-OQhiY2zP.js → PluginManager-DHHM1Xeg.js} +1 -1
- package/dist/client/assets/{RoadmapsView-DwdewIMm.js → RoadmapsView-BpqARpKn.js} +1 -1
- package/dist/client/assets/{SettingsModal-Bmz_YrW5.js → SettingsModal-B8Q5r_TT.js} +3 -3
- package/dist/client/assets/{SettingsModal-CMRJwSFd.js → SettingsModal-DFitE2kE.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-BnPgyQho.js → SetupWizardModal-CjUbb4VZ.js} +1 -1
- package/dist/client/assets/{SkillsView-pHEyP-vg.js → SkillsView-CaQNaA67.js} +1 -1
- package/dist/client/assets/{TodoView-Cg-xDGeH.js → TodoView-Bj0DcDdf.js} +1 -1
- package/dist/client/assets/{folder-open-DJxjQmf1.js → folder-open-DDanUhRq.js} +1 -1
- package/dist/client/assets/{index-Cf4wCcWp.js → index-BRTEq_-7.js} +5 -5
- package/dist/client/assets/index-w9ci2GQ7.css +1 -0
- package/dist/client/assets/{list-checks-NjVTpQgK.js → list-checks-eKLuZO4Y.js} +1 -1
- package/dist/client/assets/{upload-BQA5FG0G.js → upload-DDJr7Sat.js} +1 -1
- package/dist/client/assets/{users-p7CqLoIz.js → users-zMb4VibZ.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/extension.js +352 -154
- package/dist/pi-claude-cli/package.json +1 -1
- package/package.json +5 -5
- package/dist/client/assets/index-B7TDbn3p.css +0 -1
package/dist/bin.js
CHANGED
|
@@ -165,6 +165,8 @@ var init_settings_schema = __esm({
|
|
|
165
165
|
archiveAgentLogMode: "compact",
|
|
166
166
|
autoUpdatePrStatus: false,
|
|
167
167
|
autoCreatePr: false,
|
|
168
|
+
githubCommentOnDone: false,
|
|
169
|
+
githubCommentTemplate: void 0,
|
|
168
170
|
autoBackupEnabled: false,
|
|
169
171
|
autoBackupSchedule: "0 2 * * *",
|
|
170
172
|
autoBackupRetention: 7,
|
|
@@ -2275,8 +2277,8 @@ function normalizeTaskComments(steeringComments, comments) {
|
|
|
2275
2277
|
comments: normalizedComments
|
|
2276
2278
|
};
|
|
2277
2279
|
}
|
|
2278
|
-
function createDatabase(fusionDir) {
|
|
2279
|
-
return new Database(fusionDir);
|
|
2280
|
+
function createDatabase(fusionDir, options) {
|
|
2281
|
+
return new Database(fusionDir, options);
|
|
2280
2282
|
}
|
|
2281
2283
|
var SCHEMA_VERSION, SCHEMA_SQL, Database;
|
|
2282
2284
|
var init_db = __esm({
|
|
@@ -2284,7 +2286,7 @@ var init_db = __esm({
|
|
|
2284
2286
|
"use strict";
|
|
2285
2287
|
init_sqlite_adapter();
|
|
2286
2288
|
init_types();
|
|
2287
|
-
SCHEMA_VERSION =
|
|
2289
|
+
SCHEMA_VERSION = 48;
|
|
2288
2290
|
SCHEMA_SQL = `
|
|
2289
2291
|
-- Tasks table with JSON columns for nested data
|
|
2290
2292
|
CREATE TABLE IF NOT EXISTS tasks (
|
|
@@ -2792,16 +2794,19 @@ CREATE INDEX IF NOT EXISTS idxTodoItemsSortOrder ON todo_items(listId, sortOrder
|
|
|
2792
2794
|
/** Tracks transaction nesting depth for savepoint-based nested transactions. */
|
|
2793
2795
|
transactionDepth = 0;
|
|
2794
2796
|
_fts5Available;
|
|
2795
|
-
constructor(fusionDir) {
|
|
2796
|
-
|
|
2797
|
-
|
|
2797
|
+
constructor(fusionDir, options) {
|
|
2798
|
+
const inMemory = options?.inMemory === true;
|
|
2799
|
+
this.dbPath = inMemory ? ":memory:" : join(fusionDir, "fusion.db");
|
|
2800
|
+
if (!inMemory && !isAbsolute(fusionDir)) {
|
|
2798
2801
|
throw new Error(`[fusion] Database constructor requires an absolute fusionDir path, got: ${fusionDir}`);
|
|
2799
2802
|
}
|
|
2800
|
-
if (!existsSync(fusionDir)) {
|
|
2803
|
+
if (!inMemory && !existsSync(fusionDir)) {
|
|
2801
2804
|
mkdirSync(fusionDir, { recursive: true });
|
|
2802
2805
|
}
|
|
2803
2806
|
this.db = new DatabaseSync(this.dbPath);
|
|
2804
|
-
|
|
2807
|
+
if (!inMemory) {
|
|
2808
|
+
this.db.exec("PRAGMA journal_mode = WAL");
|
|
2809
|
+
}
|
|
2805
2810
|
this.db.exec("PRAGMA busy_timeout = 5000");
|
|
2806
2811
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
2807
2812
|
this._fts5Available = probeFts5(this.db);
|
|
@@ -3730,6 +3735,11 @@ CREATE INDEX IF NOT EXISTS idxTodoItemsSortOrder ON todo_items(listId, sortOrder
|
|
|
3730
3735
|
}
|
|
3731
3736
|
});
|
|
3732
3737
|
}
|
|
3738
|
+
if (version < 48) {
|
|
3739
|
+
this.applyMigration(48, () => {
|
|
3740
|
+
this.addColumnIfMissing("tasks", "verificationFailureCount", "INTEGER DEFAULT 0");
|
|
3741
|
+
});
|
|
3742
|
+
}
|
|
3733
3743
|
}
|
|
3734
3744
|
/**
|
|
3735
3745
|
* Run a single migration step inside a transaction and bump the version.
|
|
@@ -3919,6 +3929,7 @@ var init_agent_store = __esm({
|
|
|
3919
3929
|
locks = /* @__PURE__ */ new Map();
|
|
3920
3930
|
_db = null;
|
|
3921
3931
|
taskStore;
|
|
3932
|
+
inMemoryDb;
|
|
3922
3933
|
constructor(options = {}) {
|
|
3923
3934
|
super();
|
|
3924
3935
|
if (!options.rootDir && process.env.VITEST === "true") {
|
|
@@ -3929,10 +3940,11 @@ var init_agent_store = __esm({
|
|
|
3929
3940
|
this.rootDir = options.rootDir ?? resolve(".fusion");
|
|
3930
3941
|
this.agentsDir = join2(this.rootDir, "agents");
|
|
3931
3942
|
this.taskStore = options.taskStore;
|
|
3943
|
+
this.inMemoryDb = options.inMemoryDb === true;
|
|
3932
3944
|
}
|
|
3933
3945
|
get db() {
|
|
3934
3946
|
if (!this._db) {
|
|
3935
|
-
this._db = new Database(this.rootDir);
|
|
3947
|
+
this._db = new Database(this.rootDir, { inMemory: this.inMemoryDb });
|
|
3936
3948
|
this._db.init();
|
|
3937
3949
|
}
|
|
3938
3950
|
return this._db;
|
|
@@ -6232,9 +6244,9 @@ var init_global_settings = __esm({
|
|
|
6232
6244
|
* Serialize operations via promise chain to prevent lost-update races.
|
|
6233
6245
|
*/
|
|
6234
6246
|
withLock(fn) {
|
|
6235
|
-
let
|
|
6247
|
+
let resolve36;
|
|
6236
6248
|
const next = new Promise((r) => {
|
|
6237
|
-
|
|
6249
|
+
resolve36 = r;
|
|
6238
6250
|
});
|
|
6239
6251
|
const prev = this.lock;
|
|
6240
6252
|
this.lock = next;
|
|
@@ -6242,7 +6254,7 @@ var init_global_settings = __esm({
|
|
|
6242
6254
|
try {
|
|
6243
6255
|
return await fn();
|
|
6244
6256
|
} finally {
|
|
6245
|
-
|
|
6257
|
+
resolve36();
|
|
6246
6258
|
}
|
|
6247
6259
|
});
|
|
6248
6260
|
}
|
|
@@ -6306,12 +6318,15 @@ END;
|
|
|
6306
6318
|
ArchiveDatabase = class {
|
|
6307
6319
|
db;
|
|
6308
6320
|
_fts5Available;
|
|
6309
|
-
constructor(fusionDir) {
|
|
6310
|
-
|
|
6321
|
+
constructor(fusionDir, options) {
|
|
6322
|
+
const inMemory = options?.inMemory === true;
|
|
6323
|
+
if (!inMemory && !existsSync4(fusionDir)) {
|
|
6311
6324
|
mkdirSync3(fusionDir, { recursive: true });
|
|
6312
6325
|
}
|
|
6313
|
-
this.db = new DatabaseSync(join5(fusionDir, "archive.db"));
|
|
6314
|
-
|
|
6326
|
+
this.db = new DatabaseSync(inMemory ? ":memory:" : join5(fusionDir, "archive.db"));
|
|
6327
|
+
if (!inMemory) {
|
|
6328
|
+
this.db.exec("PRAGMA journal_mode = WAL");
|
|
6329
|
+
}
|
|
6315
6330
|
this.db.exec("PRAGMA busy_timeout = 5000");
|
|
6316
6331
|
this._fts5Available = probeFts5(this.db);
|
|
6317
6332
|
}
|
|
@@ -9526,19 +9541,21 @@ var init_plugin_store = __esm({
|
|
|
9526
9541
|
init_db();
|
|
9527
9542
|
init_plugin_types();
|
|
9528
9543
|
PluginStore = class extends EventEmitter5 {
|
|
9529
|
-
constructor(rootDir) {
|
|
9544
|
+
constructor(rootDir, options) {
|
|
9530
9545
|
super();
|
|
9531
9546
|
this.rootDir = rootDir;
|
|
9547
|
+
this.inMemoryDb = options?.inMemoryDb === true;
|
|
9532
9548
|
}
|
|
9533
9549
|
/** SQLite database instance */
|
|
9534
9550
|
_db = null;
|
|
9551
|
+
inMemoryDb;
|
|
9535
9552
|
/**
|
|
9536
9553
|
* Get the SQLite database, initializing it on first access.
|
|
9537
9554
|
*/
|
|
9538
9555
|
get db() {
|
|
9539
9556
|
if (!this._db) {
|
|
9540
9557
|
const fusionDir = join7(this.rootDir, ".fusion");
|
|
9541
|
-
this._db = new Database(fusionDir);
|
|
9558
|
+
this._db = new Database(fusionDir, { inMemory: this.inMemoryDb });
|
|
9542
9559
|
this._db.init();
|
|
9543
9560
|
}
|
|
9544
9561
|
return this._db;
|
|
@@ -27274,8 +27291,8 @@ var require_CronFileParser = __commonJS({
|
|
|
27274
27291
|
* @throws If file cannot be read
|
|
27275
27292
|
*/
|
|
27276
27293
|
static parseFileSync(filePath) {
|
|
27277
|
-
const { readFileSync:
|
|
27278
|
-
const data =
|
|
27294
|
+
const { readFileSync: readFileSync20 } = __require("fs");
|
|
27295
|
+
const data = readFileSync20(filePath, "utf8");
|
|
27279
27296
|
return _CronFileParser.#parseContent(data);
|
|
27280
27297
|
}
|
|
27281
27298
|
/**
|
|
@@ -27411,21 +27428,23 @@ var init_automation_store = __esm({
|
|
|
27411
27428
|
init_db();
|
|
27412
27429
|
CRON_TIMEZONE = "UTC";
|
|
27413
27430
|
AutomationStore = class _AutomationStore extends EventEmitter11 {
|
|
27414
|
-
constructor(rootDir) {
|
|
27431
|
+
constructor(rootDir, options) {
|
|
27415
27432
|
super();
|
|
27416
27433
|
this.rootDir = rootDir;
|
|
27434
|
+
this.inMemoryDb = options?.inMemoryDb === true;
|
|
27417
27435
|
}
|
|
27418
27436
|
/** Per-schedule promise chain for serializing writes. */
|
|
27419
27437
|
scheduleLocks = /* @__PURE__ */ new Map();
|
|
27420
27438
|
/** SQLite database instance */
|
|
27421
27439
|
_db = null;
|
|
27440
|
+
inMemoryDb;
|
|
27422
27441
|
/**
|
|
27423
27442
|
* Get the SQLite database, initializing it on first access.
|
|
27424
27443
|
*/
|
|
27425
27444
|
get db() {
|
|
27426
27445
|
if (!this._db) {
|
|
27427
27446
|
const fusionDir = join12(this.rootDir, ".fusion");
|
|
27428
|
-
this._db = new Database(fusionDir);
|
|
27447
|
+
this._db = new Database(fusionDir, { inMemory: this.inMemoryDb });
|
|
27429
27448
|
this._db.init();
|
|
27430
27449
|
}
|
|
27431
27450
|
return this._db;
|
|
@@ -27490,9 +27509,9 @@ var init_automation_store = __esm({
|
|
|
27490
27509
|
*/
|
|
27491
27510
|
withScheduleLock(id, fn) {
|
|
27492
27511
|
const prev = this.scheduleLocks.get(id) ?? Promise.resolve();
|
|
27493
|
-
let
|
|
27512
|
+
let resolve36;
|
|
27494
27513
|
const next = new Promise((r) => {
|
|
27495
|
-
|
|
27514
|
+
resolve36 = r;
|
|
27496
27515
|
});
|
|
27497
27516
|
this.scheduleLocks.set(id, next);
|
|
27498
27517
|
return prev.then(async () => {
|
|
@@ -27502,7 +27521,7 @@ var init_automation_store = __esm({
|
|
|
27502
27521
|
if (this.scheduleLocks.get(id) === next) {
|
|
27503
27522
|
this.scheduleLocks.delete(id);
|
|
27504
27523
|
}
|
|
27505
|
-
|
|
27524
|
+
resolve36();
|
|
27506
27525
|
}
|
|
27507
27526
|
});
|
|
27508
27527
|
}
|
|
@@ -29290,7 +29309,7 @@ var init_project_memory = __esm({
|
|
|
29290
29309
|
// ../core/src/run-command.ts
|
|
29291
29310
|
import { spawn } from "node:child_process";
|
|
29292
29311
|
function runCommandAsync(command, options = {}) {
|
|
29293
|
-
return new Promise((
|
|
29312
|
+
return new Promise((resolve36) => {
|
|
29294
29313
|
const maxBuffer = options.maxBuffer ?? DEFAULT_MAX_BUFFER;
|
|
29295
29314
|
let stdout = "";
|
|
29296
29315
|
let stderr = "";
|
|
@@ -29349,7 +29368,7 @@ function runCommandAsync(command, options = {}) {
|
|
|
29349
29368
|
clearTimeout(forceKillTimer);
|
|
29350
29369
|
forceKillTimer = null;
|
|
29351
29370
|
}
|
|
29352
|
-
|
|
29371
|
+
resolve36({
|
|
29353
29372
|
stdout,
|
|
29354
29373
|
stderr,
|
|
29355
29374
|
exitCode: null,
|
|
@@ -29367,7 +29386,7 @@ function runCommandAsync(command, options = {}) {
|
|
|
29367
29386
|
}
|
|
29368
29387
|
signalProcessGroup("SIGTERM");
|
|
29369
29388
|
scheduleForceKill(NORMAL_CLEANUP_FORCE_KILL_DELAY_MS);
|
|
29370
|
-
|
|
29389
|
+
resolve36({
|
|
29371
29390
|
stdout,
|
|
29372
29391
|
stderr,
|
|
29373
29392
|
exitCode: code,
|
|
@@ -29427,8 +29446,8 @@ function assertSafeGitBranchName(name) {
|
|
|
29427
29446
|
}
|
|
29428
29447
|
}
|
|
29429
29448
|
function assertSafeAbsolutePath(path4) {
|
|
29430
|
-
const
|
|
29431
|
-
if (!path4 || path4.length > 4096 || !
|
|
29449
|
+
const isAbsolute17 = path4.startsWith("/") || /^[A-Za-z]:[\\/]/.test(path4);
|
|
29450
|
+
if (!path4 || path4.length > 4096 || !isAbsolute17 || path4.startsWith("-") || // Reject shell metacharacters, quotes, control chars, and NULs.
|
|
29432
29451
|
/["'`$\n\r\t;&|<>()*?[\]{}\\\0]/.test(
|
|
29433
29452
|
path4.replace(/^[A-Za-z]:/, "")
|
|
29434
29453
|
// ignore the drive-letter colon on Windows
|
|
@@ -29520,13 +29539,14 @@ var init_store = __esm({
|
|
|
29520
29539
|
}
|
|
29521
29540
|
};
|
|
29522
29541
|
TaskStore = class _TaskStore extends EventEmitter12 {
|
|
29523
|
-
constructor(rootDir, globalSettingsDir) {
|
|
29542
|
+
constructor(rootDir, globalSettingsDir, options) {
|
|
29524
29543
|
super();
|
|
29525
29544
|
this.rootDir = rootDir;
|
|
29526
29545
|
this.setMaxListeners(100);
|
|
29527
29546
|
this.fusionDir = join15(rootDir, ".fusion");
|
|
29528
29547
|
this.tasksDir = join15(this.fusionDir, "tasks");
|
|
29529
29548
|
this.configPath = join15(this.fusionDir, "config.json");
|
|
29549
|
+
this.inMemoryDb = options?.inMemoryDb === true;
|
|
29530
29550
|
const resolvedGlobalSettingsDir = globalSettingsDir ?? (process.env.VITEST === "true" ? join15(rootDir, ".fusion-global-settings") : void 0);
|
|
29531
29551
|
this.globalSettingsStore = new GlobalSettingsStore(resolvedGlobalSettingsDir);
|
|
29532
29552
|
}
|
|
@@ -29569,6 +29589,7 @@ var init_store = __esm({
|
|
|
29569
29589
|
configPath;
|
|
29570
29590
|
/** SQLite database for structured data storage */
|
|
29571
29591
|
_db = null;
|
|
29592
|
+
activityListenersWired = false;
|
|
29572
29593
|
/** Separate SQLite database for compact archived task snapshots. */
|
|
29573
29594
|
_archiveDb = null;
|
|
29574
29595
|
/** File-system watcher instance */
|
|
@@ -29611,13 +29632,19 @@ var init_store = __esm({
|
|
|
29611
29632
|
insightStore = null;
|
|
29612
29633
|
/** Cached TodoStore instance */
|
|
29613
29634
|
todoStore = null;
|
|
29635
|
+
// Test-only: when true, both fusion.db and archive.db open as `:memory:`
|
|
29636
|
+
// SQLite connections instead of disk-backed files. Production code never
|
|
29637
|
+
// sets this; it's gated through an opt-in TaskStoreOptions field below.
|
|
29638
|
+
// Tests that need cross-instance persistence (open store A, close,
|
|
29639
|
+
// open store B on the same dir, expect data) must leave this false.
|
|
29640
|
+
inMemoryDb;
|
|
29614
29641
|
/**
|
|
29615
29642
|
* Get the SQLite database, initializing it on first access.
|
|
29616
29643
|
* Also performs auto-migration from legacy file-based storage if needed.
|
|
29617
29644
|
*/
|
|
29618
29645
|
get db() {
|
|
29619
29646
|
if (!this._db) {
|
|
29620
|
-
this._db = new Database(this.fusionDir);
|
|
29647
|
+
this._db = new Database(this.fusionDir, { inMemory: this.inMemoryDb });
|
|
29621
29648
|
this._db.init();
|
|
29622
29649
|
if (detectLegacyData(this.fusionDir)) {
|
|
29623
29650
|
}
|
|
@@ -29626,7 +29653,7 @@ var init_store = __esm({
|
|
|
29626
29653
|
}
|
|
29627
29654
|
get archiveDb() {
|
|
29628
29655
|
if (!this._archiveDb) {
|
|
29629
|
-
this._archiveDb = new ArchiveDatabase(this.fusionDir);
|
|
29656
|
+
this._archiveDb = new ArchiveDatabase(this.fusionDir, { inMemory: this.inMemoryDb });
|
|
29630
29657
|
this._archiveDb.init();
|
|
29631
29658
|
this.migrateLegacyArchiveEntriesToArchiveDb();
|
|
29632
29659
|
}
|
|
@@ -29635,7 +29662,7 @@ var init_store = __esm({
|
|
|
29635
29662
|
async init() {
|
|
29636
29663
|
await mkdir7(this.tasksDir, { recursive: true });
|
|
29637
29664
|
if (!this._db) {
|
|
29638
|
-
this._db = new Database(this.fusionDir);
|
|
29665
|
+
this._db = new Database(this.fusionDir, { inMemory: this.inMemoryDb });
|
|
29639
29666
|
this._db.init();
|
|
29640
29667
|
}
|
|
29641
29668
|
if (detectLegacyData(this.fusionDir)) {
|
|
@@ -29704,6 +29731,7 @@ var init_store = __esm({
|
|
|
29704
29731
|
postReviewFixCount: row.postReviewFixCount ?? void 0,
|
|
29705
29732
|
recoveryRetryCount: row.recoveryRetryCount ?? void 0,
|
|
29706
29733
|
taskDoneRetryCount: row.taskDoneRetryCount ?? void 0,
|
|
29734
|
+
verificationFailureCount: row.verificationFailureCount ?? void 0,
|
|
29707
29735
|
nextRecoveryAt: row.nextRecoveryAt || void 0,
|
|
29708
29736
|
error: row.error || void 0,
|
|
29709
29737
|
summary: row.summary || void 0,
|
|
@@ -29988,6 +30016,7 @@ ${recentText}` : void 0
|
|
|
29988
30016
|
"postReviewFixCount",
|
|
29989
30017
|
"recoveryRetryCount",
|
|
29990
30018
|
"taskDoneRetryCount",
|
|
30019
|
+
"verificationFailureCount",
|
|
29991
30020
|
"nextRecoveryAt",
|
|
29992
30021
|
"error",
|
|
29993
30022
|
"summary",
|
|
@@ -30057,6 +30086,7 @@ ${recentText}` : void 0
|
|
|
30057
30086
|
"postReviewFixCount",
|
|
30058
30087
|
"recoveryRetryCount",
|
|
30059
30088
|
"taskDoneRetryCount",
|
|
30089
|
+
"verificationFailureCount",
|
|
30060
30090
|
"nextRecoveryAt",
|
|
30061
30091
|
"error",
|
|
30062
30092
|
"summary",
|
|
@@ -30124,7 +30154,7 @@ ${recentText}` : void 0
|
|
|
30124
30154
|
id, title, description, priority, "column", status, size, reviewLevel, currentStep,
|
|
30125
30155
|
worktree, blockedBy, paused, baseBranch, branch, baseCommitSha, modelPresetId, modelProvider,
|
|
30126
30156
|
modelId, validatorModelProvider, validatorModelId, planningModelProvider, planningModelId, mergeRetries,
|
|
30127
|
-
workflowStepRetries, stuckKillCount, postReviewFixCount, recoveryRetryCount, taskDoneRetryCount, nextRecoveryAt, error,
|
|
30157
|
+
workflowStepRetries, stuckKillCount, postReviewFixCount, recoveryRetryCount, taskDoneRetryCount, verificationFailureCount, nextRecoveryAt, error,
|
|
30128
30158
|
summary, thinkingLevel, executionMode, tokenUsageInputTokens, tokenUsageOutputTokens, tokenUsageCachedTokens,
|
|
30129
30159
|
tokenUsageTotalTokens, tokenUsageFirstUsedAt, tokenUsageLastUsedAt, createdAt, updatedAt, columnMovedAt,
|
|
30130
30160
|
dependencies, steps, log, attachments, steeringComments,
|
|
@@ -30132,7 +30162,7 @@ ${recentText}` : void 0
|
|
|
30132
30162
|
sourceIssueProvider, sourceIssueRepository, sourceIssueExternalIssueId, sourceIssueNumber, sourceIssueUrl,
|
|
30133
30163
|
mergeDetails, breakIntoSubtasks, enabledWorkflowSteps, modifiedFiles, missionId, sliceId, assignedAgentId, assigneeUserId, checkedOutBy, checkedOutAt
|
|
30134
30164
|
) VALUES (
|
|
30135
|
-
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
30165
|
+
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
30136
30166
|
)
|
|
30137
30167
|
ON CONFLICT(id) DO UPDATE SET
|
|
30138
30168
|
title = excluded.title,
|
|
@@ -30162,6 +30192,7 @@ ${recentText}` : void 0
|
|
|
30162
30192
|
postReviewFixCount = excluded.postReviewFixCount,
|
|
30163
30193
|
recoveryRetryCount = excluded.recoveryRetryCount,
|
|
30164
30194
|
taskDoneRetryCount = excluded.taskDoneRetryCount,
|
|
30195
|
+
verificationFailureCount = excluded.verificationFailureCount,
|
|
30165
30196
|
nextRecoveryAt = excluded.nextRecoveryAt,
|
|
30166
30197
|
error = excluded.error,
|
|
30167
30198
|
summary = excluded.summary,
|
|
@@ -30229,6 +30260,7 @@ ${recentText}` : void 0
|
|
|
30229
30260
|
task.postReviewFixCount ?? 0,
|
|
30230
30261
|
task.recoveryRetryCount ?? null,
|
|
30231
30262
|
task.taskDoneRetryCount ?? 0,
|
|
30263
|
+
task.verificationFailureCount ?? 0,
|
|
30232
30264
|
task.nextRecoveryAt ?? null,
|
|
30233
30265
|
task.error ?? null,
|
|
30234
30266
|
task.summary ?? null,
|
|
@@ -30304,8 +30336,14 @@ ${recentText}` : void 0
|
|
|
30304
30336
|
/**
|
|
30305
30337
|
* Set up event listeners for activity logging.
|
|
30306
30338
|
* Call after init() to record task lifecycle events.
|
|
30339
|
+
*
|
|
30340
|
+
* Idempotent — repeated calls are no-ops. Without this guard, each duplicate
|
|
30341
|
+
* call double-registers handlers, causing the activity log to record every
|
|
30342
|
+
* `task:created` / `task:moved` event N times where N = number of init() calls.
|
|
30307
30343
|
*/
|
|
30308
30344
|
setupActivityLogListeners() {
|
|
30345
|
+
if (this.activityListenersWired) return;
|
|
30346
|
+
this.activityListenersWired = true;
|
|
30309
30347
|
this.on("task:created", (task) => {
|
|
30310
30348
|
this.recordActivityFromListener(
|
|
30311
30349
|
{
|
|
@@ -30409,9 +30447,9 @@ ${recentText}` : void 0
|
|
|
30409
30447
|
* lost-update races on the nextId counter.
|
|
30410
30448
|
*/
|
|
30411
30449
|
withConfigLock(fn) {
|
|
30412
|
-
let
|
|
30450
|
+
let resolve36;
|
|
30413
30451
|
const next = new Promise((r) => {
|
|
30414
|
-
|
|
30452
|
+
resolve36 = r;
|
|
30415
30453
|
});
|
|
30416
30454
|
const prev = this.configLock;
|
|
30417
30455
|
this.configLock = next;
|
|
@@ -30419,7 +30457,7 @@ ${recentText}` : void 0
|
|
|
30419
30457
|
try {
|
|
30420
30458
|
return await fn();
|
|
30421
30459
|
} finally {
|
|
30422
|
-
|
|
30460
|
+
resolve36();
|
|
30423
30461
|
}
|
|
30424
30462
|
});
|
|
30425
30463
|
}
|
|
@@ -30429,9 +30467,9 @@ ${recentText}` : void 0
|
|
|
30429
30467
|
*/
|
|
30430
30468
|
withTaskLock(id, fn) {
|
|
30431
30469
|
const prev = this.taskLocks.get(id) ?? Promise.resolve();
|
|
30432
|
-
let
|
|
30470
|
+
let resolve36;
|
|
30433
30471
|
const next = new Promise((r) => {
|
|
30434
|
-
|
|
30472
|
+
resolve36 = r;
|
|
30435
30473
|
});
|
|
30436
30474
|
this.taskLocks.set(id, next);
|
|
30437
30475
|
return prev.then(async () => {
|
|
@@ -30441,7 +30479,7 @@ ${recentText}` : void 0
|
|
|
30441
30479
|
if (this.taskLocks.get(id) === next) {
|
|
30442
30480
|
this.taskLocks.delete(id);
|
|
30443
30481
|
}
|
|
30444
|
-
|
|
30482
|
+
resolve36();
|
|
30445
30483
|
}
|
|
30446
30484
|
});
|
|
30447
30485
|
}
|
|
@@ -31551,6 +31589,11 @@ ${newTask.description}
|
|
|
31551
31589
|
} else if (updates.taskDoneRetryCount !== void 0) {
|
|
31552
31590
|
task.taskDoneRetryCount = updates.taskDoneRetryCount;
|
|
31553
31591
|
}
|
|
31592
|
+
if (updates.verificationFailureCount === null) {
|
|
31593
|
+
task.verificationFailureCount = void 0;
|
|
31594
|
+
} else if (updates.verificationFailureCount !== void 0) {
|
|
31595
|
+
task.verificationFailureCount = updates.verificationFailureCount;
|
|
31596
|
+
}
|
|
31554
31597
|
if (updates.nextRecoveryAt === null) {
|
|
31555
31598
|
task.nextRecoveryAt = void 0;
|
|
31556
31599
|
} else if (updates.nextRecoveryAt !== void 0) {
|
|
@@ -32542,7 +32585,7 @@ ${task.description}
|
|
|
32542
32585
|
this.emit("task:deleted", cached);
|
|
32543
32586
|
}
|
|
32544
32587
|
}
|
|
32545
|
-
await new Promise((
|
|
32588
|
+
await new Promise((resolve36) => setImmediate(resolve36));
|
|
32546
32589
|
const selectClause = this.getTaskSelectClause(true);
|
|
32547
32590
|
const changedRows = this.lastPollTime ? this.db.prepare(`SELECT ${selectClause} FROM tasks WHERE updatedAt > ? OR columnMovedAt > ?`).all(this.lastPollTime, this.lastPollTime) : this.db.prepare(`SELECT ${selectClause} FROM tasks`).all();
|
|
32548
32591
|
this.lastPollTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -32562,7 +32605,7 @@ ${task.description}
|
|
|
32562
32605
|
this.emit("task:updated", task);
|
|
32563
32606
|
}
|
|
32564
32607
|
if (i > 0 && i % 50 === 0) {
|
|
32565
|
-
await new Promise((
|
|
32608
|
+
await new Promise((resolve36) => setImmediate(resolve36));
|
|
32566
32609
|
}
|
|
32567
32610
|
}
|
|
32568
32611
|
const elapsed = Date.now() - startTime;
|
|
@@ -34383,7 +34426,7 @@ function runGh(args, cwd) {
|
|
|
34383
34426
|
}
|
|
34384
34427
|
}
|
|
34385
34428
|
function runGhAsync(args, cwd) {
|
|
34386
|
-
return new Promise((
|
|
34429
|
+
return new Promise((resolve36, reject2) => {
|
|
34387
34430
|
execFile2(
|
|
34388
34431
|
"gh",
|
|
34389
34432
|
args,
|
|
@@ -34399,7 +34442,7 @@ function runGhAsync(args, cwd) {
|
|
|
34399
34442
|
ghError.stderr = stderr ?? "";
|
|
34400
34443
|
reject2(ghError);
|
|
34401
34444
|
} else {
|
|
34402
|
-
|
|
34445
|
+
resolve36(stdout ?? "");
|
|
34403
34446
|
}
|
|
34404
34447
|
}
|
|
34405
34448
|
);
|
|
@@ -34517,14 +34560,16 @@ var init_routine_store = __esm({
|
|
|
34517
34560
|
init_routine();
|
|
34518
34561
|
CRON_TIMEZONE2 = "UTC";
|
|
34519
34562
|
RoutineStore = class _RoutineStore extends EventEmitter13 {
|
|
34520
|
-
constructor(rootDir) {
|
|
34563
|
+
constructor(rootDir, options) {
|
|
34521
34564
|
super();
|
|
34522
34565
|
this.rootDir = rootDir;
|
|
34566
|
+
this.inMemoryDb = options?.inMemoryDb === true;
|
|
34523
34567
|
}
|
|
34524
34568
|
/** SQLite database instance (lazy init). */
|
|
34525
34569
|
_db = null;
|
|
34526
34570
|
/** Per-routine promise chain for serializing writes. */
|
|
34527
34571
|
routineLocks = /* @__PURE__ */ new Map();
|
|
34572
|
+
inMemoryDb;
|
|
34528
34573
|
// ── Database Access ────────────────────────────────────────────────
|
|
34529
34574
|
/**
|
|
34530
34575
|
* Get the SQLite database, initializing it on first access.
|
|
@@ -34532,7 +34577,7 @@ var init_routine_store = __esm({
|
|
|
34532
34577
|
get db() {
|
|
34533
34578
|
if (!this._db) {
|
|
34534
34579
|
const fusionDir = `${this.rootDir}/.fusion`;
|
|
34535
|
-
this._db = new Database(fusionDir);
|
|
34580
|
+
this._db = new Database(fusionDir, { inMemory: this.inMemoryDb });
|
|
34536
34581
|
this._db.init();
|
|
34537
34582
|
}
|
|
34538
34583
|
return this._db;
|
|
@@ -34653,9 +34698,9 @@ var init_routine_store = __esm({
|
|
|
34653
34698
|
*/
|
|
34654
34699
|
withRoutineLock(id, fn) {
|
|
34655
34700
|
const prev = this.routineLocks.get(id) ?? Promise.resolve();
|
|
34656
|
-
let
|
|
34701
|
+
let resolve36;
|
|
34657
34702
|
const next = new Promise((r) => {
|
|
34658
|
-
|
|
34703
|
+
resolve36 = r;
|
|
34659
34704
|
});
|
|
34660
34705
|
this.routineLocks.set(id, next);
|
|
34661
34706
|
return prev.then(async () => {
|
|
@@ -34665,7 +34710,7 @@ var init_routine_store = __esm({
|
|
|
34665
34710
|
if (this.routineLocks.get(id) === next) {
|
|
34666
34711
|
this.routineLocks.delete(id);
|
|
34667
34712
|
}
|
|
34668
|
-
|
|
34713
|
+
resolve36();
|
|
34669
34714
|
}
|
|
34670
34715
|
});
|
|
34671
34716
|
}
|
|
@@ -35187,13 +35232,13 @@ var init_plugin_loader = __esm({
|
|
|
35187
35232
|
* Execute a promise with a timeout.
|
|
35188
35233
|
*/
|
|
35189
35234
|
withTimeout(promise, ms, timeoutMessage) {
|
|
35190
|
-
return new Promise((
|
|
35235
|
+
return new Promise((resolve36, reject2) => {
|
|
35191
35236
|
const timer = setTimeout(() => {
|
|
35192
35237
|
reject2(new Error(timeoutMessage));
|
|
35193
35238
|
}, ms);
|
|
35194
35239
|
promise.then((result) => {
|
|
35195
35240
|
clearTimeout(timer);
|
|
35196
|
-
|
|
35241
|
+
resolve36(result);
|
|
35197
35242
|
}).catch((err) => {
|
|
35198
35243
|
clearTimeout(timer);
|
|
35199
35244
|
reject2(err);
|
|
@@ -38400,7 +38445,7 @@ var require_get_stream = __commonJS({
|
|
|
38400
38445
|
};
|
|
38401
38446
|
const { maxBuffer } = options;
|
|
38402
38447
|
let stream;
|
|
38403
|
-
await new Promise((
|
|
38448
|
+
await new Promise((resolve36, reject2) => {
|
|
38404
38449
|
const rejectPromise = (error) => {
|
|
38405
38450
|
if (error && stream.getBufferedLength() <= BufferConstants.MAX_LENGTH) {
|
|
38406
38451
|
error.bufferedData = stream.getBufferedValue();
|
|
@@ -38412,7 +38457,7 @@ var require_get_stream = __commonJS({
|
|
|
38412
38457
|
rejectPromise(error);
|
|
38413
38458
|
return;
|
|
38414
38459
|
}
|
|
38415
|
-
|
|
38460
|
+
resolve36();
|
|
38416
38461
|
});
|
|
38417
38462
|
stream.on("data", () => {
|
|
38418
38463
|
if (stream.getBufferedLength() > maxBuffer) {
|
|
@@ -39706,7 +39751,7 @@ var require_extract_zip = __commonJS({
|
|
|
39706
39751
|
debug("opening", this.zipPath, "with opts", this.opts);
|
|
39707
39752
|
this.zipfile = await openZip(this.zipPath, { lazyEntries: true });
|
|
39708
39753
|
this.canceled = false;
|
|
39709
|
-
return new Promise((
|
|
39754
|
+
return new Promise((resolve36, reject2) => {
|
|
39710
39755
|
this.zipfile.on("error", (err) => {
|
|
39711
39756
|
this.canceled = true;
|
|
39712
39757
|
reject2(err);
|
|
@@ -39715,7 +39760,7 @@ var require_extract_zip = __commonJS({
|
|
|
39715
39760
|
this.zipfile.on("close", () => {
|
|
39716
39761
|
if (!this.canceled) {
|
|
39717
39762
|
debug("zip extraction complete");
|
|
39718
|
-
|
|
39763
|
+
resolve36();
|
|
39719
39764
|
}
|
|
39720
39765
|
});
|
|
39721
39766
|
this.zipfile.on("entry", async (entry) => {
|
|
@@ -50414,12 +50459,12 @@ var init_concurrency = __esm({
|
|
|
50414
50459
|
this._active++;
|
|
50415
50460
|
return Promise.resolve();
|
|
50416
50461
|
}
|
|
50417
|
-
return new Promise((
|
|
50462
|
+
return new Promise((resolve36) => {
|
|
50418
50463
|
this._waiters.push({
|
|
50419
50464
|
priority,
|
|
50420
50465
|
resolve: () => {
|
|
50421
50466
|
this._active++;
|
|
50422
|
-
|
|
50467
|
+
resolve36();
|
|
50423
50468
|
}
|
|
50424
50469
|
});
|
|
50425
50470
|
});
|
|
@@ -52839,20 +52884,20 @@ async function withRateLimitRetry(fn, options = {}) {
|
|
|
52839
52884
|
throw lastError ?? new Error("withRateLimitRetry: unexpected state");
|
|
52840
52885
|
}
|
|
52841
52886
|
function sleep(ms, signal) {
|
|
52842
|
-
return new Promise((
|
|
52887
|
+
return new Promise((resolve36, reject2) => {
|
|
52843
52888
|
if (signal?.aborted) {
|
|
52844
52889
|
reject2(signal.reason ?? new Error("Aborted"));
|
|
52845
52890
|
return;
|
|
52846
52891
|
}
|
|
52847
|
-
const timer = setTimeout(
|
|
52892
|
+
const timer = setTimeout(resolve36, ms);
|
|
52848
52893
|
if (signal) {
|
|
52849
52894
|
const onAbort = () => {
|
|
52850
52895
|
clearTimeout(timer);
|
|
52851
52896
|
reject2(signal.reason ?? new Error("Aborted"));
|
|
52852
52897
|
};
|
|
52853
52898
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
52854
|
-
const origResolve =
|
|
52855
|
-
|
|
52899
|
+
const origResolve = resolve36;
|
|
52900
|
+
resolve36 = () => {
|
|
52856
52901
|
signal.removeEventListener("abort", onAbort);
|
|
52857
52902
|
origResolve();
|
|
52858
52903
|
};
|
|
@@ -54747,7 +54792,14 @@ import { existsSync as existsSync21 } from "node:fs";
|
|
|
54747
54792
|
import { join as join26 } from "node:path";
|
|
54748
54793
|
import { Type as Type3 } from "typebox";
|
|
54749
54794
|
async function execWithProcessGroup(command, options) {
|
|
54750
|
-
return new Promise((
|
|
54795
|
+
return new Promise((resolve36, reject2) => {
|
|
54796
|
+
if (options.signal?.aborted) {
|
|
54797
|
+
reject2(Object.assign(
|
|
54798
|
+
new Error(`Command aborted before start: ${command}`),
|
|
54799
|
+
{ code: "ABORT_ERR", aborted: true, stdout: "", stderr: "" }
|
|
54800
|
+
));
|
|
54801
|
+
return;
|
|
54802
|
+
}
|
|
54751
54803
|
const child = spawn2(command, {
|
|
54752
54804
|
cwd: options.cwd,
|
|
54753
54805
|
shell: true,
|
|
@@ -54759,24 +54811,33 @@ async function execWithProcessGroup(command, options) {
|
|
|
54759
54811
|
let stdoutOverflow = false;
|
|
54760
54812
|
let stderrOverflow = false;
|
|
54761
54813
|
let timedOut = false;
|
|
54814
|
+
let aborted = false;
|
|
54762
54815
|
let settled = false;
|
|
54816
|
+
const killTree = (sig) => {
|
|
54817
|
+
if (child.pid === void 0) return;
|
|
54818
|
+
try {
|
|
54819
|
+
process.kill(-child.pid, sig);
|
|
54820
|
+
} catch {
|
|
54821
|
+
}
|
|
54822
|
+
};
|
|
54763
54823
|
const timer = setTimeout(() => {
|
|
54764
54824
|
timedOut = true;
|
|
54765
|
-
|
|
54766
|
-
|
|
54767
|
-
|
|
54768
|
-
|
|
54769
|
-
|
|
54770
|
-
setTimeout(() => {
|
|
54771
|
-
if (settled) return;
|
|
54772
|
-
try {
|
|
54773
|
-
process.kill(-child.pid, "SIGKILL");
|
|
54774
|
-
} catch {
|
|
54775
|
-
}
|
|
54776
|
-
}, 5e3).unref();
|
|
54777
|
-
}
|
|
54825
|
+
killTree("SIGTERM");
|
|
54826
|
+
setTimeout(() => {
|
|
54827
|
+
if (settled) return;
|
|
54828
|
+
killTree("SIGKILL");
|
|
54829
|
+
}, 5e3).unref();
|
|
54778
54830
|
}, options.timeout);
|
|
54779
54831
|
timer.unref();
|
|
54832
|
+
const onAbort = () => {
|
|
54833
|
+
aborted = true;
|
|
54834
|
+
killTree("SIGTERM");
|
|
54835
|
+
setTimeout(() => {
|
|
54836
|
+
if (settled) return;
|
|
54837
|
+
killTree("SIGKILL");
|
|
54838
|
+
}, 5e3).unref();
|
|
54839
|
+
};
|
|
54840
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
54780
54841
|
child.stdout?.on("data", (chunk) => {
|
|
54781
54842
|
if (stdoutOverflow) return;
|
|
54782
54843
|
if (stdout.length + chunk.length > options.maxBuffer) {
|
|
@@ -54799,6 +54860,14 @@ async function execWithProcessGroup(command, options) {
|
|
|
54799
54860
|
if (settled) return;
|
|
54800
54861
|
settled = true;
|
|
54801
54862
|
clearTimeout(timer);
|
|
54863
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
54864
|
+
if (aborted) {
|
|
54865
|
+
reject2(Object.assign(
|
|
54866
|
+
new Error(`Command aborted: ${command}`),
|
|
54867
|
+
{ code: "ABORT_ERR", aborted: true, stdout, stderr, killed: true }
|
|
54868
|
+
));
|
|
54869
|
+
return;
|
|
54870
|
+
}
|
|
54802
54871
|
if (timedOut) {
|
|
54803
54872
|
reject2(Object.assign(
|
|
54804
54873
|
new Error(`Command timed out after ${options.timeout}ms: ${command}`),
|
|
@@ -54811,7 +54880,7 @@ async function execWithProcessGroup(command, options) {
|
|
|
54811
54880
|
return;
|
|
54812
54881
|
}
|
|
54813
54882
|
if (code === 0) {
|
|
54814
|
-
|
|
54883
|
+
resolve36({ stdout, stderr, bufferOverflow: stdoutOverflow || stderrOverflow });
|
|
54815
54884
|
return;
|
|
54816
54885
|
}
|
|
54817
54886
|
reject2(Object.assign(
|
|
@@ -55152,7 +55221,8 @@ async function runVerificationCommand(store, rootDir, taskId, command, type, sig
|
|
|
55152
55221
|
const { stdout, stderr, bufferOverflow } = await execWithProcessGroup(command, {
|
|
55153
55222
|
cwd: rootDir,
|
|
55154
55223
|
timeout: VERIFICATION_COMMAND_TIMEOUT_MS,
|
|
55155
|
-
maxBuffer: VERIFICATION_COMMAND_MAX_BUFFER
|
|
55224
|
+
maxBuffer: VERIFICATION_COMMAND_MAX_BUFFER,
|
|
55225
|
+
signal
|
|
55156
55226
|
});
|
|
55157
55227
|
throwIfAborted(signal, taskId);
|
|
55158
55228
|
result.stdout = stdout?.toString?.() || "";
|
|
@@ -58269,7 +58339,7 @@ function resolveExecutorModelPair(taskModelProvider, taskModelId, settings) {
|
|
|
58269
58339
|
return { provider: void 0, modelId: void 0 };
|
|
58270
58340
|
}
|
|
58271
58341
|
function sleep2(ms) {
|
|
58272
|
-
return new Promise((
|
|
58342
|
+
return new Promise((resolve36) => setTimeout(resolve36, ms));
|
|
58273
58343
|
}
|
|
58274
58344
|
var execAsync4, stepExecLog, MAX_STEP_RETRIES, RETRY_DELAYS_MS, NOOP_TASK_STORE, StepSessionExecutor;
|
|
58275
58345
|
var init_step_session_executor = __esm({
|
|
@@ -62072,7 +62142,7 @@ Review the work done in this worktree and evaluate it against the criteria in yo
|
|
|
62072
62142
|
);
|
|
62073
62143
|
}
|
|
62074
62144
|
const delay2 = this.WORKTREE_RETRY_DELAYS[attempt] || 1e3;
|
|
62075
|
-
await new Promise((
|
|
62145
|
+
await new Promise((resolve36) => setTimeout(resolve36, delay2));
|
|
62076
62146
|
}
|
|
62077
62147
|
}
|
|
62078
62148
|
throw new Error("Unexpected exit from worktree creation retry loop");
|
|
@@ -68960,8 +69030,8 @@ ${taskDetail.prompt}` : "No PROMPT.md available.",
|
|
|
68960
69030
|
// ../engine/src/self-healing.ts
|
|
68961
69031
|
import { exec as exec8 } from "node:child_process";
|
|
68962
69032
|
import { promisify as promisify9 } from "node:util";
|
|
68963
|
-
import { existsSync as existsSync27, readdirSync as readdirSync5, statSync as statSync5 } from "node:fs";
|
|
68964
|
-
import { join as join33 } from "node:path";
|
|
69033
|
+
import { existsSync as existsSync27, readdirSync as readdirSync5, rmSync as rmSync3, statSync as statSync5 } from "node:fs";
|
|
69034
|
+
import { isAbsolute as isAbsolute11, join as join33, relative as relative7, resolve as resolve14 } from "node:path";
|
|
68965
69035
|
function shellQuote(value) {
|
|
68966
69036
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
68967
69037
|
}
|
|
@@ -70117,15 +70187,26 @@ var init_self_healing = __esm({
|
|
|
70117
70187
|
log7.error(`Worktree prune failed: ${errorMessage}`);
|
|
70118
70188
|
}
|
|
70119
70189
|
}
|
|
70120
|
-
/**
|
|
70190
|
+
/**
|
|
70191
|
+
* Remove orphaned worktrees not assigned to any active task.
|
|
70192
|
+
*
|
|
70193
|
+
* When `recycleWorktrees` is OFF: removes registered idle worktrees too —
|
|
70194
|
+
* they would otherwise pile up since the pool isn't keeping them.
|
|
70195
|
+
*
|
|
70196
|
+
* When `recycleWorktrees` is ON: leaves registered idle worktrees alone
|
|
70197
|
+
* (the pool wants them for reuse) but still reaps unregistered stale dirs
|
|
70198
|
+
* left behind by killed runs (e.g., `clear-hawk-broken`, `*-bak`). Those
|
|
70199
|
+
* dirs can never be recycled — they aren't git worktrees — so they only
|
|
70200
|
+
* waste disk.
|
|
70201
|
+
*/
|
|
70121
70202
|
async cleanupOrphans() {
|
|
70122
70203
|
try {
|
|
70123
|
-
const orphaned = await scanIdleWorktrees(this.options.rootDir, this.store);
|
|
70124
|
-
if (orphaned.length === 0) return 0;
|
|
70125
70204
|
const settings = await this.store.getSettings();
|
|
70126
70205
|
if (settings.recycleWorktrees) {
|
|
70127
|
-
return
|
|
70206
|
+
return await this.reapUnregisteredOrphans();
|
|
70128
70207
|
}
|
|
70208
|
+
const orphaned = await scanIdleWorktrees(this.options.rootDir, this.store);
|
|
70209
|
+
if (orphaned.length === 0) return 0;
|
|
70129
70210
|
let cleaned = 0;
|
|
70130
70211
|
for (const worktreePath of orphaned) {
|
|
70131
70212
|
try {
|
|
@@ -70149,6 +70230,45 @@ var init_self_healing = __esm({
|
|
|
70149
70230
|
return 0;
|
|
70150
70231
|
}
|
|
70151
70232
|
}
|
|
70233
|
+
/**
|
|
70234
|
+
* Sweep unregistered stale directories under `<rootDir>/.worktrees/` —
|
|
70235
|
+
* directories that exist on disk but are NOT registered git worktrees.
|
|
70236
|
+
* Safe to run alongside `recycleWorktrees: true` because the pool only
|
|
70237
|
+
* tracks registered idle worktrees, never these orphans.
|
|
70238
|
+
*/
|
|
70239
|
+
async reapUnregisteredOrphans() {
|
|
70240
|
+
const worktreesDir = join33(this.options.rootDir, ".worktrees");
|
|
70241
|
+
if (!existsSync27(worktreesDir)) return 0;
|
|
70242
|
+
let dirs;
|
|
70243
|
+
try {
|
|
70244
|
+
dirs = readdirSync5(worktreesDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => join33(worktreesDir, e.name));
|
|
70245
|
+
} catch (err) {
|
|
70246
|
+
log7.warn(`Failed to read .worktrees/ for unregistered orphan reap: ${err instanceof Error ? err.message : String(err)}`);
|
|
70247
|
+
return 0;
|
|
70248
|
+
}
|
|
70249
|
+
if (dirs.length === 0) return 0;
|
|
70250
|
+
const registered = await getRegisteredWorktreePaths(this.options.rootDir);
|
|
70251
|
+
const unregistered = dirs.filter((d) => !registered.has(resolve14(d)));
|
|
70252
|
+
let cleaned = 0;
|
|
70253
|
+
for (const path4 of unregistered) {
|
|
70254
|
+
const rel = relative7(worktreesDir, path4);
|
|
70255
|
+
if (rel === "" || rel.startsWith("..") || isAbsolute11(rel)) {
|
|
70256
|
+
log7.warn(`Refusing to remove path outside .worktrees: ${path4}`);
|
|
70257
|
+
continue;
|
|
70258
|
+
}
|
|
70259
|
+
try {
|
|
70260
|
+
rmSync3(path4, { recursive: true, force: true });
|
|
70261
|
+
log7.log(`Cleaned unregistered worktree dir: ${path4}`);
|
|
70262
|
+
cleaned++;
|
|
70263
|
+
} catch (err) {
|
|
70264
|
+
log7.warn(`Failed to remove unregistered worktree dir ${path4}: ${err instanceof Error ? err.message : String(err)}`);
|
|
70265
|
+
}
|
|
70266
|
+
}
|
|
70267
|
+
if (cleaned > 0) {
|
|
70268
|
+
log7.log(`Cleaned ${cleaned} unregistered worktree dir(s) (recycle mode preserves registered idle worktrees)`);
|
|
70269
|
+
}
|
|
70270
|
+
return cleaned;
|
|
70271
|
+
}
|
|
70152
70272
|
/**
|
|
70153
70273
|
* Remove orphaned `fusion/*` branches that are not associated with any
|
|
70154
70274
|
* active (non-archived, non-merger-managed) task.
|
|
@@ -70765,13 +70885,13 @@ var init_plugin_runner = __esm({
|
|
|
70765
70885
|
* Returns the result on success, throws on timeout.
|
|
70766
70886
|
*/
|
|
70767
70887
|
withTimeout(promise, ms, timeoutMessage) {
|
|
70768
|
-
return new Promise((
|
|
70888
|
+
return new Promise((resolve36, reject2) => {
|
|
70769
70889
|
const timer = setTimeout(() => {
|
|
70770
70890
|
reject2(new Error(timeoutMessage));
|
|
70771
70891
|
}, ms);
|
|
70772
70892
|
promise.then((result) => {
|
|
70773
70893
|
clearTimeout(timer);
|
|
70774
|
-
|
|
70894
|
+
resolve36(result);
|
|
70775
70895
|
}).catch((err) => {
|
|
70776
70896
|
clearTimeout(timer);
|
|
70777
70897
|
reject2(err);
|
|
@@ -71429,7 +71549,7 @@ var init_in_process_runtime = __esm({
|
|
|
71429
71549
|
runtimeLog.log(
|
|
71430
71550
|
`Waiting for ${metrics.inFlightTasks} in-flight tasks to complete...`
|
|
71431
71551
|
);
|
|
71432
|
-
await new Promise((
|
|
71552
|
+
await new Promise((resolve36) => setTimeout(resolve36, 1e3));
|
|
71433
71553
|
}
|
|
71434
71554
|
const finalMetrics = this.getMetrics();
|
|
71435
71555
|
if (finalMetrics.inFlightTasks > 0) {
|
|
@@ -71818,13 +71938,13 @@ var init_ipc_host = __esm({
|
|
|
71818
71938
|
}
|
|
71819
71939
|
const id = generateCorrelationId();
|
|
71820
71940
|
const message = { type, id, payload };
|
|
71821
|
-
return new Promise((
|
|
71941
|
+
return new Promise((resolve36, reject2) => {
|
|
71822
71942
|
const timeout2 = setTimeout(() => {
|
|
71823
71943
|
this.pendingCommands.delete(id);
|
|
71824
71944
|
reject2(new Error(`Command ${type} timed out after ${timeoutMs ?? this.commandTimeoutMs}ms`));
|
|
71825
71945
|
}, timeoutMs ?? this.commandTimeoutMs);
|
|
71826
71946
|
this.pendingCommands.set(id, {
|
|
71827
|
-
resolve:
|
|
71947
|
+
resolve: resolve36,
|
|
71828
71948
|
reject: reject2,
|
|
71829
71949
|
timeout: timeout2,
|
|
71830
71950
|
type
|
|
@@ -72633,8 +72753,8 @@ var init_remote_node_client = __esm({
|
|
|
72633
72753
|
return error instanceof TypeError;
|
|
72634
72754
|
}
|
|
72635
72755
|
async sleep(ms) {
|
|
72636
|
-
await new Promise((
|
|
72637
|
-
setTimeout(
|
|
72756
|
+
await new Promise((resolve36) => {
|
|
72757
|
+
setTimeout(resolve36, ms);
|
|
72638
72758
|
});
|
|
72639
72759
|
}
|
|
72640
72760
|
};
|
|
@@ -72898,14 +73018,14 @@ var init_remote_node_runtime = __esm({
|
|
|
72898
73018
|
return error instanceof Error ? error : new Error(String(error));
|
|
72899
73019
|
}
|
|
72900
73020
|
async sleep(ms, signal) {
|
|
72901
|
-
await new Promise((
|
|
73021
|
+
await new Promise((resolve36) => {
|
|
72902
73022
|
const timeout2 = setTimeout(() => {
|
|
72903
73023
|
cleanup();
|
|
72904
|
-
|
|
73024
|
+
resolve36();
|
|
72905
73025
|
}, ms);
|
|
72906
73026
|
const onAbort = () => {
|
|
72907
73027
|
cleanup();
|
|
72908
|
-
|
|
73028
|
+
resolve36();
|
|
72909
73029
|
};
|
|
72910
73030
|
const cleanup = () => {
|
|
72911
73031
|
clearTimeout(timeout2);
|
|
@@ -73666,10 +73786,10 @@ var init_tunnel_process_manager = __esm({
|
|
|
73666
73786
|
lastError: null
|
|
73667
73787
|
});
|
|
73668
73788
|
this.emitLog("info", "manager", `Stopping ${currentHandle.provider} tunnel (pid=${currentHandle.child.pid ?? "n/a"})`);
|
|
73669
|
-
this.activeStopPromise = new Promise((
|
|
73789
|
+
this.activeStopPromise = new Promise((resolve36) => {
|
|
73670
73790
|
const onClose = () => {
|
|
73671
73791
|
currentHandle.child.removeListener("close", onClose);
|
|
73672
|
-
|
|
73792
|
+
resolve36();
|
|
73673
73793
|
};
|
|
73674
73794
|
currentHandle.child.once("close", onClose);
|
|
73675
73795
|
killManagedProcess(currentHandle.child, "SIGTERM");
|
|
@@ -73848,6 +73968,12 @@ var init_project_engine = __esm({
|
|
|
73848
73968
|
manualMergeResolvers = /* @__PURE__ */ new Map();
|
|
73849
73969
|
shuttingDown = false;
|
|
73850
73970
|
static MAX_AUTO_MERGE_RETRIES = 3;
|
|
73971
|
+
/** Cap on outer in-review→in-progress bounces caused by deterministic
|
|
73972
|
+
* verification failures during auto-merge. After this many failed merges
|
|
73973
|
+
* for the same task, we stop bouncing it back, mark it failed, and create
|
|
73974
|
+
* a follow-up triage task so a fresh agent (or human) can investigate
|
|
73975
|
+
* the underlying flake/regression instead of looping forever. */
|
|
73976
|
+
static MAX_VERIFICATION_FAILURE_BOUNCES = 3;
|
|
73851
73977
|
/** 30-minute cooldown before a retry-exhausted task gets another sweep attempt */
|
|
73852
73978
|
static AUTO_MERGE_COOLDOWN_MS = 30 * 60 * 1e3;
|
|
73853
73979
|
// Event handler references for cleanup
|
|
@@ -74132,12 +74258,12 @@ var init_project_engine = __esm({
|
|
|
74132
74258
|
*/
|
|
74133
74259
|
async onMerge(taskId) {
|
|
74134
74260
|
if (this.mergeActive.has(taskId)) {
|
|
74135
|
-
return new Promise((
|
|
74136
|
-
this.manualMergeResolvers.set(taskId, { resolve:
|
|
74261
|
+
return new Promise((resolve36, reject2) => {
|
|
74262
|
+
this.manualMergeResolvers.set(taskId, { resolve: resolve36, reject: reject2 });
|
|
74137
74263
|
});
|
|
74138
74264
|
}
|
|
74139
|
-
return new Promise((
|
|
74140
|
-
this.manualMergeResolvers.set(taskId, { resolve:
|
|
74265
|
+
return new Promise((resolve36, reject2) => {
|
|
74266
|
+
this.manualMergeResolvers.set(taskId, { resolve: resolve36, reject: reject2 });
|
|
74141
74267
|
this.internalEnqueueMerge(taskId);
|
|
74142
74268
|
});
|
|
74143
74269
|
}
|
|
@@ -74524,20 +74650,61 @@ var init_project_engine = __esm({
|
|
|
74524
74650
|
const isVerificationError = err instanceof Error && err.name === "VerificationError" || errorMsg.includes("Deterministic test verification failed") || errorMsg.includes("Deterministic build verification failed");
|
|
74525
74651
|
if (taskOnErr && isVerificationError) {
|
|
74526
74652
|
const failedKind = errorMsg.includes("build verification") ? "build" : "test";
|
|
74653
|
+
const previousBounces = taskOnErr.verificationFailureCount ?? 0;
|
|
74654
|
+
const nextBounces = previousBounces + 1;
|
|
74655
|
+
const cap = _ProjectEngine.MAX_VERIFICATION_FAILURE_BOUNCES;
|
|
74656
|
+
if (nextBounces >= cap) {
|
|
74657
|
+
try {
|
|
74658
|
+
await store.updateTask(taskId, {
|
|
74659
|
+
status: "failed",
|
|
74660
|
+
verificationFailureCount: nextBounces,
|
|
74661
|
+
error: `Deterministic ${failedKind} verification failed ${nextBounces}\xD7 \u2014 auto-merge giving up to avoid infinite retry loop. See follow-up task for investigation.`
|
|
74662
|
+
});
|
|
74663
|
+
const followUpDescription = `Investigate repeated ${failedKind} verification failure on ${taskId} (${taskOnErr.title || "untitled"}). Auto-merge attempted to fix and re-verify ${nextBounces} times without success \u2014 likely a flaky test or unrelated regression rather than a fix this task can produce on its own. Look at the most recent [verification] log entries on ${taskId} for the failing command and output, then either fix the underlying issue or quarantine the flake.`;
|
|
74664
|
+
const followUp = await store.createTask({
|
|
74665
|
+
description: followUpDescription,
|
|
74666
|
+
column: "triage",
|
|
74667
|
+
priority: "high"
|
|
74668
|
+
});
|
|
74669
|
+
await store.addTaskComment(
|
|
74670
|
+
taskId,
|
|
74671
|
+
`Auto-merge giving up after ${nextBounces} verification-failure bounces. Created follow-up ${followUp.id} to investigate.`,
|
|
74672
|
+
"agent"
|
|
74673
|
+
);
|
|
74674
|
+
await store.logEntry(
|
|
74675
|
+
taskId,
|
|
74676
|
+
`Auto-merge gave up after ${nextBounces} verification-failure bounces \u2014 created follow-up ${followUp.id}`,
|
|
74677
|
+
"VerificationError"
|
|
74678
|
+
);
|
|
74679
|
+
runtimeLog.warn(
|
|
74680
|
+
`Auto-merge: ${taskId} hit verification-failure cap (${nextBounces}/${cap}) \u2014 failed task and created follow-up ${followUp.id}`
|
|
74681
|
+
);
|
|
74682
|
+
} catch (followUpErr) {
|
|
74683
|
+
runtimeLog.error(
|
|
74684
|
+
`Auto-merge: failed to fail-and-followup ${taskId} after verification cap: ${followUpErr instanceof Error ? followUpErr.message : String(followUpErr)}`
|
|
74685
|
+
);
|
|
74686
|
+
}
|
|
74687
|
+
continue;
|
|
74688
|
+
}
|
|
74527
74689
|
try {
|
|
74528
74690
|
await store.addTaskComment(
|
|
74529
74691
|
taskId,
|
|
74530
|
-
`Deterministic ${failedKind} verification failed during merge. See the prior [verification] log entry for the truncated command output. Please fix the failing ${failedKind} and push the update so the merge can retry.`,
|
|
74692
|
+
`Deterministic ${failedKind} verification failed during merge (attempt ${nextBounces}/${cap}). See the prior [verification] log entry for the truncated command output. Please fix the failing ${failedKind} and push the update so the merge can retry.`,
|
|
74531
74693
|
"agent"
|
|
74532
74694
|
);
|
|
74533
|
-
await store.updateTask(taskId, {
|
|
74695
|
+
await store.updateTask(taskId, {
|
|
74696
|
+
status: null,
|
|
74697
|
+
mergeRetries: 0,
|
|
74698
|
+
error: null,
|
|
74699
|
+
verificationFailureCount: nextBounces
|
|
74700
|
+
});
|
|
74534
74701
|
await store.moveTask(taskId, "in-progress");
|
|
74535
74702
|
await store.logEntry(
|
|
74536
74703
|
taskId,
|
|
74537
|
-
`Deterministic ${failedKind} verification failed \u2014 moved back to in-progress for remediation`
|
|
74704
|
+
`Deterministic ${failedKind} verification failed (${nextBounces}/${cap}) \u2014 moved back to in-progress for remediation`
|
|
74538
74705
|
);
|
|
74539
74706
|
runtimeLog.log(
|
|
74540
|
-
`Auto-merge: ${taskId} deterministic ${failedKind} verification failed \u2014 moved to in-progress`
|
|
74707
|
+
`Auto-merge: ${taskId} deterministic ${failedKind} verification failed (${nextBounces}/${cap}) \u2014 moved to in-progress`
|
|
74541
74708
|
);
|
|
74542
74709
|
} catch {
|
|
74543
74710
|
runtimeLog.error(
|
|
@@ -74751,6 +74918,11 @@ var init_project_engine = __esm({
|
|
|
74751
74918
|
wireSettingsListeners(store) {
|
|
74752
74919
|
const onGlobalPause = ({ settings, previous }) => {
|
|
74753
74920
|
if (settings.globalPause && !previous.globalPause) {
|
|
74921
|
+
if (this.mergeAbortController) {
|
|
74922
|
+
runtimeLog.log("Global pause \u2014 aborting in-flight merge verification");
|
|
74923
|
+
this.mergeAbortController.abort();
|
|
74924
|
+
this.mergeAbortController = null;
|
|
74925
|
+
}
|
|
74754
74926
|
if (this.activeMergeSession) {
|
|
74755
74927
|
runtimeLog.log("Global pause \u2014 terminating active merge session");
|
|
74756
74928
|
this.activeMergeSession.dispose();
|
|
@@ -75793,7 +75965,6 @@ __export(src_exports2, {
|
|
|
75793
75965
|
taskLogParams: () => taskLogParams,
|
|
75794
75966
|
withRateLimitRetry: () => withRateLimitRetry
|
|
75795
75967
|
});
|
|
75796
|
-
var fusionCoreExports;
|
|
75797
75968
|
var init_src2 = __esm({
|
|
75798
75969
|
"../engine/src/index.ts"() {
|
|
75799
75970
|
"use strict";
|
|
@@ -75808,7 +75979,6 @@ var init_src2 = __esm({
|
|
|
75808
75979
|
init_merger();
|
|
75809
75980
|
init_reviewer();
|
|
75810
75981
|
init_pi();
|
|
75811
|
-
init_src();
|
|
75812
75982
|
init_pi();
|
|
75813
75983
|
init_skill_resolver();
|
|
75814
75984
|
init_agent_reflection();
|
|
@@ -75839,12 +76009,12 @@ var init_src2 = __esm({
|
|
|
75839
76009
|
init_remote_node_client();
|
|
75840
76010
|
init_remote_node_runtime();
|
|
75841
76011
|
init_step_session_executor();
|
|
75842
|
-
|
|
75843
|
-
|
|
75844
|
-
|
|
75845
|
-
|
|
75846
|
-
|
|
75847
|
-
}
|
|
76012
|
+
void Promise.resolve().then(() => (init_src(), src_exports)).then((core) => {
|
|
76013
|
+
if ("setCreateFnAgent" in core && typeof core.setCreateFnAgent === "function") {
|
|
76014
|
+
core.setCreateFnAgent(createFnAgent2);
|
|
76015
|
+
}
|
|
76016
|
+
}).catch(() => {
|
|
76017
|
+
});
|
|
75848
76018
|
}
|
|
75849
76019
|
});
|
|
75850
76020
|
|
|
@@ -75882,17 +76052,6 @@ __export(planning_exports, {
|
|
|
75882
76052
|
});
|
|
75883
76053
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
75884
76054
|
import { EventEmitter as EventEmitter24 } from "node:events";
|
|
75885
|
-
function buildDefaultPlanningNtfyHelpers() {
|
|
75886
|
-
const isNtfyEventEnabled2 = "isNtfyEventEnabled" in src_exports2 ? isNtfyEventEnabled : (events, event) => Array.isArray(events) ? events.includes(event) : false;
|
|
75887
|
-
const buildNtfyClickUrl2 = "buildNtfyClickUrl" in src_exports2 ? buildNtfyClickUrl : () => void 0;
|
|
75888
|
-
const sendNtfyNotification2 = "sendNtfyNotification" in src_exports2 ? sendNtfyNotification : async () => {
|
|
75889
|
-
};
|
|
75890
|
-
return {
|
|
75891
|
-
isNtfyEventEnabled: isNtfyEventEnabled2,
|
|
75892
|
-
buildNtfyClickUrl: buildNtfyClickUrl2,
|
|
75893
|
-
sendNtfyNotification: sendNtfyNotification2
|
|
75894
|
-
};
|
|
75895
|
-
}
|
|
75896
76055
|
function __getPlanningDiagnostics() {
|
|
75897
76056
|
return diagnostics2;
|
|
75898
76057
|
}
|
|
@@ -76860,7 +77019,7 @@ function __resetPlanningState() {
|
|
|
76860
77019
|
}
|
|
76861
77020
|
_aiSessionDeletedListener = void 0;
|
|
76862
77021
|
_aiSessionStore = void 0;
|
|
76863
|
-
planningNtfyHelpers =
|
|
77022
|
+
planningNtfyHelpers = void 0;
|
|
76864
77023
|
resetDiagnosticsSink();
|
|
76865
77024
|
}
|
|
76866
77025
|
function __setCreateFnAgent(mock) {
|
|
@@ -76869,7 +77028,7 @@ function __setCreateFnAgent(mock) {
|
|
|
76869
77028
|
function __setPlanningNtfyHelpers(mock) {
|
|
76870
77029
|
planningNtfyHelpers = mock;
|
|
76871
77030
|
}
|
|
76872
|
-
var createFnAgent4,
|
|
77031
|
+
var createFnAgent4, planningNtfyHelpers, diagnostics2, PLANNING_SYSTEM_PROMPT, SESSION_TTL_MS, CLEANUP_INTERVAL_MS2, MAX_SESSIONS_PER_IP_PER_HOUR, RATE_LIMIT_WINDOW_MS2, sessions, rateLimits2, _aiSessionStore, _aiSessionDeletedListener, cleanupInterval2, PlanningStreamManager, planningStreamManager, MAX_PARSE_RETRIES, RateLimitError2, SessionNotFoundError, InvalidSessionStateError;
|
|
76873
77032
|
var init_planning = __esm({
|
|
76874
77033
|
"../dashboard/src/planning.ts"() {
|
|
76875
77034
|
"use strict";
|
|
@@ -76878,12 +77037,6 @@ var init_planning = __esm({
|
|
|
76878
77037
|
init_ai_session_diagnostics();
|
|
76879
77038
|
init_src2();
|
|
76880
77039
|
createFnAgent4 = createFnAgent2;
|
|
76881
|
-
engineExports = src_exports2;
|
|
76882
|
-
engineIsNtfyEventEnabled = "isNtfyEventEnabled" in engineExports && typeof engineExports["isNtfyEventEnabled"] === "function" ? engineExports["isNtfyEventEnabled"] : (events, event) => Array.isArray(events) && events.includes(event);
|
|
76883
|
-
engineBuildNtfyClickUrl = "buildNtfyClickUrl" in engineExports && typeof engineExports["buildNtfyClickUrl"] === "function" ? engineExports["buildNtfyClickUrl"] : (_options) => void 0;
|
|
76884
|
-
engineSendNtfyNotification = "sendNtfyNotification" in engineExports && typeof engineExports["sendNtfyNotification"] === "function" ? engineExports["sendNtfyNotification"] : async (_input) => {
|
|
76885
|
-
};
|
|
76886
|
-
planningNtfyHelpers = buildDefaultPlanningNtfyHelpers();
|
|
76887
77040
|
diagnostics2 = createSessionDiagnostics("planning");
|
|
76888
77041
|
PLANNING_SYSTEM_PROMPT = `You are a planning assistant for the fn task board system.
|
|
76889
77042
|
|
|
@@ -79511,7 +79664,7 @@ var init_api_error = __esm({
|
|
|
79511
79664
|
// ../dashboard/src/plugin-routes.ts
|
|
79512
79665
|
import { Router } from "express";
|
|
79513
79666
|
import { access as access3, stat as stat6, readFile as readFile17 } from "node:fs/promises";
|
|
79514
|
-
import { join as join35, isAbsolute as
|
|
79667
|
+
import { join as join35, isAbsolute as isAbsolute12, dirname as dirname9, basename as basename8 } from "node:path";
|
|
79515
79668
|
async function resolvePluginManifest(sourcePath) {
|
|
79516
79669
|
try {
|
|
79517
79670
|
await access3(sourcePath);
|
|
@@ -79651,7 +79804,7 @@ var init_project_store_resolver = __esm({
|
|
|
79651
79804
|
|
|
79652
79805
|
// ../dashboard/src/routes/context.ts
|
|
79653
79806
|
import { Router as Router2 } from "express";
|
|
79654
|
-
import { resolve as
|
|
79807
|
+
import { resolve as resolve15, sep as sep5 } from "node:path";
|
|
79655
79808
|
function rethrowAsApiError2(error, fallbackMessage = "Internal server error") {
|
|
79656
79809
|
if (error instanceof ApiError) {
|
|
79657
79810
|
throw error;
|
|
@@ -79753,9 +79906,9 @@ function createApiRoutesContext(store, options) {
|
|
|
79753
79906
|
const planningLogger = runtimeLogger.child("planning");
|
|
79754
79907
|
const chatLogger = runtimeLogger.child("chat");
|
|
79755
79908
|
function prioritizeProjectsForCurrentDirectory(projects) {
|
|
79756
|
-
const cwd =
|
|
79909
|
+
const cwd = resolve15(process.cwd());
|
|
79757
79910
|
const rankProject = (projectPath) => {
|
|
79758
|
-
const normalizedProjectPath =
|
|
79911
|
+
const normalizedProjectPath = resolve15(projectPath);
|
|
79759
79912
|
if (normalizedProjectPath === cwd) {
|
|
79760
79913
|
return Number.MAX_SAFE_INTEGER;
|
|
79761
79914
|
}
|
|
@@ -79769,6 +79922,7 @@ function createApiRoutesContext(store, options) {
|
|
|
79769
79922
|
}
|
|
79770
79923
|
const resolveScopedStore2 = (req) => getScopedStore(req, store);
|
|
79771
79924
|
const resolveProjectContext = (req) => getProjectContext(req, store, options);
|
|
79925
|
+
const disposeCallbacks = [];
|
|
79772
79926
|
function emitAuthSyncAuditLog(input) {
|
|
79773
79927
|
const logger2 = runtimeLogger.child("settings-sync").child("auth");
|
|
79774
79928
|
const level = input.level ?? "info";
|
|
@@ -79890,6 +80044,19 @@ function createApiRoutesContext(store, options) {
|
|
|
79890
80044
|
resolveAutomationStore,
|
|
79891
80045
|
resolveRoutineStore,
|
|
79892
80046
|
resolveRoutineRunner,
|
|
80047
|
+
registerDispose: (callback) => {
|
|
80048
|
+
disposeCallbacks.push(callback);
|
|
80049
|
+
},
|
|
80050
|
+
dispose: () => {
|
|
80051
|
+
while (disposeCallbacks.length > 0) {
|
|
80052
|
+
const callback = disposeCallbacks.pop();
|
|
80053
|
+
if (!callback) continue;
|
|
80054
|
+
try {
|
|
80055
|
+
callback();
|
|
80056
|
+
} catch {
|
|
80057
|
+
}
|
|
80058
|
+
}
|
|
80059
|
+
},
|
|
79893
80060
|
rethrowAsApiError: rethrowAsApiError2
|
|
79894
80061
|
};
|
|
79895
80062
|
}
|
|
@@ -82033,7 +82200,7 @@ __export(chat_exports, {
|
|
|
82033
82200
|
resolveFileReferences: () => resolveFileReferences
|
|
82034
82201
|
});
|
|
82035
82202
|
import { EventEmitter as EventEmitter28 } from "node:events";
|
|
82036
|
-
import { join as join36, resolve as
|
|
82203
|
+
import { join as join36, resolve as resolve16, relative as relative8 } from "node:path";
|
|
82037
82204
|
function __getChatDiagnostics() {
|
|
82038
82205
|
return _diagnostics;
|
|
82039
82206
|
}
|
|
@@ -82060,9 +82227,9 @@ function validateFilePath(basePath, filePath) {
|
|
|
82060
82227
|
if (decodedPath.startsWith("/") || decodedPath.match(/^[a-zA-Z]:/)) {
|
|
82061
82228
|
throw new Error(`Access denied: Absolute paths not allowed`);
|
|
82062
82229
|
}
|
|
82063
|
-
const resolvedBase =
|
|
82064
|
-
const resolvedPath =
|
|
82065
|
-
const relativePath =
|
|
82230
|
+
const resolvedBase = resolve16(basePath);
|
|
82231
|
+
const resolvedPath = resolve16(join36(resolvedBase, decodedPath));
|
|
82232
|
+
const relativePath = relative8(resolvedBase, resolvedPath);
|
|
82066
82233
|
if (relativePath.startsWith("..") || relativePath.startsWith("../") || relativePath === "..") {
|
|
82067
82234
|
throw new Error(`Access denied: Path traversal detected`);
|
|
82068
82235
|
}
|
|
@@ -82144,20 +82311,17 @@ function __setBuildAgentChatPrompt(mock) {
|
|
|
82144
82311
|
function __resetChatState() {
|
|
82145
82312
|
chatStreamManager.reset();
|
|
82146
82313
|
rateLimits5.clear();
|
|
82147
|
-
buildAgentChatPromptFn =
|
|
82314
|
+
buildAgentChatPromptFn = void 0;
|
|
82148
82315
|
__setChatDiagnostics(null);
|
|
82149
82316
|
}
|
|
82150
|
-
var
|
|
82317
|
+
var createFnAgent8, buildAgentChatPromptFn, defaultDiagnostics, _diagnostics, diagnostics6, CHAT_SYSTEM_PROMPT, RATE_LIMIT_WINDOW_MS5, MAX_MESSAGES_PER_IP_PER_MINUTE, MAX_REFERENCED_FILE_SIZE, rateLimits5, ChatStreamManager, chatStreamManager, ChatManager;
|
|
82151
82318
|
var init_chat = __esm({
|
|
82152
82319
|
"../dashboard/src/chat.ts"() {
|
|
82153
82320
|
"use strict";
|
|
82154
82321
|
init_src();
|
|
82155
82322
|
init_sse_buffer();
|
|
82156
82323
|
init_src2();
|
|
82157
|
-
engineExports2 = src_exports2;
|
|
82158
82324
|
createFnAgent8 = createFnAgent2;
|
|
82159
|
-
defaultBuildAgentChatPromptFn = "buildAgentChatPrompt" in engineExports2 && typeof engineExports2["buildAgentChatPrompt"] === "function" ? engineExports2["buildAgentChatPrompt"] : void 0;
|
|
82160
|
-
buildAgentChatPromptFn = defaultBuildAgentChatPromptFn;
|
|
82161
82325
|
defaultDiagnostics = {
|
|
82162
82326
|
log(message, ...args) {
|
|
82163
82327
|
console.log(`[chat] ${message}`, ...args);
|
|
@@ -85259,7 +85423,7 @@ var init_register_messaging_scripts = __esm({
|
|
|
85259
85423
|
|
|
85260
85424
|
// ../dashboard/src/github.ts
|
|
85261
85425
|
function delay(ms) {
|
|
85262
|
-
return new Promise((
|
|
85426
|
+
return new Promise((resolve36) => setTimeout(resolve36, ms));
|
|
85263
85427
|
}
|
|
85264
85428
|
function normalizeCheckState(state) {
|
|
85265
85429
|
switch ((state ?? "").toLowerCase()) {
|
|
@@ -86003,6 +86167,43 @@ var init_github = __esm({
|
|
|
86003
86167
|
}
|
|
86004
86168
|
return response.json();
|
|
86005
86169
|
}
|
|
86170
|
+
async commentOnIssue(owner, repo, issueNumber, body) {
|
|
86171
|
+
if (this.hasGhAuth()) {
|
|
86172
|
+
try {
|
|
86173
|
+
runGh([
|
|
86174
|
+
"issue",
|
|
86175
|
+
"comment",
|
|
86176
|
+
String(issueNumber),
|
|
86177
|
+
"--repo",
|
|
86178
|
+
`${owner}/${repo}`,
|
|
86179
|
+
"--body",
|
|
86180
|
+
body
|
|
86181
|
+
]);
|
|
86182
|
+
return;
|
|
86183
|
+
} catch (err) {
|
|
86184
|
+
if (!this.token) {
|
|
86185
|
+
throw new Error(getGhErrorMessage(err));
|
|
86186
|
+
}
|
|
86187
|
+
}
|
|
86188
|
+
}
|
|
86189
|
+
if (!this.token) {
|
|
86190
|
+
throw new Error("GitHub CLI (gh) is not available or not authenticated, and no GITHUB_TOKEN provided.");
|
|
86191
|
+
}
|
|
86192
|
+
const url = `${this.baseUrl}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${issueNumber}/comments`;
|
|
86193
|
+
const result = await this.fetchThrottled(
|
|
86194
|
+
url,
|
|
86195
|
+
{
|
|
86196
|
+
method: "POST",
|
|
86197
|
+
headers: {
|
|
86198
|
+
"Content-Type": "application/json"
|
|
86199
|
+
},
|
|
86200
|
+
body: JSON.stringify({ body })
|
|
86201
|
+
}
|
|
86202
|
+
);
|
|
86203
|
+
if (!result.success) {
|
|
86204
|
+
throw new Error(result.error ?? "Failed to comment on GitHub issue");
|
|
86205
|
+
}
|
|
86206
|
+
}
|
|
86006
86207
|
/**
|
|
86007
86208
|
* Fetch current issue status using gh CLI if available, otherwise REST API.
|
|
86008
86209
|
* Returns null if the issue is not found or is a pull request.
|
|
@@ -86764,6 +86965,79 @@ var init_github = __esm({
|
|
|
86764
86965
|
}
|
|
86765
86966
|
});
|
|
86766
86967
|
|
|
86968
|
+
// ../dashboard/src/github-issue-comment.ts
|
|
86969
|
+
var DEFAULT_COMMENT_TEMPLATE, GitHubIssueCommentService;
|
|
86970
|
+
var init_github_issue_comment = __esm({
|
|
86971
|
+
"../dashboard/src/github-issue-comment.ts"() {
|
|
86972
|
+
"use strict";
|
|
86973
|
+
init_github();
|
|
86974
|
+
DEFAULT_COMMENT_TEMPLATE = "\u2705 Task {taskId} ({taskTitle}) has been completed and resolved.";
|
|
86975
|
+
GitHubIssueCommentService = class {
|
|
86976
|
+
store;
|
|
86977
|
+
getGitHubToken;
|
|
86978
|
+
onTaskMoved = (event) => {
|
|
86979
|
+
void this.handleTaskMoved(event);
|
|
86980
|
+
};
|
|
86981
|
+
started = false;
|
|
86982
|
+
constructor(store, getGitHubToken) {
|
|
86983
|
+
this.store = store;
|
|
86984
|
+
this.getGitHubToken = getGitHubToken ?? (() => process.env.GITHUB_TOKEN);
|
|
86985
|
+
}
|
|
86986
|
+
start() {
|
|
86987
|
+
if (this.started) return;
|
|
86988
|
+
this.started = true;
|
|
86989
|
+
this.store.on("task:moved", this.onTaskMoved);
|
|
86990
|
+
}
|
|
86991
|
+
stop() {
|
|
86992
|
+
if (!this.started) return;
|
|
86993
|
+
this.started = false;
|
|
86994
|
+
this.store.off("task:moved", this.onTaskMoved);
|
|
86995
|
+
}
|
|
86996
|
+
async handleTaskMoved(event) {
|
|
86997
|
+
if (event.to !== "done") {
|
|
86998
|
+
return;
|
|
86999
|
+
}
|
|
87000
|
+
const task = event.task;
|
|
87001
|
+
const settings = await this.store.getSettings();
|
|
87002
|
+
if (!settings.githubCommentOnDone) {
|
|
87003
|
+
return;
|
|
87004
|
+
}
|
|
87005
|
+
const sourceIssue = task.sourceIssue;
|
|
87006
|
+
if (!sourceIssue || sourceIssue.provider !== "github") {
|
|
87007
|
+
return;
|
|
87008
|
+
}
|
|
87009
|
+
const [owner, repo] = sourceIssue.repository.split("/");
|
|
87010
|
+
if (!owner || !repo) {
|
|
87011
|
+
await this.store.logEntry(
|
|
87012
|
+
task.id,
|
|
87013
|
+
"Failed to post GitHub issue comment",
|
|
87014
|
+
`Invalid GitHub repository format: ${sourceIssue.repository}`
|
|
87015
|
+
);
|
|
87016
|
+
return;
|
|
87017
|
+
}
|
|
87018
|
+
const template = settings.githubCommentTemplate || DEFAULT_COMMENT_TEMPLATE;
|
|
87019
|
+
const commentBody = template.replaceAll("{taskId}", task.id).replaceAll("{taskTitle}", task.title ?? "");
|
|
87020
|
+
try {
|
|
87021
|
+
const client = new GitHubClient(this.getGitHubToken());
|
|
87022
|
+
await client.commentOnIssue(owner, repo, sourceIssue.issueNumber, commentBody);
|
|
87023
|
+
await this.store.logEntry(
|
|
87024
|
+
task.id,
|
|
87025
|
+
"Posted GitHub issue completion comment",
|
|
87026
|
+
`${sourceIssue.repository}#${sourceIssue.issueNumber}`
|
|
87027
|
+
);
|
|
87028
|
+
} catch (error) {
|
|
87029
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
87030
|
+
await this.store.logEntry(
|
|
87031
|
+
task.id,
|
|
87032
|
+
"Failed to post GitHub issue comment",
|
|
87033
|
+
message
|
|
87034
|
+
);
|
|
87035
|
+
}
|
|
87036
|
+
}
|
|
87037
|
+
};
|
|
87038
|
+
}
|
|
87039
|
+
});
|
|
87040
|
+
|
|
86767
87041
|
// ../dashboard/src/github-poll.ts
|
|
86768
87042
|
import { EventEmitter as EventEmitter30 } from "node:events";
|
|
86769
87043
|
function toAlias(type, number) {
|
|
@@ -87117,7 +87391,7 @@ var init_resolve_diff_base = __esm({
|
|
|
87117
87391
|
});
|
|
87118
87392
|
|
|
87119
87393
|
// ../dashboard/src/routes/register-git-github.ts
|
|
87120
|
-
import { isAbsolute as
|
|
87394
|
+
import { isAbsolute as isAbsolute13 } from "node:path";
|
|
87121
87395
|
function getCommandErrorMessage2(error) {
|
|
87122
87396
|
if (error instanceof Error) {
|
|
87123
87397
|
const anyError = error;
|
|
@@ -87717,7 +87991,7 @@ async function getGitWorkingDiff(cwd) {
|
|
|
87717
87991
|
function isValidGitFilePath(filePath) {
|
|
87718
87992
|
if (!filePath || !filePath.trim()) return false;
|
|
87719
87993
|
if (filePath.startsWith("-")) return false;
|
|
87720
|
-
if (
|
|
87994
|
+
if (isAbsolute13(filePath)) return false;
|
|
87721
87995
|
if (filePath.includes("\0")) return false;
|
|
87722
87996
|
if (filePath.includes("..")) return false;
|
|
87723
87997
|
if (/[;&|`$(){}[\]\r\n]/.test(filePath)) return false;
|
|
@@ -87929,8 +88203,16 @@ async function refreshIssueInBackground(store, taskId, currentIssueInfo, token)
|
|
|
87929
88203
|
}
|
|
87930
88204
|
}
|
|
87931
88205
|
function registerGitGitHubRoutes(ctx) {
|
|
87932
|
-
const { router, getProjectContext: getProjectContext3, rethrowAsApiError: rethrowAsApiError7 } = ctx;
|
|
88206
|
+
const { router, getProjectContext: getProjectContext3, rethrowAsApiError: rethrowAsApiError7, store } = ctx;
|
|
87933
88207
|
const githubToken = ctx.options?.githubToken ?? process.env.GITHUB_TOKEN;
|
|
88208
|
+
if (typeof store.on === "function" && typeof store.off === "function") {
|
|
88209
|
+
const githubIssueCommentService = new GitHubIssueCommentService(
|
|
88210
|
+
store,
|
|
88211
|
+
() => ctx.options?.githubToken ?? process.env.GITHUB_TOKEN
|
|
88212
|
+
);
|
|
88213
|
+
githubIssueCommentService.start();
|
|
88214
|
+
ctx.registerDispose(() => githubIssueCommentService.stop());
|
|
88215
|
+
}
|
|
87934
88216
|
router.get("/git/remotes", async (req, res) => {
|
|
87935
88217
|
try {
|
|
87936
88218
|
const { store: scopedStore } = await getProjectContext3(req);
|
|
@@ -89473,6 +89755,7 @@ var init_register_git_github = __esm({
|
|
|
89473
89755
|
init_src();
|
|
89474
89756
|
init_api_error();
|
|
89475
89757
|
init_github();
|
|
89758
|
+
init_github_issue_comment();
|
|
89476
89759
|
init_github_poll();
|
|
89477
89760
|
init_github_webhooks();
|
|
89478
89761
|
init_resolve_diff_base();
|
|
@@ -89768,7 +90051,7 @@ var init_terminal = __esm({
|
|
|
89768
90051
|
});
|
|
89769
90052
|
|
|
89770
90053
|
// ../dashboard/src/file-service.ts
|
|
89771
|
-
import { join as join38, resolve as
|
|
90054
|
+
import { join as join38, resolve as resolve18, relative as relative9, dirname as dirname11, basename as basename10 } from "node:path";
|
|
89772
90055
|
import { readdir as readdir8, readFile as fsReadFile, writeFile as fsWriteFile, stat as stat7, copyFile as fsCopyFile, rename as fsRename, rm as fsRm, mkdir as mkdir12, access as access4 } from "node:fs/promises";
|
|
89773
90056
|
async function getTaskBasePath(store, taskId) {
|
|
89774
90057
|
try {
|
|
@@ -89776,12 +90059,12 @@ async function getTaskBasePath(store, taskId) {
|
|
|
89776
90059
|
if (task.worktree) {
|
|
89777
90060
|
try {
|
|
89778
90061
|
await access4(task.worktree);
|
|
89779
|
-
return
|
|
90062
|
+
return resolve18(task.worktree);
|
|
89780
90063
|
} catch {
|
|
89781
90064
|
}
|
|
89782
90065
|
}
|
|
89783
90066
|
const rootDir = store.getRootDir();
|
|
89784
|
-
return
|
|
90067
|
+
return resolve18(join38(rootDir, ".fusion", "tasks", taskId));
|
|
89785
90068
|
} catch (err) {
|
|
89786
90069
|
const error = err;
|
|
89787
90070
|
if (error.code === "ENOENT" || error.message && error.message.includes("not found")) {
|
|
@@ -89791,7 +90074,7 @@ async function getTaskBasePath(store, taskId) {
|
|
|
89791
90074
|
}
|
|
89792
90075
|
}
|
|
89793
90076
|
function getProjectBasePath(store) {
|
|
89794
|
-
return
|
|
90077
|
+
return resolve18(store.getRootDir());
|
|
89795
90078
|
}
|
|
89796
90079
|
async function getWorkspaceBasePath(store, workspace) {
|
|
89797
90080
|
if (workspace === "project") {
|
|
@@ -89807,9 +90090,9 @@ function validatePath(basePath, filePath) {
|
|
|
89807
90090
|
if (decodedPath.startsWith("/") || decodedPath.match(/^[a-zA-Z]:/)) {
|
|
89808
90091
|
throw new FileServiceError(`Access denied: Absolute paths not allowed`, "EINVAL");
|
|
89809
90092
|
}
|
|
89810
|
-
const resolvedBase =
|
|
89811
|
-
const resolvedPath =
|
|
89812
|
-
const relativePath =
|
|
90093
|
+
const resolvedBase = resolve18(basePath);
|
|
90094
|
+
const resolvedPath = resolve18(join38(resolvedBase, decodedPath));
|
|
90095
|
+
const relativePath = relative9(resolvedBase, resolvedPath);
|
|
89813
90096
|
if (relativePath.startsWith("..") || relativePath.startsWith("../") || relativePath === "..") {
|
|
89814
90097
|
throw new FileServiceError(`Access denied: Path traversal detected`, "EINVAL");
|
|
89815
90098
|
}
|
|
@@ -89852,7 +90135,7 @@ async function listFilesForBasePath(basePath, subPath) {
|
|
|
89852
90135
|
}
|
|
89853
90136
|
return a.name.localeCompare(b.name);
|
|
89854
90137
|
});
|
|
89855
|
-
const relativeBase =
|
|
90138
|
+
const relativeBase = relative9(basePath, targetPath);
|
|
89856
90139
|
return {
|
|
89857
90140
|
path: relativeBase || ".",
|
|
89858
90141
|
entries: fileNodes
|
|
@@ -89986,7 +90269,7 @@ async function writeWorkspaceFile(store, workspace, filePath, content) {
|
|
|
89986
90269
|
function validateSourceAndDestination(basePath, sourcePath, destinationPath) {
|
|
89987
90270
|
const resolvedSource = validatePath(basePath, sourcePath);
|
|
89988
90271
|
const resolvedDest = validatePath(basePath, destinationPath);
|
|
89989
|
-
const sourceRelative =
|
|
90272
|
+
const sourceRelative = relative9(resolve18(basePath), resolvedSource);
|
|
89990
90273
|
if (!sourceRelative || sourceRelative === "." || sourceRelative === "") {
|
|
89991
90274
|
throw new FileServiceError("Cannot operate on workspace root directory", "EINVAL");
|
|
89992
90275
|
}
|
|
@@ -90110,7 +90393,7 @@ async function deleteWorkspaceFile(store, workspace, filePath) {
|
|
|
90110
90393
|
}
|
|
90111
90394
|
const workspaceBase = await getWorkspaceBasePath(store, workspace);
|
|
90112
90395
|
const resolvedPath = validatePath(workspaceBase, filePath);
|
|
90113
|
-
const relativePath =
|
|
90396
|
+
const relativePath = relative9(resolve18(workspaceBase), resolvedPath);
|
|
90114
90397
|
if (!relativePath || relativePath === "." || relativePath === "") {
|
|
90115
90398
|
throw new FileServiceError("Cannot delete workspace root directory", "EINVAL");
|
|
90116
90399
|
}
|
|
@@ -90151,7 +90434,7 @@ async function renameWorkspaceFile(store, workspace, filePath, newName) {
|
|
|
90151
90434
|
}
|
|
90152
90435
|
const workspaceBase = await getWorkspaceBasePath(store, workspace);
|
|
90153
90436
|
const resolvedPath = validatePath(workspaceBase, filePath);
|
|
90154
|
-
const relativePath =
|
|
90437
|
+
const relativePath = relative9(resolve18(workspaceBase), resolvedPath);
|
|
90155
90438
|
if (!relativePath || relativePath === "." || relativePath === "") {
|
|
90156
90439
|
throw new FileServiceError("Cannot rename workspace root directory", "EINVAL");
|
|
90157
90440
|
}
|
|
@@ -90165,11 +90448,11 @@ async function renameWorkspaceFile(store, workspace, filePath, newName) {
|
|
|
90165
90448
|
throw err;
|
|
90166
90449
|
}
|
|
90167
90450
|
const destPath = join38(dirname11(resolvedPath), newName);
|
|
90168
|
-
const destRelative =
|
|
90451
|
+
const destRelative = relative9(resolve18(workspaceBase), destPath);
|
|
90169
90452
|
if (destRelative.startsWith("..") || destRelative.startsWith("../") || destRelative === "..") {
|
|
90170
90453
|
throw new FileServiceError("Destination would be outside workspace", "EINVAL");
|
|
90171
90454
|
}
|
|
90172
|
-
if (!destPath.startsWith(
|
|
90455
|
+
if (!destPath.startsWith(resolve18(workspaceBase))) {
|
|
90173
90456
|
throw new FileServiceError("Destination would be outside workspace", "EINVAL");
|
|
90174
90457
|
}
|
|
90175
90458
|
try {
|
|
@@ -90198,7 +90481,7 @@ async function getWorkspaceFileForDownload(store, workspace, filePath) {
|
|
|
90198
90481
|
}
|
|
90199
90482
|
const workspaceBase = await getWorkspaceBasePath(store, workspace);
|
|
90200
90483
|
const resolvedPath = validatePath(workspaceBase, filePath);
|
|
90201
|
-
const relativePath =
|
|
90484
|
+
const relativePath = relative9(resolve18(workspaceBase), resolvedPath);
|
|
90202
90485
|
if (!relativePath || relativePath === "." || relativePath === "") {
|
|
90203
90486
|
throw new FileServiceError("Cannot download workspace root", "EINVAL");
|
|
90204
90487
|
}
|
|
@@ -90231,7 +90514,7 @@ async function getWorkspaceFolderForZip(store, workspace, dirPath) {
|
|
|
90231
90514
|
}
|
|
90232
90515
|
const workspaceBase = await getWorkspaceBasePath(store, workspace);
|
|
90233
90516
|
const resolvedPath = validatePath(workspaceBase, dirPath);
|
|
90234
|
-
const relativePath =
|
|
90517
|
+
const relativePath = relative9(resolve18(workspaceBase), resolvedPath);
|
|
90235
90518
|
if (!relativePath || relativePath === "." || relativePath === "") {
|
|
90236
90519
|
throw new FileServiceError("Cannot download workspace root as ZIP", "EINVAL");
|
|
90237
90520
|
}
|
|
@@ -91362,9 +91645,9 @@ var require_readdir_glob = __commonJS({
|
|
|
91362
91645
|
var fs2 = __require("fs");
|
|
91363
91646
|
var { EventEmitter: EventEmitter35 } = __require("events");
|
|
91364
91647
|
var { Minimatch } = require_minimatch();
|
|
91365
|
-
var { resolve:
|
|
91648
|
+
var { resolve: resolve36 } = __require("path");
|
|
91366
91649
|
function readdir12(dir2, strict) {
|
|
91367
|
-
return new Promise((
|
|
91650
|
+
return new Promise((resolve37, reject2) => {
|
|
91368
91651
|
fs2.readdir(dir2, { withFileTypes: true }, (err, files) => {
|
|
91369
91652
|
if (err) {
|
|
91370
91653
|
switch (err.code) {
|
|
@@ -91372,7 +91655,7 @@ var require_readdir_glob = __commonJS({
|
|
|
91372
91655
|
if (strict) {
|
|
91373
91656
|
reject2(err);
|
|
91374
91657
|
} else {
|
|
91375
|
-
|
|
91658
|
+
resolve37([]);
|
|
91376
91659
|
}
|
|
91377
91660
|
break;
|
|
91378
91661
|
case "ENOTSUP":
|
|
@@ -91382,7 +91665,7 @@ var require_readdir_glob = __commonJS({
|
|
|
91382
91665
|
case "ENAMETOOLONG":
|
|
91383
91666
|
// Filename too long
|
|
91384
91667
|
case "UNKNOWN":
|
|
91385
|
-
|
|
91668
|
+
resolve37([]);
|
|
91386
91669
|
break;
|
|
91387
91670
|
case "ELOOP":
|
|
91388
91671
|
// Too many levels of symbolic links
|
|
@@ -91391,30 +91674,30 @@ var require_readdir_glob = __commonJS({
|
|
|
91391
91674
|
break;
|
|
91392
91675
|
}
|
|
91393
91676
|
} else {
|
|
91394
|
-
|
|
91677
|
+
resolve37(files);
|
|
91395
91678
|
}
|
|
91396
91679
|
});
|
|
91397
91680
|
});
|
|
91398
91681
|
}
|
|
91399
91682
|
function stat12(file, followSymlinks) {
|
|
91400
|
-
return new Promise((
|
|
91683
|
+
return new Promise((resolve37, reject2) => {
|
|
91401
91684
|
const statFunc = followSymlinks ? fs2.stat : fs2.lstat;
|
|
91402
91685
|
statFunc(file, (err, stats) => {
|
|
91403
91686
|
if (err) {
|
|
91404
91687
|
switch (err.code) {
|
|
91405
91688
|
case "ENOENT":
|
|
91406
91689
|
if (followSymlinks) {
|
|
91407
|
-
|
|
91690
|
+
resolve37(stat12(file, false));
|
|
91408
91691
|
} else {
|
|
91409
|
-
|
|
91692
|
+
resolve37(null);
|
|
91410
91693
|
}
|
|
91411
91694
|
break;
|
|
91412
91695
|
default:
|
|
91413
|
-
|
|
91696
|
+
resolve37(null);
|
|
91414
91697
|
break;
|
|
91415
91698
|
}
|
|
91416
91699
|
} else {
|
|
91417
|
-
|
|
91700
|
+
resolve37(stats);
|
|
91418
91701
|
}
|
|
91419
91702
|
});
|
|
91420
91703
|
});
|
|
@@ -91428,8 +91711,8 @@ var require_readdir_glob = __commonJS({
|
|
|
91428
91711
|
useStat = true;
|
|
91429
91712
|
}
|
|
91430
91713
|
const filename = dir2 + "/" + name;
|
|
91431
|
-
const
|
|
91432
|
-
const absolute = path4 + "/" +
|
|
91714
|
+
const relative13 = filename.slice(1);
|
|
91715
|
+
const absolute = path4 + "/" + relative13;
|
|
91433
91716
|
let stats = null;
|
|
91434
91717
|
if (useStat || followSymlinks) {
|
|
91435
91718
|
stats = await stat12(absolute, followSymlinks);
|
|
@@ -91441,12 +91724,12 @@ var require_readdir_glob = __commonJS({
|
|
|
91441
91724
|
stats = { isDirectory: () => false };
|
|
91442
91725
|
}
|
|
91443
91726
|
if (stats.isDirectory()) {
|
|
91444
|
-
if (!shouldSkip(
|
|
91445
|
-
yield { relative:
|
|
91727
|
+
if (!shouldSkip(relative13)) {
|
|
91728
|
+
yield { relative: relative13, absolute, stats };
|
|
91446
91729
|
yield* exploreWalkAsync(filename, path4, followSymlinks, useStat, shouldSkip, false);
|
|
91447
91730
|
}
|
|
91448
91731
|
} else {
|
|
91449
|
-
yield { relative:
|
|
91732
|
+
yield { relative: relative13, absolute, stats };
|
|
91450
91733
|
}
|
|
91451
91734
|
}
|
|
91452
91735
|
}
|
|
@@ -91504,7 +91787,7 @@ var require_readdir_glob = __commonJS({
|
|
|
91504
91787
|
(skip) => new Minimatch(skip, { dot: true })
|
|
91505
91788
|
);
|
|
91506
91789
|
}
|
|
91507
|
-
this.iterator = explore(
|
|
91790
|
+
this.iterator = explore(resolve36(cwd || "."), this.options.follow, this.options.stat, this._shouldSkipDirectory.bind(this));
|
|
91508
91791
|
this.paused = false;
|
|
91509
91792
|
this.inactive = false;
|
|
91510
91793
|
this.aborted = false;
|
|
@@ -91516,11 +91799,11 @@ var require_readdir_glob = __commonJS({
|
|
|
91516
91799
|
}
|
|
91517
91800
|
setTimeout(() => this._next(), 0);
|
|
91518
91801
|
}
|
|
91519
|
-
_shouldSkipDirectory(
|
|
91520
|
-
return this.skipMatchers.some((m) => m.match(
|
|
91802
|
+
_shouldSkipDirectory(relative13) {
|
|
91803
|
+
return this.skipMatchers.some((m) => m.match(relative13));
|
|
91521
91804
|
}
|
|
91522
|
-
_fileMatches(
|
|
91523
|
-
const file =
|
|
91805
|
+
_fileMatches(relative13, isDirectory) {
|
|
91806
|
+
const file = relative13 + (isDirectory ? "/" : "");
|
|
91524
91807
|
return (this.matchers.length === 0 || this.matchers.some((m) => m.match(file))) && !this.ignoreMatchers.some((m) => m.match(file)) && (!this.options.nodir || !isDirectory);
|
|
91525
91808
|
}
|
|
91526
91809
|
_next() {
|
|
@@ -91529,16 +91812,16 @@ var require_readdir_glob = __commonJS({
|
|
|
91529
91812
|
if (!obj.done) {
|
|
91530
91813
|
const isDirectory = obj.value.stats.isDirectory();
|
|
91531
91814
|
if (this._fileMatches(obj.value.relative, isDirectory)) {
|
|
91532
|
-
let
|
|
91815
|
+
let relative13 = obj.value.relative;
|
|
91533
91816
|
let absolute = obj.value.absolute;
|
|
91534
91817
|
if (this.options.mark && isDirectory) {
|
|
91535
|
-
|
|
91818
|
+
relative13 += "/";
|
|
91536
91819
|
absolute += "/";
|
|
91537
91820
|
}
|
|
91538
91821
|
if (this.options.stat) {
|
|
91539
|
-
this.emit("match", { relative:
|
|
91822
|
+
this.emit("match", { relative: relative13, absolute, stat: obj.value.stats });
|
|
91540
91823
|
} else {
|
|
91541
|
-
this.emit("match", { relative:
|
|
91824
|
+
this.emit("match", { relative: relative13, absolute });
|
|
91542
91825
|
}
|
|
91543
91826
|
}
|
|
91544
91827
|
this._next(this.iterator);
|
|
@@ -91758,10 +92041,10 @@ function awaitify(asyncFn, arity) {
|
|
|
91758
92041
|
if (typeof args[arity - 1] === "function") {
|
|
91759
92042
|
return asyncFn.apply(this, args);
|
|
91760
92043
|
}
|
|
91761
|
-
return new Promise((
|
|
92044
|
+
return new Promise((resolve36, reject2) => {
|
|
91762
92045
|
args[arity - 1] = (err, ...cbArgs) => {
|
|
91763
92046
|
if (err) return reject2(err);
|
|
91764
|
-
|
|
92047
|
+
resolve36(cbArgs.length > 1 ? cbArgs : cbArgs[0]);
|
|
91765
92048
|
};
|
|
91766
92049
|
asyncFn.apply(this, args);
|
|
91767
92050
|
});
|
|
@@ -91943,13 +92226,13 @@ function mapSeries(coll, iteratee, callback) {
|
|
|
91943
92226
|
return _asyncMap(eachOfSeries$1, coll, iteratee, callback);
|
|
91944
92227
|
}
|
|
91945
92228
|
function promiseCallback() {
|
|
91946
|
-
let
|
|
92229
|
+
let resolve36, reject2;
|
|
91947
92230
|
function callback(err, ...args) {
|
|
91948
92231
|
if (err) return reject2(err);
|
|
91949
|
-
|
|
92232
|
+
resolve36(args.length > 1 ? args : args[0]);
|
|
91950
92233
|
}
|
|
91951
92234
|
callback[PROMISE_SYMBOL] = new Promise((res, rej) => {
|
|
91952
|
-
|
|
92235
|
+
resolve36 = res, reject2 = rej;
|
|
91953
92236
|
});
|
|
91954
92237
|
return callback;
|
|
91955
92238
|
}
|
|
@@ -92222,8 +92505,8 @@ function queue$1(worker, concurrency, payload) {
|
|
|
92222
92505
|
});
|
|
92223
92506
|
}
|
|
92224
92507
|
if (rejectOnError || !callback) {
|
|
92225
|
-
return new Promise((
|
|
92226
|
-
res =
|
|
92508
|
+
return new Promise((resolve36, reject2) => {
|
|
92509
|
+
res = resolve36;
|
|
92227
92510
|
rej = reject2;
|
|
92228
92511
|
});
|
|
92229
92512
|
}
|
|
@@ -92262,10 +92545,10 @@ function queue$1(worker, concurrency, payload) {
|
|
|
92262
92545
|
}
|
|
92263
92546
|
const eventMethod = (name) => (handler) => {
|
|
92264
92547
|
if (!handler) {
|
|
92265
|
-
return new Promise((
|
|
92548
|
+
return new Promise((resolve36, reject2) => {
|
|
92266
92549
|
once3(name, (err, data) => {
|
|
92267
92550
|
if (err) return reject2(err);
|
|
92268
|
-
|
|
92551
|
+
resolve36(data);
|
|
92269
92552
|
});
|
|
92270
92553
|
});
|
|
92271
92554
|
}
|
|
@@ -98271,25 +98554,25 @@ var require_util2 = __commonJS({
|
|
|
98271
98554
|
};
|
|
98272
98555
|
},
|
|
98273
98556
|
createDeferredPromise: function() {
|
|
98274
|
-
let
|
|
98557
|
+
let resolve36;
|
|
98275
98558
|
let reject2;
|
|
98276
98559
|
const promise = new Promise((res, rej) => {
|
|
98277
|
-
|
|
98560
|
+
resolve36 = res;
|
|
98278
98561
|
reject2 = rej;
|
|
98279
98562
|
});
|
|
98280
98563
|
return {
|
|
98281
98564
|
promise,
|
|
98282
|
-
resolve:
|
|
98565
|
+
resolve: resolve36,
|
|
98283
98566
|
reject: reject2
|
|
98284
98567
|
};
|
|
98285
98568
|
},
|
|
98286
98569
|
promisify(fn) {
|
|
98287
|
-
return new Promise((
|
|
98570
|
+
return new Promise((resolve36, reject2) => {
|
|
98288
98571
|
fn((err, ...args) => {
|
|
98289
98572
|
if (err) {
|
|
98290
98573
|
return reject2(err);
|
|
98291
98574
|
}
|
|
98292
|
-
return
|
|
98575
|
+
return resolve36(...args);
|
|
98293
98576
|
});
|
|
98294
98577
|
});
|
|
98295
98578
|
},
|
|
@@ -99081,7 +99364,7 @@ var require_end_of_stream2 = __commonJS({
|
|
|
99081
99364
|
validateBoolean3(opts.cleanup, "cleanup");
|
|
99082
99365
|
autoCleanup = opts.cleanup;
|
|
99083
99366
|
}
|
|
99084
|
-
return new Promise2((
|
|
99367
|
+
return new Promise2((resolve36, reject2) => {
|
|
99085
99368
|
const cleanup = eos(stream, opts, (err) => {
|
|
99086
99369
|
if (autoCleanup) {
|
|
99087
99370
|
cleanup();
|
|
@@ -99089,7 +99372,7 @@ var require_end_of_stream2 = __commonJS({
|
|
|
99089
99372
|
if (err) {
|
|
99090
99373
|
reject2(err);
|
|
99091
99374
|
} else {
|
|
99092
|
-
|
|
99375
|
+
resolve36();
|
|
99093
99376
|
}
|
|
99094
99377
|
});
|
|
99095
99378
|
});
|
|
@@ -100256,7 +100539,7 @@ var require_readable2 = __commonJS({
|
|
|
100256
100539
|
error = this.readableEnded ? null : new AbortError();
|
|
100257
100540
|
this.destroy(error);
|
|
100258
100541
|
}
|
|
100259
|
-
return new Promise2((
|
|
100542
|
+
return new Promise2((resolve36, reject2) => eos(this, (err) => err && err !== error ? reject2(err) : resolve36(null)));
|
|
100260
100543
|
};
|
|
100261
100544
|
Readable2.prototype.push = function(chunk, encoding) {
|
|
100262
100545
|
return readableAddChunk(this, chunk, encoding, false);
|
|
@@ -100800,12 +101083,12 @@ var require_readable2 = __commonJS({
|
|
|
100800
101083
|
}
|
|
100801
101084
|
async function* createAsyncIterator(stream, options) {
|
|
100802
101085
|
let callback = nop;
|
|
100803
|
-
function next(
|
|
101086
|
+
function next(resolve36) {
|
|
100804
101087
|
if (this === stream) {
|
|
100805
101088
|
callback();
|
|
100806
101089
|
callback = nop;
|
|
100807
101090
|
} else {
|
|
100808
|
-
callback =
|
|
101091
|
+
callback = resolve36;
|
|
100809
101092
|
}
|
|
100810
101093
|
}
|
|
100811
101094
|
stream.on("readable", next);
|
|
@@ -101858,7 +102141,7 @@ var require_duplexify = __commonJS({
|
|
|
101858
102141
|
);
|
|
101859
102142
|
};
|
|
101860
102143
|
function fromAsyncGen(fn) {
|
|
101861
|
-
let { promise, resolve:
|
|
102144
|
+
let { promise, resolve: resolve36 } = createDeferredPromise();
|
|
101862
102145
|
const ac = new AbortController2();
|
|
101863
102146
|
const signal = ac.signal;
|
|
101864
102147
|
const value = fn(
|
|
@@ -101873,7 +102156,7 @@ var require_duplexify = __commonJS({
|
|
|
101873
102156
|
throw new AbortError(void 0, {
|
|
101874
102157
|
cause: signal.reason
|
|
101875
102158
|
});
|
|
101876
|
-
({ promise, resolve:
|
|
102159
|
+
({ promise, resolve: resolve36 } = createDeferredPromise());
|
|
101877
102160
|
yield chunk;
|
|
101878
102161
|
}
|
|
101879
102162
|
})(),
|
|
@@ -101884,8 +102167,8 @@ var require_duplexify = __commonJS({
|
|
|
101884
102167
|
return {
|
|
101885
102168
|
value,
|
|
101886
102169
|
write(chunk, encoding, cb) {
|
|
101887
|
-
const _resolve =
|
|
101888
|
-
|
|
102170
|
+
const _resolve = resolve36;
|
|
102171
|
+
resolve36 = null;
|
|
101889
102172
|
_resolve({
|
|
101890
102173
|
chunk,
|
|
101891
102174
|
done: false,
|
|
@@ -101893,8 +102176,8 @@ var require_duplexify = __commonJS({
|
|
|
101893
102176
|
});
|
|
101894
102177
|
},
|
|
101895
102178
|
final(cb) {
|
|
101896
|
-
const _resolve =
|
|
101897
|
-
|
|
102179
|
+
const _resolve = resolve36;
|
|
102180
|
+
resolve36 = null;
|
|
101898
102181
|
_resolve({
|
|
101899
102182
|
done: true,
|
|
101900
102183
|
cb
|
|
@@ -102346,7 +102629,7 @@ var require_pipeline = __commonJS({
|
|
|
102346
102629
|
callback();
|
|
102347
102630
|
}
|
|
102348
102631
|
};
|
|
102349
|
-
const wait = () => new Promise2((
|
|
102632
|
+
const wait = () => new Promise2((resolve36, reject2) => {
|
|
102350
102633
|
if (error) {
|
|
102351
102634
|
reject2(error);
|
|
102352
102635
|
} else {
|
|
@@ -102354,7 +102637,7 @@ var require_pipeline = __commonJS({
|
|
|
102354
102637
|
if (error) {
|
|
102355
102638
|
reject2(error);
|
|
102356
102639
|
} else {
|
|
102357
|
-
|
|
102640
|
+
resolve36();
|
|
102358
102641
|
}
|
|
102359
102642
|
};
|
|
102360
102643
|
}
|
|
@@ -102998,8 +103281,8 @@ var require_operators = __commonJS({
|
|
|
102998
103281
|
next = null;
|
|
102999
103282
|
}
|
|
103000
103283
|
if (!done && (queue2.length >= highWaterMark2 || cnt >= concurrency)) {
|
|
103001
|
-
await new Promise2((
|
|
103002
|
-
resume =
|
|
103284
|
+
await new Promise2((resolve36) => {
|
|
103285
|
+
resume = resolve36;
|
|
103003
103286
|
});
|
|
103004
103287
|
}
|
|
103005
103288
|
}
|
|
@@ -103033,8 +103316,8 @@ var require_operators = __commonJS({
|
|
|
103033
103316
|
queue2.shift();
|
|
103034
103317
|
maybeResume();
|
|
103035
103318
|
}
|
|
103036
|
-
await new Promise2((
|
|
103037
|
-
next =
|
|
103319
|
+
await new Promise2((resolve36) => {
|
|
103320
|
+
next = resolve36;
|
|
103038
103321
|
});
|
|
103039
103322
|
}
|
|
103040
103323
|
} finally {
|
|
@@ -103292,7 +103575,7 @@ var require_promises = __commonJS({
|
|
|
103292
103575
|
var { finished } = require_end_of_stream2();
|
|
103293
103576
|
require_stream2();
|
|
103294
103577
|
function pipeline(...streams) {
|
|
103295
|
-
return new Promise2((
|
|
103578
|
+
return new Promise2((resolve36, reject2) => {
|
|
103296
103579
|
let signal;
|
|
103297
103580
|
let end;
|
|
103298
103581
|
const lastArg = streams[streams.length - 1];
|
|
@@ -103307,7 +103590,7 @@ var require_promises = __commonJS({
|
|
|
103307
103590
|
if (err) {
|
|
103308
103591
|
reject2(err);
|
|
103309
103592
|
} else {
|
|
103310
|
-
|
|
103593
|
+
resolve36(value);
|
|
103311
103594
|
}
|
|
103312
103595
|
},
|
|
103313
103596
|
{
|
|
@@ -108080,10 +108363,10 @@ var require_commonjs3 = __commonJS({
|
|
|
108080
108363
|
* Return a void Promise that resolves once the stream ends.
|
|
108081
108364
|
*/
|
|
108082
108365
|
async promise() {
|
|
108083
|
-
return new Promise((
|
|
108366
|
+
return new Promise((resolve36, reject2) => {
|
|
108084
108367
|
this.on(DESTROYED, () => reject2(new Error("stream destroyed")));
|
|
108085
108368
|
this.on("error", (er) => reject2(er));
|
|
108086
|
-
this.on("end", () =>
|
|
108369
|
+
this.on("end", () => resolve36());
|
|
108087
108370
|
});
|
|
108088
108371
|
}
|
|
108089
108372
|
/**
|
|
@@ -108107,7 +108390,7 @@ var require_commonjs3 = __commonJS({
|
|
|
108107
108390
|
return Promise.resolve({ done: false, value: res });
|
|
108108
108391
|
if (this[EOF])
|
|
108109
108392
|
return stop();
|
|
108110
|
-
let
|
|
108393
|
+
let resolve36;
|
|
108111
108394
|
let reject2;
|
|
108112
108395
|
const onerr = (er) => {
|
|
108113
108396
|
this.off("data", ondata);
|
|
@@ -108121,19 +108404,19 @@ var require_commonjs3 = __commonJS({
|
|
|
108121
108404
|
this.off("end", onend);
|
|
108122
108405
|
this.off(DESTROYED, ondestroy);
|
|
108123
108406
|
this.pause();
|
|
108124
|
-
|
|
108407
|
+
resolve36({ value, done: !!this[EOF] });
|
|
108125
108408
|
};
|
|
108126
108409
|
const onend = () => {
|
|
108127
108410
|
this.off("error", onerr);
|
|
108128
108411
|
this.off("data", ondata);
|
|
108129
108412
|
this.off(DESTROYED, ondestroy);
|
|
108130
108413
|
stop();
|
|
108131
|
-
|
|
108414
|
+
resolve36({ done: true, value: void 0 });
|
|
108132
108415
|
};
|
|
108133
108416
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
108134
108417
|
return new Promise((res2, rej) => {
|
|
108135
108418
|
reject2 = rej;
|
|
108136
|
-
|
|
108419
|
+
resolve36 = res2;
|
|
108137
108420
|
this.once(DESTROYED, ondestroy);
|
|
108138
108421
|
this.once("error", onerr);
|
|
108139
108422
|
this.once("end", onend);
|
|
@@ -109149,9 +109432,9 @@ var require_commonjs4 = __commonJS({
|
|
|
109149
109432
|
if (this.#asyncReaddirInFlight) {
|
|
109150
109433
|
await this.#asyncReaddirInFlight;
|
|
109151
109434
|
} else {
|
|
109152
|
-
let
|
|
109435
|
+
let resolve36 = () => {
|
|
109153
109436
|
};
|
|
109154
|
-
this.#asyncReaddirInFlight = new Promise((res) =>
|
|
109437
|
+
this.#asyncReaddirInFlight = new Promise((res) => resolve36 = res);
|
|
109155
109438
|
try {
|
|
109156
109439
|
for (const e of await this.#fs.promises.readdir(fullpath, {
|
|
109157
109440
|
withFileTypes: true
|
|
@@ -109164,7 +109447,7 @@ var require_commonjs4 = __commonJS({
|
|
|
109164
109447
|
children.provisional = 0;
|
|
109165
109448
|
}
|
|
109166
109449
|
this.#asyncReaddirInFlight = void 0;
|
|
109167
|
-
|
|
109450
|
+
resolve36();
|
|
109168
109451
|
}
|
|
109169
109452
|
return children.slice(0, children.provisional);
|
|
109170
109453
|
}
|
|
@@ -110251,10 +110534,10 @@ var require_ignore = __commonJS({
|
|
|
110251
110534
|
ignored(p) {
|
|
110252
110535
|
const fullpath = p.fullpath();
|
|
110253
110536
|
const fullpaths = `${fullpath}/`;
|
|
110254
|
-
const
|
|
110255
|
-
const relatives = `${
|
|
110537
|
+
const relative13 = p.relative() || ".";
|
|
110538
|
+
const relatives = `${relative13}/`;
|
|
110256
110539
|
for (const m of this.relative) {
|
|
110257
|
-
if (m.match(
|
|
110540
|
+
if (m.match(relative13) || m.match(relatives))
|
|
110258
110541
|
return true;
|
|
110259
110542
|
}
|
|
110260
110543
|
for (const m of this.absolute) {
|
|
@@ -110265,9 +110548,9 @@ var require_ignore = __commonJS({
|
|
|
110265
110548
|
}
|
|
110266
110549
|
childrenIgnored(p) {
|
|
110267
110550
|
const fullpath = p.fullpath() + "/";
|
|
110268
|
-
const
|
|
110551
|
+
const relative13 = (p.relative() || ".") + "/";
|
|
110269
110552
|
for (const m of this.relativeChildren) {
|
|
110270
|
-
if (m.match(
|
|
110553
|
+
if (m.match(relative13))
|
|
110271
110554
|
return true;
|
|
110272
110555
|
}
|
|
110273
110556
|
for (const m of this.absoluteChildren) {
|
|
@@ -111937,11 +112220,11 @@ var require_core = __commonJS({
|
|
|
111937
112220
|
this._finalize();
|
|
111938
112221
|
}
|
|
111939
112222
|
var self2 = this;
|
|
111940
|
-
return new Promise(function(
|
|
112223
|
+
return new Promise(function(resolve36, reject2) {
|
|
111941
112224
|
var errored;
|
|
111942
112225
|
self2._module.on("end", function() {
|
|
111943
112226
|
if (!errored) {
|
|
111944
|
-
|
|
112227
|
+
resolve36();
|
|
111945
112228
|
}
|
|
111946
112229
|
});
|
|
111947
112230
|
self2._module.on("error", function(err) {
|
|
@@ -114381,8 +114664,8 @@ var require_streamx = __commonJS({
|
|
|
114381
114664
|
return this;
|
|
114382
114665
|
},
|
|
114383
114666
|
next() {
|
|
114384
|
-
return new Promise(function(
|
|
114385
|
-
promiseResolve =
|
|
114667
|
+
return new Promise(function(resolve36, reject2) {
|
|
114668
|
+
promiseResolve = resolve36;
|
|
114386
114669
|
promiseReject = reject2;
|
|
114387
114670
|
const data = stream.read();
|
|
114388
114671
|
if (data !== null) ondata(data);
|
|
@@ -114412,11 +114695,11 @@ var require_streamx = __commonJS({
|
|
|
114412
114695
|
}
|
|
114413
114696
|
function destroy(err) {
|
|
114414
114697
|
stream.destroy(err);
|
|
114415
|
-
return new Promise((
|
|
114416
|
-
if (stream._duplexState & DESTROYED) return
|
|
114698
|
+
return new Promise((resolve36, reject2) => {
|
|
114699
|
+
if (stream._duplexState & DESTROYED) return resolve36({ value: void 0, done: true });
|
|
114417
114700
|
stream.once("close", function() {
|
|
114418
114701
|
if (err) reject2(err);
|
|
114419
|
-
else
|
|
114702
|
+
else resolve36({ value: void 0, done: true });
|
|
114420
114703
|
});
|
|
114421
114704
|
});
|
|
114422
114705
|
}
|
|
@@ -114460,8 +114743,8 @@ var require_streamx = __commonJS({
|
|
|
114460
114743
|
const writes = pending + (ws._duplexState & WRITE_WRITING ? 1 : 0);
|
|
114461
114744
|
if (writes === 0) return Promise.resolve(true);
|
|
114462
114745
|
if (state.drains === null) state.drains = [];
|
|
114463
|
-
return new Promise((
|
|
114464
|
-
state.drains.push({ writes, resolve:
|
|
114746
|
+
return new Promise((resolve36) => {
|
|
114747
|
+
state.drains.push({ writes, resolve: resolve36 });
|
|
114465
114748
|
});
|
|
114466
114749
|
}
|
|
114467
114750
|
write(data) {
|
|
@@ -114566,10 +114849,10 @@ var require_streamx = __commonJS({
|
|
|
114566
114849
|
cb(null);
|
|
114567
114850
|
}
|
|
114568
114851
|
function pipelinePromise(...streams) {
|
|
114569
|
-
return new Promise((
|
|
114852
|
+
return new Promise((resolve36, reject2) => {
|
|
114570
114853
|
return pipeline(...streams, (err) => {
|
|
114571
114854
|
if (err) return reject2(err);
|
|
114572
|
-
|
|
114855
|
+
resolve36();
|
|
114573
114856
|
});
|
|
114574
114857
|
});
|
|
114575
114858
|
}
|
|
@@ -115226,16 +115509,16 @@ var require_extract = __commonJS({
|
|
|
115226
115509
|
entryCallback = null;
|
|
115227
115510
|
cb(err);
|
|
115228
115511
|
}
|
|
115229
|
-
function onnext(
|
|
115512
|
+
function onnext(resolve36, reject2) {
|
|
115230
115513
|
if (error) {
|
|
115231
115514
|
return reject2(error);
|
|
115232
115515
|
}
|
|
115233
115516
|
if (entryStream) {
|
|
115234
|
-
|
|
115517
|
+
resolve36({ value: entryStream, done: false });
|
|
115235
115518
|
entryStream = null;
|
|
115236
115519
|
return;
|
|
115237
115520
|
}
|
|
115238
|
-
promiseResolve =
|
|
115521
|
+
promiseResolve = resolve36;
|
|
115239
115522
|
promiseReject = reject2;
|
|
115240
115523
|
consumeCallback(null);
|
|
115241
115524
|
if (extract._finished && promiseResolve) {
|
|
@@ -115263,11 +115546,11 @@ var require_extract = __commonJS({
|
|
|
115263
115546
|
function destroy(err) {
|
|
115264
115547
|
extract.destroy(err);
|
|
115265
115548
|
consumeCallback(err);
|
|
115266
|
-
return new Promise((
|
|
115267
|
-
if (extract.destroyed) return
|
|
115549
|
+
return new Promise((resolve36, reject2) => {
|
|
115550
|
+
if (extract.destroyed) return resolve36({ value: void 0, done: true });
|
|
115268
115551
|
extract.once("close", function() {
|
|
115269
115552
|
if (err) reject2(err);
|
|
115270
|
-
else
|
|
115553
|
+
else resolve36({ value: void 0, done: true });
|
|
115271
115554
|
});
|
|
115272
115555
|
});
|
|
115273
115556
|
}
|
|
@@ -117015,7 +117298,7 @@ var init_register_agents_projects_nodes = __esm({
|
|
|
117015
117298
|
// ../dashboard/src/routes/register-project-routes.ts
|
|
117016
117299
|
import { execFile as execFile5 } from "node:child_process";
|
|
117017
117300
|
import * as fsPromises from "node:fs/promises";
|
|
117018
|
-
import { dirname as dirname12, isAbsolute as
|
|
117301
|
+
import { dirname as dirname12, isAbsolute as isAbsolute14, join as join39 } from "node:path";
|
|
117019
117302
|
import { promisify as promisify12 } from "node:util";
|
|
117020
117303
|
var access7, stat8, mkdir13, readdir9, rm2, execFileAsync3, registerProjectRoutes;
|
|
117021
117304
|
var init_register_project_routes = __esm({
|
|
@@ -117132,7 +117415,7 @@ var init_register_project_routes = __esm({
|
|
|
117132
117415
|
if (normalizedPath.includes("\0")) {
|
|
117133
117416
|
throw badRequest("path cannot contain null bytes");
|
|
117134
117417
|
}
|
|
117135
|
-
if (!
|
|
117418
|
+
if (!isAbsolute14(normalizedPath)) {
|
|
117136
117419
|
throw badRequest("path must be an absolute path");
|
|
117137
117420
|
}
|
|
117138
117421
|
if (cloneUrl !== void 0) {
|
|
@@ -120668,7 +120951,7 @@ You MUST respond with ONLY valid JSON (no markdown, no explanation):
|
|
|
120668
120951
|
import { createWriteStream } from "node:fs";
|
|
120669
120952
|
import * as fsPromises2 from "node:fs/promises";
|
|
120670
120953
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
120671
|
-
import { join as join40, resolve as
|
|
120954
|
+
import { join as join40, resolve as resolve19 } from "node:path";
|
|
120672
120955
|
import { Readable } from "node:stream";
|
|
120673
120956
|
import { pipeline as streamPipeline } from "node:stream/promises";
|
|
120674
120957
|
function registerAgentImportExportRoutes(ctx) {
|
|
@@ -120705,7 +120988,7 @@ function registerAgentImportExportRoutes(ctx) {
|
|
|
120705
120988
|
}
|
|
120706
120989
|
let resolvedOutputDir;
|
|
120707
120990
|
if (typeof outputDir === "string" && outputDir.trim().length > 0) {
|
|
120708
|
-
resolvedOutputDir =
|
|
120991
|
+
resolvedOutputDir = resolve19(outputDir.trim());
|
|
120709
120992
|
} else if (typeof outputDir === "string") {
|
|
120710
120993
|
throw badRequest("outputDir cannot be empty");
|
|
120711
120994
|
} else {
|
|
@@ -120940,7 +121223,7 @@ ${body}`;
|
|
|
120940
121223
|
tasks: []
|
|
120941
121224
|
};
|
|
120942
121225
|
} else if (typeof source === "string" && source.trim()) {
|
|
120943
|
-
const sourcePath =
|
|
121226
|
+
const sourcePath = resolve19(source);
|
|
120944
121227
|
const isArchive = sourcePath.endsWith(".tar.gz") || sourcePath.endsWith(".tgz") || sourcePath.endsWith(".zip");
|
|
120945
121228
|
if (isArchive) {
|
|
120946
121229
|
try {
|
|
@@ -121741,9 +122024,9 @@ function registerProxyRoutes(router, deps) {
|
|
|
121741
122024
|
if (req.rawBody && req.rawBody.length > 0) {
|
|
121742
122025
|
body = req.rawBody;
|
|
121743
122026
|
} else {
|
|
121744
|
-
await new Promise((
|
|
122027
|
+
await new Promise((resolve36, reject2) => {
|
|
121745
122028
|
req.on("data", (chunk) => chunks.push(chunk));
|
|
121746
|
-
req.on("end",
|
|
122029
|
+
req.on("end", resolve36);
|
|
121747
122030
|
req.on("error", reject2);
|
|
121748
122031
|
});
|
|
121749
122032
|
if (chunks.length > 0) {
|
|
@@ -121918,13 +122201,13 @@ import { readFile as readFile19 } from "node:fs/promises";
|
|
|
121918
122201
|
import * as https from "node:https";
|
|
121919
122202
|
import * as child_process from "node:child_process";
|
|
121920
122203
|
function execFileAsync4(file, args, options) {
|
|
121921
|
-
return new Promise((
|
|
122204
|
+
return new Promise((resolve36, reject2) => {
|
|
121922
122205
|
child_process.execFile(file, args, options, (error, stdout, stderr) => {
|
|
121923
122206
|
if (error) {
|
|
121924
122207
|
reject2(error);
|
|
121925
122208
|
return;
|
|
121926
122209
|
}
|
|
121927
|
-
|
|
122210
|
+
resolve36({ stdout: String(stdout), stderr: String(stderr) });
|
|
121928
122211
|
});
|
|
121929
122212
|
});
|
|
121930
122213
|
}
|
|
@@ -121983,7 +122266,7 @@ function formatDuration(ms) {
|
|
|
121983
122266
|
return remHours > 0 ? `${days}d ${remHours}h` : `${days}d`;
|
|
121984
122267
|
}
|
|
121985
122268
|
function httpsRequest(url, options) {
|
|
121986
|
-
return new Promise((
|
|
122269
|
+
return new Promise((resolve36, reject2) => {
|
|
121987
122270
|
const parsed = new URL(url);
|
|
121988
122271
|
const req = https.request(
|
|
121989
122272
|
{
|
|
@@ -122003,7 +122286,7 @@ function httpsRequest(url, options) {
|
|
|
122003
122286
|
if (typeof v === "string") hdrs[k.toLowerCase()] = v;
|
|
122004
122287
|
else if (Array.isArray(v)) hdrs[k.toLowerCase()] = v.join(", ");
|
|
122005
122288
|
}
|
|
122006
|
-
|
|
122289
|
+
resolve36({
|
|
122007
122290
|
status: res.statusCode || 0,
|
|
122008
122291
|
headers: hdrs,
|
|
122009
122292
|
body: Buffer.concat(chunks).toString("utf-8")
|
|
@@ -122250,7 +122533,7 @@ async function fetchClaudeUsageViaCli() {
|
|
|
122250
122533
|
env: { ...process.env, TERM: "xterm-256color" }
|
|
122251
122534
|
};
|
|
122252
122535
|
if (isWindows) ptyOptions.useConpty = false;
|
|
122253
|
-
const output = await new Promise((
|
|
122536
|
+
const output = await new Promise((resolve36, reject2) => {
|
|
122254
122537
|
let buf = "";
|
|
122255
122538
|
let settled = false;
|
|
122256
122539
|
let sentCommand = false;
|
|
@@ -122266,7 +122549,7 @@ async function fetchClaudeUsageViaCli() {
|
|
|
122266
122549
|
}
|
|
122267
122550
|
const clean = _stripClaudeAnsi(buf);
|
|
122268
122551
|
if (clean.includes("Current session") || clean.includes("% left") || clean.includes("% used")) {
|
|
122269
|
-
|
|
122552
|
+
resolve36(buf);
|
|
122270
122553
|
} else {
|
|
122271
122554
|
reject2(new Error("Claude CLI timed out after 60s \u2014 got output but no usage data. Try running `claude /usage` manually."));
|
|
122272
122555
|
}
|
|
@@ -122317,7 +122600,7 @@ async function fetchClaudeUsageViaCli() {
|
|
|
122317
122600
|
ptyProcess.kill();
|
|
122318
122601
|
} catch {
|
|
122319
122602
|
}
|
|
122320
|
-
|
|
122603
|
+
resolve36(buf);
|
|
122321
122604
|
}
|
|
122322
122605
|
}, 2e3);
|
|
122323
122606
|
}
|
|
@@ -122328,7 +122611,7 @@ async function fetchClaudeUsageViaCli() {
|
|
|
122328
122611
|
if (settled) return;
|
|
122329
122612
|
settled = true;
|
|
122330
122613
|
clearTimeout(timeout2);
|
|
122331
|
-
|
|
122614
|
+
resolve36(buf);
|
|
122332
122615
|
});
|
|
122333
122616
|
});
|
|
122334
122617
|
const cleanOutput = _stripClaudeAnsi(output);
|
|
@@ -122996,9 +123279,9 @@ async function fetchGitHubCopilotUsage() {
|
|
|
122996
123279
|
return usage;
|
|
122997
123280
|
}
|
|
122998
123281
|
function withTimeout(providerPromise, providerName, timeoutMs = PROVIDER_FETCH_TIMEOUT_MS) {
|
|
122999
|
-
return new Promise((
|
|
123282
|
+
return new Promise((resolve36) => {
|
|
123000
123283
|
const timer = setTimeout(() => {
|
|
123001
|
-
|
|
123284
|
+
resolve36({
|
|
123002
123285
|
name: providerName,
|
|
123003
123286
|
icon: "\u23F1\uFE0F",
|
|
123004
123287
|
status: "error",
|
|
@@ -123008,10 +123291,10 @@ function withTimeout(providerPromise, providerName, timeoutMs = PROVIDER_FETCH_T
|
|
|
123008
123291
|
}, timeoutMs);
|
|
123009
123292
|
providerPromise.then((result) => {
|
|
123010
123293
|
clearTimeout(timer);
|
|
123011
|
-
|
|
123294
|
+
resolve36(result);
|
|
123012
123295
|
}).catch((err) => {
|
|
123013
123296
|
clearTimeout(timer);
|
|
123014
|
-
|
|
123297
|
+
resolve36({
|
|
123015
123298
|
name: providerName,
|
|
123016
123299
|
icon: "\u23F1\uFE0F",
|
|
123017
123300
|
status: "error",
|
|
@@ -123065,7 +123348,7 @@ var init_usage = __esm({
|
|
|
123065
123348
|
ANTHROPIC_OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
123066
123349
|
ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
|
|
123067
123350
|
CLAUDE_USAGE_USER_AGENT = "claude-code-fusion-dashboard";
|
|
123068
|
-
_sleep = (ms) => new Promise((
|
|
123351
|
+
_sleep = (ms) => new Promise((resolve36) => setTimeout(resolve36, ms));
|
|
123069
123352
|
sleepFn = _sleep;
|
|
123070
123353
|
PROVIDER_FETCH_TIMEOUT_MS = 1e4;
|
|
123071
123354
|
CLAUDE_FETCH_TIMEOUT_MS = 75e3;
|
|
@@ -123379,8 +123662,8 @@ var init_register_auth_routes = __esm({
|
|
|
123379
123662
|
loginInProgress.set(provider, abortController);
|
|
123380
123663
|
let authResolve;
|
|
123381
123664
|
let authReject;
|
|
123382
|
-
const authUrlPromise = new Promise((
|
|
123383
|
-
authResolve =
|
|
123665
|
+
const authUrlPromise = new Promise((resolve36, reject2) => {
|
|
123666
|
+
authResolve = resolve36;
|
|
123384
123667
|
authReject = reject2;
|
|
123385
123668
|
});
|
|
123386
123669
|
const loginPromise = storage.login(provider, {
|
|
@@ -127423,7 +127706,7 @@ var init_todo_routes = __esm({
|
|
|
127423
127706
|
|
|
127424
127707
|
// ../dashboard/src/dev-server-detect.ts
|
|
127425
127708
|
import { glob, readFile as readFile20 } from "node:fs/promises";
|
|
127426
|
-
import { dirname as dirname13, join as join42, relative as
|
|
127709
|
+
import { dirname as dirname13, join as join42, relative as relative10, resolve as resolve20 } from "node:path";
|
|
127427
127710
|
async function readPackageJson(filePath) {
|
|
127428
127711
|
try {
|
|
127429
127712
|
const raw = await readFile20(filePath, "utf-8");
|
|
@@ -127473,7 +127756,7 @@ async function collectWorkspacePackageJsons(projectRoot) {
|
|
|
127473
127756
|
try {
|
|
127474
127757
|
for await (const match of glob(pattern, { cwd: projectRoot })) {
|
|
127475
127758
|
if (typeof match === "string") {
|
|
127476
|
-
discovered.add(
|
|
127759
|
+
discovered.add(resolve20(projectRoot, match));
|
|
127477
127760
|
}
|
|
127478
127761
|
}
|
|
127479
127762
|
} catch {
|
|
@@ -127494,11 +127777,11 @@ function extractScripts(pkg) {
|
|
|
127494
127777
|
}
|
|
127495
127778
|
function toSource(projectRoot, packageJsonPath) {
|
|
127496
127779
|
const packageDir = dirname13(packageJsonPath);
|
|
127497
|
-
const rel =
|
|
127780
|
+
const rel = relative10(projectRoot, packageDir).replace(/\\/g, "/");
|
|
127498
127781
|
return rel.length > 0 ? rel : "root";
|
|
127499
127782
|
}
|
|
127500
127783
|
async function detectDevServerScripts(projectRoot) {
|
|
127501
|
-
const root =
|
|
127784
|
+
const root = resolve20(projectRoot);
|
|
127502
127785
|
const candidates = [];
|
|
127503
127786
|
const rootPackagePath = join42(root, "package.json");
|
|
127504
127787
|
const rootPackage = await readPackageJson(rootPackagePath);
|
|
@@ -127567,9 +127850,9 @@ var init_dev_server_detect = __esm({
|
|
|
127567
127850
|
|
|
127568
127851
|
// ../dashboard/src/dev-server-store.ts
|
|
127569
127852
|
import { mkdir as mkdir15, readFile as readFile21, writeFile as writeFile13 } from "node:fs/promises";
|
|
127570
|
-
import { dirname as dirname14, join as join43, resolve as
|
|
127853
|
+
import { dirname as dirname14, join as join43, resolve as resolve21 } from "node:path";
|
|
127571
127854
|
function devServerFilePath(projectDir) {
|
|
127572
|
-
return join43(
|
|
127855
|
+
return join43(resolve21(projectDir), ".fusion", "dev-server.json");
|
|
127573
127856
|
}
|
|
127574
127857
|
function normalizeState(candidate) {
|
|
127575
127858
|
const defaults = DEV_SERVER_DEFAULT_STATE();
|
|
@@ -127604,7 +127887,7 @@ function normalizeConfig(candidate) {
|
|
|
127604
127887
|
};
|
|
127605
127888
|
}
|
|
127606
127889
|
async function loadDevServerStore(projectDir) {
|
|
127607
|
-
const storeKey =
|
|
127890
|
+
const storeKey = resolve21(projectDir);
|
|
127608
127891
|
let store = storeInstances.get(storeKey);
|
|
127609
127892
|
if (!store) {
|
|
127610
127893
|
store = new DevServerStore(projectDir);
|
|
@@ -127882,7 +128165,7 @@ function detectPortFromLogLine(line) {
|
|
|
127882
128165
|
return detectViteLine(cleanLine) ?? detectNextLine(cleanLine) ?? detectStorybookLine(cleanLine) ?? detectAngularLine(cleanLine) ?? detectGenericUrl(cleanLine) ?? detectGenericPortLine(cleanLine);
|
|
127883
128166
|
}
|
|
127884
128167
|
function probePort(host, port, timeoutMs) {
|
|
127885
|
-
return new Promise((
|
|
128168
|
+
return new Promise((resolve36) => {
|
|
127886
128169
|
let settled = false;
|
|
127887
128170
|
const socket = createConnection({ host, port });
|
|
127888
128171
|
const settle = (isOpen) => {
|
|
@@ -127896,7 +128179,7 @@ function probePort(host, port, timeoutMs) {
|
|
|
127896
128179
|
} else {
|
|
127897
128180
|
socket.destroy();
|
|
127898
128181
|
}
|
|
127899
|
-
|
|
128182
|
+
resolve36(isOpen);
|
|
127900
128183
|
};
|
|
127901
128184
|
socket.setTimeout(timeoutMs);
|
|
127902
128185
|
socket.once("connect", () => settle(true));
|
|
@@ -128023,8 +128306,8 @@ var init_dev_server_process = __esm({
|
|
|
128023
128306
|
stdio: ["pipe", "pipe", "pipe"]
|
|
128024
128307
|
});
|
|
128025
128308
|
this.childProcess = child;
|
|
128026
|
-
this.closePromise = new Promise((
|
|
128027
|
-
this.resolveClosePromise =
|
|
128309
|
+
this.closePromise = new Promise((resolve36) => {
|
|
128310
|
+
this.resolveClosePromise = resolve36;
|
|
128028
128311
|
});
|
|
128029
128312
|
const runningState = await this.store.updateState({
|
|
128030
128313
|
pid: child.pid,
|
|
@@ -128821,7 +129104,7 @@ Your job is to refine task descriptions based on the user's selected refinement
|
|
|
128821
129104
|
|
|
128822
129105
|
// ../dashboard/src/routes.ts
|
|
128823
129106
|
import multer from "multer";
|
|
128824
|
-
import { resolve as
|
|
129107
|
+
import { resolve as resolve22, sep as sep6, join as join44, isAbsolute as isAbsolute15 } from "node:path";
|
|
128825
129108
|
import * as nodeFs from "node:fs";
|
|
128826
129109
|
function readJsonObject3(path4) {
|
|
128827
129110
|
if (!nodeFs.existsSync(path4)) {
|
|
@@ -128851,7 +129134,7 @@ function getPiPackageManagerAgentDir() {
|
|
|
128851
129134
|
return nodeFs.existsSync(fusionAgentDir) ? fusionAgentDir : legacyAgentDir;
|
|
128852
129135
|
}
|
|
128853
129136
|
function packageExtensionName(extensionPath, source) {
|
|
128854
|
-
const base =
|
|
129137
|
+
const base = resolve22(extensionPath).split(sep6).pop()?.replace(/\.(ts|js)$/i, "") || source;
|
|
128855
129138
|
if (base !== "index") {
|
|
128856
129139
|
return base;
|
|
128857
129140
|
}
|
|
@@ -128859,7 +129142,7 @@ function packageExtensionName(extensionPath, source) {
|
|
|
128859
129142
|
}
|
|
128860
129143
|
async function discoverDashboardPiExtensions(cwd) {
|
|
128861
129144
|
const settings = discoverPiExtensions(cwd);
|
|
128862
|
-
const disabled = new Set(settings.disabledIds.map((id) =>
|
|
129145
|
+
const disabled = new Set(settings.disabledIds.map((id) => resolve22(id)));
|
|
128863
129146
|
const byPath = new Map(settings.extensions.map((entry) => [entry.id, entry]));
|
|
128864
129147
|
try {
|
|
128865
129148
|
const { DefaultPackageManager: DefaultPackageManager5 } = await import("@mariozechner/pi-coding-agent");
|
|
@@ -128881,7 +129164,7 @@ async function discoverDashboardPiExtensions(cwd) {
|
|
|
128881
129164
|
});
|
|
128882
129165
|
const resolved = await packageManager.resolve(async () => "skip");
|
|
128883
129166
|
for (const extension2 of resolved.extensions) {
|
|
128884
|
-
const id =
|
|
129167
|
+
const id = resolve22(extension2.path);
|
|
128885
129168
|
const source = extension2.metadata?.source || "package";
|
|
128886
129169
|
byPath.set(id, {
|
|
128887
129170
|
id,
|
|
@@ -129003,7 +129286,7 @@ function sanitizeOverlapIgnorePaths(value) {
|
|
|
129003
129286
|
if (!trimmed) {
|
|
129004
129287
|
throw badRequest(`overlapIgnorePaths[${index2}] cannot be empty`);
|
|
129005
129288
|
}
|
|
129006
|
-
if (
|
|
129289
|
+
if (isAbsolute15(trimmed) || /^[a-zA-Z]:\//.test(trimmed)) {
|
|
129007
129290
|
throw badRequest(`overlapIgnorePaths[${index2}] must be a project-relative path`);
|
|
129008
129291
|
}
|
|
129009
129292
|
if (/^\.{1,2}(\/|$)/.test(trimmed) || /(^|\/)\.\.(\/|$)/.test(trimmed)) {
|
|
@@ -129218,7 +129501,9 @@ function createApiRoutes(store, options) {
|
|
|
129218
129501
|
parseScopeParam,
|
|
129219
129502
|
resolveAutomationStore,
|
|
129220
129503
|
resolveRoutineStore,
|
|
129221
|
-
resolveRoutineRunner
|
|
129504
|
+
resolveRoutineRunner,
|
|
129505
|
+
registerDispose,
|
|
129506
|
+
dispose
|
|
129222
129507
|
} = createApiRoutesContext(store, options);
|
|
129223
129508
|
const summarizeDiagnostics = createSessionDiagnostics("ai-summarize");
|
|
129224
129509
|
const routeContext = {
|
|
@@ -129238,6 +129523,8 @@ function createApiRoutes(store, options) {
|
|
|
129238
129523
|
resolveAutomationStore,
|
|
129239
129524
|
resolveRoutineStore,
|
|
129240
129525
|
resolveRoutineRunner,
|
|
129526
|
+
registerDispose,
|
|
129527
|
+
dispose,
|
|
129241
129528
|
rethrowAsApiError
|
|
129242
129529
|
};
|
|
129243
129530
|
const githubToken = options?.githubToken ?? process.env.GITHUB_TOKEN;
|
|
@@ -129279,8 +129566,8 @@ function createApiRoutes(store, options) {
|
|
|
129279
129566
|
function isHeartbeatMonitorForProject(scopedStore) {
|
|
129280
129567
|
if (!heartbeatMonitor?.rootDir) return true;
|
|
129281
129568
|
try {
|
|
129282
|
-
const monitorRoot =
|
|
129283
|
-
const storeRoot =
|
|
129569
|
+
const monitorRoot = resolve22(heartbeatMonitor.rootDir);
|
|
129570
|
+
const storeRoot = resolve22(scopedStore.getRootDir());
|
|
129284
129571
|
return monitorRoot === storeRoot;
|
|
129285
129572
|
} catch {
|
|
129286
129573
|
return true;
|
|
@@ -131066,15 +131353,15 @@ Description: ${step.description}`
|
|
|
131066
131353
|
return;
|
|
131067
131354
|
}
|
|
131068
131355
|
}
|
|
131069
|
-
const { resolve:
|
|
131356
|
+
const { resolve: resolve36, dirname: dirname27, join: join62 } = await import("node:path");
|
|
131070
131357
|
const { readdir: readdir12, stat: stat12 } = await import("node:fs/promises");
|
|
131071
131358
|
const rawPath = req.query.path || process.env.HOME || process.env.USERPROFILE || "/";
|
|
131072
131359
|
const showHidden = req.query.showHidden === "true";
|
|
131073
|
-
const resolvedPath =
|
|
131360
|
+
const resolvedPath = resolve36(rawPath);
|
|
131074
131361
|
if (rawPath.includes("..")) {
|
|
131075
131362
|
throw badRequest("Path must not contain '..' traversal");
|
|
131076
131363
|
}
|
|
131077
|
-
if (resolvedPath !==
|
|
131364
|
+
if (resolvedPath !== resolve36(resolvedPath)) {
|
|
131078
131365
|
throw badRequest("Path must be absolute");
|
|
131079
131366
|
}
|
|
131080
131367
|
let pathStat;
|
|
@@ -131101,7 +131388,7 @@ Description: ${step.description}`
|
|
|
131101
131388
|
entries.push({ name: entry.name, path: entryPath, hasChildren });
|
|
131102
131389
|
}
|
|
131103
131390
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
131104
|
-
const parentPath = resolvedPath === "/" ? null :
|
|
131391
|
+
const parentPath = resolvedPath === "/" ? null : dirname27(resolvedPath);
|
|
131105
131392
|
res.json({ currentPath: resolvedPath, parentPath, entries });
|
|
131106
131393
|
} catch (err) {
|
|
131107
131394
|
if (err instanceof ApiError) {
|
|
@@ -131260,6 +131547,7 @@ Description: ${step.description}`
|
|
|
131260
131547
|
});
|
|
131261
131548
|
registerAgentSkillsRoutes(routeContext);
|
|
131262
131549
|
registerProxyRoutes(router, { store, runtimeLogger });
|
|
131550
|
+
router.dispose = dispose;
|
|
131263
131551
|
return router;
|
|
131264
131552
|
}
|
|
131265
131553
|
function validateAutomationSteps(steps) {
|
|
@@ -136927,14 +137215,15 @@ data: ${JSON.stringify({ type: event.type, data: event.data })}
|
|
|
136927
137215
|
}
|
|
136928
137216
|
res.redirect(302, "/");
|
|
136929
137217
|
});
|
|
136930
|
-
|
|
137218
|
+
const apiRouter = createApiRoutes(store, {
|
|
136931
137219
|
...options,
|
|
136932
137220
|
runtimeLogger,
|
|
136933
137221
|
aiSessionStore,
|
|
136934
137222
|
chatStore,
|
|
136935
137223
|
chatManager,
|
|
136936
137224
|
skillsAdapter: options?.skillsAdapter
|
|
136937
|
-
})
|
|
137225
|
+
});
|
|
137226
|
+
app.use("/api", apiRouter);
|
|
136938
137227
|
app.use("/api", (_req, res) => {
|
|
136939
137228
|
sendErrorResponse(res, 404, "Not found");
|
|
136940
137229
|
});
|
|
@@ -136983,6 +137272,7 @@ data: ${JSON.stringify({ type: event.type, data: event.data })}
|
|
|
136983
137272
|
server.once("close", () => {
|
|
136984
137273
|
clearAiSessionCleanupInterval();
|
|
136985
137274
|
aiSessionStore.stopScheduledCleanup();
|
|
137275
|
+
apiRouter.dispose?.();
|
|
136986
137276
|
void stopAllDevServers().catch((error) => {
|
|
136987
137277
|
runtimeLogger.warn("Failed to shutdown dev-server managers", {
|
|
136988
137278
|
message: "Failed to shutdown dev-server managers",
|
|
@@ -137416,7 +137706,7 @@ var init_server = __esm({
|
|
|
137416
137706
|
|
|
137417
137707
|
// ../dashboard/src/skills-adapter.ts
|
|
137418
137708
|
import { access as access9, readFile as readFile22, writeFile as writeFile14, mkdir as mkdir16, readdir as readdir10, stat as stat10 } from "node:fs/promises";
|
|
137419
|
-
import { join as join46, relative as
|
|
137709
|
+
import { join as join46, relative as relative11, dirname as dirname16 } from "node:path";
|
|
137420
137710
|
async function pathExists(path4) {
|
|
137421
137711
|
try {
|
|
137422
137712
|
await access9(path4);
|
|
@@ -137480,7 +137770,7 @@ function createSkillsAdapter(options) {
|
|
|
137480
137770
|
}
|
|
137481
137771
|
const discoveredSkills = [];
|
|
137482
137772
|
for (const resource of skillResources) {
|
|
137483
|
-
const skillRelativePath = "skills/" +
|
|
137773
|
+
const skillRelativePath = "skills/" + relative11(resource.metadata.baseDir ?? "", resource.path);
|
|
137484
137774
|
const skillId = computeSkillId(resource.metadata.source, skillRelativePath);
|
|
137485
137775
|
const skillName = extractSkillName(skillRelativePath, resource.metadata.source);
|
|
137486
137776
|
discoveredSkills.push({
|
|
@@ -137935,6 +138225,7 @@ var init_src3 = __esm({
|
|
|
137935
138225
|
init_github();
|
|
137936
138226
|
init_rate_limit();
|
|
137937
138227
|
init_github_poll();
|
|
138228
|
+
init_github_issue_comment();
|
|
137938
138229
|
init_api_error();
|
|
137939
138230
|
init_badge_pubsub();
|
|
137940
138231
|
init_plugins();
|
|
@@ -138054,7 +138345,7 @@ var init_task_lifecycle = __esm({
|
|
|
138054
138345
|
// src/commands/port-prompt.ts
|
|
138055
138346
|
import { createInterface } from "node:readline";
|
|
138056
138347
|
function promptForPort(defaultPort = 4040, input = process.stdin) {
|
|
138057
|
-
return new Promise((
|
|
138348
|
+
return new Promise((resolve36, reject2) => {
|
|
138058
138349
|
const rl = createInterface({
|
|
138059
138350
|
input,
|
|
138060
138351
|
output: process.stdout
|
|
@@ -138071,7 +138362,7 @@ function promptForPort(defaultPort = 4040, input = process.stdin) {
|
|
|
138071
138362
|
if (trimmed === "") {
|
|
138072
138363
|
process.removeListener("SIGINT", sigintHandler);
|
|
138073
138364
|
rl.close();
|
|
138074
|
-
|
|
138365
|
+
resolve36(defaultPort);
|
|
138075
138366
|
return;
|
|
138076
138367
|
}
|
|
138077
138368
|
const port = parseInt(trimmed, 10);
|
|
@@ -138087,7 +138378,7 @@ function promptForPort(defaultPort = 4040, input = process.stdin) {
|
|
|
138087
138378
|
}
|
|
138088
138379
|
process.removeListener("SIGINT", sigintHandler);
|
|
138089
138380
|
rl.close();
|
|
138090
|
-
|
|
138381
|
+
resolve36(port);
|
|
138091
138382
|
});
|
|
138092
138383
|
};
|
|
138093
138384
|
ask();
|
|
@@ -138378,7 +138669,7 @@ var init_auth_paths2 = __esm({
|
|
|
138378
138669
|
});
|
|
138379
138670
|
|
|
138380
138671
|
// src/project-context.ts
|
|
138381
|
-
import { resolve as
|
|
138672
|
+
import { resolve as resolve23, dirname as dirname18 } from "node:path";
|
|
138382
138673
|
import { existsSync as existsSync34 } from "node:fs";
|
|
138383
138674
|
async function resolveProject(projectNameFlag, cwd = process.cwd(), globalDir) {
|
|
138384
138675
|
const central = new CentralCore(globalDir);
|
|
@@ -138470,9 +138761,9 @@ async function clearDefaultProject(globalDir) {
|
|
|
138470
138761
|
await globalStore.updateSettings(rest);
|
|
138471
138762
|
}
|
|
138472
138763
|
async function detectProjectFromCwd(cwd, central) {
|
|
138473
|
-
let currentDir =
|
|
138764
|
+
let currentDir = resolve23(cwd);
|
|
138474
138765
|
while (true) {
|
|
138475
|
-
const kbPath =
|
|
138766
|
+
const kbPath = resolve23(currentDir, ".fusion", "fusion.db");
|
|
138476
138767
|
if (existsSync34(kbPath)) {
|
|
138477
138768
|
const project = await central.getProjectByPath(currentDir);
|
|
138478
138769
|
if (project) {
|
|
@@ -138532,11 +138823,11 @@ import {
|
|
|
138532
138823
|
lstatSync as lstatSync2,
|
|
138533
138824
|
mkdirSync as mkdirSync7,
|
|
138534
138825
|
readlinkSync,
|
|
138535
|
-
rmSync as
|
|
138826
|
+
rmSync as rmSync4,
|
|
138536
138827
|
symlinkSync,
|
|
138537
138828
|
unlinkSync
|
|
138538
138829
|
} from "node:fs";
|
|
138539
|
-
import { dirname as dirname19, join as join49, resolve as
|
|
138830
|
+
import { dirname as dirname19, join as join49, resolve as resolve24 } from "node:path";
|
|
138540
138831
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
138541
138832
|
function isPiClaudeCliConfigured(globalSettings) {
|
|
138542
138833
|
if (!globalSettings || typeof globalSettings !== "object") {
|
|
@@ -138556,7 +138847,7 @@ function isPiClaudeCliConfigured(globalSettings) {
|
|
|
138556
138847
|
}
|
|
138557
138848
|
function resolveFusionSkillSource() {
|
|
138558
138849
|
const here = fileURLToPath4(import.meta.url);
|
|
138559
|
-
const candidate =
|
|
138850
|
+
const candidate = resolve24(dirname19(here), "..", "..", "skill", FUSION_SKILL_NAME);
|
|
138560
138851
|
return existsSync35(candidate) ? candidate : null;
|
|
138561
138852
|
}
|
|
138562
138853
|
function installFusionSkillIntoProject(projectPath, options = {}) {
|
|
@@ -138579,7 +138870,7 @@ function installFusionSkillIntoProject(projectPath, options = {}) {
|
|
|
138579
138870
|
const stat12 = lstatSync2(target);
|
|
138580
138871
|
if (stat12.isSymbolicLink()) {
|
|
138581
138872
|
const current = safeReadlink(target);
|
|
138582
|
-
if (current &&
|
|
138873
|
+
if (current && resolve24(dirname19(target), current) === resolve24(source)) {
|
|
138583
138874
|
return { outcome: "already-installed", target, source };
|
|
138584
138875
|
}
|
|
138585
138876
|
unlinkSync(target);
|
|
@@ -138658,7 +138949,7 @@ function safeReadlink(path4) {
|
|
|
138658
138949
|
}
|
|
138659
138950
|
}
|
|
138660
138951
|
function removeRecursive(path4) {
|
|
138661
|
-
|
|
138952
|
+
rmSync4(path4, { recursive: true, force: true });
|
|
138662
138953
|
}
|
|
138663
138954
|
var FUSION_SKILL_NAME;
|
|
138664
138955
|
var init_claude_skills = __esm({
|
|
@@ -138744,13 +139035,13 @@ var init_claude_skills_runner = __esm({
|
|
|
138744
139035
|
// src/commands/claude-cli-extension.ts
|
|
138745
139036
|
import { existsSync as existsSync36, readFileSync as readFileSync13 } from "node:fs";
|
|
138746
139037
|
import { createRequire as createRequire4 } from "node:module";
|
|
138747
|
-
import { dirname as dirname20, resolve as
|
|
139038
|
+
import { dirname as dirname20, resolve as resolve25 } from "node:path";
|
|
138748
139039
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
138749
139040
|
function resolveClaudeCliExtension() {
|
|
138750
139041
|
let pkgJsonPath;
|
|
138751
139042
|
const here = dirname20(fileURLToPath5(import.meta.url));
|
|
138752
139043
|
for (const rel of ["pi-claude-cli", "../pi-claude-cli", "../../pi-claude-cli"]) {
|
|
138753
|
-
const candidate =
|
|
139044
|
+
const candidate = resolve25(here, rel, "package.json");
|
|
138754
139045
|
if (existsSync36(candidate)) {
|
|
138755
139046
|
pkgJsonPath = candidate;
|
|
138756
139047
|
break;
|
|
@@ -138786,7 +139077,7 @@ function resolveClaudeCliExtension() {
|
|
|
138786
139077
|
reason: "@fusion/pi-claude-cli pi.extensions[0] is not a valid path string"
|
|
138787
139078
|
};
|
|
138788
139079
|
}
|
|
138789
|
-
const entryPath =
|
|
139080
|
+
const entryPath = resolve25(dirname20(pkgJsonPath), rawEntry);
|
|
138790
139081
|
if (!existsSync36(entryPath)) {
|
|
138791
139082
|
return {
|
|
138792
139083
|
status: "missing-entry",
|
|
@@ -138836,16 +139127,16 @@ var init_claude_cli_extension = __esm({
|
|
|
138836
139127
|
|
|
138837
139128
|
// src/commands/self-extension.ts
|
|
138838
139129
|
import { existsSync as existsSync37, readFileSync as readFileSync14 } from "node:fs";
|
|
138839
|
-
import { dirname as dirname21, resolve as
|
|
139130
|
+
import { dirname as dirname21, resolve as resolve26 } from "node:path";
|
|
138840
139131
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
138841
139132
|
function resolveSelfExtension() {
|
|
138842
139133
|
const here = dirname21(fileURLToPath6(import.meta.url));
|
|
138843
139134
|
let pkgDir;
|
|
138844
139135
|
let cur = here;
|
|
138845
139136
|
for (let i = 0; i < 5; i++) {
|
|
138846
|
-
if (existsSync37(
|
|
139137
|
+
if (existsSync37(resolve26(cur, "package.json"))) {
|
|
138847
139138
|
try {
|
|
138848
|
-
const parsed = JSON.parse(readFileSync14(
|
|
139139
|
+
const parsed = JSON.parse(readFileSync14(resolve26(cur, "package.json"), "utf-8"));
|
|
138849
139140
|
if (parsed.name === "@runfusion/fusion") {
|
|
138850
139141
|
pkgDir = cur;
|
|
138851
139142
|
break;
|
|
@@ -138853,7 +139144,7 @@ function resolveSelfExtension() {
|
|
|
138853
139144
|
} catch {
|
|
138854
139145
|
}
|
|
138855
139146
|
}
|
|
138856
|
-
const parent2 =
|
|
139147
|
+
const parent2 = resolve26(cur, "..");
|
|
138857
139148
|
if (parent2 === cur) break;
|
|
138858
139149
|
cur = parent2;
|
|
138859
139150
|
}
|
|
@@ -138862,11 +139153,11 @@ function resolveSelfExtension() {
|
|
|
138862
139153
|
}
|
|
138863
139154
|
let pkgJson;
|
|
138864
139155
|
try {
|
|
138865
|
-
pkgJson = JSON.parse(readFileSync14(
|
|
139156
|
+
pkgJson = JSON.parse(readFileSync14(resolve26(pkgDir, "package.json"), "utf-8"));
|
|
138866
139157
|
} catch (err) {
|
|
138867
139158
|
return { status: "missing", reason: `Failed to read @runfusion/fusion package.json: ${err instanceof Error ? err.message : String(err)}` };
|
|
138868
139159
|
}
|
|
138869
|
-
const srcEntry =
|
|
139160
|
+
const srcEntry = resolve26(pkgDir, "src", "extension.ts");
|
|
138870
139161
|
if (existsSync37(srcEntry)) {
|
|
138871
139162
|
return { status: "ok", path: srcEntry, packageVersion: pkgJson.version ?? "unknown" };
|
|
138872
139163
|
}
|
|
@@ -138878,7 +139169,7 @@ function resolveSelfExtension() {
|
|
|
138878
139169
|
if (typeof rawEntry !== "string" || rawEntry.length === 0) {
|
|
138879
139170
|
return { status: "missing", reason: "@runfusion/fusion pi.extensions[0] is not a valid path string" };
|
|
138880
139171
|
}
|
|
138881
|
-
const entryPath =
|
|
139172
|
+
const entryPath = resolve26(pkgDir, rawEntry);
|
|
138882
139173
|
if (!existsSync37(entryPath)) {
|
|
138883
139174
|
return { status: "missing", reason: `@runfusion/fusion extension file not found at ${entryPath}` };
|
|
138884
139175
|
}
|
|
@@ -138938,7 +139229,29 @@ var init_state = __esm({
|
|
|
138938
139229
|
});
|
|
138939
139230
|
|
|
138940
139231
|
// src/commands/dashboard-tui/logo.ts
|
|
138941
|
-
|
|
139232
|
+
import { existsSync as existsSync38, readFileSync as readFileSync15 } from "node:fs";
|
|
139233
|
+
import { dirname as dirname22, resolve as resolve27 } from "node:path";
|
|
139234
|
+
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
139235
|
+
function readFusionVersion() {
|
|
139236
|
+
try {
|
|
139237
|
+
let cur = dirname22(fileURLToPath7(import.meta.url));
|
|
139238
|
+
for (let i = 0; i < 6; i++) {
|
|
139239
|
+
const pkgPath = resolve27(cur, "package.json");
|
|
139240
|
+
if (existsSync38(pkgPath)) {
|
|
139241
|
+
const parsed = JSON.parse(readFileSync15(pkgPath, "utf-8"));
|
|
139242
|
+
if (parsed.name === "@runfusion/fusion" && typeof parsed.version === "string") {
|
|
139243
|
+
return parsed.version;
|
|
139244
|
+
}
|
|
139245
|
+
}
|
|
139246
|
+
const parent2 = resolve27(cur, "..");
|
|
139247
|
+
if (parent2 === cur) break;
|
|
139248
|
+
cur = parent2;
|
|
139249
|
+
}
|
|
139250
|
+
} catch {
|
|
139251
|
+
}
|
|
139252
|
+
return "unknown";
|
|
139253
|
+
}
|
|
139254
|
+
var FUSION_LOGO_LINES, FUSION_LOGO_LARGE_LINES, FUSION_TAGLINE, FUSION_URL, FUSION_VERSION2;
|
|
138942
139255
|
var init_logo = __esm({
|
|
138943
139256
|
"src/commands/dashboard-tui/logo.ts"() {
|
|
138944
139257
|
"use strict";
|
|
@@ -138964,7 +139277,9 @@ var init_logo = __esm({
|
|
|
138964
139277
|
"\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D",
|
|
138965
139278
|
"\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D"
|
|
138966
139279
|
];
|
|
138967
|
-
FUSION_TAGLINE = "
|
|
139280
|
+
FUSION_TAGLINE = "multi node agent orchestrator";
|
|
139281
|
+
FUSION_URL = "runfusion.ai";
|
|
139282
|
+
FUSION_VERSION2 = readFusionVersion();
|
|
138968
139283
|
}
|
|
138969
139284
|
});
|
|
138970
139285
|
|
|
@@ -139096,6 +139411,8 @@ function SplashScreen({ loadingStatus }) {
|
|
|
139096
139411
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
|
|
139097
139412
|
compact ? /* @__PURE__ */ jsx(Text, { bold: true, color: "cyanBright", children: "FUSION" }) : /* @__PURE__ */ jsx(AnimatedFusionLogo, { lines: large ? FUSION_LOGO_LARGE_LINES : FUSION_LOGO_LINES }),
|
|
139098
139413
|
/* @__PURE__ */ jsx(Text, { color: "cyanBright", dimColor: true, children: FUSION_TAGLINE }),
|
|
139414
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", dimColor: true, children: FUSION_URL }),
|
|
139415
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", dimColor: true, children: `v${FUSION_VERSION2}` }),
|
|
139099
139416
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
139100
139417
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
139101
139418
|
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
@@ -139127,6 +139444,10 @@ function Panel({ title, isFocused, children, flexGrow, flexShrink, width }) {
|
|
|
139127
139444
|
function SystemPanel({ state, isFocused }) {
|
|
139128
139445
|
const info = state.systemInfo;
|
|
139129
139446
|
return /* @__PURE__ */ jsx(Panel, { title: "System", isFocused, flexGrow: 1, children: !info ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "System information not available." }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
139447
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
139448
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Version:" }),
|
|
139449
|
+
/* @__PURE__ */ jsx(Text, { children: `v${FUSION_VERSION2}` })
|
|
139450
|
+
] }),
|
|
139130
139451
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
139131
139452
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Host:" }),
|
|
139132
139453
|
/* @__PURE__ */ jsx(Text, { children: info.host })
|
|
@@ -139560,7 +139881,7 @@ function StatusBar({ state, controller: _controller }) {
|
|
|
139560
139881
|
}
|
|
139561
139882
|
const statusParts = [];
|
|
139562
139883
|
if (systemInfo) {
|
|
139563
|
-
statusParts.push(systemInfo.baseUrl);
|
|
139884
|
+
statusParts.push(`${systemInfo.baseUrl} v${FUSION_VERSION2}`);
|
|
139564
139885
|
statusParts.push(formatUptime(Date.now() - systemInfo.startTimeMs));
|
|
139565
139886
|
}
|
|
139566
139887
|
return /* @__PURE__ */ jsxs(Box, { height: 1, justifyContent: "space-between", paddingX: 1, flexShrink: 0, overflow: "hidden", children: [
|
|
@@ -145380,8 +145701,8 @@ async function runServe(port, opts = {}) {
|
|
|
145380
145701
|
https: loadTlsCredentialsFromEnv()
|
|
145381
145702
|
});
|
|
145382
145703
|
const server = app.listen(selectedPort, selectedHost);
|
|
145383
|
-
await new Promise((
|
|
145384
|
-
server.once("listening",
|
|
145704
|
+
await new Promise((resolve36, reject2) => {
|
|
145705
|
+
server.once("listening", resolve36);
|
|
145385
145706
|
server.once("error", reject2);
|
|
145386
145707
|
});
|
|
145387
145708
|
const actualPort = server.address().port;
|
|
@@ -145891,8 +146212,8 @@ async function runDaemon(opts = {}) {
|
|
|
145891
146212
|
https: loadTlsCredentialsFromEnv()
|
|
145892
146213
|
});
|
|
145893
146214
|
const server = app.listen(selectedPort, selectedHost);
|
|
145894
|
-
await new Promise((
|
|
145895
|
-
server.once("listening",
|
|
146215
|
+
await new Promise((resolve36, reject2) => {
|
|
146216
|
+
server.once("listening", resolve36);
|
|
145896
146217
|
server.once("error", reject2);
|
|
145897
146218
|
});
|
|
145898
146219
|
const actualPort = server.address().port;
|
|
@@ -146006,7 +146327,7 @@ import { once as once2 } from "node:events";
|
|
|
146006
146327
|
import { join as join53 } from "node:path";
|
|
146007
146328
|
import { createRequire as createRequire5 } from "node:module";
|
|
146008
146329
|
function runCommand(command, args, cwd) {
|
|
146009
|
-
return new Promise((
|
|
146330
|
+
return new Promise((resolve36, reject2) => {
|
|
146010
146331
|
const child = spawn8(command, args, {
|
|
146011
146332
|
cwd,
|
|
146012
146333
|
stdio: "inherit",
|
|
@@ -146015,7 +146336,7 @@ function runCommand(command, args, cwd) {
|
|
|
146015
146336
|
child.on("error", (error) => reject2(error));
|
|
146016
146337
|
child.on("exit", (code) => {
|
|
146017
146338
|
if (code === 0) {
|
|
146018
|
-
|
|
146339
|
+
resolve36();
|
|
146019
146340
|
return;
|
|
146020
146341
|
}
|
|
146021
146342
|
reject2(new Error(`${command} ${args.join(" ")} exited with code ${code ?? "unknown"}`));
|
|
@@ -146058,8 +146379,8 @@ async function startDashboardRuntime(rootDir, paused) {
|
|
|
146058
146379
|
};
|
|
146059
146380
|
}
|
|
146060
146381
|
async function closeDashboardRuntime(runtime) {
|
|
146061
|
-
await new Promise((
|
|
146062
|
-
runtime.server.close(() =>
|
|
146382
|
+
await new Promise((resolve36) => {
|
|
146383
|
+
runtime.server.close(() => resolve36());
|
|
146063
146384
|
});
|
|
146064
146385
|
runtime.store.close();
|
|
146065
146386
|
}
|
|
@@ -146165,7 +146486,7 @@ __export(task_exports, {
|
|
|
146165
146486
|
runTaskUpdate: () => runTaskUpdate
|
|
146166
146487
|
});
|
|
146167
146488
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
146168
|
-
import { watchFile, unwatchFile, statSync as statSync6, existsSync as
|
|
146489
|
+
import { watchFile, unwatchFile, statSync as statSync6, existsSync as existsSync39, readFileSync as readFileSync16 } from "node:fs";
|
|
146169
146490
|
import { join as join54 } from "node:path";
|
|
146170
146491
|
function asLocalProjectContext(store) {
|
|
146171
146492
|
const cwd = process.cwd();
|
|
@@ -146256,9 +146577,9 @@ async function runTaskCreate(descriptionArg, attachFiles, depends, projectName)
|
|
|
146256
146577
|
console.log(` Path: .fusion/tasks/${task.id}/`);
|
|
146257
146578
|
if (attachFiles && attachFiles.length > 0) {
|
|
146258
146579
|
const { readFile: readFile24 } = await import("node:fs/promises");
|
|
146259
|
-
const { basename: basename16, extname: extname2, resolve:
|
|
146580
|
+
const { basename: basename16, extname: extname2, resolve: resolve36 } = await import("node:path");
|
|
146260
146581
|
for (const filePath of attachFiles) {
|
|
146261
|
-
const resolvedPath =
|
|
146582
|
+
const resolvedPath = resolve36(filePath);
|
|
146262
146583
|
const filename = basename16(resolvedPath);
|
|
146263
146584
|
const ext = extname2(filename).toLowerCase();
|
|
146264
146585
|
const mimeType = MIME_TYPES[ext];
|
|
@@ -146393,7 +146714,7 @@ async function runTaskLogs(id, options = {}, projectName) {
|
|
|
146393
146714
|
if (options.follow) {
|
|
146394
146715
|
const projectPath = projectContext?.projectPath ?? process.cwd();
|
|
146395
146716
|
const logPath = join54(projectPath, ".fusion", "tasks", id, "agent.log");
|
|
146396
|
-
if (!
|
|
146717
|
+
if (!existsSync39(logPath)) {
|
|
146397
146718
|
console.log(`
|
|
146398
146719
|
Waiting for log file to be created...`);
|
|
146399
146720
|
}
|
|
@@ -146422,7 +146743,7 @@ async function runTaskLogs(id, options = {}, projectName) {
|
|
|
146422
146743
|
lastPosition = 0;
|
|
146423
146744
|
}
|
|
146424
146745
|
if (stats.size > lastPosition) {
|
|
146425
|
-
const content =
|
|
146746
|
+
const content = readFileSync16(logPath, "utf-8");
|
|
146426
146747
|
const lines = content.slice(lastPosition).split("\n");
|
|
146427
146748
|
for (const line of lines) {
|
|
146428
146749
|
if (!line.trim()) continue;
|
|
@@ -146505,8 +146826,8 @@ async function runTaskMerge(id, projectName) {
|
|
|
146505
146826
|
async function runTaskAttach(id, filePath, projectName) {
|
|
146506
146827
|
const { readFile: readFile24 } = await import("node:fs/promises");
|
|
146507
146828
|
const { basename: basename16, extname: extname2 } = await import("node:path");
|
|
146508
|
-
const { resolve:
|
|
146509
|
-
const resolvedPath =
|
|
146829
|
+
const { resolve: resolve36 } = await import("node:path");
|
|
146830
|
+
const resolvedPath = resolve36(filePath);
|
|
146510
146831
|
const filename = basename16(resolvedPath);
|
|
146511
146832
|
const ext = extname2(filename).toLowerCase();
|
|
146512
146833
|
const mimeType = MIME_TYPES[ext];
|
|
@@ -147023,12 +147344,12 @@ async function promptText(question) {
|
|
|
147023
147344
|
console.log(" (Enter your response. Type DONE on its own line when finished):\n");
|
|
147024
147345
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
147025
147346
|
const lines = [];
|
|
147026
|
-
return new Promise((
|
|
147347
|
+
return new Promise((resolve36) => {
|
|
147027
147348
|
const askLine = () => {
|
|
147028
147349
|
rl.question(" ").then((line) => {
|
|
147029
147350
|
if (line.trim() === "DONE") {
|
|
147030
147351
|
rl.close();
|
|
147031
|
-
|
|
147352
|
+
resolve36(lines.join("\n"));
|
|
147032
147353
|
} else {
|
|
147033
147354
|
lines.push(line);
|
|
147034
147355
|
askLine();
|
|
@@ -147586,7 +147907,7 @@ __export(settings_export_exports, {
|
|
|
147586
147907
|
runSettingsExport: () => runSettingsExport
|
|
147587
147908
|
});
|
|
147588
147909
|
import { writeFile as writeFile15 } from "node:fs/promises";
|
|
147589
|
-
import { resolve as
|
|
147910
|
+
import { resolve as resolve28, join as join55 } from "node:path";
|
|
147590
147911
|
async function runSettingsExport(options = {}) {
|
|
147591
147912
|
const scope = options.scope ?? "both";
|
|
147592
147913
|
const project = options.projectName ? await resolveProject(options.projectName) : void 0;
|
|
@@ -147597,7 +147918,7 @@ async function runSettingsExport(options = {}) {
|
|
|
147597
147918
|
const exportData = await exportSettings(store, { scope });
|
|
147598
147919
|
let targetPath;
|
|
147599
147920
|
if (outputPath) {
|
|
147600
|
-
targetPath =
|
|
147921
|
+
targetPath = resolve28(outputPath);
|
|
147601
147922
|
} else {
|
|
147602
147923
|
const filename = generateExportFilename();
|
|
147603
147924
|
targetPath = join55(process.cwd(), filename);
|
|
@@ -147646,8 +147967,8 @@ var settings_import_exports = {};
|
|
|
147646
147967
|
__export(settings_import_exports, {
|
|
147647
147968
|
runSettingsImport: () => runSettingsImport
|
|
147648
147969
|
});
|
|
147649
|
-
import { existsSync as
|
|
147650
|
-
import { resolve as
|
|
147970
|
+
import { existsSync as existsSync40 } from "node:fs";
|
|
147971
|
+
import { resolve as resolve29 } from "node:path";
|
|
147651
147972
|
async function runSettingsImport(filePath, options = {}) {
|
|
147652
147973
|
const scope = options.scope ?? "both";
|
|
147653
147974
|
const project = options.projectName ? await resolveProject(options.projectName) : void 0;
|
|
@@ -147656,8 +147977,8 @@ async function runSettingsImport(filePath, options = {}) {
|
|
|
147656
147977
|
const merge = options.merge ?? true;
|
|
147657
147978
|
const skipConfirm = options.yes ?? false;
|
|
147658
147979
|
try {
|
|
147659
|
-
const resolvedPath =
|
|
147660
|
-
if (!
|
|
147980
|
+
const resolvedPath = resolve29(filePath);
|
|
147981
|
+
if (!existsSync40(resolvedPath)) {
|
|
147661
147982
|
console.error(`Error: File not found: ${filePath}`);
|
|
147662
147983
|
process.exit(1);
|
|
147663
147984
|
}
|
|
@@ -148130,8 +148451,8 @@ var init_backup2 = __esm({
|
|
|
148130
148451
|
});
|
|
148131
148452
|
|
|
148132
148453
|
// src/project-resolver.ts
|
|
148133
|
-
import { existsSync as
|
|
148134
|
-
import { dirname as
|
|
148454
|
+
import { existsSync as existsSync41, statSync as statSync7 } from "node:fs";
|
|
148455
|
+
import { dirname as dirname23, resolve as resolve30, normalize as normalize5 } from "node:path";
|
|
148135
148456
|
import { createInterface as createInterface5 } from "node:readline/promises";
|
|
148136
148457
|
async function getCentralCore() {
|
|
148137
148458
|
if (!centralCoreInstance) {
|
|
@@ -148148,13 +148469,13 @@ async function getProjectManager() {
|
|
|
148148
148469
|
return projectManagerInstance;
|
|
148149
148470
|
}
|
|
148150
148471
|
function findKbDir(startPath) {
|
|
148151
|
-
let current =
|
|
148472
|
+
let current = resolve30(startPath);
|
|
148152
148473
|
for (let i = 0; i < 100; i++) {
|
|
148153
|
-
const kbPath =
|
|
148154
|
-
if (
|
|
148474
|
+
const kbPath = resolve30(current, ".fusion");
|
|
148475
|
+
if (existsSync41(kbPath) && statSync7(kbPath).isDirectory()) {
|
|
148155
148476
|
return current;
|
|
148156
148477
|
}
|
|
148157
|
-
const parent2 =
|
|
148478
|
+
const parent2 = dirname23(current);
|
|
148158
148479
|
if (parent2 === current) {
|
|
148159
148480
|
break;
|
|
148160
148481
|
}
|
|
@@ -148206,7 +148527,7 @@ async function resolveProject2(options = {}) {
|
|
|
148206
148527
|
{ searchedName: options.project, availableProjects: projects.map((p) => p.name) }
|
|
148207
148528
|
);
|
|
148208
148529
|
}
|
|
148209
|
-
if (!
|
|
148530
|
+
if (!existsSync41(match.path)) {
|
|
148210
148531
|
throw new ProjectResolutionError(
|
|
148211
148532
|
`Project "${match.name}" is registered but the directory no longer exists: ${match.path}
|
|
148212
148533
|
|
|
@@ -148217,14 +148538,14 @@ Run \`fn project remove ` + match.name + "` to clean up the registry entry.",
|
|
|
148217
148538
|
}
|
|
148218
148539
|
return createResolvedProject(match);
|
|
148219
148540
|
}
|
|
148220
|
-
const cwd = options.cwd ?
|
|
148541
|
+
const cwd = options.cwd ? resolve30(options.cwd) : process.cwd();
|
|
148221
148542
|
const fusionDir = findKbDir(cwd);
|
|
148222
148543
|
if (fusionDir) {
|
|
148223
148544
|
const allProjects2 = await central.listProjects();
|
|
148224
148545
|
const normalizedKbDir = normalize5(fusionDir);
|
|
148225
148546
|
const match = allProjects2.find((p) => normalize5(p.path) === normalizedKbDir);
|
|
148226
148547
|
if (match) {
|
|
148227
|
-
if (!
|
|
148548
|
+
if (!existsSync41(match.path)) {
|
|
148228
148549
|
throw new ProjectResolutionError(
|
|
148229
148550
|
`Project "${match.name}" is registered but the directory no longer exists: ${match.path}
|
|
148230
148551
|
|
|
@@ -148289,7 +148610,7 @@ Run \`fn project add ` + fusionDir + "` to register it, or use --project <name>.
|
|
|
148289
148610
|
}
|
|
148290
148611
|
if (allProjects.length === 1) {
|
|
148291
148612
|
const project = allProjects[0];
|
|
148292
|
-
if (!
|
|
148613
|
+
if (!existsSync41(project.path)) {
|
|
148293
148614
|
throw new ProjectResolutionError(
|
|
148294
148615
|
`The only registered project "${project.name}" has a missing directory: ${project.path}
|
|
148295
148616
|
|
|
@@ -148729,11 +149050,11 @@ __export(project_exports, {
|
|
|
148729
149050
|
runProjectSetDefault: () => runProjectSetDefault,
|
|
148730
149051
|
runProjectShow: () => runProjectShow
|
|
148731
149052
|
});
|
|
148732
|
-
import { resolve as
|
|
148733
|
-
import { existsSync as
|
|
149053
|
+
import { resolve as resolve31, isAbsolute as isAbsolute16, relative as relative12, basename as basename13 } from "node:path";
|
|
149054
|
+
import { existsSync as existsSync42, statSync as statSync8 } from "node:fs";
|
|
148734
149055
|
import { createInterface as createInterface7 } from "node:readline/promises";
|
|
148735
149056
|
function formatDisplayPath(projectPath) {
|
|
148736
|
-
const rel =
|
|
149057
|
+
const rel = relative12(process.cwd(), projectPath);
|
|
148737
149058
|
if (rel && !rel.startsWith("..") && rel !== "") {
|
|
148738
149059
|
return rel;
|
|
148739
149060
|
}
|
|
@@ -148858,8 +149179,8 @@ async function runProjectAdd(name, path4, options = {}) {
|
|
|
148858
149179
|
const pathInput = await rl.question(` Project path [${defaultPath}]: `);
|
|
148859
149180
|
projectPath = pathInput.trim() || defaultPath;
|
|
148860
149181
|
}
|
|
148861
|
-
const absolutePath2 =
|
|
148862
|
-
if (!
|
|
149182
|
+
const absolutePath2 = isAbsolute16(projectPath) ? projectPath : resolve31(process.cwd(), projectPath);
|
|
149183
|
+
if (!existsSync42(absolutePath2)) {
|
|
148863
149184
|
console.error(`
|
|
148864
149185
|
\u2717 Path does not exist: ${projectPath}`);
|
|
148865
149186
|
rl.close();
|
|
@@ -148871,8 +149192,8 @@ async function runProjectAdd(name, path4, options = {}) {
|
|
|
148871
149192
|
rl.close();
|
|
148872
149193
|
process.exit(1);
|
|
148873
149194
|
}
|
|
148874
|
-
const kbDbPath2 =
|
|
148875
|
-
if (!
|
|
149195
|
+
const kbDbPath2 = resolve31(absolutePath2, ".fusion", "fusion.db");
|
|
149196
|
+
if (!existsSync42(kbDbPath2) && !options.force) {
|
|
148876
149197
|
console.log(`
|
|
148877
149198
|
No fn project found at ${formatDisplayPath(absolutePath2)}`);
|
|
148878
149199
|
const init = await rl.question(" Initialize fn here first? [Y/n] ");
|
|
@@ -148903,8 +149224,8 @@ async function runProjectAdd(name, path4, options = {}) {
|
|
|
148903
149224
|
console.error(" Name must be 1-64 characters and contain only: a-z, A-Z, 0-9, _, -\n");
|
|
148904
149225
|
process.exit(1);
|
|
148905
149226
|
}
|
|
148906
|
-
const absolutePath =
|
|
148907
|
-
if (!
|
|
149227
|
+
const absolutePath = isAbsolute16(projectPath) ? projectPath : resolve31(process.cwd(), projectPath);
|
|
149228
|
+
if (!existsSync42(absolutePath)) {
|
|
148908
149229
|
console.error(`
|
|
148909
149230
|
\u2717 Path does not exist: ${projectPath}
|
|
148910
149231
|
`);
|
|
@@ -148916,8 +149237,8 @@ async function runProjectAdd(name, path4, options = {}) {
|
|
|
148916
149237
|
`);
|
|
148917
149238
|
process.exit(1);
|
|
148918
149239
|
}
|
|
148919
|
-
const kbDbPath =
|
|
148920
|
-
if (!
|
|
149240
|
+
const kbDbPath = resolve31(absolutePath, ".fusion", "fusion.db");
|
|
149241
|
+
if (!existsSync42(kbDbPath) && !options.force) {
|
|
148921
149242
|
console.error(`
|
|
148922
149243
|
\u2717 No fn project found at ${formatDisplayPath(absolutePath)}`);
|
|
148923
149244
|
console.error(" Run `fn init` first to initialize the project.\n");
|
|
@@ -149173,10 +149494,10 @@ var init_project = __esm({
|
|
|
149173
149494
|
});
|
|
149174
149495
|
|
|
149175
149496
|
// src/commands/skill-installation.ts
|
|
149176
|
-
import { cpSync as cpSync2, existsSync as
|
|
149497
|
+
import { cpSync as cpSync2, existsSync as existsSync43, mkdirSync as mkdirSync8 } from "node:fs";
|
|
149177
149498
|
import { homedir as homedir7 } from "node:os";
|
|
149178
|
-
import { dirname as
|
|
149179
|
-
import { fileURLToPath as
|
|
149499
|
+
import { dirname as dirname24, join as join56, resolve as resolve32 } from "node:path";
|
|
149500
|
+
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
149180
149501
|
function getSupportedSkillInstallTargets(homeDir = process.env.HOME || process.env.USERPROFILE || homedir7()) {
|
|
149181
149502
|
return [
|
|
149182
149503
|
{ client: "claude", targetDir: join56(homeDir, ".claude", "skills", FUSION_SKILL_NAME2) },
|
|
@@ -149185,9 +149506,9 @@ function getSupportedSkillInstallTargets(homeDir = process.env.HOME || process.e
|
|
|
149185
149506
|
];
|
|
149186
149507
|
}
|
|
149187
149508
|
function resolveBundledFusionSkillSource() {
|
|
149188
|
-
const here =
|
|
149189
|
-
const source =
|
|
149190
|
-
return
|
|
149509
|
+
const here = fileURLToPath8(import.meta.url);
|
|
149510
|
+
const source = resolve32(dirname24(here), "..", "..", "skill", FUSION_SKILL_NAME2);
|
|
149511
|
+
return existsSync43(source) ? source : null;
|
|
149191
149512
|
}
|
|
149192
149513
|
function installBundledFusionSkill(options = {}) {
|
|
149193
149514
|
const sourceDir = options.sourceDir ?? resolveBundledFusionSkillSource();
|
|
@@ -149205,7 +149526,7 @@ function installBundledFusionSkill(options = {}) {
|
|
|
149205
149526
|
}
|
|
149206
149527
|
const results = targets.map((target) => {
|
|
149207
149528
|
try {
|
|
149208
|
-
if (
|
|
149529
|
+
if (existsSync43(target.targetDir)) {
|
|
149209
149530
|
return {
|
|
149210
149531
|
client: target.client,
|
|
149211
149532
|
targetDir: target.targetDir,
|
|
@@ -149213,7 +149534,7 @@ function installBundledFusionSkill(options = {}) {
|
|
|
149213
149534
|
reason: "existing install preserved"
|
|
149214
149535
|
};
|
|
149215
149536
|
}
|
|
149216
|
-
mkdirSync8(
|
|
149537
|
+
mkdirSync8(dirname24(target.targetDir), { recursive: true });
|
|
149217
149538
|
cpSync2(sourceDir, target.targetDir, { recursive: true });
|
|
149218
149539
|
return {
|
|
149219
149540
|
client: target.client,
|
|
@@ -149244,15 +149565,15 @@ var init_exports = {};
|
|
|
149244
149565
|
__export(init_exports, {
|
|
149245
149566
|
runInit: () => runInit
|
|
149246
149567
|
});
|
|
149247
|
-
import { existsSync as
|
|
149248
|
-
import { join as join57, resolve as
|
|
149568
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync9, writeFileSync as writeFileSync3, readFileSync as readFileSync17 } from "node:fs";
|
|
149569
|
+
import { join as join57, resolve as resolve33, basename as basename14 } from "node:path";
|
|
149249
149570
|
import { exec as exec11 } from "node:child_process";
|
|
149250
149571
|
import { promisify as promisify16 } from "node:util";
|
|
149251
149572
|
async function runInit(options = {}) {
|
|
149252
|
-
const cwd = options.path ?
|
|
149573
|
+
const cwd = options.path ? resolve33(options.path) : process.cwd();
|
|
149253
149574
|
const fusionDir = join57(cwd, ".fusion");
|
|
149254
149575
|
const dbPath = join57(fusionDir, "fusion.db");
|
|
149255
|
-
if (
|
|
149576
|
+
if (existsSync44(fusionDir) && existsSync44(dbPath)) {
|
|
149256
149577
|
const central2 = new CentralCore();
|
|
149257
149578
|
await central2.init();
|
|
149258
149579
|
const existing = await central2.getProjectByPath(cwd);
|
|
@@ -149277,13 +149598,20 @@ async function runInit(options = {}) {
|
|
|
149277
149598
|
const projectName = options.name ?? await detectProjectName(cwd);
|
|
149278
149599
|
console.log(`Initializing fn project: "${projectName}"`);
|
|
149279
149600
|
console.log(` Path: ${cwd}`);
|
|
149280
|
-
if (!
|
|
149601
|
+
if (!existsSync44(fusionDir)) {
|
|
149281
149602
|
mkdirSync9(fusionDir, { recursive: true });
|
|
149282
149603
|
console.log(` \u2713 Created .fusion/ directory`);
|
|
149283
149604
|
}
|
|
149605
|
+
const hasGitRepo = await isGitRepo2(cwd);
|
|
149606
|
+
if (!hasGitRepo && options.git) {
|
|
149607
|
+
await initializeGitRepo(cwd);
|
|
149608
|
+
console.log(` \u2713 Initialized git repository`);
|
|
149609
|
+
} else if (!hasGitRepo) {
|
|
149610
|
+
console.log(` \u26A0 Not a git repository. Run 'fn init --git' to auto-initialize one.`);
|
|
149611
|
+
}
|
|
149284
149612
|
await addLocalStorageToGitignore(cwd);
|
|
149285
149613
|
await warnIfQmdMissing();
|
|
149286
|
-
if (!
|
|
149614
|
+
if (!existsSync44(dbPath)) {
|
|
149287
149615
|
const sqliteHeader = Buffer.from([
|
|
149288
149616
|
83,
|
|
149289
149617
|
81,
|
|
@@ -149351,7 +149679,7 @@ async function runInit(options = {}) {
|
|
|
149351
149679
|
}
|
|
149352
149680
|
}
|
|
149353
149681
|
async function detectProjectName(dir2) {
|
|
149354
|
-
if (!
|
|
149682
|
+
if (!existsSync44(join57(dir2, ".git"))) {
|
|
149355
149683
|
return basename14(dir2) || "my-project";
|
|
149356
149684
|
}
|
|
149357
149685
|
try {
|
|
@@ -149373,9 +149701,9 @@ async function detectProjectName(dir2) {
|
|
|
149373
149701
|
async function addLocalStorageToGitignore(cwd) {
|
|
149374
149702
|
const gitignorePath = join57(cwd, ".gitignore");
|
|
149375
149703
|
let content = "";
|
|
149376
|
-
if (
|
|
149704
|
+
if (existsSync44(gitignorePath)) {
|
|
149377
149705
|
try {
|
|
149378
|
-
content =
|
|
149706
|
+
content = readFileSync17(gitignorePath, "utf-8");
|
|
149379
149707
|
} catch {
|
|
149380
149708
|
}
|
|
149381
149709
|
}
|
|
@@ -149395,6 +149723,45 @@ async function addLocalStorageToGitignore(cwd) {
|
|
|
149395
149723
|
console.log(` \u26A0 Could not update .gitignore (best-effort)`);
|
|
149396
149724
|
}
|
|
149397
149725
|
}
|
|
149726
|
+
async function initializeGitRepo(cwd) {
|
|
149727
|
+
await execAsync11("git init", { cwd, timeout: 1e4 });
|
|
149728
|
+
try {
|
|
149729
|
+
const { stdout } = await execAsync11("git symbolic-ref --quiet --short HEAD", {
|
|
149730
|
+
cwd,
|
|
149731
|
+
timeout: 1e4
|
|
149732
|
+
});
|
|
149733
|
+
if (stdout.trim() !== "main") {
|
|
149734
|
+
await execAsync11("git checkout -b main", { cwd, timeout: 1e4 });
|
|
149735
|
+
}
|
|
149736
|
+
} catch {
|
|
149737
|
+
try {
|
|
149738
|
+
await execAsync11("git checkout -b main", { cwd, timeout: 1e4 });
|
|
149739
|
+
} catch {
|
|
149740
|
+
await execAsync11("git checkout main", { cwd, timeout: 1e4 });
|
|
149741
|
+
}
|
|
149742
|
+
}
|
|
149743
|
+
await ensureGitConfig(cwd, "user.name", "Fusion");
|
|
149744
|
+
await ensureGitConfig(cwd, "user.email", "noreply@runfusion.ai");
|
|
149745
|
+
const gitkeepPath = join57(cwd, ".gitkeep");
|
|
149746
|
+
if (!existsSync44(gitkeepPath)) {
|
|
149747
|
+
writeFileSync3(gitkeepPath, "\n");
|
|
149748
|
+
}
|
|
149749
|
+
await execAsync11("git add .gitkeep", { cwd, timeout: 1e4 });
|
|
149750
|
+
await execAsync11('git commit --allow-empty -m "chore: initial commit"', {
|
|
149751
|
+
cwd,
|
|
149752
|
+
timeout: 1e4
|
|
149753
|
+
});
|
|
149754
|
+
}
|
|
149755
|
+
async function ensureGitConfig(cwd, key, value) {
|
|
149756
|
+
try {
|
|
149757
|
+
const { stdout } = await execAsync11(`git config --get ${key}`, { cwd, timeout: 1e4 });
|
|
149758
|
+
if (stdout.trim().length > 0) {
|
|
149759
|
+
return;
|
|
149760
|
+
}
|
|
149761
|
+
} catch {
|
|
149762
|
+
}
|
|
149763
|
+
await execAsync11(`git config ${key} "${value}"`, { cwd, timeout: 1e4 });
|
|
149764
|
+
}
|
|
149398
149765
|
async function warnIfQmdMissing() {
|
|
149399
149766
|
if (await isQmdAvailable()) {
|
|
149400
149767
|
console.log(` \u2713 qmd available for memory search`);
|
|
@@ -149425,6 +149792,7 @@ var init_init = __esm({
|
|
|
149425
149792
|
"use strict";
|
|
149426
149793
|
init_src();
|
|
149427
149794
|
init_claude_skills_runner();
|
|
149795
|
+
init_git();
|
|
149428
149796
|
init_skill_installation();
|
|
149429
149797
|
execAsync11 = promisify16(exec11);
|
|
149430
149798
|
}
|
|
@@ -149513,8 +149881,8 @@ var agent_import_exports = {};
|
|
|
149513
149881
|
__export(agent_import_exports, {
|
|
149514
149882
|
runAgentImport: () => runAgentImport
|
|
149515
149883
|
});
|
|
149516
|
-
import { existsSync as
|
|
149517
|
-
import { resolve as
|
|
149884
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync10, readFileSync as readFileSync18, statSync as statSync9, writeFileSync as writeFileSync4 } from "node:fs";
|
|
149885
|
+
import { resolve as resolve34 } from "node:path";
|
|
149518
149886
|
function slugifyPathSegment(input) {
|
|
149519
149887
|
if (!input || typeof input !== "string") {
|
|
149520
149888
|
return "unnamed";
|
|
@@ -149563,16 +149931,16 @@ async function importSkillsToProject(projectPath, skills, companySlug, dryRun) {
|
|
|
149563
149931
|
errors: []
|
|
149564
149932
|
};
|
|
149565
149933
|
const companyDir = slugifyPathSegment(companySlug ?? "unknown-company");
|
|
149566
|
-
const baseSkillsDir =
|
|
149934
|
+
const baseSkillsDir = resolve34(projectPath, "skills", "imported", companyDir);
|
|
149567
149935
|
for (const skill of skills) {
|
|
149568
149936
|
if (!skill.name || typeof skill.name !== "string" || skill.name.trim().length === 0) {
|
|
149569
149937
|
result.errors.push({ name: "(unnamed)", error: "Skill is missing required 'name' field" });
|
|
149570
149938
|
continue;
|
|
149571
149939
|
}
|
|
149572
149940
|
const skillSlug = slugifyPathSegment(skill.name);
|
|
149573
|
-
const skillDir =
|
|
149574
|
-
const skillPath =
|
|
149575
|
-
if (
|
|
149941
|
+
const skillDir = resolve34(baseSkillsDir, skillSlug);
|
|
149942
|
+
const skillPath = resolve34(skillDir, "SKILL.md");
|
|
149943
|
+
if (existsSync45(skillPath)) {
|
|
149576
149944
|
result.skipped.push(skill.name);
|
|
149577
149945
|
continue;
|
|
149578
149946
|
}
|
|
@@ -149644,8 +150012,8 @@ function isArchivePath(path4) {
|
|
|
149644
150012
|
async function runAgentImport(source, options) {
|
|
149645
150013
|
const dryRun = options?.dryRun ?? false;
|
|
149646
150014
|
const skipExisting = options?.skipExisting ?? false;
|
|
149647
|
-
const sourcePath =
|
|
149648
|
-
if (!
|
|
150015
|
+
const sourcePath = resolve34(source);
|
|
150016
|
+
if (!existsSync45(sourcePath)) {
|
|
149649
150017
|
console.error(`Path not found: ${sourcePath}`);
|
|
149650
150018
|
process.exit(1);
|
|
149651
150019
|
}
|
|
@@ -149691,7 +150059,7 @@ async function runAgentImport(source, options) {
|
|
|
149691
150059
|
isPackageImport = true;
|
|
149692
150060
|
({ items: importItems, result } = prepareAgentCompaniesImport(pkg, conversionOptions));
|
|
149693
150061
|
} else if (sourcePath.endsWith(".md")) {
|
|
149694
|
-
const content =
|
|
150062
|
+
const content = readFileSync18(sourcePath, "utf-8");
|
|
149695
150063
|
const { manifest } = parseSingleAgentManifest(content);
|
|
149696
150064
|
const pkg = {
|
|
149697
150065
|
company: void 0,
|
|
@@ -149783,7 +150151,7 @@ var agent_export_exports = {};
|
|
|
149783
150151
|
__export(agent_export_exports, {
|
|
149784
150152
|
runAgentExport: () => runAgentExport
|
|
149785
150153
|
});
|
|
149786
|
-
import { resolve as
|
|
150154
|
+
import { resolve as resolve35 } from "node:path";
|
|
149787
150155
|
async function getProjectPath4(projectName) {
|
|
149788
150156
|
if (projectName) {
|
|
149789
150157
|
const context = await resolveProject(projectName);
|
|
@@ -149821,7 +150189,7 @@ async function runAgentExport(outputDir, options) {
|
|
|
149821
150189
|
console.error("No agents found to export");
|
|
149822
150190
|
process.exit(1);
|
|
149823
150191
|
}
|
|
149824
|
-
const result = await exportAgentsToDirectory(agents,
|
|
150192
|
+
const result = await exportAgentsToDirectory(agents, resolve35(outputDir), {
|
|
149825
150193
|
companyName: options?.companyName,
|
|
149826
150194
|
companySlug: options?.companySlug
|
|
149827
150195
|
});
|
|
@@ -150040,7 +150408,7 @@ __export(plugin_exports, {
|
|
|
150040
150408
|
runPluginList: () => runPluginList,
|
|
150041
150409
|
runPluginUninstall: () => runPluginUninstall
|
|
150042
150410
|
});
|
|
150043
|
-
import { existsSync as
|
|
150411
|
+
import { existsSync as existsSync46 } from "node:fs";
|
|
150044
150412
|
import { join as join58 } from "node:path";
|
|
150045
150413
|
import { readFile as readFile23 } from "node:fs/promises";
|
|
150046
150414
|
import * as readline from "node:readline";
|
|
@@ -150079,7 +150447,7 @@ async function createPluginLoader(pluginStore, projectName) {
|
|
|
150079
150447
|
}
|
|
150080
150448
|
async function loadManifestFromPath(pluginPath) {
|
|
150081
150449
|
const manifestPath = join58(pluginPath, "manifest.json");
|
|
150082
|
-
if (!
|
|
150450
|
+
if (!existsSync46(manifestPath)) {
|
|
150083
150451
|
throw new Error(`Plugin manifest not found at: ${manifestPath}`);
|
|
150084
150452
|
}
|
|
150085
150453
|
const content = await readFile23(manifestPath, "utf-8");
|
|
@@ -150137,7 +150505,7 @@ async function runPluginInstall(source, options) {
|
|
|
150137
150505
|
console.error("Please provide a local path to the plugin directory.");
|
|
150138
150506
|
process.exit(1);
|
|
150139
150507
|
}
|
|
150140
|
-
if (!
|
|
150508
|
+
if (!existsSync46(source)) {
|
|
150141
150509
|
console.error(`Plugin path does not exist: ${source}`);
|
|
150142
150510
|
process.exit(1);
|
|
150143
150511
|
}
|
|
@@ -150182,14 +150550,14 @@ async function runPluginUninstall(id, options) {
|
|
|
150182
150550
|
console.log(` Uninstall "${plugin.name}"?`);
|
|
150183
150551
|
console.log(` This will stop and remove the plugin.`);
|
|
150184
150552
|
console.log();
|
|
150185
|
-
const response = await new Promise((
|
|
150553
|
+
const response = await new Promise((resolve36) => {
|
|
150186
150554
|
const rl = readline.createInterface({
|
|
150187
150555
|
input: process.stdin,
|
|
150188
150556
|
output: process.stdout
|
|
150189
150557
|
});
|
|
150190
150558
|
rl.question(" Continue? [y/N] ", (answer) => {
|
|
150191
150559
|
rl.close();
|
|
150192
|
-
|
|
150560
|
+
resolve36(answer.toLowerCase());
|
|
150193
150561
|
});
|
|
150194
150562
|
});
|
|
150195
150563
|
if (response !== "y" && response !== "yes") {
|
|
@@ -150269,7 +150637,7 @@ var plugin_scaffold_exports = {};
|
|
|
150269
150637
|
__export(plugin_scaffold_exports, {
|
|
150270
150638
|
runPluginCreate: () => runPluginCreate
|
|
150271
150639
|
});
|
|
150272
|
-
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync5, existsSync as
|
|
150640
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync5, existsSync as existsSync47 } from "node:fs";
|
|
150273
150641
|
import { join as join59 } from "node:path";
|
|
150274
150642
|
function toTitleCase(str) {
|
|
150275
150643
|
return str.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
@@ -150404,7 +150772,7 @@ async function runPluginCreate(name, options) {
|
|
|
150404
150772
|
}
|
|
150405
150773
|
const targetDir = options?.output ?? name;
|
|
150406
150774
|
const targetPath = join59(process.cwd(), targetDir);
|
|
150407
|
-
if (
|
|
150775
|
+
if (existsSync47(targetPath)) {
|
|
150408
150776
|
console.error(`Error: Directory '${targetDir}' already exists.`);
|
|
150409
150777
|
console.error("Please choose a different name or remove the existing directory.");
|
|
150410
150778
|
process.exit(1);
|
|
@@ -150536,9 +150904,9 @@ async function runSkillsInstall(args, options) {
|
|
|
150536
150904
|
cwd: process.cwd(),
|
|
150537
150905
|
stdio: "inherit"
|
|
150538
150906
|
});
|
|
150539
|
-
const exitCode = await new Promise((
|
|
150907
|
+
const exitCode = await new Promise((resolve36, reject2) => {
|
|
150540
150908
|
child.on("exit", (code) => {
|
|
150541
|
-
|
|
150909
|
+
resolve36(code ?? 1);
|
|
150542
150910
|
});
|
|
150543
150911
|
child.on("error", (err) => {
|
|
150544
150912
|
reject2(err);
|
|
@@ -150569,21 +150937,21 @@ __export(native_patch_exports, {
|
|
|
150569
150937
|
isTerminalAvailable: () => isTerminalAvailable,
|
|
150570
150938
|
setupNativeResolution: () => setupNativeResolution
|
|
150571
150939
|
});
|
|
150572
|
-
import { join as join60, basename as basename15, dirname as
|
|
150573
|
-
import { existsSync as
|
|
150940
|
+
import { join as join60, basename as basename15, dirname as dirname25 } from "node:path";
|
|
150941
|
+
import { existsSync as existsSync48, copyFileSync, mkdirSync as mkdirSync12, symlinkSync as symlinkSync2, rmSync as rmSync5, lstatSync as lstatSync3, readlinkSync as readlinkSync2 } from "node:fs";
|
|
150574
150942
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
150575
150943
|
function findStagedNativeDir2() {
|
|
150576
150944
|
const platform3 = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : process.platform === "win32" ? "win32" : "unknown";
|
|
150577
150945
|
const arch = process.arch === "arm64" ? "arm64" : process.arch === "x64" ? "x64" : "unknown";
|
|
150578
150946
|
const prebuildName = `${platform3}-${arch}`;
|
|
150579
|
-
const execDir =
|
|
150947
|
+
const execDir = dirname25(process.execPath);
|
|
150580
150948
|
const nextToBinary = join60(execDir, "runtime", prebuildName);
|
|
150581
|
-
if (
|
|
150949
|
+
if (existsSync48(join60(nextToBinary, "pty.node"))) {
|
|
150582
150950
|
return nextToBinary;
|
|
150583
150951
|
}
|
|
150584
150952
|
if (process.env.FUSION_RUNTIME_DIR) {
|
|
150585
150953
|
const envPath = join60(process.env.FUSION_RUNTIME_DIR, prebuildName);
|
|
150586
|
-
if (
|
|
150954
|
+
if (existsSync48(join60(envPath, "pty.node"))) {
|
|
150587
150955
|
return envPath;
|
|
150588
150956
|
}
|
|
150589
150957
|
}
|
|
@@ -150593,12 +150961,12 @@ function cleanupStaleBunfsLinks() {
|
|
|
150593
150961
|
if (process.platform === "win32") return;
|
|
150594
150962
|
const bunfsRoot = "/$bunfs/root";
|
|
150595
150963
|
try {
|
|
150596
|
-
if (
|
|
150964
|
+
if (existsSync48(bunfsRoot)) {
|
|
150597
150965
|
const stats = lstatSync3(bunfsRoot);
|
|
150598
150966
|
if (stats.isSymbolicLink()) {
|
|
150599
150967
|
const target = readlinkSync2(bunfsRoot);
|
|
150600
|
-
if (target.includes("fn-bunfs-") && !
|
|
150601
|
-
|
|
150968
|
+
if (target.includes("fn-bunfs-") && !existsSync48(target)) {
|
|
150969
|
+
rmSync5(bunfsRoot);
|
|
150602
150970
|
console.log("[fn-native-patch] Cleaned up stale /$bunfs/root symlink");
|
|
150603
150971
|
}
|
|
150604
150972
|
}
|
|
@@ -150625,17 +150993,17 @@ function setupNativeResolution() {
|
|
|
150625
150993
|
mkdirSync12(platformDir, { recursive: true });
|
|
150626
150994
|
const ptyNodeDest = join60(platformDir, "pty.node");
|
|
150627
150995
|
copyFileSync(join60(nativeDir, "pty.node"), ptyNodeDest);
|
|
150628
|
-
if (
|
|
150996
|
+
if (existsSync48(join60(nativeDir, "spawn-helper"))) {
|
|
150629
150997
|
copyFileSync(join60(nativeDir, "spawn-helper"), join60(platformDir, "spawn-helper"));
|
|
150630
150998
|
}
|
|
150631
150999
|
process.env.FUSION_FAKE_BUNFS_ROOT = tmpRoot;
|
|
150632
151000
|
if (process.platform !== "win32") {
|
|
150633
151001
|
const bunfsRoot = "/$bunfs/root";
|
|
150634
151002
|
try {
|
|
150635
|
-
if (
|
|
151003
|
+
if (existsSync48(bunfsRoot)) {
|
|
150636
151004
|
const stats = lstatSync3(bunfsRoot);
|
|
150637
151005
|
if (stats.isSymbolicLink()) {
|
|
150638
|
-
|
|
151006
|
+
rmSync5(bunfsRoot);
|
|
150639
151007
|
}
|
|
150640
151008
|
}
|
|
150641
151009
|
symlinkSync2(fnDir, bunfsRoot);
|
|
@@ -150655,10 +151023,10 @@ function setupNativeResolution() {
|
|
|
150655
151023
|
function cleanupNativeResolution() {
|
|
150656
151024
|
if (bunfsSymlinkPath && process.platform !== "win32") {
|
|
150657
151025
|
try {
|
|
150658
|
-
if (
|
|
151026
|
+
if (existsSync48(bunfsSymlinkPath)) {
|
|
150659
151027
|
const stats = lstatSync3(bunfsSymlinkPath);
|
|
150660
151028
|
if (stats.isSymbolicLink()) {
|
|
150661
|
-
|
|
151029
|
+
rmSync5(bunfsSymlinkPath);
|
|
150662
151030
|
}
|
|
150663
151031
|
}
|
|
150664
151032
|
} catch {
|
|
@@ -150701,9 +151069,9 @@ var init_native_patch = __esm({
|
|
|
150701
151069
|
});
|
|
150702
151070
|
|
|
150703
151071
|
// src/bin.ts
|
|
150704
|
-
import { existsSync as
|
|
151072
|
+
import { existsSync as existsSync49, mkdtempSync as mkdtempSync2, readFileSync as readFileSync19, symlinkSync as symlinkSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
150705
151073
|
import { createRequire as createRequire6 } from "node:module";
|
|
150706
|
-
import { join as join61, dirname as
|
|
151074
|
+
import { join as join61, dirname as dirname26 } from "node:path";
|
|
150707
151075
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
150708
151076
|
import { performance as performance3 } from "node:perf_hooks";
|
|
150709
151077
|
var isBunBinary3 = typeof Bun !== "undefined" && !!Bun.embeddedFiles;
|
|
@@ -150720,11 +151088,11 @@ function configurePiPackage() {
|
|
|
150720
151088
|
try {
|
|
150721
151089
|
const require4 = createRequire6(import.meta.url);
|
|
150722
151090
|
const piPackagePath = require4.resolve("@mariozechner/pi-coding-agent/package.json");
|
|
150723
|
-
const piPackageDir =
|
|
150724
|
-
packageJson = JSON.parse(
|
|
151091
|
+
const piPackageDir = dirname26(piPackagePath);
|
|
151092
|
+
packageJson = JSON.parse(readFileSync19(piPackagePath, "utf-8"));
|
|
150725
151093
|
for (const entry of ["dist", "docs", "examples", "README.md", "CHANGELOG.md"]) {
|
|
150726
151094
|
const source = join61(piPackageDir, entry);
|
|
150727
|
-
if (
|
|
151095
|
+
if (existsSync49(source)) {
|
|
150728
151096
|
symlinkSync3(source, join61(tmp, entry));
|
|
150729
151097
|
}
|
|
150730
151098
|
}
|
|
@@ -150743,8 +151111,8 @@ setInterval(() => {
|
|
|
150743
151111
|
performance3.clearMarks();
|
|
150744
151112
|
}, 3e4).unref();
|
|
150745
151113
|
function loadEnvFile(path4) {
|
|
150746
|
-
if (!
|
|
150747
|
-
const contents =
|
|
151114
|
+
if (!existsSync49(path4)) return;
|
|
151115
|
+
const contents = readFileSync19(path4, "utf-8");
|
|
150748
151116
|
for (const rawLine of contents.split(/\r?\n/)) {
|
|
150749
151117
|
const line = rawLine.trim();
|
|
150750
151118
|
if (!line || line.startsWith("#")) continue;
|
|
@@ -150872,7 +151240,7 @@ fn \u2014 AI-orchestrated task board
|
|
|
150872
151240
|
|
|
150873
151241
|
Usage:
|
|
150874
151242
|
fn Launch the dashboard (same as fn dashboard)
|
|
150875
|
-
fn init [opts] Initialize a new fn project
|
|
151243
|
+
fn init [opts] Initialize a new fn project (--name, --path, --git)
|
|
150876
151244
|
fn dashboard Start the board web UI
|
|
150877
151245
|
fn dashboard --paused Start with automation paused
|
|
150878
151246
|
fn dashboard --dev Start web UI only (no AI engine)
|
|
@@ -151131,7 +151499,8 @@ async function main() {
|
|
|
151131
151499
|
const name = nameIdx !== -1 && nameIdx + 1 < args.length ? args[nameIdx + 1] : void 0;
|
|
151132
151500
|
const pathIdx = args.indexOf("--path");
|
|
151133
151501
|
const path4 = pathIdx !== -1 && pathIdx + 1 < args.length ? args[pathIdx + 1] : void 0;
|
|
151134
|
-
|
|
151502
|
+
const git = args.includes("--git");
|
|
151503
|
+
await runInit2({ name, path: path4, git });
|
|
151135
151504
|
break;
|
|
151136
151505
|
}
|
|
151137
151506
|
case "dashboard": {
|