@runfusion/fusion 0.8.0 → 0.8.2
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 +962 -566
- package/dist/client/assets/{AgentDetailView-C3Xcrxnp.js → AgentDetailView-B6wfIQ9j.js} +1 -1
- package/dist/client/assets/{AgentsView-EjE4y4rM.js → AgentsView-Fcym0XCw.js} +3 -3
- package/dist/client/assets/{ChatView-DQLvKCYj.js → ChatView-DEckS3f3.js} +1 -1
- package/dist/client/assets/{DevServerView-CX7paFRQ.js → DevServerView-CmMS4D6V.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-_cBPx6Nx.js → DirectoryPicker-CQtE-YyA.js} +1 -1
- package/dist/client/assets/{DocumentsView-Wz33aYqp.js → DocumentsView-C4HDkN_0.js} +1 -1
- package/dist/client/assets/{InsightsView-C7YPnS92.js → InsightsView-oNQ7h5e8.js} +1 -1
- package/dist/client/assets/{MemoryView-DKQtFzFQ.js → MemoryView-DPYGW09y.js} +1 -1
- package/dist/client/assets/{NodesView-CI4rUQC4.js → NodesView-DsM-c8RF.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-BFmdKgHZ.js → PiExtensionsManager-DHgMjjRE.js} +1 -1
- package/dist/client/assets/{PluginManager-BGQU1IIw.js → PluginManager-N-7Sw_tE.js} +1 -1
- package/dist/client/assets/{RoadmapsView-Cts3hoIS.js → RoadmapsView-BgX79uYM.js} +1 -1
- package/dist/client/assets/{SettingsModal-DXvBGZHf.js → SettingsModal-BIKEMPwb.js} +1 -1
- package/dist/client/assets/{SettingsModal-DvRd0ZOE.js → SettingsModal-C4EwtN6K.js} +4 -4
- package/dist/client/assets/SetupWizardModal-D2m0i9Io.js +1 -0
- package/dist/client/assets/{SkillsView-BXvrHzEZ.js → SkillsView-Eb1Mngnt.js} +1 -1
- package/dist/client/assets/{TodoView-NZHkv9YQ.js → TodoView-BN8FQYyp.js} +1 -1
- package/dist/client/assets/{folder-open-Kh0ScTc5.js → folder-open-BqZBHfoZ.js} +1 -1
- package/dist/client/assets/{index-CWz44REw.css → index-D2fXOwWF.css} +1 -1
- package/dist/client/assets/{index-D1gavMG-.js → index-DlHPhpDu.js} +3 -3
- package/dist/client/assets/{list-checks-CvoT0bwU.js → list-checks-D2EURsP0.js} +1 -1
- package/dist/client/assets/{star-BdfwSLBU.js → star-CNQlAD8p.js} +1 -1
- package/dist/client/assets/{upload-Bx8Yk_7Q.js → upload-uoxlYkig.js} +1 -1
- package/dist/client/assets/{users-DgVaFEsz.js → users-BLvidusm.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/extension.js +500 -196
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/pi-claude-cli/src/process-manager.ts +1 -1
- package/package.json +1 -1
- package/dist/client/assets/SetupWizardModal-Y2ewEE8Y.js +0 -1
- package/dist/pi-claude-cli/src/types/cross-spawn.d.ts +0 -7
package/dist/bin.js
CHANGED
|
@@ -2434,7 +2434,7 @@ var init_db = __esm({
|
|
|
2434
2434
|
"use strict";
|
|
2435
2435
|
init_sqlite_adapter();
|
|
2436
2436
|
init_types();
|
|
2437
|
-
SCHEMA_VERSION =
|
|
2437
|
+
SCHEMA_VERSION = 51;
|
|
2438
2438
|
SCHEMA_SQL = `
|
|
2439
2439
|
-- Tasks table with JSON columns for nested data
|
|
2440
2440
|
CREATE TABLE IF NOT EXISTS tasks (
|
|
@@ -3967,6 +3967,13 @@ CREATE INDEX IF NOT EXISTS idxTodoItemsSortOrder ON todo_items(listId, sortOrder
|
|
|
3967
3967
|
this.addColumnIfMissing("tasks", "effectiveNodeSource", "TEXT");
|
|
3968
3968
|
});
|
|
3969
3969
|
}
|
|
3970
|
+
if (version < 51) {
|
|
3971
|
+
this.applyMigration(51, () => {
|
|
3972
|
+
if (this.hasTable("chat_messages")) {
|
|
3973
|
+
this.addColumnIfMissing("chat_messages", "attachments", "TEXT");
|
|
3974
|
+
}
|
|
3975
|
+
});
|
|
3976
|
+
}
|
|
3970
3977
|
}
|
|
3971
3978
|
/**
|
|
3972
3979
|
* Run a single migration step inside a transaction and bump the version.
|
|
@@ -6479,9 +6486,9 @@ var init_global_settings = __esm({
|
|
|
6479
6486
|
* Serialize operations via promise chain to prevent lost-update races.
|
|
6480
6487
|
*/
|
|
6481
6488
|
withLock(fn) {
|
|
6482
|
-
let
|
|
6489
|
+
let resolve39;
|
|
6483
6490
|
const next = new Promise((r) => {
|
|
6484
|
-
|
|
6491
|
+
resolve39 = r;
|
|
6485
6492
|
});
|
|
6486
6493
|
const prev = this.lock;
|
|
6487
6494
|
this.lock = next;
|
|
@@ -6489,7 +6496,7 @@ var init_global_settings = __esm({
|
|
|
6489
6496
|
try {
|
|
6490
6497
|
return await fn();
|
|
6491
6498
|
} finally {
|
|
6492
|
-
|
|
6499
|
+
resolve39();
|
|
6493
6500
|
}
|
|
6494
6501
|
});
|
|
6495
6502
|
}
|
|
@@ -11799,8 +11806,8 @@ import { join as join8, dirname as dirname2 } from "node:path";
|
|
|
11799
11806
|
import { fileURLToPath } from "node:url";
|
|
11800
11807
|
function getAppVersion() {
|
|
11801
11808
|
if (cachedVersion !== null) return cachedVersion;
|
|
11802
|
-
const
|
|
11803
|
-
let currentDir =
|
|
11809
|
+
const __dirname2 = dirname2(fileURLToPath(import.meta.url));
|
|
11810
|
+
let currentDir = __dirname2;
|
|
11804
11811
|
for (let i = 0; i < 10; i++) {
|
|
11805
11812
|
try {
|
|
11806
11813
|
const pkgPath = join8(currentDir, "package.json");
|
|
@@ -27785,9 +27792,9 @@ var init_automation_store = __esm({
|
|
|
27785
27792
|
*/
|
|
27786
27793
|
withScheduleLock(id, fn) {
|
|
27787
27794
|
const prev = this.scheduleLocks.get(id) ?? Promise.resolve();
|
|
27788
|
-
let
|
|
27795
|
+
let resolve39;
|
|
27789
27796
|
const next = new Promise((r) => {
|
|
27790
|
-
|
|
27797
|
+
resolve39 = r;
|
|
27791
27798
|
});
|
|
27792
27799
|
this.scheduleLocks.set(id, next);
|
|
27793
27800
|
return prev.then(async () => {
|
|
@@ -27797,7 +27804,7 @@ var init_automation_store = __esm({
|
|
|
27797
27804
|
if (this.scheduleLocks.get(id) === next) {
|
|
27798
27805
|
this.scheduleLocks.delete(id);
|
|
27799
27806
|
}
|
|
27800
|
-
|
|
27807
|
+
resolve39();
|
|
27801
27808
|
}
|
|
27802
27809
|
});
|
|
27803
27810
|
}
|
|
@@ -29585,7 +29592,7 @@ var init_project_memory = __esm({
|
|
|
29585
29592
|
// ../core/src/run-command.ts
|
|
29586
29593
|
import { spawn } from "node:child_process";
|
|
29587
29594
|
function runCommandAsync(command, options = {}) {
|
|
29588
|
-
return new Promise((
|
|
29595
|
+
return new Promise((resolve39) => {
|
|
29589
29596
|
const maxBuffer = options.maxBuffer ?? DEFAULT_MAX_BUFFER;
|
|
29590
29597
|
let stdout = "";
|
|
29591
29598
|
let stderr = "";
|
|
@@ -29644,7 +29651,7 @@ function runCommandAsync(command, options = {}) {
|
|
|
29644
29651
|
clearTimeout(forceKillTimer);
|
|
29645
29652
|
forceKillTimer = null;
|
|
29646
29653
|
}
|
|
29647
|
-
|
|
29654
|
+
resolve39({
|
|
29648
29655
|
stdout,
|
|
29649
29656
|
stderr,
|
|
29650
29657
|
exitCode: null,
|
|
@@ -29662,7 +29669,7 @@ function runCommandAsync(command, options = {}) {
|
|
|
29662
29669
|
}
|
|
29663
29670
|
signalProcessGroup("SIGTERM");
|
|
29664
29671
|
scheduleForceKill(NORMAL_CLEANUP_FORCE_KILL_DELAY_MS);
|
|
29665
|
-
|
|
29672
|
+
resolve39({
|
|
29666
29673
|
stdout,
|
|
29667
29674
|
stderr,
|
|
29668
29675
|
exitCode: code,
|
|
@@ -30812,9 +30819,9 @@ ${outcome}`;
|
|
|
30812
30819
|
* lost-update races on the nextId counter.
|
|
30813
30820
|
*/
|
|
30814
30821
|
withConfigLock(fn) {
|
|
30815
|
-
let
|
|
30822
|
+
let resolve39;
|
|
30816
30823
|
const next = new Promise((r) => {
|
|
30817
|
-
|
|
30824
|
+
resolve39 = r;
|
|
30818
30825
|
});
|
|
30819
30826
|
const prev = this.configLock;
|
|
30820
30827
|
this.configLock = next;
|
|
@@ -30822,7 +30829,7 @@ ${outcome}`;
|
|
|
30822
30829
|
try {
|
|
30823
30830
|
return await fn();
|
|
30824
30831
|
} finally {
|
|
30825
|
-
|
|
30832
|
+
resolve39();
|
|
30826
30833
|
}
|
|
30827
30834
|
});
|
|
30828
30835
|
}
|
|
@@ -30832,9 +30839,9 @@ ${outcome}`;
|
|
|
30832
30839
|
*/
|
|
30833
30840
|
withTaskLock(id, fn) {
|
|
30834
30841
|
const prev = this.taskLocks.get(id) ?? Promise.resolve();
|
|
30835
|
-
let
|
|
30842
|
+
let resolve39;
|
|
30836
30843
|
const next = new Promise((r) => {
|
|
30837
|
-
|
|
30844
|
+
resolve39 = r;
|
|
30838
30845
|
});
|
|
30839
30846
|
this.taskLocks.set(id, next);
|
|
30840
30847
|
return prev.then(async () => {
|
|
@@ -30844,7 +30851,7 @@ ${outcome}`;
|
|
|
30844
30851
|
if (this.taskLocks.get(id) === next) {
|
|
30845
30852
|
this.taskLocks.delete(id);
|
|
30846
30853
|
}
|
|
30847
|
-
|
|
30854
|
+
resolve39();
|
|
30848
30855
|
}
|
|
30849
30856
|
});
|
|
30850
30857
|
}
|
|
@@ -32502,8 +32509,8 @@ ${task.description}
|
|
|
32502
32509
|
if (this.isWatching) this.taskCache.delete(id);
|
|
32503
32510
|
const dir2 = this.taskDir(id);
|
|
32504
32511
|
if (existsSync12(dir2)) {
|
|
32505
|
-
const { rm:
|
|
32506
|
-
await
|
|
32512
|
+
const { rm: rm6 } = await import("node:fs/promises");
|
|
32513
|
+
await rm6(dir2, { recursive: true });
|
|
32507
32514
|
}
|
|
32508
32515
|
for (const dependentTask of rewrittenDependents) {
|
|
32509
32516
|
this.emit("task:updated", dependentTask);
|
|
@@ -32838,8 +32845,8 @@ ${task.description}
|
|
|
32838
32845
|
this.archiveDb.upsert(entry);
|
|
32839
32846
|
this.db.prepare("DELETE FROM tasks WHERE id = ?").run(id);
|
|
32840
32847
|
this.db.bumpLastModified();
|
|
32841
|
-
const { rm:
|
|
32842
|
-
await
|
|
32848
|
+
const { rm: rm6 } = await import("node:fs/promises");
|
|
32849
|
+
await rm6(dir2, { recursive: true, force: true });
|
|
32843
32850
|
if (this.isWatching) {
|
|
32844
32851
|
this.taskCache.delete(id);
|
|
32845
32852
|
}
|
|
@@ -32999,7 +33006,7 @@ ${task.description}
|
|
|
32999
33006
|
}
|
|
33000
33007
|
}
|
|
33001
33008
|
}
|
|
33002
|
-
await new Promise((
|
|
33009
|
+
await new Promise((resolve39) => setImmediate(resolve39));
|
|
33003
33010
|
const selectClause = this.getTaskSelectClause(true);
|
|
33004
33011
|
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();
|
|
33005
33012
|
this.lastPollTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -33019,7 +33026,7 @@ ${task.description}
|
|
|
33019
33026
|
this.emit("task:updated", task);
|
|
33020
33027
|
}
|
|
33021
33028
|
if (i > 0 && i % 50 === 0) {
|
|
33022
|
-
await new Promise((
|
|
33029
|
+
await new Promise((resolve39) => setImmediate(resolve39));
|
|
33023
33030
|
}
|
|
33024
33031
|
}
|
|
33025
33032
|
const elapsed = Date.now() - startTime;
|
|
@@ -33802,14 +33809,14 @@ ${task.description}
|
|
|
33802
33809
|
if (rows.length === 0) {
|
|
33803
33810
|
return;
|
|
33804
33811
|
}
|
|
33805
|
-
const { rm:
|
|
33812
|
+
const { rm: rm6 } = await import("node:fs/promises");
|
|
33806
33813
|
for (const row of rows) {
|
|
33807
33814
|
const task = this.rowToTask(row);
|
|
33808
33815
|
const archivedAt = task.columnMovedAt ?? task.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
33809
33816
|
const entry = await this.taskToArchiveEntry(task, archivedAt);
|
|
33810
33817
|
this.archiveDb.upsert(entry);
|
|
33811
33818
|
this.db.prepare("DELETE FROM tasks WHERE id = ?").run(task.id);
|
|
33812
|
-
await
|
|
33819
|
+
await rm6(this.taskDir(task.id), { recursive: true, force: true });
|
|
33813
33820
|
if (this.isWatching) {
|
|
33814
33821
|
this.taskCache.delete(task.id);
|
|
33815
33822
|
}
|
|
@@ -33832,8 +33839,8 @@ ${task.description}
|
|
|
33832
33839
|
this.archiveDb.upsert(entry);
|
|
33833
33840
|
this.db.prepare("DELETE FROM tasks WHERE id = ?").run(task.id);
|
|
33834
33841
|
this.db.bumpLastModified();
|
|
33835
|
-
const { rm:
|
|
33836
|
-
await
|
|
33842
|
+
const { rm: rm6 } = await import("node:fs/promises");
|
|
33843
|
+
await rm6(dir2, { recursive: true, force: true });
|
|
33837
33844
|
if (this.isWatching) {
|
|
33838
33845
|
this.taskCache.delete(task.id);
|
|
33839
33846
|
}
|
|
@@ -34845,7 +34852,7 @@ function runGh(args, cwd) {
|
|
|
34845
34852
|
}
|
|
34846
34853
|
function runGhAsync(args, cwdOrOptions) {
|
|
34847
34854
|
const { cwd, signal: externalSignal, timeoutMs = DEFAULT_GH_TIMEOUT_MS } = normalizeRunGhOptions(cwdOrOptions);
|
|
34848
|
-
return new Promise((
|
|
34855
|
+
return new Promise((resolve39, reject2) => {
|
|
34849
34856
|
if (externalSignal?.aborted) {
|
|
34850
34857
|
reject2(makeGhError(`gh command aborted: ${describeAbortReason(externalSignal.reason)}`, "ABORT_ERR"));
|
|
34851
34858
|
return;
|
|
@@ -34896,7 +34903,7 @@ function runGhAsync(args, cwdOrOptions) {
|
|
|
34896
34903
|
ghError.stderr = stderr ?? "";
|
|
34897
34904
|
reject2(ghError);
|
|
34898
34905
|
} else {
|
|
34899
|
-
|
|
34906
|
+
resolve39(stdout ?? "");
|
|
34900
34907
|
}
|
|
34901
34908
|
}
|
|
34902
34909
|
);
|
|
@@ -35184,9 +35191,9 @@ var init_routine_store = __esm({
|
|
|
35184
35191
|
*/
|
|
35185
35192
|
withRoutineLock(id, fn) {
|
|
35186
35193
|
const prev = this.routineLocks.get(id) ?? Promise.resolve();
|
|
35187
|
-
let
|
|
35194
|
+
let resolve39;
|
|
35188
35195
|
const next = new Promise((r) => {
|
|
35189
|
-
|
|
35196
|
+
resolve39 = r;
|
|
35190
35197
|
});
|
|
35191
35198
|
this.routineLocks.set(id, next);
|
|
35192
35199
|
return prev.then(async () => {
|
|
@@ -35196,7 +35203,7 @@ var init_routine_store = __esm({
|
|
|
35196
35203
|
if (this.routineLocks.get(id) === next) {
|
|
35197
35204
|
this.routineLocks.delete(id);
|
|
35198
35205
|
}
|
|
35199
|
-
|
|
35206
|
+
resolve39();
|
|
35200
35207
|
}
|
|
35201
35208
|
});
|
|
35202
35209
|
}
|
|
@@ -35795,13 +35802,13 @@ var init_plugin_loader = __esm({
|
|
|
35795
35802
|
* Execute a promise with a timeout.
|
|
35796
35803
|
*/
|
|
35797
35804
|
withTimeout(promise, ms, timeoutMessage) {
|
|
35798
|
-
return new Promise((
|
|
35805
|
+
return new Promise((resolve39, reject2) => {
|
|
35799
35806
|
const timer = setTimeout(() => {
|
|
35800
35807
|
reject2(new Error(timeoutMessage));
|
|
35801
35808
|
}, ms);
|
|
35802
35809
|
promise.then((result) => {
|
|
35803
35810
|
clearTimeout(timer);
|
|
35804
|
-
|
|
35811
|
+
resolve39(result);
|
|
35805
35812
|
}).catch((err) => {
|
|
35806
35813
|
clearTimeout(timer);
|
|
35807
35814
|
reject2(err);
|
|
@@ -39008,7 +39015,7 @@ var require_get_stream = __commonJS({
|
|
|
39008
39015
|
};
|
|
39009
39016
|
const { maxBuffer } = options;
|
|
39010
39017
|
let stream;
|
|
39011
|
-
await new Promise((
|
|
39018
|
+
await new Promise((resolve39, reject2) => {
|
|
39012
39019
|
const rejectPromise = (error) => {
|
|
39013
39020
|
if (error && stream.getBufferedLength() <= BufferConstants.MAX_LENGTH) {
|
|
39014
39021
|
error.bufferedData = stream.getBufferedValue();
|
|
@@ -39020,7 +39027,7 @@ var require_get_stream = __commonJS({
|
|
|
39020
39027
|
rejectPromise(error);
|
|
39021
39028
|
return;
|
|
39022
39029
|
}
|
|
39023
|
-
|
|
39030
|
+
resolve39();
|
|
39024
39031
|
});
|
|
39025
39032
|
stream.on("data", () => {
|
|
39026
39033
|
if (stream.getBufferedLength() > maxBuffer) {
|
|
@@ -40314,7 +40321,7 @@ var require_extract_zip = __commonJS({
|
|
|
40314
40321
|
debug("opening", this.zipPath, "with opts", this.opts);
|
|
40315
40322
|
this.zipfile = await openZip(this.zipPath, { lazyEntries: true });
|
|
40316
40323
|
this.canceled = false;
|
|
40317
|
-
return new Promise((
|
|
40324
|
+
return new Promise((resolve39, reject2) => {
|
|
40318
40325
|
this.zipfile.on("error", (err) => {
|
|
40319
40326
|
this.canceled = true;
|
|
40320
40327
|
reject2(err);
|
|
@@ -40323,7 +40330,7 @@ var require_extract_zip = __commonJS({
|
|
|
40323
40330
|
this.zipfile.on("close", () => {
|
|
40324
40331
|
if (!this.canceled) {
|
|
40325
40332
|
debug("zip extraction complete");
|
|
40326
|
-
|
|
40333
|
+
resolve39();
|
|
40327
40334
|
}
|
|
40328
40335
|
});
|
|
40329
40336
|
this.zipfile.on("entry", async (entry) => {
|
|
@@ -47773,10 +47780,10 @@ function pushAlias(aliases, value) {
|
|
|
47773
47780
|
if (pathRef !== normalized && pathRef.length > 0) {
|
|
47774
47781
|
aliases.add(pathRef);
|
|
47775
47782
|
}
|
|
47776
|
-
const
|
|
47777
|
-
if (
|
|
47778
|
-
aliases.add(
|
|
47779
|
-
const basenameSlug = slugifyAgentReference(
|
|
47783
|
+
const basename17 = extractPathBasename(value);
|
|
47784
|
+
if (basename17) {
|
|
47785
|
+
aliases.add(basename17);
|
|
47786
|
+
const basenameSlug = slugifyAgentReference(basename17);
|
|
47780
47787
|
if (basenameSlug.length > 0) {
|
|
47781
47788
|
aliases.add(basenameSlug);
|
|
47782
47789
|
}
|
|
@@ -48503,6 +48510,7 @@ var init_chat_store = __esm({
|
|
|
48503
48510
|
content: row.content,
|
|
48504
48511
|
thinkingOutput: row.thinkingOutput ?? null,
|
|
48505
48512
|
metadata: fromJson(row.metadata) ?? null,
|
|
48513
|
+
attachments: fromJson(row.attachments) ?? void 0,
|
|
48506
48514
|
createdAt: row.createdAt
|
|
48507
48515
|
};
|
|
48508
48516
|
}
|
|
@@ -48721,11 +48729,12 @@ var init_chat_store = __esm({
|
|
|
48721
48729
|
content: input.content,
|
|
48722
48730
|
thinkingOutput: input.thinkingOutput ?? null,
|
|
48723
48731
|
metadata: input.metadata ?? null,
|
|
48732
|
+
attachments: input.attachments,
|
|
48724
48733
|
createdAt: now
|
|
48725
48734
|
};
|
|
48726
48735
|
this.db.prepare(`
|
|
48727
|
-
INSERT INTO chat_messages (id, sessionId, role, content, thinkingOutput, metadata, createdAt)
|
|
48728
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
48736
|
+
INSERT INTO chat_messages (id, sessionId, role, content, thinkingOutput, metadata, attachments, createdAt)
|
|
48737
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
48729
48738
|
`).run(
|
|
48730
48739
|
message.id,
|
|
48731
48740
|
message.sessionId,
|
|
@@ -48733,6 +48742,7 @@ var init_chat_store = __esm({
|
|
|
48733
48742
|
message.content,
|
|
48734
48743
|
message.thinkingOutput,
|
|
48735
48744
|
toJsonNullable(message.metadata),
|
|
48745
|
+
toJsonNullable(message.attachments),
|
|
48736
48746
|
message.createdAt
|
|
48737
48747
|
);
|
|
48738
48748
|
this.db.prepare("UPDATE chat_sessions SET updatedAt = ? WHERE id = ?").run(now, sessionId);
|
|
@@ -48740,6 +48750,28 @@ var init_chat_store = __esm({
|
|
|
48740
48750
|
this.emit("chat:message:added", message);
|
|
48741
48751
|
return message;
|
|
48742
48752
|
}
|
|
48753
|
+
/**
|
|
48754
|
+
* Append a file attachment metadata record to an existing message.
|
|
48755
|
+
*/
|
|
48756
|
+
addMessageAttachment(sessionId, messageId, attachment) {
|
|
48757
|
+
const message = this.getMessage(messageId);
|
|
48758
|
+
if (!message || message.sessionId !== sessionId) {
|
|
48759
|
+
throw new Error(`Message ${messageId} not found in session ${sessionId}`);
|
|
48760
|
+
}
|
|
48761
|
+
const updatedAttachments = [...message.attachments ?? [], attachment];
|
|
48762
|
+
this.db.prepare(`
|
|
48763
|
+
UPDATE chat_messages
|
|
48764
|
+
SET attachments = ?
|
|
48765
|
+
WHERE id = ?
|
|
48766
|
+
`).run(toJsonNullable(updatedAttachments), messageId);
|
|
48767
|
+
const updated = this.getMessage(messageId);
|
|
48768
|
+
if (!updated) {
|
|
48769
|
+
throw new Error(`Failed to update message ${messageId}`);
|
|
48770
|
+
}
|
|
48771
|
+
this.db.bumpLastModified();
|
|
48772
|
+
this.emit("chat:message:updated", updated);
|
|
48773
|
+
return updated;
|
|
48774
|
+
}
|
|
48743
48775
|
/**
|
|
48744
48776
|
* Get messages for a chat session with optional filtering.
|
|
48745
48777
|
*
|
|
@@ -51040,12 +51072,12 @@ var init_concurrency = __esm({
|
|
|
51040
51072
|
this._active++;
|
|
51041
51073
|
return Promise.resolve();
|
|
51042
51074
|
}
|
|
51043
|
-
return new Promise((
|
|
51075
|
+
return new Promise((resolve39) => {
|
|
51044
51076
|
this._waiters.push({
|
|
51045
51077
|
priority,
|
|
51046
51078
|
resolve: () => {
|
|
51047
51079
|
this._active++;
|
|
51048
|
-
|
|
51080
|
+
resolve39();
|
|
51049
51081
|
}
|
|
51050
51082
|
});
|
|
51051
51083
|
});
|
|
@@ -53466,20 +53498,20 @@ async function withRateLimitRetry(fn, options = {}) {
|
|
|
53466
53498
|
throw lastError ?? new Error("withRateLimitRetry: unexpected state");
|
|
53467
53499
|
}
|
|
53468
53500
|
function sleep(ms, signal) {
|
|
53469
|
-
return new Promise((
|
|
53501
|
+
return new Promise((resolve39, reject2) => {
|
|
53470
53502
|
if (signal?.aborted) {
|
|
53471
53503
|
reject2(signal.reason ?? new Error("Aborted"));
|
|
53472
53504
|
return;
|
|
53473
53505
|
}
|
|
53474
|
-
const timer = setTimeout(
|
|
53506
|
+
const timer = setTimeout(resolve39, ms);
|
|
53475
53507
|
if (signal) {
|
|
53476
53508
|
const onAbort = () => {
|
|
53477
53509
|
clearTimeout(timer);
|
|
53478
53510
|
reject2(signal.reason ?? new Error("Aborted"));
|
|
53479
53511
|
};
|
|
53480
53512
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
53481
|
-
const origResolve =
|
|
53482
|
-
|
|
53513
|
+
const origResolve = resolve39;
|
|
53514
|
+
resolve39 = () => {
|
|
53483
53515
|
signal.removeEventListener("abort", onAbort);
|
|
53484
53516
|
origResolve();
|
|
53485
53517
|
};
|
|
@@ -55446,7 +55478,7 @@ import { existsSync as existsSync21 } from "node:fs";
|
|
|
55446
55478
|
import { join as join26 } from "node:path";
|
|
55447
55479
|
import { Type as Type3 } from "typebox";
|
|
55448
55480
|
async function execWithProcessGroup(command, options) {
|
|
55449
|
-
return new Promise((
|
|
55481
|
+
return new Promise((resolve39, reject2) => {
|
|
55450
55482
|
if (options.signal?.aborted) {
|
|
55451
55483
|
reject2(Object.assign(
|
|
55452
55484
|
new Error(`Command aborted before start: ${command}`),
|
|
@@ -55539,7 +55571,7 @@ async function execWithProcessGroup(command, options) {
|
|
|
55539
55571
|
return;
|
|
55540
55572
|
}
|
|
55541
55573
|
if (code === 0) {
|
|
55542
|
-
|
|
55574
|
+
resolve39({ stdout, stderr, bufferOverflow: stdoutOverflow || stderrOverflow });
|
|
55543
55575
|
return;
|
|
55544
55576
|
}
|
|
55545
55577
|
reject2(Object.assign(
|
|
@@ -56102,21 +56134,31 @@ ${failureContext.output.slice(0, VERIFICATION_LOG_MAX_CHARS)}
|
|
|
56102
56134
|
return false;
|
|
56103
56135
|
}
|
|
56104
56136
|
}
|
|
56105
|
-
|
|
56137
|
+
function resetMergeWithWarn(rootDir, taskId, label) {
|
|
56138
|
+
try {
|
|
56139
|
+
execSync("git reset --merge", { cwd: rootDir, stdio: "pipe" });
|
|
56140
|
+
} catch (err) {
|
|
56141
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
56142
|
+
mergerLog.warn(`${taskId}: git reset --merge cleanup failed during ${label}: ${msg}`);
|
|
56143
|
+
}
|
|
56144
|
+
}
|
|
56145
|
+
function buildDeterministicMergeMessage(params) {
|
|
56146
|
+
const { taskId, branch, commitLog, includeTaskId } = params;
|
|
56147
|
+
const prefix = includeTaskId ? `feat(${taskId})` : "feat";
|
|
56148
|
+
const subject = `${prefix}: merge ${branch}`;
|
|
56149
|
+
const body = commitLog && commitLog.trim().length > 0 ? commitLog.trim() : `- merge ${branch}`;
|
|
56150
|
+
const escape = (s) => s.replace(/(["\\$`])/g, "\\$1");
|
|
56151
|
+
return {
|
|
56152
|
+
subjectArg: `-m "${escape(subject)}"`,
|
|
56153
|
+
bodyArg: `-m "${escape(body)}"`
|
|
56154
|
+
};
|
|
56155
|
+
}
|
|
56156
|
+
async function commitOrAmendMergeWithFixes(rootDir, taskId, branch, commitLog, includeTaskId, preAttemptHeadSha, authorArg) {
|
|
56106
56157
|
try {
|
|
56107
|
-
const { stdout: stagedFiles } = await execAsync2("git diff --cached --name-only", {
|
|
56108
|
-
cwd: rootDir,
|
|
56109
|
-
encoding: "utf-8"
|
|
56110
|
-
});
|
|
56111
56158
|
const { stdout: unstagedFiles } = await execAsync2("git diff --name-only", {
|
|
56112
56159
|
cwd: rootDir,
|
|
56113
56160
|
encoding: "utf-8"
|
|
56114
56161
|
});
|
|
56115
|
-
const hasChanges = stagedFiles.trim().length > 0 || unstagedFiles.trim().length > 0;
|
|
56116
|
-
if (!hasChanges) {
|
|
56117
|
-
mergerLog.log(`${taskId}: no changes to amend after verification fix`);
|
|
56118
|
-
return false;
|
|
56119
|
-
}
|
|
56120
56162
|
if (unstagedFiles.trim().length > 0) {
|
|
56121
56163
|
await execAsync2("git add -A", { cwd: rootDir });
|
|
56122
56164
|
}
|
|
@@ -56124,12 +56166,10 @@ async function amendMergeCommitWithFixes(rootDir, taskId, authorArg) {
|
|
|
56124
56166
|
cwd: rootDir,
|
|
56125
56167
|
encoding: "utf-8"
|
|
56126
56168
|
});
|
|
56127
|
-
const gitlinkPaths = [];
|
|
56128
56169
|
for (const line of staged.split("\n")) {
|
|
56129
56170
|
const match = line.match(/^:\d{6} 160000 [^\t]+\t(.+)$/);
|
|
56130
|
-
if (match)
|
|
56131
|
-
|
|
56132
|
-
for (const path5 of gitlinkPaths) {
|
|
56171
|
+
if (!match) continue;
|
|
56172
|
+
const path5 = match[1];
|
|
56133
56173
|
mergerLog.warn(`${taskId}: refusing to stage gitlink "${path5}" (project uses no submodules \u2014 likely a nested worktree). Unstaging.`);
|
|
56134
56174
|
try {
|
|
56135
56175
|
await execAsync2(`git reset HEAD -- "${path5}"`, { cwd: rootDir });
|
|
@@ -56142,15 +56182,43 @@ async function amendMergeCommitWithFixes(rootDir, taskId, authorArg) {
|
|
|
56142
56182
|
cwd: rootDir,
|
|
56143
56183
|
encoding: "utf-8"
|
|
56144
56184
|
});
|
|
56145
|
-
|
|
56146
|
-
|
|
56147
|
-
|
|
56185
|
+
const hasStaged = finalStaged.trim().length > 0;
|
|
56186
|
+
const { stdout: currentHeadOut } = await execAsync2("git rev-parse HEAD", {
|
|
56187
|
+
cwd: rootDir,
|
|
56188
|
+
encoding: "utf-8"
|
|
56189
|
+
});
|
|
56190
|
+
const currentHead = currentHeadOut.trim();
|
|
56191
|
+
const headMoved = currentHead !== preAttemptHeadSha;
|
|
56192
|
+
if (!hasStaged && !headMoved) {
|
|
56193
|
+
mergerLog.warn(
|
|
56194
|
+
`${taskId}: refusing to record merge \u2014 no commit was created and no changes are staged. This usually means the AI agent never ran git commit and the in-merge fix had nothing to add.`
|
|
56195
|
+
);
|
|
56196
|
+
return false;
|
|
56197
|
+
}
|
|
56198
|
+
const { subjectArg, bodyArg } = buildDeterministicMergeMessage({
|
|
56199
|
+
taskId,
|
|
56200
|
+
branch,
|
|
56201
|
+
commitLog,
|
|
56202
|
+
includeTaskId
|
|
56203
|
+
});
|
|
56204
|
+
const trailerArg = buildTaskIdTrailerArg(taskId);
|
|
56205
|
+
if (!headMoved) {
|
|
56206
|
+
await execAsync2(
|
|
56207
|
+
`git commit ${subjectArg} ${bodyArg}${trailerArg}${authorArg}`,
|
|
56208
|
+
{ cwd: rootDir }
|
|
56209
|
+
);
|
|
56210
|
+
mergerLog.log(`${taskId}: created fresh merge commit after verification fix (no prior commit to amend)`);
|
|
56148
56211
|
return true;
|
|
56149
56212
|
}
|
|
56150
|
-
|
|
56213
|
+
await execAsync2(
|
|
56214
|
+
`git commit --amend ${subjectArg} ${bodyArg}${trailerArg}${authorArg}`,
|
|
56215
|
+
{ cwd: rootDir }
|
|
56216
|
+
);
|
|
56217
|
+
mergerLog.log(`${taskId}: amended merge commit with verification fixes (deterministic message)`);
|
|
56218
|
+
return true;
|
|
56151
56219
|
} catch (err) {
|
|
56152
56220
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
56153
|
-
mergerLog.warn(`${taskId}: failed to
|
|
56221
|
+
mergerLog.warn(`${taskId}: failed to finalize merge commit: ${errorMessage}`);
|
|
56154
56222
|
return false;
|
|
56155
56223
|
}
|
|
56156
56224
|
}
|
|
@@ -56401,6 +56469,11 @@ function getCommitAuthorArg(settings) {
|
|
|
56401
56469
|
const email = settings.commitAuthorEmail || "noreply@runfusion.ai";
|
|
56402
56470
|
return ` --author="${name} <${email}>"`;
|
|
56403
56471
|
}
|
|
56472
|
+
function buildSourceIssueRef(sourceIssue) {
|
|
56473
|
+
if (!sourceIssue || sourceIssue.provider !== "github") return "";
|
|
56474
|
+
if (!sourceIssue.repository || !sourceIssue.issueNumber) return "";
|
|
56475
|
+
return `${sourceIssue.repository}#${sourceIssue.issueNumber}`;
|
|
56476
|
+
}
|
|
56404
56477
|
function buildMergeSystemPrompt(includeTaskId, agentPrompts, authorArg) {
|
|
56405
56478
|
const commitFormat = includeTaskId ? `\`\`\`
|
|
56406
56479
|
git commit -m "<type>(<scope>): <summary>" -m "<body>"${authorArg || ""}
|
|
@@ -56411,6 +56484,7 @@ Message format:
|
|
|
56411
56484
|
- **Scope:** the task ID (e.g., KB-001)
|
|
56412
56485
|
- **Summary:** one line describing what the squash brings in (imperative mood)
|
|
56413
56486
|
- **Body:** 2-5 bullet points summarizing the key changes, each starting with "- "
|
|
56487
|
+
- **GitHub reference:** when the prompt includes a source issue reference, add \`Ref: owner/repo#N\` to the commit body
|
|
56414
56488
|
${authorArg ? `- **Author:** Always include the --author flag as shown in the example above.` : ""}
|
|
56415
56489
|
|
|
56416
56490
|
Example:
|
|
@@ -56428,6 +56502,7 @@ Message format:
|
|
|
56428
56502
|
- **Type:** feat, fix, refactor, docs, test, chore
|
|
56429
56503
|
- **Summary:** one line describing what the squash brings in (imperative mood)
|
|
56430
56504
|
- **Body:** 2-5 bullet points summarizing the key changes, each starting with "- "
|
|
56505
|
+
- **GitHub reference:** when the prompt includes a source issue reference, add \`Ref: owner/repo#N\` to the commit body
|
|
56431
56506
|
${authorArg ? `- **Author:** Always include the --author flag as shown in the example above.` : ""}
|
|
56432
56507
|
Do NOT include a scope in the commit message type.
|
|
56433
56508
|
|
|
@@ -56811,6 +56886,7 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
|
|
|
56811
56886
|
throw new Error(`Cannot merge ${taskId}: ${mergeBlocker}`);
|
|
56812
56887
|
}
|
|
56813
56888
|
const branch = task.branch || `fusion/${taskId.toLowerCase()}`;
|
|
56889
|
+
const sourceIssueRef = buildSourceIssueRef(task.sourceIssue);
|
|
56814
56890
|
const worktreePath = task.worktree;
|
|
56815
56891
|
const result = {
|
|
56816
56892
|
task,
|
|
@@ -57114,6 +57190,17 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
|
|
|
57114
57190
|
void 0,
|
|
57115
57191
|
"merger"
|
|
57116
57192
|
);
|
|
57193
|
+
let preAttemptHeadSha = "";
|
|
57194
|
+
try {
|
|
57195
|
+
const { stdout } = await execAsync2("git rev-parse HEAD", {
|
|
57196
|
+
cwd: rootDir,
|
|
57197
|
+
encoding: "utf-8"
|
|
57198
|
+
});
|
|
57199
|
+
preAttemptHeadSha = stdout.trim();
|
|
57200
|
+
} catch (err) {
|
|
57201
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
57202
|
+
mergerLog.warn(`${taskId}: failed to capture pre-attempt HEAD (${msg}) \u2014 verification-fix finalizer will fall back to amend`);
|
|
57203
|
+
}
|
|
57117
57204
|
try {
|
|
57118
57205
|
const success = await executeMergeAttempt({
|
|
57119
57206
|
store,
|
|
@@ -57123,6 +57210,7 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
|
|
|
57123
57210
|
commitLog,
|
|
57124
57211
|
diffStat,
|
|
57125
57212
|
includeTaskId,
|
|
57213
|
+
sourceIssueRef,
|
|
57126
57214
|
smartConflictResolution,
|
|
57127
57215
|
mergeConflictStrategy,
|
|
57128
57216
|
attemptNum,
|
|
@@ -57231,12 +57319,27 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
|
|
|
57231
57319
|
}
|
|
57232
57320
|
if (fixSuccess) {
|
|
57233
57321
|
const authorArg = getCommitAuthorArg(settings);
|
|
57234
|
-
await
|
|
57322
|
+
const finalized = await commitOrAmendMergeWithFixes(
|
|
57323
|
+
rootDir,
|
|
57324
|
+
taskId,
|
|
57325
|
+
branch,
|
|
57326
|
+
commitLog,
|
|
57327
|
+
includeTaskId,
|
|
57328
|
+
preAttemptHeadSha,
|
|
57329
|
+
authorArg
|
|
57330
|
+
);
|
|
57331
|
+
if (!finalized) {
|
|
57332
|
+
resetMergeWithWarn(rootDir, taskId, "verification-fix finalize");
|
|
57333
|
+
throw new Error(
|
|
57334
|
+
`${taskId}: verification fix succeeded but no merge commit could be created \u2014 refusing to mark merge complete.`
|
|
57335
|
+
);
|
|
57336
|
+
}
|
|
57235
57337
|
return true;
|
|
57236
57338
|
}
|
|
57237
57339
|
}
|
|
57238
57340
|
}
|
|
57239
57341
|
mergerLog.error(`${taskId}: deterministic verification failed \u2014 aborting merge (in-merge fix exhausted or disabled)`);
|
|
57342
|
+
resetMergeWithWarn(rootDir, taskId, "deterministic-verification rollback");
|
|
57240
57343
|
throw error;
|
|
57241
57344
|
}
|
|
57242
57345
|
if (error.message?.includes("Build verification failed")) {
|
|
@@ -57307,7 +57410,21 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
|
|
|
57307
57410
|
}
|
|
57308
57411
|
if (fixSuccess) {
|
|
57309
57412
|
const authorArg = getCommitAuthorArg(settings);
|
|
57310
|
-
await
|
|
57413
|
+
const finalized = await commitOrAmendMergeWithFixes(
|
|
57414
|
+
rootDir,
|
|
57415
|
+
taskId,
|
|
57416
|
+
branch,
|
|
57417
|
+
commitLog,
|
|
57418
|
+
includeTaskId,
|
|
57419
|
+
preAttemptHeadSha,
|
|
57420
|
+
authorArg
|
|
57421
|
+
);
|
|
57422
|
+
if (!finalized) {
|
|
57423
|
+
resetMergeWithWarn(rootDir, taskId, "build-verification fix finalize");
|
|
57424
|
+
throw new Error(
|
|
57425
|
+
`${taskId}: build verification fix succeeded but no merge commit could be created \u2014 refusing to mark merge complete.`
|
|
57426
|
+
);
|
|
57427
|
+
}
|
|
57311
57428
|
return true;
|
|
57312
57429
|
}
|
|
57313
57430
|
}
|
|
@@ -57321,10 +57438,11 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
|
|
|
57321
57438
|
await audit.git({ type: "reset:hard", target: branch, metadata: { purpose: "build-retry" } });
|
|
57322
57439
|
} catch (err) {
|
|
57323
57440
|
const msg = err instanceof Error ? err.message : String(err);
|
|
57324
|
-
mergerLog.warn(`${taskId}: git reset --merge cleanup failed (build-retry): ${msg}`);
|
|
57441
|
+
mergerLog.warn(`${taskId}: git reset --merge cleanup failed during build-verification rollback (build-retry): ${msg}`);
|
|
57325
57442
|
}
|
|
57326
57443
|
return false;
|
|
57327
57444
|
}
|
|
57445
|
+
resetMergeWithWarn(rootDir, taskId, "build-verification rollback (no retries left)");
|
|
57328
57446
|
throw error;
|
|
57329
57447
|
}
|
|
57330
57448
|
if (error.name === "MergeNonConflictError") {
|
|
@@ -57672,6 +57790,7 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
57672
57790
|
commitLog,
|
|
57673
57791
|
diffStat,
|
|
57674
57792
|
includeTaskId,
|
|
57793
|
+
sourceIssueRef,
|
|
57675
57794
|
smartConflictResolution,
|
|
57676
57795
|
attemptNum,
|
|
57677
57796
|
options,
|
|
@@ -57862,19 +57981,12 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
57862
57981
|
simplifiedContext: attemptNum === 2,
|
|
57863
57982
|
options,
|
|
57864
57983
|
testCommand,
|
|
57865
|
-
buildCommand: buildCommand2
|
|
57984
|
+
buildCommand: buildCommand2,
|
|
57985
|
+
sourceIssueRef
|
|
57866
57986
|
});
|
|
57867
57987
|
if (!agentResult.success) {
|
|
57868
57988
|
const errorMessage = agentResult.error || "Build verification failed";
|
|
57869
57989
|
await store.logEntry(taskId, "Build verification failed during merge", errorMessage);
|
|
57870
|
-
try {
|
|
57871
|
-
execSync("git reset --merge", { cwd: rootDir, stdio: "pipe" });
|
|
57872
|
-
} catch (resetErr) {
|
|
57873
|
-
const msg = resetErr instanceof Error ? resetErr.message : String(resetErr);
|
|
57874
|
-
mergerLog.warn(
|
|
57875
|
-
`${taskId}: git reset --merge cleanup failed during build-verification rollback (build-verification reset, build-retry): ${msg}`
|
|
57876
|
-
);
|
|
57877
|
-
}
|
|
57878
57990
|
throw new Error(`Build verification failed for ${taskId}: ${errorMessage}`);
|
|
57879
57991
|
}
|
|
57880
57992
|
if (testCommand || buildCommand2) {
|
|
@@ -57890,6 +58002,24 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
57890
58002
|
options.signal
|
|
57891
58003
|
);
|
|
57892
58004
|
}
|
|
58005
|
+
try {
|
|
58006
|
+
const authorArg = getCommitAuthorArg(params.settings);
|
|
58007
|
+
const { subjectArg, bodyArg } = buildDeterministicMergeMessage({
|
|
58008
|
+
taskId,
|
|
58009
|
+
branch,
|
|
58010
|
+
commitLog,
|
|
58011
|
+
includeTaskId
|
|
58012
|
+
});
|
|
58013
|
+
const trailerArg = buildTaskIdTrailerArg(taskId);
|
|
58014
|
+
await execAsync2(
|
|
58015
|
+
`git commit --amend ${subjectArg} ${bodyArg}${trailerArg}${authorArg}`,
|
|
58016
|
+
{ cwd: rootDir }
|
|
58017
|
+
);
|
|
58018
|
+
mergerLog.log(`${taskId}: rewrote AI-authored merge commit message with deterministic body`);
|
|
58019
|
+
} catch (err) {
|
|
58020
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
58021
|
+
mergerLog.warn(`${taskId}: failed to canonicalize merge commit message (${msg}) \u2014 keeping AI-written message`);
|
|
58022
|
+
}
|
|
57893
58023
|
return true;
|
|
57894
58024
|
} catch (error) {
|
|
57895
58025
|
if (error instanceof Error && error.name === "MergeAbortedError") {
|
|
@@ -57912,7 +58042,7 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
57912
58042
|
}
|
|
57913
58043
|
}
|
|
57914
58044
|
async function attemptWithSideStrategy(params, side = "theirs", aiTracker) {
|
|
57915
|
-
const { rootDir, branch, commitLog, includeTaskId, taskId, store, settings, testCommand, buildCommand: buildCommand2, testSource, buildSource } = params;
|
|
58045
|
+
const { rootDir, branch, commitLog, includeTaskId, sourceIssueRef, taskId, store, settings, testCommand, buildCommand: buildCommand2, testSource, buildSource } = params;
|
|
57916
58046
|
mergerLog.log(`${taskId}: attempting merge with -X ${side} strategy`);
|
|
57917
58047
|
try {
|
|
57918
58048
|
throwIfAborted(params.options.signal, taskId);
|
|
@@ -57953,8 +58083,9 @@ async function attemptWithSideStrategy(params, side = "theirs", aiTracker) {
|
|
|
57953
58083
|
const fallbackPrefix = includeTaskId ? `feat(${taskId})` : "feat";
|
|
57954
58084
|
const authorArg = getCommitAuthorArg(settings);
|
|
57955
58085
|
const trailerArg = buildTaskIdTrailerArg(taskId);
|
|
58086
|
+
const issueRefBodyArg = sourceIssueRef ? ` -m "Ref: ${sourceIssueRef}"` : "";
|
|
57956
58087
|
await execAsync2(
|
|
57957
|
-
`git commit -m "${fallbackPrefix}: merge ${branch} (auto-resolved)" -m "${escapedLog}"${trailerArg}${authorArg}`,
|
|
58088
|
+
`git commit -m "${fallbackPrefix}: merge ${branch} (auto-resolved)" -m "${escapedLog}"${issueRefBodyArg}${trailerArg}${authorArg}`,
|
|
57958
58089
|
{ cwd: rootDir }
|
|
57959
58090
|
);
|
|
57960
58091
|
mergerLog.log(`${taskId}: committed with -X ${side} auto-resolution`);
|
|
@@ -57991,6 +58122,7 @@ async function runAiAgentForCommit(params) {
|
|
|
57991
58122
|
includeTaskId,
|
|
57992
58123
|
hasConflicts,
|
|
57993
58124
|
simplifiedContext,
|
|
58125
|
+
sourceIssueRef,
|
|
57994
58126
|
options,
|
|
57995
58127
|
testCommand,
|
|
57996
58128
|
buildCommand: buildCommand2
|
|
@@ -58089,7 +58221,8 @@ async function runAiAgentForCommit(params) {
|
|
|
58089
58221
|
simplifiedContext,
|
|
58090
58222
|
testCommand,
|
|
58091
58223
|
buildCommand: buildCommand2,
|
|
58092
|
-
authorArg
|
|
58224
|
+
authorArg,
|
|
58225
|
+
sourceIssueRef
|
|
58093
58226
|
});
|
|
58094
58227
|
mergerLog.log(`${taskId}: starting fresh merge agent session`);
|
|
58095
58228
|
try {
|
|
@@ -58121,7 +58254,8 @@ async function runAiAgentForCommit(params) {
|
|
|
58121
58254
|
// Also skip detailed context
|
|
58122
58255
|
testCommand,
|
|
58123
58256
|
buildCommand: buildCommand2,
|
|
58124
|
-
authorArg
|
|
58257
|
+
authorArg,
|
|
58258
|
+
sourceIssueRef
|
|
58125
58259
|
});
|
|
58126
58260
|
try {
|
|
58127
58261
|
await withRateLimitRetry(async () => {
|
|
@@ -58163,8 +58297,9 @@ async function runAiAgentForCommit(params) {
|
|
|
58163
58297
|
const fallbackPrefix = includeTaskId ? `feat(${taskId})` : "feat";
|
|
58164
58298
|
const authorArg2 = getCommitAuthorArg(settings);
|
|
58165
58299
|
const trailerArg = buildTaskIdTrailerArg(taskId);
|
|
58300
|
+
const issueRefBodyArg = sourceIssueRef ? ` -m "Ref: ${sourceIssueRef}"` : "";
|
|
58166
58301
|
await execAsync2(
|
|
58167
|
-
`git commit -m "${fallbackPrefix}: merge ${branch}" -m "${escapedLog}"${trailerArg}${authorArg2}`,
|
|
58302
|
+
`git commit -m "${fallbackPrefix}: merge ${branch}" -m "${escapedLog}"${issueRefBodyArg}${trailerArg}${authorArg2}`,
|
|
58168
58303
|
{ cwd: rootDir }
|
|
58169
58304
|
);
|
|
58170
58305
|
} else {
|
|
@@ -58187,7 +58322,7 @@ async function runAiAgentForCommit(params) {
|
|
|
58187
58322
|
}
|
|
58188
58323
|
}
|
|
58189
58324
|
function buildMergePrompt(params) {
|
|
58190
|
-
const { taskId, branch, commitLog, diffStat, hasConflicts, simplifiedContext, testCommand, buildCommand: buildCommand2, authorArg } = params;
|
|
58325
|
+
const { taskId, branch, commitLog, diffStat, hasConflicts, simplifiedContext, sourceIssueRef, testCommand, buildCommand: buildCommand2, authorArg } = params;
|
|
58191
58326
|
const truncatedCommitLog = truncateWithEllipsis(commitLog, MERGE_COMMIT_LOG_MAX_CHARS);
|
|
58192
58327
|
const truncatedDiffStat = truncateWithEllipsis(diffStat, MERGE_DIFF_STAT_MAX_CHARS);
|
|
58193
58328
|
const parts = [
|
|
@@ -58223,6 +58358,13 @@ function buildMergePrompt(params) {
|
|
|
58223
58358
|
`Write and run the \`git commit\` command with a good message summarizing the work.${authorArg ? ` Be sure to include \`${authorArg.trim()}\` in the commit command.` : ""}`
|
|
58224
58359
|
);
|
|
58225
58360
|
}
|
|
58361
|
+
if (sourceIssueRef) {
|
|
58362
|
+
parts.push(
|
|
58363
|
+
"",
|
|
58364
|
+
"Include this in the commit message body:",
|
|
58365
|
+
`- Ref: ${sourceIssueRef}`
|
|
58366
|
+
);
|
|
58367
|
+
}
|
|
58226
58368
|
if (testCommand) {
|
|
58227
58369
|
parts.push(
|
|
58228
58370
|
"",
|
|
@@ -59398,7 +59540,7 @@ function resolveExecutorModelPair(taskModelProvider, taskModelId, settings) {
|
|
|
59398
59540
|
return { provider: void 0, modelId: void 0 };
|
|
59399
59541
|
}
|
|
59400
59542
|
function sleep2(ms) {
|
|
59401
|
-
return new Promise((
|
|
59543
|
+
return new Promise((resolve39) => setTimeout(resolve39, ms));
|
|
59402
59544
|
}
|
|
59403
59545
|
var execAsync4, stepExecLog, MAX_STEP_RETRIES, RETRY_DELAYS_MS, NOOP_TASK_STORE, StepSessionExecutor;
|
|
59404
59546
|
var init_step_session_executor = __esm({
|
|
@@ -60146,6 +60288,7 @@ function buildExecutionPrompt(task, rootDir, settings, worktreePath) {
|
|
|
60146
60288
|
const reviewMatch = prompt.match(/##\s*Review Level[:\s]*(\d)/);
|
|
60147
60289
|
const reviewLevel = reviewMatch ? parseInt(reviewMatch[1], 10) : 0;
|
|
60148
60290
|
const authorArg = settings?.commitAuthorEnabled !== false ? ` --author="${settings?.commitAuthorName || "Fusion"} <${settings?.commitAuthorEmail || "noreply@runfusion.ai"}>"` : "";
|
|
60291
|
+
const sourceIssueRef = task.sourceIssue?.provider === "github" && task.sourceIssue.repository && task.sourceIssue.issueNumber ? `${task.sourceIssue.repository}#${task.sourceIssue.issueNumber}` : "";
|
|
60149
60292
|
const hasProgress = task.steps.length > 0 && task.steps.some((s) => s.status !== "pending");
|
|
60150
60293
|
let progressSection = "";
|
|
60151
60294
|
if (hasProgress) {
|
|
@@ -60248,7 +60391,7 @@ ${hasProgress ? `Resume from Step ${task.currentStep}. Do NOT redo completed ste
|
|
|
60248
60391
|
Use \`fn_task_update\` to report progress on every step transition.
|
|
60249
60392
|
Use \`fn_task_log\` for important actions and decisions.
|
|
60250
60393
|
Use \`fn_task_create\` for truly separate follow-up work, not for fixes required to get tests, build, or typecheck back to green.
|
|
60251
|
-
Commit at step boundaries: \`git commit -m "feat(${task.id}): complete Step N \u2014 description"${authorArg}\`
|
|
60394
|
+
Commit at step boundaries: \`git commit -m "feat(${task.id}): complete Step N \u2014 description"${sourceIssueRef ? ` -m "Ref: ${sourceIssueRef}"` : ""}${authorArg}\`
|
|
60252
60395
|
When all steps are complete: call \`fn_task_done()\`
|
|
60253
60396
|
|
|
60254
60397
|
If a build command is configured, run that exact command in this worktree before calling \`fn_task_done()\`.
|
|
@@ -60281,7 +60424,7 @@ function detectReviewHandoffIntent(commentText) {
|
|
|
60281
60424
|
];
|
|
60282
60425
|
return handoffPhrases.some((phrase) => text.includes(phrase));
|
|
60283
60426
|
}
|
|
60284
|
-
var execAsync5, STEP_STATUSES, MAX_WORKFLOW_STEP_RETRIES, MAX_TASK_DONE_SESSION_RETRIES, MAX_TASK_DONE_REQUEUE_RETRIES, WORKFLOW_SCRIPT_OUTPUT_MAX_CHARS2, NonRetryableWorktreeError, taskUpdateParams, taskAddDepParams, spawnAgentParams, reviewStepParams, EXECUTOR_SYSTEM_PROMPT, TaskExecutor;
|
|
60427
|
+
var execAsync5, STEP_STATUSES, MAX_WORKFLOW_STEP_RETRIES, MAX_TASK_DONE_SESSION_RETRIES, MAX_TASK_DONE_REQUEUE_RETRIES, COMPLETED_TASK_WATCHDOG_MS, WORKFLOW_RERUN_WATCHDOG_MS, WORKFLOW_SCRIPT_OUTPUT_MAX_CHARS2, NonRetryableWorktreeError, taskUpdateParams, taskAddDepParams, spawnAgentParams, reviewStepParams, EXECUTOR_SYSTEM_PROMPT, TaskExecutor;
|
|
60285
60428
|
var init_executor = __esm({
|
|
60286
60429
|
"../engine/src/executor.ts"() {
|
|
60287
60430
|
"use strict";
|
|
@@ -60317,6 +60460,8 @@ var init_executor = __esm({
|
|
|
60317
60460
|
MAX_WORKFLOW_STEP_RETRIES = 3;
|
|
60318
60461
|
MAX_TASK_DONE_SESSION_RETRIES = 3;
|
|
60319
60462
|
MAX_TASK_DONE_REQUEUE_RETRIES = 3;
|
|
60463
|
+
COMPLETED_TASK_WATCHDOG_MS = 6e4;
|
|
60464
|
+
WORKFLOW_RERUN_WATCHDOG_MS = 15e3;
|
|
60320
60465
|
WORKFLOW_SCRIPT_OUTPUT_MAX_CHARS2 = 4e3;
|
|
60321
60466
|
NonRetryableWorktreeError = class extends Error {
|
|
60322
60467
|
};
|
|
@@ -60434,6 +60579,7 @@ If the task's PROMPT.md includes a "Documentation Requirements" section listing
|
|
|
60434
60579
|
## Git discipline
|
|
60435
60580
|
- Commit after completing each step (not after every file change)
|
|
60436
60581
|
- Use conventional commit messages prefixed with the task ID
|
|
60582
|
+
- When the task has a GitHub issue reference, include \`Ref: owner/repo#N\` in the commit body
|
|
60437
60583
|
- Do NOT commit broken or half-implemented code
|
|
60438
60584
|
|
|
60439
60585
|
## Worktree Boundaries
|
|
@@ -60526,6 +60672,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
60526
60672
|
store.on("task:moved", ({ task, from, to }) => {
|
|
60527
60673
|
executorLog.log(`[event:task:moved] ${task.id}: ${from} \u2192 ${to}`);
|
|
60528
60674
|
if (to === "in-progress") {
|
|
60675
|
+
this.clearWorkflowRerunWatchdog(task.id);
|
|
60529
60676
|
executorLog.log(`[event:task:moved] Initiating execute() for ${task.id}`);
|
|
60530
60677
|
void (async () => {
|
|
60531
60678
|
const taskForExecution = await this.resetMergeStateIfNeeded(task, from);
|
|
@@ -60534,6 +60681,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
60534
60681
|
(err) => executorLog.error(`Failed to start ${task.id}:`, err)
|
|
60535
60682
|
);
|
|
60536
60683
|
} else if (from === "in-progress") {
|
|
60684
|
+
this.clearCompletedTaskWatchdog(task.id);
|
|
60537
60685
|
if (this.activeSessions.has(task.id)) {
|
|
60538
60686
|
executorLog.log(`${task.id} moved from in-progress to ${to} \u2014 terminating agent session`);
|
|
60539
60687
|
this.pausedAborted.add(task.id);
|
|
@@ -60725,6 +60873,10 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
60725
60873
|
spawnedAgents = /* @__PURE__ */ new Map();
|
|
60726
60874
|
/** Per-task baseline of session stats used for delta persistence across repeated updates. */
|
|
60727
60875
|
tokenUsageBaselines = /* @__PURE__ */ new Map();
|
|
60876
|
+
/** One-shot watchdogs for completed tasks that should have transitioned to in-review. */
|
|
60877
|
+
completedTaskWatchdogs = /* @__PURE__ */ new Map();
|
|
60878
|
+
/** One-shot watchdogs for workflow reruns that should have bounced back to in-progress. */
|
|
60879
|
+
workflowRerunWatchdogs = /* @__PURE__ */ new Map();
|
|
60728
60880
|
async finalizeAlreadyReviewedTask(taskId) {
|
|
60729
60881
|
const latestTask = await this.store.getTask(taskId);
|
|
60730
60882
|
if (!latestTask || latestTask.column !== "in-review") {
|
|
@@ -60880,6 +61032,120 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
60880
61032
|
await this.store.updateTask(task.id, updates);
|
|
60881
61033
|
}
|
|
60882
61034
|
}
|
|
61035
|
+
clearCompletedTaskWatchdog(taskId) {
|
|
61036
|
+
const handle = this.completedTaskWatchdogs.get(taskId);
|
|
61037
|
+
if (!handle) return;
|
|
61038
|
+
clearTimeout(handle);
|
|
61039
|
+
this.completedTaskWatchdogs.delete(taskId);
|
|
61040
|
+
}
|
|
61041
|
+
clearWorkflowRerunWatchdog(taskId) {
|
|
61042
|
+
const handle = this.workflowRerunWatchdogs.get(taskId);
|
|
61043
|
+
if (!handle) return;
|
|
61044
|
+
clearTimeout(handle);
|
|
61045
|
+
this.workflowRerunWatchdogs.delete(taskId);
|
|
61046
|
+
}
|
|
61047
|
+
scheduleCompletedTaskWatchdog(taskId, trigger) {
|
|
61048
|
+
this.clearCompletedTaskWatchdog(taskId);
|
|
61049
|
+
const handle = setTimeout(async () => {
|
|
61050
|
+
this.completedTaskWatchdogs.delete(taskId);
|
|
61051
|
+
let currentTask = null;
|
|
61052
|
+
try {
|
|
61053
|
+
currentTask = await this.store.getTask(taskId);
|
|
61054
|
+
} catch (err) {
|
|
61055
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
61056
|
+
executorLog.warn(`${taskId}: completed-task watchdog could not read latest task state: ${errorMessage}`);
|
|
61057
|
+
return;
|
|
61058
|
+
}
|
|
61059
|
+
if (!currentTask || currentTask.column !== "in-progress" || currentTask.paused) {
|
|
61060
|
+
return;
|
|
61061
|
+
}
|
|
61062
|
+
if (this.activeSessions.has(taskId) || this.activeStepExecutors.has(taskId) || this.recoveringCompleted.has(taskId)) {
|
|
61063
|
+
return;
|
|
61064
|
+
}
|
|
61065
|
+
if (!this.isTaskWorkComplete(currentTask)) {
|
|
61066
|
+
return;
|
|
61067
|
+
}
|
|
61068
|
+
executorLog.warn(
|
|
61069
|
+
`${taskId}: completed-task watchdog fired after ${COMPLETED_TASK_WATCHDOG_MS / 1e3}s (${trigger}) \u2014 attempting direct recovery to in-review`
|
|
61070
|
+
);
|
|
61071
|
+
await this.store.logEntry(
|
|
61072
|
+
taskId,
|
|
61073
|
+
`Watchdog: task remained in-progress ${COMPLETED_TASK_WATCHDOG_MS / 1e3}s after ${trigger} \u2014 attempting direct recovery to in-review`
|
|
61074
|
+
).catch(() => void 0);
|
|
61075
|
+
this.recoveringCompleted.add(taskId);
|
|
61076
|
+
try {
|
|
61077
|
+
const recovered = await this.recoverCompletedTask(currentTask);
|
|
61078
|
+
if (!recovered) {
|
|
61079
|
+
await this.store.logEntry(
|
|
61080
|
+
taskId,
|
|
61081
|
+
"Watchdog recovery attempt could not finalize completed task \u2014 leaving for follow-up recovery"
|
|
61082
|
+
).catch(() => void 0);
|
|
61083
|
+
}
|
|
61084
|
+
} finally {
|
|
61085
|
+
this.recoveringCompleted.delete(taskId);
|
|
61086
|
+
}
|
|
61087
|
+
}, COMPLETED_TASK_WATCHDOG_MS);
|
|
61088
|
+
this.completedTaskWatchdogs.set(taskId, handle);
|
|
61089
|
+
}
|
|
61090
|
+
async performWorkflowRerunBounce(taskId, worktreePath) {
|
|
61091
|
+
const latestTask = await this.store.getTask(taskId);
|
|
61092
|
+
if (!latestTask) {
|
|
61093
|
+
throw new Error("task missing during workflow rerun bounce");
|
|
61094
|
+
}
|
|
61095
|
+
if (latestTask.column === "in-progress") {
|
|
61096
|
+
await this.store.moveTask(taskId, "todo");
|
|
61097
|
+
await this.store.updateTask(taskId, { worktree: worktreePath });
|
|
61098
|
+
await this.store.moveTask(taskId, "in-progress");
|
|
61099
|
+
return;
|
|
61100
|
+
}
|
|
61101
|
+
if (latestTask.column === "todo") {
|
|
61102
|
+
await this.store.updateTask(taskId, { worktree: worktreePath });
|
|
61103
|
+
await this.store.moveTask(taskId, "in-progress");
|
|
61104
|
+
return;
|
|
61105
|
+
}
|
|
61106
|
+
throw new Error(`task is in '${latestTask.column}', cannot bounce to in-progress`);
|
|
61107
|
+
}
|
|
61108
|
+
scheduleWorkflowRerun(taskId, worktreePath, successMessage) {
|
|
61109
|
+
this.clearWorkflowRerunWatchdog(taskId);
|
|
61110
|
+
setTimeout(async () => {
|
|
61111
|
+
try {
|
|
61112
|
+
await this.performWorkflowRerunBounce(taskId, worktreePath);
|
|
61113
|
+
executorLog.log(successMessage);
|
|
61114
|
+
} catch (err) {
|
|
61115
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
61116
|
+
executorLog.error(`${taskId}: failed to schedule rerun bounce: ${errorMessage}`);
|
|
61117
|
+
}
|
|
61118
|
+
}, 0);
|
|
61119
|
+
const watchdog = setTimeout(async () => {
|
|
61120
|
+
this.workflowRerunWatchdogs.delete(taskId);
|
|
61121
|
+
let currentTask = null;
|
|
61122
|
+
try {
|
|
61123
|
+
currentTask = await this.store.getTask(taskId);
|
|
61124
|
+
} catch (err) {
|
|
61125
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
61126
|
+
executorLog.warn(`${taskId}: workflow rerun watchdog could not read latest task state: ${errorMessage}`);
|
|
61127
|
+
return;
|
|
61128
|
+
}
|
|
61129
|
+
if (!currentTask || currentTask.paused || currentTask.column === "in-progress") {
|
|
61130
|
+
return;
|
|
61131
|
+
}
|
|
61132
|
+
executorLog.warn(
|
|
61133
|
+
`${taskId}: workflow rerun watchdog fired after ${WORKFLOW_RERUN_WATCHDOG_MS / 1e3}s \u2014 task is still ${currentTask.column}; retrying handoff once`
|
|
61134
|
+
);
|
|
61135
|
+
await this.store.logEntry(
|
|
61136
|
+
taskId,
|
|
61137
|
+
`Watchdog: workflow rerun handoff stalled for ${WORKFLOW_RERUN_WATCHDOG_MS / 1e3}s (still ${currentTask.column}) \u2014 retrying once`
|
|
61138
|
+
).catch(() => void 0);
|
|
61139
|
+
try {
|
|
61140
|
+
await this.performWorkflowRerunBounce(taskId, worktreePath);
|
|
61141
|
+
executorLog.warn(`${taskId}: workflow rerun watchdog retry succeeded`);
|
|
61142
|
+
} catch (err) {
|
|
61143
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
61144
|
+
executorLog.error(`${taskId}: workflow rerun watchdog retry failed: ${errorMessage}`);
|
|
61145
|
+
}
|
|
61146
|
+
}, WORKFLOW_RERUN_WATCHDOG_MS);
|
|
61147
|
+
this.workflowRerunWatchdogs.set(taskId, watchdog);
|
|
61148
|
+
}
|
|
60883
61149
|
async shouldFinalizeCompletedTask(taskId, taskDone) {
|
|
60884
61150
|
const task = await this.store.getTask(taskId);
|
|
60885
61151
|
const completionBlocker = await this.getTaskCompletionBlocker(task);
|
|
@@ -61013,6 +61279,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
61013
61279
|
}
|
|
61014
61280
|
await this.persistTokenUsage(task.id);
|
|
61015
61281
|
await this.store.moveTask(task.id, "in-review");
|
|
61282
|
+
this.clearCompletedTaskWatchdog(task.id);
|
|
61016
61283
|
await this.store.logEntry(task.id, "Auto-recovered: task work was complete but stuck in in-progress \u2014 moved to in-review");
|
|
61017
61284
|
executorLog.log(`\u2713 ${task.id} auto-recovered completed task \u2192 in-review`);
|
|
61018
61285
|
this.options.onComplete?.(task);
|
|
@@ -61509,6 +61776,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
61509
61776
|
executorLog.log(`${task.id}: captured ${modifiedFiles.length} modified files`);
|
|
61510
61777
|
await audit.filesystem({ type: "file:capture-modified", target: task.id, metadata: { files: modifiedFiles } });
|
|
61511
61778
|
}
|
|
61779
|
+
this.scheduleCompletedTaskWatchdog(task.id, "step-session completion");
|
|
61512
61780
|
if (executionMode !== "fast") {
|
|
61513
61781
|
const workflowResult = await this.runWorkflowSteps(task, worktreePath, settings);
|
|
61514
61782
|
if (!workflowResult.allPassed) {
|
|
@@ -61529,6 +61797,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
61529
61797
|
}
|
|
61530
61798
|
await this.store.updateTask(task.id, { workflowStepRetries: void 0, taskDoneRetryCount: null });
|
|
61531
61799
|
await this.store.moveTask(task.id, "in-review");
|
|
61800
|
+
this.clearCompletedTaskWatchdog(task.id);
|
|
61532
61801
|
await audit.database({ type: "task:move", target: task.id, metadata: { to: "in-review" } });
|
|
61533
61802
|
executorLog.log(`\u2713 ${task.id} completed (step-session) \u2192 in-review`);
|
|
61534
61803
|
this.options.onComplete?.(task);
|
|
@@ -61865,6 +62134,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
61865
62134
|
await this.store.logEntry(task.id, "Execution paused after completion \u2014 finalizing to in-review");
|
|
61866
62135
|
await this.persistTokenUsage(task.id);
|
|
61867
62136
|
await this.store.moveTask(task.id, "in-review");
|
|
62137
|
+
this.clearCompletedTaskWatchdog(task.id);
|
|
61868
62138
|
this.options.onComplete?.(task);
|
|
61869
62139
|
} else {
|
|
61870
62140
|
executorLog.log(`${task.id} paused (graceful session exit) \u2014 moving to todo`);
|
|
@@ -61885,6 +62155,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
61885
62155
|
taskDone = true;
|
|
61886
62156
|
executorLog.log(`${task.id} all steps done \u2014 treating as implicit fn_task_done`);
|
|
61887
62157
|
await this.store.logEntry(task.id, "All steps complete \u2014 implicit fn_task_done (agent did not call tool explicitly)", void 0, this.currentRunContext);
|
|
62158
|
+
this.scheduleCompletedTaskWatchdog(task.id, "implicit fn_task_done");
|
|
61888
62159
|
}
|
|
61889
62160
|
}
|
|
61890
62161
|
if (taskDone) {
|
|
@@ -61894,6 +62165,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
61894
62165
|
await this.store.updateTask(task.id, { modifiedFiles });
|
|
61895
62166
|
executorLog.log(`${task.id}: captured ${modifiedFiles.length} modified files`);
|
|
61896
62167
|
}
|
|
62168
|
+
this.scheduleCompletedTaskWatchdog(task.id, "task completion");
|
|
61897
62169
|
if (executionMode !== "fast") {
|
|
61898
62170
|
const workflowResult = await this.runWorkflowSteps(task, worktreePath, settings);
|
|
61899
62171
|
if (!workflowResult.allPassed) {
|
|
@@ -61915,6 +62187,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
61915
62187
|
await this.store.updateTask(task.id, { workflowStepRetries: void 0, taskDoneRetryCount: null });
|
|
61916
62188
|
await this.persistTokenUsage(task.id);
|
|
61917
62189
|
await this.store.moveTask(task.id, "in-review");
|
|
62190
|
+
this.clearCompletedTaskWatchdog(task.id);
|
|
61918
62191
|
executorLog.log(`\u2713 ${task.id} completed \u2192 in-review`);
|
|
61919
62192
|
this.options.onComplete?.(task);
|
|
61920
62193
|
} else {
|
|
@@ -61988,6 +62261,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
61988
62261
|
taskDone = true;
|
|
61989
62262
|
executorLog.log(`${task.id} all steps done \u2014 treating as implicit fn_task_done`);
|
|
61990
62263
|
await this.store.logEntry(task.id, "All steps complete \u2014 implicit fn_task_done (agent did not call tool explicitly)", void 0, this.currentRunContext);
|
|
62264
|
+
this.scheduleCompletedTaskWatchdog(task.id, "implicit fn_task_done");
|
|
61991
62265
|
}
|
|
61992
62266
|
}
|
|
61993
62267
|
}
|
|
@@ -61998,6 +62272,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
61998
62272
|
await this.store.updateTask(task.id, { modifiedFiles });
|
|
61999
62273
|
executorLog.log(`${task.id}: captured ${modifiedFiles.length} modified files`);
|
|
62000
62274
|
}
|
|
62275
|
+
this.scheduleCompletedTaskWatchdog(task.id, "task completion retry");
|
|
62001
62276
|
if (executionMode !== "fast") {
|
|
62002
62277
|
const workflowResult = await this.runWorkflowSteps(task, worktreePath, settings);
|
|
62003
62278
|
if (!workflowResult.allPassed) {
|
|
@@ -62015,6 +62290,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
62015
62290
|
await this.store.updateTask(task.id, { workflowStepRetries: void 0, taskDoneRetryCount: null });
|
|
62016
62291
|
await this.persistTokenUsage(task.id);
|
|
62017
62292
|
await this.store.moveTask(task.id, "in-review");
|
|
62293
|
+
this.clearCompletedTaskWatchdog(task.id);
|
|
62018
62294
|
executorLog.log(`\u2713 ${task.id} completed on retry \u2192 in-review`);
|
|
62019
62295
|
this.options.onComplete?.(task);
|
|
62020
62296
|
} else {
|
|
@@ -62442,6 +62718,7 @@ Lint, tests, and typecheck are also hard quality gates:
|
|
|
62442
62718
|
await store.updateTask(taskId, { summary: params.summary });
|
|
62443
62719
|
}
|
|
62444
62720
|
await store.logEntry(taskId, "Task marked done by agent");
|
|
62721
|
+
this.scheduleCompletedTaskWatchdog(taskId, "fn_task_done");
|
|
62445
62722
|
const successMessage = params.summary ? "Task marked complete with summary. All steps done. Moving to in-review." : "Task marked complete. All steps done. Moving to in-review.";
|
|
62446
62723
|
return {
|
|
62447
62724
|
content: [{ type: "text", text: successMessage }],
|
|
@@ -62668,6 +62945,7 @@ Take a different approach. Do NOT repeat the rejected strategy. Re-read the step
|
|
|
62668
62945
|
*/
|
|
62669
62946
|
async handleWorkflowRevisionRequest(task, worktreePath, feedback, stepName) {
|
|
62670
62947
|
executorLog.log(`${task.id}: workflow revision requested by step "${stepName}"`);
|
|
62948
|
+
this.clearCompletedTaskWatchdog(task.id);
|
|
62671
62949
|
const updatedTask = await this.store.getTask(task.id);
|
|
62672
62950
|
const reopen = await this.reopenLastStepForRevision(task.id, updatedTask);
|
|
62673
62951
|
const reopenSummary = reopen ? `re-opening Step ${reopen.index + 1} ("${reopen.name}") for in-place fix` : "no step to re-open (none were completed)";
|
|
@@ -62682,21 +62960,11 @@ Take a different approach. Do NOT repeat the rejected strategy. Re-read the step
|
|
|
62682
62960
|
sessionFile: null
|
|
62683
62961
|
});
|
|
62684
62962
|
executorLog.log(`${task.id}: scheduling fresh execution after revision request`);
|
|
62685
|
-
|
|
62686
|
-
|
|
62687
|
-
|
|
62688
|
-
|
|
62689
|
-
|
|
62690
|
-
executorLog.log(`${task.id}: revision rerun scheduled \u2014 moved to todo then in-progress`);
|
|
62691
|
-
} catch (err) {
|
|
62692
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
62693
|
-
executorLog.error(`${task.id}: failed to schedule revision rerun: ${errorMessage}`);
|
|
62694
|
-
await this.store.logEntry(
|
|
62695
|
-
task.id,
|
|
62696
|
-
"Workflow revision requested \u2014 executor ready for fresh execution"
|
|
62697
|
-
);
|
|
62698
|
-
}
|
|
62699
|
-
}, 0);
|
|
62963
|
+
this.scheduleWorkflowRerun(
|
|
62964
|
+
task.id,
|
|
62965
|
+
worktreePath,
|
|
62966
|
+
`${task.id}: revision rerun scheduled \u2014 moved to todo then in-progress`
|
|
62967
|
+
);
|
|
62700
62968
|
}
|
|
62701
62969
|
/**
|
|
62702
62970
|
* Re-open the last non-pending step so a revision/failure handler gives the
|
|
@@ -62783,6 +63051,7 @@ ${feedback}
|
|
|
62783
63051
|
* @returns true if a retry was scheduled, false if retries are exhausted
|
|
62784
63052
|
*/
|
|
62785
63053
|
async handleWorkflowStepFailure(task, worktreePath, failureFeedback, stepName) {
|
|
63054
|
+
this.clearCompletedTaskWatchdog(task.id);
|
|
62786
63055
|
const currentRetries = task.workflowStepRetries ?? 0;
|
|
62787
63056
|
if (currentRetries >= MAX_WORKFLOW_STEP_RETRIES) {
|
|
62788
63057
|
executorLog.warn(`${task.id}: workflow step "${stepName}" failed \u2014 retries exhausted (${MAX_WORKFLOW_STEP_RETRIES}/${MAX_WORKFLOW_STEP_RETRIES})`);
|
|
@@ -62801,21 +63070,11 @@ ${feedback}
|
|
|
62801
63070
|
sessionFile: null
|
|
62802
63071
|
});
|
|
62803
63072
|
executorLog.log(`${task.id}: scheduling fresh execution after workflow step failure (retry ${retryCount}/${MAX_WORKFLOW_STEP_RETRIES})`);
|
|
62804
|
-
|
|
62805
|
-
|
|
62806
|
-
|
|
62807
|
-
|
|
62808
|
-
|
|
62809
|
-
executorLog.log(`${task.id}: workflow step retry scheduled \u2014 moved to todo then in-progress`);
|
|
62810
|
-
} catch (err) {
|
|
62811
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
62812
|
-
executorLog.error(`${task.id}: failed to schedule workflow step retry: ${errorMessage}`);
|
|
62813
|
-
await this.store.logEntry(
|
|
62814
|
-
task.id,
|
|
62815
|
-
"Workflow step failed \u2014 executor ready for fresh execution"
|
|
62816
|
-
);
|
|
62817
|
-
}
|
|
62818
|
-
}, 0);
|
|
63073
|
+
this.scheduleWorkflowRerun(
|
|
63074
|
+
task.id,
|
|
63075
|
+
worktreePath,
|
|
63076
|
+
`${task.id}: workflow step retry scheduled \u2014 moved to todo then in-progress`
|
|
63077
|
+
);
|
|
62819
63078
|
return true;
|
|
62820
63079
|
}
|
|
62821
63080
|
/**
|
|
@@ -62825,6 +63084,7 @@ ${feedback}
|
|
|
62825
63084
|
*/
|
|
62826
63085
|
async sendTaskBackForFix(task, worktreePath, failureFeedback, stepName, reason) {
|
|
62827
63086
|
const taskId = task.id;
|
|
63087
|
+
this.clearCompletedTaskWatchdog(taskId);
|
|
62828
63088
|
await this.store.addTaskComment(
|
|
62829
63089
|
taskId,
|
|
62830
63090
|
`${reason}. The failing workflow step was "${stepName}". Feedback:
|
|
@@ -62846,17 +63106,11 @@ Please fix the issues so the verification can pass on the next attempt.`,
|
|
|
62846
63106
|
sessionFile: null,
|
|
62847
63107
|
workflowStepRetries: 0
|
|
62848
63108
|
});
|
|
62849
|
-
|
|
62850
|
-
|
|
62851
|
-
|
|
62852
|
-
|
|
62853
|
-
|
|
62854
|
-
executorLog.log(`${taskId}: sent back to in-progress for remediation`);
|
|
62855
|
-
} catch (err) {
|
|
62856
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
62857
|
-
executorLog.error(`${taskId}: failed to move back to in-progress: ${errorMessage}`);
|
|
62858
|
-
}
|
|
62859
|
-
}, 0);
|
|
63109
|
+
this.scheduleWorkflowRerun(
|
|
63110
|
+
taskId,
|
|
63111
|
+
worktreePath,
|
|
63112
|
+
`${taskId}: sent back to in-progress for remediation`
|
|
63113
|
+
);
|
|
62860
63114
|
}
|
|
62861
63115
|
/**
|
|
62862
63116
|
* Inject or update the "Workflow Step Failure" section in PROMPT.md.
|
|
@@ -63407,7 +63661,7 @@ Review the work done in this worktree and evaluate it against the criteria in yo
|
|
|
63407
63661
|
);
|
|
63408
63662
|
}
|
|
63409
63663
|
const delay2 = this.WORKTREE_RETRY_DELAYS[attempt] || 1e3;
|
|
63410
|
-
await new Promise((
|
|
63664
|
+
await new Promise((resolve39) => setTimeout(resolve39, delay2));
|
|
63411
63665
|
}
|
|
63412
63666
|
}
|
|
63413
63667
|
throw new Error("Unexpected exit from worktree creation retry loop");
|
|
@@ -72731,13 +72985,13 @@ var init_plugin_runner = __esm({
|
|
|
72731
72985
|
* Returns the result on success, throws on timeout.
|
|
72732
72986
|
*/
|
|
72733
72987
|
withTimeout(promise, ms, timeoutMessage) {
|
|
72734
|
-
return new Promise((
|
|
72988
|
+
return new Promise((resolve39, reject2) => {
|
|
72735
72989
|
const timer = setTimeout(() => {
|
|
72736
72990
|
reject2(new Error(timeoutMessage));
|
|
72737
72991
|
}, ms);
|
|
72738
72992
|
promise.then((result) => {
|
|
72739
72993
|
clearTimeout(timer);
|
|
72740
|
-
|
|
72994
|
+
resolve39(result);
|
|
72741
72995
|
}).catch((err) => {
|
|
72742
72996
|
clearTimeout(timer);
|
|
72743
72997
|
reject2(err);
|
|
@@ -73406,7 +73660,7 @@ var init_in_process_runtime = __esm({
|
|
|
73406
73660
|
runtimeLog.log(
|
|
73407
73661
|
`Waiting for ${metrics.inFlightTasks} in-flight tasks to complete...`
|
|
73408
73662
|
);
|
|
73409
|
-
await new Promise((
|
|
73663
|
+
await new Promise((resolve39) => setTimeout(resolve39, 1e3));
|
|
73410
73664
|
}
|
|
73411
73665
|
const finalMetrics = this.getMetrics();
|
|
73412
73666
|
if (finalMetrics.inFlightTasks > 0) {
|
|
@@ -73803,13 +74057,13 @@ var init_ipc_host = __esm({
|
|
|
73803
74057
|
}
|
|
73804
74058
|
const id = generateCorrelationId();
|
|
73805
74059
|
const message = { type, id, payload };
|
|
73806
|
-
return new Promise((
|
|
74060
|
+
return new Promise((resolve39, reject2) => {
|
|
73807
74061
|
const timeout2 = setTimeout(() => {
|
|
73808
74062
|
this.pendingCommands.delete(id);
|
|
73809
74063
|
reject2(new Error(`Command ${type} timed out after ${timeoutMs ?? this.commandTimeoutMs}ms`));
|
|
73810
74064
|
}, timeoutMs ?? this.commandTimeoutMs);
|
|
73811
74065
|
this.pendingCommands.set(id, {
|
|
73812
|
-
resolve:
|
|
74066
|
+
resolve: resolve39,
|
|
73813
74067
|
reject: reject2,
|
|
73814
74068
|
timeout: timeout2,
|
|
73815
74069
|
type
|
|
@@ -74618,8 +74872,8 @@ var init_remote_node_client = __esm({
|
|
|
74618
74872
|
return error instanceof TypeError;
|
|
74619
74873
|
}
|
|
74620
74874
|
async sleep(ms) {
|
|
74621
|
-
await new Promise((
|
|
74622
|
-
setTimeout(
|
|
74875
|
+
await new Promise((resolve39) => {
|
|
74876
|
+
setTimeout(resolve39, ms);
|
|
74623
74877
|
});
|
|
74624
74878
|
}
|
|
74625
74879
|
};
|
|
@@ -74883,14 +75137,14 @@ var init_remote_node_runtime = __esm({
|
|
|
74883
75137
|
return error instanceof Error ? error : new Error(String(error));
|
|
74884
75138
|
}
|
|
74885
75139
|
async sleep(ms, signal) {
|
|
74886
|
-
await new Promise((
|
|
75140
|
+
await new Promise((resolve39) => {
|
|
74887
75141
|
const timeout2 = setTimeout(() => {
|
|
74888
75142
|
cleanup();
|
|
74889
|
-
|
|
75143
|
+
resolve39();
|
|
74890
75144
|
}, ms);
|
|
74891
75145
|
const onAbort = () => {
|
|
74892
75146
|
cleanup();
|
|
74893
|
-
|
|
75147
|
+
resolve39();
|
|
74894
75148
|
};
|
|
74895
75149
|
const cleanup = () => {
|
|
74896
75150
|
clearTimeout(timeout2);
|
|
@@ -75777,10 +76031,10 @@ var init_tunnel_process_manager = __esm({
|
|
|
75777
76031
|
lastError: null
|
|
75778
76032
|
});
|
|
75779
76033
|
this.emitLog("info", "manager", `Stopping ${currentHandle.provider} tunnel (pid=${currentHandle.child.pid ?? "n/a"})`);
|
|
75780
|
-
this.activeStopPromise = new Promise((
|
|
76034
|
+
this.activeStopPromise = new Promise((resolve39) => {
|
|
75781
76035
|
const onClose = () => {
|
|
75782
76036
|
currentHandle.child.removeListener("close", onClose);
|
|
75783
|
-
|
|
76037
|
+
resolve39();
|
|
75784
76038
|
};
|
|
75785
76039
|
currentHandle.child.once("close", onClose);
|
|
75786
76040
|
killManagedProcess(currentHandle.child, "SIGTERM");
|
|
@@ -76336,12 +76590,12 @@ ${detail}`
|
|
|
76336
76590
|
*/
|
|
76337
76591
|
async onMerge(taskId) {
|
|
76338
76592
|
if (this.mergeActive.has(taskId)) {
|
|
76339
|
-
return new Promise((
|
|
76340
|
-
this.manualMergeResolvers.set(taskId, { resolve:
|
|
76593
|
+
return new Promise((resolve39, reject2) => {
|
|
76594
|
+
this.manualMergeResolvers.set(taskId, { resolve: resolve39, reject: reject2 });
|
|
76341
76595
|
});
|
|
76342
76596
|
}
|
|
76343
|
-
return new Promise((
|
|
76344
|
-
this.manualMergeResolvers.set(taskId, { resolve:
|
|
76597
|
+
return new Promise((resolve39, reject2) => {
|
|
76598
|
+
this.manualMergeResolvers.set(taskId, { resolve: resolve39, reject: reject2 });
|
|
76345
76599
|
this.internalEnqueueMerge(taskId);
|
|
76346
76600
|
});
|
|
76347
76601
|
}
|
|
@@ -82211,7 +82465,7 @@ function hermesProfileHome(profileName) {
|
|
|
82211
82465
|
async function listHermesProfiles(opts) {
|
|
82212
82466
|
const binary = resolveBinaryForSpawn(opts?.binaryPath ?? "hermes");
|
|
82213
82467
|
const timeoutMs = opts?.timeoutMs ?? 5e3;
|
|
82214
|
-
return new Promise((
|
|
82468
|
+
return new Promise((resolve39, reject2) => {
|
|
82215
82469
|
let settled = false;
|
|
82216
82470
|
const child = spawn4(binary, ["profile", "list"], {
|
|
82217
82471
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -82254,7 +82508,7 @@ async function listHermesProfiles(opts) {
|
|
|
82254
82508
|
${combined}`));
|
|
82255
82509
|
return;
|
|
82256
82510
|
}
|
|
82257
|
-
|
|
82511
|
+
resolve39(parseProfileListOutput(stdout));
|
|
82258
82512
|
});
|
|
82259
82513
|
});
|
|
82260
82514
|
}
|
|
@@ -82331,7 +82585,7 @@ function buildHermesArgs(prompt, settings, resumeSessionId) {
|
|
|
82331
82585
|
async function invokeHermesCli(prompt, settings, resumeSessionId, signal) {
|
|
82332
82586
|
const args = buildHermesArgs(prompt, settings, resumeSessionId);
|
|
82333
82587
|
const binary = resolveBinaryForSpawn(settings.binaryPath);
|
|
82334
|
-
return new Promise((
|
|
82588
|
+
return new Promise((resolve39, reject2) => {
|
|
82335
82589
|
let settled = false;
|
|
82336
82590
|
const spawnEnv = { ...process.env, PYTHONUNBUFFERED: "1" };
|
|
82337
82591
|
if (settings.profile) {
|
|
@@ -82399,7 +82653,7 @@ ${combined}`));
|
|
|
82399
82653
|
return;
|
|
82400
82654
|
}
|
|
82401
82655
|
try {
|
|
82402
|
-
|
|
82656
|
+
resolve39(parseHermesOutput(stdout, stderr));
|
|
82403
82657
|
} catch (parseErr) {
|
|
82404
82658
|
reject2(parseErr);
|
|
82405
82659
|
}
|
|
@@ -82717,7 +82971,7 @@ async function promptCli(session, message, config, callbacks, signal) {
|
|
|
82717
82971
|
const args = buildOpenClawArgs(config, session.sessionId, message);
|
|
82718
82972
|
const cb = { ...session.callbacks, ...callbacks };
|
|
82719
82973
|
cb.onToolStart?.("openclaw.agent", { sessionId: session.sessionId });
|
|
82720
|
-
return new Promise((
|
|
82974
|
+
return new Promise((resolve39, reject2) => {
|
|
82721
82975
|
let settled = false;
|
|
82722
82976
|
const child = spawn6(config.binaryPath, args, {
|
|
82723
82977
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -82810,7 +83064,7 @@ async function promptCli(session, message, config, callbacks, signal) {
|
|
|
82810
83064
|
...metaError ? { error: metaError } : {},
|
|
82811
83065
|
...errorText.length > 0 ? { toolErrors: errorText } : {}
|
|
82812
83066
|
});
|
|
82813
|
-
|
|
83067
|
+
resolve39();
|
|
82814
83068
|
});
|
|
82815
83069
|
});
|
|
82816
83070
|
}
|
|
@@ -83552,10 +83806,10 @@ function registerTaskWorkflowRoutes(ctx, deps) {
|
|
|
83552
83806
|
nextRecoveryAt: null
|
|
83553
83807
|
});
|
|
83554
83808
|
if (retrySpecification) {
|
|
83555
|
-
const { rm:
|
|
83809
|
+
const { rm: rm6 } = await import("node:fs/promises");
|
|
83556
83810
|
const { join: join65 } = await import("node:path");
|
|
83557
83811
|
const promptPath = join65(scopedStore.getRootDir(), ".fusion", "tasks", task.id, "PROMPT.md");
|
|
83558
|
-
await
|
|
83812
|
+
await rm6(promptPath, { force: true });
|
|
83559
83813
|
await scopedStore.logEntry(req.params.id, "Retry requested from dashboard (planning retry budget reset)");
|
|
83560
83814
|
const updated2 = await scopedStore.getTask(req.params.id);
|
|
83561
83815
|
res.json(updated2);
|
|
@@ -83975,10 +84229,10 @@ function registerTaskWorkflowRoutes(ctx, deps) {
|
|
|
83975
84229
|
}
|
|
83976
84230
|
await scopedStore.logEntry(task.id, "Plan rejected by user", "Specification will be regenerated");
|
|
83977
84231
|
await scopedStore.updateTask(task.id, { status: void 0 });
|
|
83978
|
-
const { rm:
|
|
84232
|
+
const { rm: rm6 } = await import("node:fs/promises");
|
|
83979
84233
|
const { join: join65 } = await import("node:path");
|
|
83980
84234
|
const promptPath = join65(scopedStore.getRootDir(), ".fusion", "tasks", task.id, "PROMPT.md");
|
|
83981
|
-
await
|
|
84235
|
+
await rm6(promptPath, { force: true });
|
|
83982
84236
|
const updated = await scopedStore.getTask(task.id);
|
|
83983
84237
|
res.json(updated);
|
|
83984
84238
|
} catch (err) {
|
|
@@ -84246,10 +84500,10 @@ function registerTaskWorkflowRoutes(ctx, deps) {
|
|
|
84246
84500
|
const task = await scopedStore.getTask(req.params.id);
|
|
84247
84501
|
if (task.column === "triage") {
|
|
84248
84502
|
await scopedStore.logEntry(task.id, "AI spec revision requested", feedback);
|
|
84249
|
-
const { rm:
|
|
84503
|
+
const { rm: rm7 } = await import("node:fs/promises");
|
|
84250
84504
|
const { join: join66 } = await import("node:path");
|
|
84251
84505
|
const promptPath2 = join66(scopedStore.getRootDir(), ".fusion", "tasks", task.id, "PROMPT.md");
|
|
84252
|
-
await
|
|
84506
|
+
await rm7(promptPath2, { force: true });
|
|
84253
84507
|
await scopedStore.updateTask(task.id, { status: "needs-replan" });
|
|
84254
84508
|
const updated2 = await scopedStore.getTask(task.id);
|
|
84255
84509
|
res.json(updated2);
|
|
@@ -84263,10 +84517,10 @@ function registerTaskWorkflowRoutes(ctx, deps) {
|
|
|
84263
84517
|
}
|
|
84264
84518
|
await scopedStore.logEntry(task.id, "AI spec revision requested", feedback);
|
|
84265
84519
|
const updated = await scopedStore.moveTask(task.id, "triage");
|
|
84266
|
-
const { rm:
|
|
84520
|
+
const { rm: rm6 } = await import("node:fs/promises");
|
|
84267
84521
|
const { join: join65 } = await import("node:path");
|
|
84268
84522
|
const promptPath = join65(scopedStore.getRootDir(), ".fusion", "tasks", task.id, "PROMPT.md");
|
|
84269
|
-
await
|
|
84523
|
+
await rm6(promptPath, { force: true });
|
|
84270
84524
|
await scopedStore.updateTask(task.id, { status: "needs-replan" });
|
|
84271
84525
|
res.json(updated);
|
|
84272
84526
|
} catch (err) {
|
|
@@ -84284,10 +84538,10 @@ function registerTaskWorkflowRoutes(ctx, deps) {
|
|
|
84284
84538
|
const task = await scopedStore.getTask(req.params.id);
|
|
84285
84539
|
if (task.column === "triage") {
|
|
84286
84540
|
await scopedStore.logEntry(task.id, "Specification rebuild requested by user");
|
|
84287
|
-
const { rm:
|
|
84541
|
+
const { rm: rm7 } = await import("node:fs/promises");
|
|
84288
84542
|
const { join: join66 } = await import("node:path");
|
|
84289
84543
|
const promptPath2 = join66(scopedStore.getRootDir(), ".fusion", "tasks", task.id, "PROMPT.md");
|
|
84290
|
-
await
|
|
84544
|
+
await rm7(promptPath2, { force: true });
|
|
84291
84545
|
await scopedStore.updateTask(task.id, { status: "needs-replan" });
|
|
84292
84546
|
const updated2 = await scopedStore.getTask(task.id);
|
|
84293
84547
|
res.json(updated2);
|
|
@@ -84299,10 +84553,10 @@ function registerTaskWorkflowRoutes(ctx, deps) {
|
|
|
84299
84553
|
}
|
|
84300
84554
|
await scopedStore.logEntry(task.id, "Specification rebuild requested by user");
|
|
84301
84555
|
const updated = await scopedStore.moveTask(task.id, "triage");
|
|
84302
|
-
const { rm:
|
|
84556
|
+
const { rm: rm6 } = await import("node:fs/promises");
|
|
84303
84557
|
const { join: join65 } = await import("node:path");
|
|
84304
84558
|
const promptPath = join65(scopedStore.getRootDir(), ".fusion", "tasks", task.id, "PROMPT.md");
|
|
84305
|
-
await
|
|
84559
|
+
await rm6(promptPath, { force: true });
|
|
84306
84560
|
await scopedStore.updateTask(task.id, { status: "needs-replan" });
|
|
84307
84561
|
res.json(updated);
|
|
84308
84562
|
} catch (err) {
|
|
@@ -85582,6 +85836,11 @@ async function ensureEngineReady5() {
|
|
|
85582
85836
|
} catch {
|
|
85583
85837
|
}
|
|
85584
85838
|
}
|
|
85839
|
+
function formatAttachmentSize(size) {
|
|
85840
|
+
if (size < 1024) return `${size}B`;
|
|
85841
|
+
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}KB`;
|
|
85842
|
+
return `${(size / (1024 * 1024)).toFixed(1)}MB`;
|
|
85843
|
+
}
|
|
85585
85844
|
function validateFilePath(basePath, filePath) {
|
|
85586
85845
|
if (filePath.includes("\0")) {
|
|
85587
85846
|
throw new Error(`Access denied: Invalid characters in path`);
|
|
@@ -85911,7 +86170,7 @@ var init_chat = __esm({
|
|
|
85911
86170
|
* @param modelProvider - Optional model provider override
|
|
85912
86171
|
* @param modelId - Optional model ID override
|
|
85913
86172
|
*/
|
|
85914
|
-
async sendMessage(sessionId, content, modelProvider, modelId) {
|
|
86173
|
+
async sendMessage(sessionId, content, modelProvider, modelId, attachments) {
|
|
85915
86174
|
const abortController = new AbortController();
|
|
85916
86175
|
this.activeGenerations.set(sessionId, { abortController });
|
|
85917
86176
|
const session = this.chatStore.getSession(sessionId);
|
|
@@ -85935,7 +86194,8 @@ var init_chat = __esm({
|
|
|
85935
86194
|
this.chatStore.addMessage(sessionId, {
|
|
85936
86195
|
role: "user",
|
|
85937
86196
|
content,
|
|
85938
|
-
metadata: mentions.length > 0 ? { mentions } : void 0
|
|
86197
|
+
metadata: mentions.length > 0 ? { mentions } : void 0,
|
|
86198
|
+
attachments
|
|
85939
86199
|
});
|
|
85940
86200
|
} catch (err) {
|
|
85941
86201
|
chatStreamManager.broadcast(sessionId, {
|
|
@@ -86012,6 +86272,7 @@ ${mentionContext}`;
|
|
|
86012
86272
|
(message) => message.role === "user" || message.role === "assistant"
|
|
86013
86273
|
);
|
|
86014
86274
|
const resolvedContent = await resolveFileReferences(content, this.rootDir);
|
|
86275
|
+
const attachmentSummary = attachments && attachments.length > 0 ? `[User attached: ${attachments.map((attachment) => `${attachment.originalName} (${attachment.mimeType}, ${formatAttachmentSize(attachment.size)})`).join(", ")}]` : "";
|
|
86015
86276
|
const promptContent = conversationMessages.length > 0 ? [
|
|
86016
86277
|
"## Previous Conversation",
|
|
86017
86278
|
"",
|
|
@@ -86022,8 +86283,9 @@ ${mentionContext}`;
|
|
|
86022
86283
|
"",
|
|
86023
86284
|
"## Current Message",
|
|
86024
86285
|
"",
|
|
86286
|
+
attachmentSummary,
|
|
86025
86287
|
resolvedContent
|
|
86026
|
-
].join("\n") : resolvedContent;
|
|
86288
|
+
].filter(Boolean).join("\n") : [attachmentSummary, resolvedContent].filter(Boolean).join("\n\n");
|
|
86027
86289
|
agentResult = await createFnAgent8({
|
|
86028
86290
|
cwd: this.rootDir,
|
|
86029
86291
|
systemPrompt,
|
|
@@ -86100,7 +86362,7 @@ ${mentionContext}`;
|
|
|
86100
86362
|
});
|
|
86101
86363
|
chatStreamManager.broadcast(sessionId, {
|
|
86102
86364
|
type: "done",
|
|
86103
|
-
data: { messageId: assistantMessage.id }
|
|
86365
|
+
data: { messageId: assistantMessage.id, attachments }
|
|
86104
86366
|
});
|
|
86105
86367
|
} catch (err) {
|
|
86106
86368
|
if (abortController.signal.aborted) {
|
|
@@ -86166,9 +86428,36 @@ ${mentionContext}`;
|
|
|
86166
86428
|
});
|
|
86167
86429
|
|
|
86168
86430
|
// ../dashboard/src/routes/register-chat-routes.ts
|
|
86431
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
86432
|
+
import { createReadStream as createReadStream2 } from "node:fs";
|
|
86433
|
+
import { mkdir as mkdir12, rm as rm2, writeFile as writeFile12 } from "node:fs/promises";
|
|
86434
|
+
import { basename as basename9, join as join37, resolve as resolve17 } from "node:path";
|
|
86435
|
+
function resolveAttachmentPath(rootDir, sessionId, filename) {
|
|
86436
|
+
const sessionDir = resolve17(rootDir, ".fusion", "chat-attachments", sessionId);
|
|
86437
|
+
const safeName = basename9(filename);
|
|
86438
|
+
const filePath = resolve17(sessionDir, safeName);
|
|
86439
|
+
if (!filePath.startsWith(`${sessionDir}/`) && filePath !== sessionDir) {
|
|
86440
|
+
throw badRequest("Invalid attachment path");
|
|
86441
|
+
}
|
|
86442
|
+
return { sessionDir, filePath };
|
|
86443
|
+
}
|
|
86169
86444
|
function registerChatRoutes(ctx, deps) {
|
|
86170
86445
|
const { router, options, getProjectContext: getProjectContext3, chatLogger, rethrowAsApiError: rethrowAsApiError7 } = ctx;
|
|
86171
|
-
const { parseLastEventId: parseLastEventId3, validateOptionalModelField: validateOptionalModelField2 } = deps;
|
|
86446
|
+
const { parseLastEventId: parseLastEventId3, validateOptionalModelField: validateOptionalModelField2, upload: upload2 } = deps;
|
|
86447
|
+
const uploadChatAttachment = (req, res, next) => {
|
|
86448
|
+
upload2.single("file")(req, res, (err) => {
|
|
86449
|
+
if (!err) {
|
|
86450
|
+
next();
|
|
86451
|
+
return;
|
|
86452
|
+
}
|
|
86453
|
+
const multerError = err;
|
|
86454
|
+
if (multerError?.code === "LIMIT_FILE_SIZE") {
|
|
86455
|
+
next(badRequest(`File too large. Maximum: ${CHAT_MAX_ATTACHMENT_SIZE} bytes (5MB)`));
|
|
86456
|
+
return;
|
|
86457
|
+
}
|
|
86458
|
+
next(err);
|
|
86459
|
+
});
|
|
86460
|
+
};
|
|
86172
86461
|
router.get("/chat/sessions", rateLimit(RATE_LIMITS.api), async (req, res) => {
|
|
86173
86462
|
try {
|
|
86174
86463
|
const chatStore = options?.chatStore;
|
|
@@ -86368,6 +86657,84 @@ function registerChatRoutes(ctx, deps) {
|
|
|
86368
86657
|
rethrowAsApiError7(err, "Failed to get chat messages");
|
|
86369
86658
|
}
|
|
86370
86659
|
});
|
|
86660
|
+
router.post("/chat/sessions/:id/attachments", rateLimit(RATE_LIMITS.mutation), uploadChatAttachment, async (req, res) => {
|
|
86661
|
+
try {
|
|
86662
|
+
const chatStore = options?.chatStore;
|
|
86663
|
+
if (!chatStore) {
|
|
86664
|
+
throw internalError("Chat store not available");
|
|
86665
|
+
}
|
|
86666
|
+
const sessionId = String(req.params.id);
|
|
86667
|
+
const session = chatStore.getSession(sessionId);
|
|
86668
|
+
if (!session) {
|
|
86669
|
+
throw notFound(`Chat session ${sessionId} not found`);
|
|
86670
|
+
}
|
|
86671
|
+
const file = req.file;
|
|
86672
|
+
if (!file) {
|
|
86673
|
+
throw badRequest("file is required");
|
|
86674
|
+
}
|
|
86675
|
+
if (!CHAT_ALLOWED_MIME_TYPES.has(file.mimetype)) {
|
|
86676
|
+
throw badRequest(`Invalid mime type '${file.mimetype}'`);
|
|
86677
|
+
}
|
|
86678
|
+
if (file.size > CHAT_MAX_ATTACHMENT_SIZE) {
|
|
86679
|
+
throw badRequest(`File too large (${file.size} bytes). Maximum: ${CHAT_MAX_ATTACHMENT_SIZE} bytes (5MB)`);
|
|
86680
|
+
}
|
|
86681
|
+
const { store: scopedStore } = await getProjectContext3(req);
|
|
86682
|
+
const rootDir = scopedStore.getRootDir();
|
|
86683
|
+
const sessionDir = resolve17(rootDir, ".fusion", "chat-attachments", sessionId);
|
|
86684
|
+
await mkdir12(sessionDir, { recursive: true });
|
|
86685
|
+
const sanitizedFilename = (file.originalname || "attachment").replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
86686
|
+
const filename = `${Date.now()}-${sanitizedFilename}`;
|
|
86687
|
+
const filePath = join37(sessionDir, filename);
|
|
86688
|
+
await writeFile12(filePath, file.buffer);
|
|
86689
|
+
const attachment = {
|
|
86690
|
+
id: `att-${randomUUID15().slice(0, 8)}`,
|
|
86691
|
+
filename,
|
|
86692
|
+
originalName: file.originalname,
|
|
86693
|
+
mimeType: file.mimetype,
|
|
86694
|
+
size: file.size,
|
|
86695
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
86696
|
+
};
|
|
86697
|
+
res.status(201).json({ attachment });
|
|
86698
|
+
} catch (err) {
|
|
86699
|
+
if (err instanceof ApiError) throw err;
|
|
86700
|
+
rethrowAsApiError7(err, "Failed to upload chat attachment");
|
|
86701
|
+
}
|
|
86702
|
+
});
|
|
86703
|
+
router.get("/chat/sessions/:id/attachments/:filename", async (req, res) => {
|
|
86704
|
+
try {
|
|
86705
|
+
const { store: scopedStore } = await getProjectContext3(req);
|
|
86706
|
+
const rootDir = scopedStore.getRootDir();
|
|
86707
|
+
const { filePath } = resolveAttachmentPath(rootDir, String(req.params.id), String(req.params.filename));
|
|
86708
|
+
const stream = createReadStream2(filePath);
|
|
86709
|
+
stream.on("error", () => {
|
|
86710
|
+
if (!res.headersSent) {
|
|
86711
|
+
res.status(404).json({ error: "Attachment not found" });
|
|
86712
|
+
} else {
|
|
86713
|
+
res.end();
|
|
86714
|
+
}
|
|
86715
|
+
});
|
|
86716
|
+
res.setHeader("Content-Type", "application/octet-stream");
|
|
86717
|
+
stream.pipe(res);
|
|
86718
|
+
} catch (err) {
|
|
86719
|
+
if (err instanceof ApiError) throw err;
|
|
86720
|
+
rethrowAsApiError7(err, "Failed to fetch chat attachment");
|
|
86721
|
+
}
|
|
86722
|
+
});
|
|
86723
|
+
router.delete("/chat/sessions/:id/attachments/:filename", rateLimit(RATE_LIMITS.mutation), async (req, res) => {
|
|
86724
|
+
try {
|
|
86725
|
+
const { store: scopedStore } = await getProjectContext3(req);
|
|
86726
|
+
const rootDir = scopedStore.getRootDir();
|
|
86727
|
+
const { filePath } = resolveAttachmentPath(rootDir, String(req.params.id), String(req.params.filename));
|
|
86728
|
+
await rm2(filePath);
|
|
86729
|
+
res.json({ success: true });
|
|
86730
|
+
} catch (err) {
|
|
86731
|
+
if (err?.code === "ENOENT") {
|
|
86732
|
+
throw notFound("Attachment not found");
|
|
86733
|
+
}
|
|
86734
|
+
if (err instanceof ApiError) throw err;
|
|
86735
|
+
rethrowAsApiError7(err, "Failed to delete chat attachment");
|
|
86736
|
+
}
|
|
86737
|
+
});
|
|
86371
86738
|
router.post("/chat/sessions/:id/messages", rateLimit(RATE_LIMITS.sse), async (req, res) => {
|
|
86372
86739
|
try {
|
|
86373
86740
|
const chatStore = options?.chatStore;
|
|
@@ -86375,7 +86742,7 @@ function registerChatRoutes(ctx, deps) {
|
|
|
86375
86742
|
if (!chatStore || !chatManager) {
|
|
86376
86743
|
throw internalError("Chat store or manager not available");
|
|
86377
86744
|
}
|
|
86378
|
-
const { content, modelProvider, modelId } = req.body;
|
|
86745
|
+
const { content, modelProvider, modelId, attachments } = req.body;
|
|
86379
86746
|
const sessionId = String(req.params.id);
|
|
86380
86747
|
if (!content || typeof content !== "string" || !content.trim()) {
|
|
86381
86748
|
throw badRequest("content is required and must be a non-empty string");
|
|
@@ -86449,7 +86816,8 @@ function registerChatRoutes(ctx, deps) {
|
|
|
86449
86816
|
sessionId,
|
|
86450
86817
|
content.trim(),
|
|
86451
86818
|
normalizedProvider,
|
|
86452
|
-
normalizedModelId
|
|
86819
|
+
normalizedModelId,
|
|
86820
|
+
Array.isArray(attachments) ? attachments : void 0
|
|
86453
86821
|
).catch((err) => {
|
|
86454
86822
|
chatLogger.error("Error in sendMessage", {
|
|
86455
86823
|
error: err.message
|
|
@@ -86518,6 +86886,9 @@ function registerChatRoutes(ctx, deps) {
|
|
|
86518
86886
|
"PATCH /chat/sessions/:id",
|
|
86519
86887
|
"DELETE /chat/sessions/:id",
|
|
86520
86888
|
"GET /chat/sessions/:id/messages",
|
|
86889
|
+
"POST /chat/sessions/:id/attachments",
|
|
86890
|
+
"GET /chat/sessions/:id/attachments/:filename",
|
|
86891
|
+
"DELETE /chat/sessions/:id/attachments/:filename",
|
|
86521
86892
|
"POST /chat/sessions/:id/messages",
|
|
86522
86893
|
"POST /chat/sessions/:id/cancel",
|
|
86523
86894
|
"DELETE /chat/sessions/:id/messages/:messageId"
|
|
@@ -86525,12 +86896,26 @@ function registerChatRoutes(ctx, deps) {
|
|
|
86525
86896
|
chatLogger.info("routes registered", { chatRoutes });
|
|
86526
86897
|
}
|
|
86527
86898
|
}
|
|
86899
|
+
var CHAT_ALLOWED_MIME_TYPES, CHAT_MAX_ATTACHMENT_SIZE;
|
|
86528
86900
|
var init_register_chat_routes = __esm({
|
|
86529
86901
|
"../dashboard/src/routes/register-chat-routes.ts"() {
|
|
86530
86902
|
"use strict";
|
|
86531
86903
|
init_api_error();
|
|
86532
86904
|
init_rate_limit();
|
|
86533
86905
|
init_sse_buffer();
|
|
86906
|
+
CHAT_ALLOWED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
86907
|
+
"image/png",
|
|
86908
|
+
"image/jpeg",
|
|
86909
|
+
"image/gif",
|
|
86910
|
+
"image/webp",
|
|
86911
|
+
"text/plain",
|
|
86912
|
+
"application/json",
|
|
86913
|
+
"text/yaml",
|
|
86914
|
+
"text/x-toml",
|
|
86915
|
+
"text/csv",
|
|
86916
|
+
"application/xml"
|
|
86917
|
+
]);
|
|
86918
|
+
CHAT_MAX_ATTACHMENT_SIZE = 5 * 1024 * 1024;
|
|
86534
86919
|
}
|
|
86535
86920
|
});
|
|
86536
86921
|
|
|
@@ -87879,7 +88264,7 @@ import * as os3 from "os";
|
|
|
87879
88264
|
import * as path2 from "path";
|
|
87880
88265
|
import * as fs from "node:fs";
|
|
87881
88266
|
import { createRequire as createRequire3 } from "node:module";
|
|
87882
|
-
import { join as
|
|
88267
|
+
import { join as join38, dirname as dirname10 } from "node:path";
|
|
87883
88268
|
function getNativePrebuildName() {
|
|
87884
88269
|
const platform3 = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : process.platform === "win32" ? "win32" : "unknown";
|
|
87885
88270
|
const arch = process.arch === "arm64" ? "arm64" : process.arch === "x64" ? "x64" : "unknown";
|
|
@@ -87889,12 +88274,12 @@ function findInstalledNodePtyNativeDir() {
|
|
|
87889
88274
|
try {
|
|
87890
88275
|
const packageJsonPath = require2.resolve("node-pty/package.json");
|
|
87891
88276
|
const pkgRoot = dirname10(packageJsonPath);
|
|
87892
|
-
const releaseDir =
|
|
87893
|
-
if (fs.existsSync(
|
|
88277
|
+
const releaseDir = join38(pkgRoot, "build", "Release");
|
|
88278
|
+
if (fs.existsSync(join38(releaseDir, "pty.node"))) {
|
|
87894
88279
|
return releaseDir;
|
|
87895
88280
|
}
|
|
87896
|
-
const prebuildDir =
|
|
87897
|
-
if (fs.existsSync(
|
|
88281
|
+
const prebuildDir = join38(pkgRoot, "prebuilds", getNativePrebuildName());
|
|
88282
|
+
if (fs.existsSync(join38(prebuildDir, "pty.node"))) {
|
|
87898
88283
|
return prebuildDir;
|
|
87899
88284
|
}
|
|
87900
88285
|
return null;
|
|
@@ -87920,8 +88305,8 @@ function ensureNodePtyNativePermissions() {
|
|
|
87920
88305
|
candidateDirs.add(installedNativeDir);
|
|
87921
88306
|
}
|
|
87922
88307
|
for (const nativeDir of candidateDirs) {
|
|
87923
|
-
const helperPath =
|
|
87924
|
-
const nativeModulePath =
|
|
88308
|
+
const helperPath = join38(nativeDir, "spawn-helper");
|
|
88309
|
+
const nativeModulePath = join38(nativeDir, "pty.node");
|
|
87925
88310
|
try {
|
|
87926
88311
|
fs.chmodSync(helperPath, 493);
|
|
87927
88312
|
} catch {
|
|
@@ -87939,14 +88324,14 @@ function ensureNodePtyNativePermissions() {
|
|
|
87939
88324
|
function findStagedNativeDir() {
|
|
87940
88325
|
const prebuildName = getNativePrebuildName();
|
|
87941
88326
|
if (process.env.FUSION_RUNTIME_DIR) {
|
|
87942
|
-
const envPath =
|
|
87943
|
-
if (fs.existsSync(
|
|
88327
|
+
const envPath = join38(process.env.FUSION_RUNTIME_DIR, prebuildName);
|
|
88328
|
+
if (fs.existsSync(join38(envPath, "pty.node"))) {
|
|
87944
88329
|
return envPath;
|
|
87945
88330
|
}
|
|
87946
88331
|
}
|
|
87947
88332
|
const execDir = dirname10(process.execPath);
|
|
87948
|
-
const nextToBinary =
|
|
87949
|
-
if (fs.existsSync(
|
|
88333
|
+
const nextToBinary = join38(execDir, "runtime", prebuildName);
|
|
88334
|
+
if (fs.existsSync(join38(nextToBinary, "pty.node"))) {
|
|
87950
88335
|
return nextToBinary;
|
|
87951
88336
|
}
|
|
87952
88337
|
return null;
|
|
@@ -87966,7 +88351,7 @@ async function loadPtyModule() {
|
|
|
87966
88351
|
process.env.NODE_PTY_SPAWN_HELPER_DIR = nativeDir;
|
|
87967
88352
|
}
|
|
87968
88353
|
process.env.FUSION_NATIVE_ASSETS_PATH = nativeDir;
|
|
87969
|
-
const nativePath =
|
|
88354
|
+
const nativePath = join38(nativeDir, "pty.node");
|
|
87970
88355
|
if (fs.existsSync(nativePath)) {
|
|
87971
88356
|
try {
|
|
87972
88357
|
const nativeModule = { exports: {} };
|
|
@@ -88943,7 +89328,7 @@ var init_register_messaging_scripts = __esm({
|
|
|
88943
89328
|
|
|
88944
89329
|
// ../dashboard/src/github.ts
|
|
88945
89330
|
function delay(ms) {
|
|
88946
|
-
return new Promise((
|
|
89331
|
+
return new Promise((resolve39) => setTimeout(resolve39, ms));
|
|
88947
89332
|
}
|
|
88948
89333
|
function normalizeCheckState(state) {
|
|
88949
89334
|
switch ((state ?? "").toLowerCase()) {
|
|
@@ -93302,7 +93687,7 @@ var init_register_git_github = __esm({
|
|
|
93302
93687
|
|
|
93303
93688
|
// ../dashboard/src/terminal.ts
|
|
93304
93689
|
import { spawn as spawn8 } from "node:child_process";
|
|
93305
|
-
import { randomUUID as
|
|
93690
|
+
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
93306
93691
|
import { EventEmitter as EventEmitter31 } from "node:events";
|
|
93307
93692
|
function extractBaseCommand(command) {
|
|
93308
93693
|
let trimmed = command.trim();
|
|
@@ -93462,7 +93847,7 @@ var init_terminal = __esm({
|
|
|
93462
93847
|
if (!validation.valid) {
|
|
93463
93848
|
return { sessionId: "", error: validation.error };
|
|
93464
93849
|
}
|
|
93465
|
-
const sessionId =
|
|
93850
|
+
const sessionId = randomUUID16();
|
|
93466
93851
|
const childProcess = spawn8(command, [], {
|
|
93467
93852
|
cwd,
|
|
93468
93853
|
shell: true,
|
|
@@ -93587,20 +93972,20 @@ var init_terminal = __esm({
|
|
|
93587
93972
|
});
|
|
93588
93973
|
|
|
93589
93974
|
// ../dashboard/src/file-service.ts
|
|
93590
|
-
import { join as
|
|
93591
|
-
import { readdir as readdir8, readFile as fsReadFile, writeFile as fsWriteFile, stat as stat7, copyFile as fsCopyFile, rename as fsRename, rm as fsRm, mkdir as
|
|
93975
|
+
import { join as join39, resolve as resolve19, relative as relative9, dirname as dirname11, basename as basename11 } from "node:path";
|
|
93976
|
+
import { readdir as readdir8, readFile as fsReadFile, writeFile as fsWriteFile, stat as stat7, copyFile as fsCopyFile, rename as fsRename, rm as fsRm, mkdir as mkdir13, access as access4 } from "node:fs/promises";
|
|
93592
93977
|
async function getTaskBasePath(store, taskId) {
|
|
93593
93978
|
try {
|
|
93594
93979
|
const task = await store.getTask(taskId);
|
|
93595
93980
|
if (task.worktree) {
|
|
93596
93981
|
try {
|
|
93597
93982
|
await access4(task.worktree);
|
|
93598
|
-
return
|
|
93983
|
+
return resolve19(task.worktree);
|
|
93599
93984
|
} catch {
|
|
93600
93985
|
}
|
|
93601
93986
|
}
|
|
93602
93987
|
const rootDir = store.getRootDir();
|
|
93603
|
-
return
|
|
93988
|
+
return resolve19(join39(rootDir, ".fusion", "tasks", taskId));
|
|
93604
93989
|
} catch (err) {
|
|
93605
93990
|
const error = err;
|
|
93606
93991
|
if (error.code === "ENOENT" || error.message && error.message.includes("not found")) {
|
|
@@ -93610,7 +93995,7 @@ async function getTaskBasePath(store, taskId) {
|
|
|
93610
93995
|
}
|
|
93611
93996
|
}
|
|
93612
93997
|
function getProjectBasePath(store) {
|
|
93613
|
-
return
|
|
93998
|
+
return resolve19(store.getRootDir());
|
|
93614
93999
|
}
|
|
93615
94000
|
async function getWorkspaceBasePath(store, workspace) {
|
|
93616
94001
|
if (workspace === "project") {
|
|
@@ -93626,8 +94011,8 @@ function validatePath(basePath, filePath) {
|
|
|
93626
94011
|
if (decodedPath.startsWith("/") || decodedPath.match(/^[a-zA-Z]:/)) {
|
|
93627
94012
|
throw new FileServiceError(`Access denied: Absolute paths not allowed`, "EINVAL");
|
|
93628
94013
|
}
|
|
93629
|
-
const resolvedBase =
|
|
93630
|
-
const resolvedPath =
|
|
94014
|
+
const resolvedBase = resolve19(basePath);
|
|
94015
|
+
const resolvedPath = resolve19(join39(resolvedBase, decodedPath));
|
|
93631
94016
|
const relativePath = relative9(resolvedBase, resolvedPath);
|
|
93632
94017
|
if (relativePath.startsWith("..") || relativePath.startsWith("../") || relativePath === "..") {
|
|
93633
94018
|
throw new FileServiceError(`Access denied: Path traversal detected`, "EINVAL");
|
|
@@ -93656,7 +94041,7 @@ async function listFilesForBasePath(basePath, subPath) {
|
|
|
93656
94041
|
const entries = await readdir8(targetPath, { withFileTypes: true });
|
|
93657
94042
|
const fileNodes = [];
|
|
93658
94043
|
for (const entry of entries) {
|
|
93659
|
-
const entryPath =
|
|
94044
|
+
const entryPath = join39(targetPath, entry.name);
|
|
93660
94045
|
const entryStats = await stat7(entryPath);
|
|
93661
94046
|
fileNodes.push({
|
|
93662
94047
|
name: entry.name,
|
|
@@ -93786,7 +94171,7 @@ async function readFile18(store, taskId, filePath) {
|
|
|
93786
94171
|
const taskBase = await getTaskBasePath(store, taskId);
|
|
93787
94172
|
return readFileForBasePath(taskBase, filePath);
|
|
93788
94173
|
}
|
|
93789
|
-
async function
|
|
94174
|
+
async function writeFile13(store, taskId, filePath, content) {
|
|
93790
94175
|
const taskBase = await getTaskBasePath(store, taskId);
|
|
93791
94176
|
return writeFileForBasePath(taskBase, filePath, content);
|
|
93792
94177
|
}
|
|
@@ -93805,7 +94190,7 @@ async function writeWorkspaceFile(store, workspace, filePath, content) {
|
|
|
93805
94190
|
function validateSourceAndDestination(basePath, sourcePath, destinationPath) {
|
|
93806
94191
|
const resolvedSource = validatePath(basePath, sourcePath);
|
|
93807
94192
|
const resolvedDest = validatePath(basePath, destinationPath);
|
|
93808
|
-
const sourceRelative = relative9(
|
|
94193
|
+
const sourceRelative = relative9(resolve19(basePath), resolvedSource);
|
|
93809
94194
|
if (!sourceRelative || sourceRelative === "." || sourceRelative === "") {
|
|
93810
94195
|
throw new FileServiceError("Cannot operate on workspace root directory", "EINVAL");
|
|
93811
94196
|
}
|
|
@@ -93929,7 +94314,7 @@ async function deleteWorkspaceFile(store, workspace, filePath) {
|
|
|
93929
94314
|
}
|
|
93930
94315
|
const workspaceBase = await getWorkspaceBasePath(store, workspace);
|
|
93931
94316
|
const resolvedPath = validatePath(workspaceBase, filePath);
|
|
93932
|
-
const relativePath = relative9(
|
|
94317
|
+
const relativePath = relative9(resolve19(workspaceBase), resolvedPath);
|
|
93933
94318
|
if (!relativePath || relativePath === "." || relativePath === "") {
|
|
93934
94319
|
throw new FileServiceError("Cannot delete workspace root directory", "EINVAL");
|
|
93935
94320
|
}
|
|
@@ -93970,7 +94355,7 @@ async function renameWorkspaceFile(store, workspace, filePath, newName) {
|
|
|
93970
94355
|
}
|
|
93971
94356
|
const workspaceBase = await getWorkspaceBasePath(store, workspace);
|
|
93972
94357
|
const resolvedPath = validatePath(workspaceBase, filePath);
|
|
93973
|
-
const relativePath = relative9(
|
|
94358
|
+
const relativePath = relative9(resolve19(workspaceBase), resolvedPath);
|
|
93974
94359
|
if (!relativePath || relativePath === "." || relativePath === "") {
|
|
93975
94360
|
throw new FileServiceError("Cannot rename workspace root directory", "EINVAL");
|
|
93976
94361
|
}
|
|
@@ -93983,12 +94368,12 @@ async function renameWorkspaceFile(store, workspace, filePath, newName) {
|
|
|
93983
94368
|
}
|
|
93984
94369
|
throw err;
|
|
93985
94370
|
}
|
|
93986
|
-
const destPath =
|
|
93987
|
-
const destRelative = relative9(
|
|
94371
|
+
const destPath = join39(dirname11(resolvedPath), newName);
|
|
94372
|
+
const destRelative = relative9(resolve19(workspaceBase), destPath);
|
|
93988
94373
|
if (destRelative.startsWith("..") || destRelative.startsWith("../") || destRelative === "..") {
|
|
93989
94374
|
throw new FileServiceError("Destination would be outside workspace", "EINVAL");
|
|
93990
94375
|
}
|
|
93991
|
-
if (!destPath.startsWith(
|
|
94376
|
+
if (!destPath.startsWith(resolve19(workspaceBase))) {
|
|
93992
94377
|
throw new FileServiceError("Destination would be outside workspace", "EINVAL");
|
|
93993
94378
|
}
|
|
93994
94379
|
try {
|
|
@@ -94017,7 +94402,7 @@ async function getWorkspaceFileForDownload(store, workspace, filePath) {
|
|
|
94017
94402
|
}
|
|
94018
94403
|
const workspaceBase = await getWorkspaceBasePath(store, workspace);
|
|
94019
94404
|
const resolvedPath = validatePath(workspaceBase, filePath);
|
|
94020
|
-
const relativePath = relative9(
|
|
94405
|
+
const relativePath = relative9(resolve19(workspaceBase), resolvedPath);
|
|
94021
94406
|
if (!relativePath || relativePath === "." || relativePath === "") {
|
|
94022
94407
|
throw new FileServiceError("Cannot download workspace root", "EINVAL");
|
|
94023
94408
|
}
|
|
@@ -94041,7 +94426,7 @@ async function getWorkspaceFileForDownload(store, workspace, filePath) {
|
|
|
94041
94426
|
mtime: stats.mtime,
|
|
94042
94427
|
isFile: true
|
|
94043
94428
|
},
|
|
94044
|
-
fileName:
|
|
94429
|
+
fileName: basename11(resolvedPath)
|
|
94045
94430
|
};
|
|
94046
94431
|
}
|
|
94047
94432
|
async function getWorkspaceFolderForZip(store, workspace, dirPath) {
|
|
@@ -94050,7 +94435,7 @@ async function getWorkspaceFolderForZip(store, workspace, dirPath) {
|
|
|
94050
94435
|
}
|
|
94051
94436
|
const workspaceBase = await getWorkspaceBasePath(store, workspace);
|
|
94052
94437
|
const resolvedPath = validatePath(workspaceBase, dirPath);
|
|
94053
|
-
const relativePath = relative9(
|
|
94438
|
+
const relativePath = relative9(resolve19(workspaceBase), resolvedPath);
|
|
94054
94439
|
if (!relativePath || relativePath === "." || relativePath === "") {
|
|
94055
94440
|
throw new FileServiceError("Cannot download workspace root as ZIP", "EINVAL");
|
|
94056
94441
|
}
|
|
@@ -94069,14 +94454,14 @@ async function getWorkspaceFolderForZip(store, workspace, dirPath) {
|
|
|
94069
94454
|
}
|
|
94070
94455
|
return {
|
|
94071
94456
|
absolutePath: resolvedPath,
|
|
94072
|
-
dirName:
|
|
94457
|
+
dirName: basename11(resolvedPath)
|
|
94073
94458
|
};
|
|
94074
94459
|
}
|
|
94075
94460
|
function isHiddenPathSegment(name) {
|
|
94076
94461
|
return name.startsWith(".");
|
|
94077
94462
|
}
|
|
94078
94463
|
async function walkDirForMarkdown(basePath, currentRelative, results, options) {
|
|
94079
|
-
const currentPath = currentRelative ?
|
|
94464
|
+
const currentPath = currentRelative ? join39(basePath, currentRelative) : basePath;
|
|
94080
94465
|
let entries;
|
|
94081
94466
|
try {
|
|
94082
94467
|
entries = await readdir8(currentPath, { withFileTypes: true });
|
|
@@ -94084,7 +94469,7 @@ async function walkDirForMarkdown(basePath, currentRelative, results, options) {
|
|
|
94084
94469
|
return;
|
|
94085
94470
|
}
|
|
94086
94471
|
for (const entry of entries) {
|
|
94087
|
-
const entryRelativePath = currentRelative ?
|
|
94472
|
+
const entryRelativePath = currentRelative ? join39(currentRelative, entry.name) : entry.name;
|
|
94088
94473
|
if (entry.isDirectory()) {
|
|
94089
94474
|
if (MARKDOWN_SCAN_EXCLUDED_DIRS.has(entry.name)) {
|
|
94090
94475
|
continue;
|
|
@@ -94101,7 +94486,7 @@ async function walkDirForMarkdown(basePath, currentRelative, results, options) {
|
|
|
94101
94486
|
if (!options.showHidden && isHiddenPathSegment(entry.name)) {
|
|
94102
94487
|
continue;
|
|
94103
94488
|
}
|
|
94104
|
-
const fullPath =
|
|
94489
|
+
const fullPath = join39(basePath, entryRelativePath);
|
|
94105
94490
|
let fileStats;
|
|
94106
94491
|
try {
|
|
94107
94492
|
fileStats = await stat7(fullPath);
|
|
@@ -94151,7 +94536,7 @@ async function scanMarkdownFiles(store, options) {
|
|
|
94151
94536
|
return;
|
|
94152
94537
|
}
|
|
94153
94538
|
for (const entry of entries) {
|
|
94154
|
-
const entryRelativePath = relativeDir ?
|
|
94539
|
+
const entryRelativePath = relativeDir ? join39(relativeDir, entry.name) : entry.name;
|
|
94155
94540
|
let shouldRecurse = entry.isDirectory();
|
|
94156
94541
|
if (!shouldRecurse && typeof entry.isSymbolicLink === "function" && entry.isSymbolicLink()) {
|
|
94157
94542
|
let symlinkPath;
|
|
@@ -94241,8 +94626,8 @@ async function searchWorkspaceFiles(store, workspace, query) {
|
|
|
94241
94626
|
if (entry.isDirectory() && EXCLUDED_DIRS.has(entry.name)) {
|
|
94242
94627
|
continue;
|
|
94243
94628
|
}
|
|
94244
|
-
const fullPath =
|
|
94245
|
-
const relPath =
|
|
94629
|
+
const fullPath = join39(dir2, entry.name);
|
|
94630
|
+
const relPath = join39(relativeDir, entry.name);
|
|
94246
94631
|
if (entry.isFile()) {
|
|
94247
94632
|
if (entry.name.toLowerCase().includes(lowerQuery)) {
|
|
94248
94633
|
results.push({
|
|
@@ -94260,11 +94645,11 @@ async function searchWorkspaceFiles(store, workspace, query) {
|
|
|
94260
94645
|
return { files: results };
|
|
94261
94646
|
}
|
|
94262
94647
|
async function copyDirectoryRecursive(source, destination) {
|
|
94263
|
-
await
|
|
94648
|
+
await mkdir13(destination, { recursive: true });
|
|
94264
94649
|
const entries = await readdir8(source, { withFileTypes: true });
|
|
94265
94650
|
for (const entry of entries) {
|
|
94266
|
-
const sourcePath =
|
|
94267
|
-
const destPath =
|
|
94651
|
+
const sourcePath = join39(source, entry.name);
|
|
94652
|
+
const destPath = join39(destination, entry.name);
|
|
94268
94653
|
if (entry.isDirectory()) {
|
|
94269
94654
|
await copyDirectoryRecursive(sourcePath, destPath);
|
|
94270
94655
|
} else {
|
|
@@ -95181,9 +95566,9 @@ var require_readdir_glob = __commonJS({
|
|
|
95181
95566
|
var fs2 = __require("fs");
|
|
95182
95567
|
var { EventEmitter: EventEmitter35 } = __require("events");
|
|
95183
95568
|
var { Minimatch } = require_minimatch();
|
|
95184
|
-
var { resolve:
|
|
95569
|
+
var { resolve: resolve39 } = __require("path");
|
|
95185
95570
|
function readdir12(dir2, strict) {
|
|
95186
|
-
return new Promise((
|
|
95571
|
+
return new Promise((resolve40, reject2) => {
|
|
95187
95572
|
fs2.readdir(dir2, { withFileTypes: true }, (err, files) => {
|
|
95188
95573
|
if (err) {
|
|
95189
95574
|
switch (err.code) {
|
|
@@ -95191,7 +95576,7 @@ var require_readdir_glob = __commonJS({
|
|
|
95191
95576
|
if (strict) {
|
|
95192
95577
|
reject2(err);
|
|
95193
95578
|
} else {
|
|
95194
|
-
|
|
95579
|
+
resolve40([]);
|
|
95195
95580
|
}
|
|
95196
95581
|
break;
|
|
95197
95582
|
case "ENOTSUP":
|
|
@@ -95201,7 +95586,7 @@ var require_readdir_glob = __commonJS({
|
|
|
95201
95586
|
case "ENAMETOOLONG":
|
|
95202
95587
|
// Filename too long
|
|
95203
95588
|
case "UNKNOWN":
|
|
95204
|
-
|
|
95589
|
+
resolve40([]);
|
|
95205
95590
|
break;
|
|
95206
95591
|
case "ELOOP":
|
|
95207
95592
|
// Too many levels of symbolic links
|
|
@@ -95210,30 +95595,30 @@ var require_readdir_glob = __commonJS({
|
|
|
95210
95595
|
break;
|
|
95211
95596
|
}
|
|
95212
95597
|
} else {
|
|
95213
|
-
|
|
95598
|
+
resolve40(files);
|
|
95214
95599
|
}
|
|
95215
95600
|
});
|
|
95216
95601
|
});
|
|
95217
95602
|
}
|
|
95218
95603
|
function stat12(file, followSymlinks) {
|
|
95219
|
-
return new Promise((
|
|
95604
|
+
return new Promise((resolve40, reject2) => {
|
|
95220
95605
|
const statFunc = followSymlinks ? fs2.stat : fs2.lstat;
|
|
95221
95606
|
statFunc(file, (err, stats) => {
|
|
95222
95607
|
if (err) {
|
|
95223
95608
|
switch (err.code) {
|
|
95224
95609
|
case "ENOENT":
|
|
95225
95610
|
if (followSymlinks) {
|
|
95226
|
-
|
|
95611
|
+
resolve40(stat12(file, false));
|
|
95227
95612
|
} else {
|
|
95228
|
-
|
|
95613
|
+
resolve40(null);
|
|
95229
95614
|
}
|
|
95230
95615
|
break;
|
|
95231
95616
|
default:
|
|
95232
|
-
|
|
95617
|
+
resolve40(null);
|
|
95233
95618
|
break;
|
|
95234
95619
|
}
|
|
95235
95620
|
} else {
|
|
95236
|
-
|
|
95621
|
+
resolve40(stats);
|
|
95237
95622
|
}
|
|
95238
95623
|
});
|
|
95239
95624
|
});
|
|
@@ -95323,7 +95708,7 @@ var require_readdir_glob = __commonJS({
|
|
|
95323
95708
|
(skip) => new Minimatch(skip, { dot: true })
|
|
95324
95709
|
);
|
|
95325
95710
|
}
|
|
95326
|
-
this.iterator = explore(
|
|
95711
|
+
this.iterator = explore(resolve39(cwd || "."), this.options.follow, this.options.stat, this._shouldSkipDirectory.bind(this));
|
|
95327
95712
|
this.paused = false;
|
|
95328
95713
|
this.inactive = false;
|
|
95329
95714
|
this.aborted = false;
|
|
@@ -95577,10 +95962,10 @@ function awaitify(asyncFn, arity) {
|
|
|
95577
95962
|
if (typeof args[arity - 1] === "function") {
|
|
95578
95963
|
return asyncFn.apply(this, args);
|
|
95579
95964
|
}
|
|
95580
|
-
return new Promise((
|
|
95965
|
+
return new Promise((resolve39, reject2) => {
|
|
95581
95966
|
args[arity - 1] = (err, ...cbArgs) => {
|
|
95582
95967
|
if (err) return reject2(err);
|
|
95583
|
-
|
|
95968
|
+
resolve39(cbArgs.length > 1 ? cbArgs : cbArgs[0]);
|
|
95584
95969
|
};
|
|
95585
95970
|
asyncFn.apply(this, args);
|
|
95586
95971
|
});
|
|
@@ -95762,13 +96147,13 @@ function mapSeries(coll, iteratee, callback) {
|
|
|
95762
96147
|
return _asyncMap(eachOfSeries$1, coll, iteratee, callback);
|
|
95763
96148
|
}
|
|
95764
96149
|
function promiseCallback() {
|
|
95765
|
-
let
|
|
96150
|
+
let resolve39, reject2;
|
|
95766
96151
|
function callback(err, ...args) {
|
|
95767
96152
|
if (err) return reject2(err);
|
|
95768
|
-
|
|
96153
|
+
resolve39(args.length > 1 ? args : args[0]);
|
|
95769
96154
|
}
|
|
95770
96155
|
callback[PROMISE_SYMBOL] = new Promise((res, rej) => {
|
|
95771
|
-
|
|
96156
|
+
resolve39 = res, reject2 = rej;
|
|
95772
96157
|
});
|
|
95773
96158
|
return callback;
|
|
95774
96159
|
}
|
|
@@ -96041,8 +96426,8 @@ function queue$1(worker, concurrency, payload) {
|
|
|
96041
96426
|
});
|
|
96042
96427
|
}
|
|
96043
96428
|
if (rejectOnError || !callback) {
|
|
96044
|
-
return new Promise((
|
|
96045
|
-
res =
|
|
96429
|
+
return new Promise((resolve39, reject2) => {
|
|
96430
|
+
res = resolve39;
|
|
96046
96431
|
rej = reject2;
|
|
96047
96432
|
});
|
|
96048
96433
|
}
|
|
@@ -96081,10 +96466,10 @@ function queue$1(worker, concurrency, payload) {
|
|
|
96081
96466
|
}
|
|
96082
96467
|
const eventMethod = (name) => (handler) => {
|
|
96083
96468
|
if (!handler) {
|
|
96084
|
-
return new Promise((
|
|
96469
|
+
return new Promise((resolve39, reject2) => {
|
|
96085
96470
|
once3(name, (err, data) => {
|
|
96086
96471
|
if (err) return reject2(err);
|
|
96087
|
-
|
|
96472
|
+
resolve39(data);
|
|
96088
96473
|
});
|
|
96089
96474
|
});
|
|
96090
96475
|
}
|
|
@@ -97745,7 +98130,7 @@ var require_graceful_fs = __commonJS({
|
|
|
97745
98130
|
function patch(fs3) {
|
|
97746
98131
|
polyfills(fs3);
|
|
97747
98132
|
fs3.gracefulify = patch;
|
|
97748
|
-
fs3.createReadStream =
|
|
98133
|
+
fs3.createReadStream = createReadStream4;
|
|
97749
98134
|
fs3.createWriteStream = createWriteStream2;
|
|
97750
98135
|
var fs$readFile = fs3.readFile;
|
|
97751
98136
|
fs3.readFile = readFile24;
|
|
@@ -97765,8 +98150,8 @@ var require_graceful_fs = __commonJS({
|
|
|
97765
98150
|
}
|
|
97766
98151
|
}
|
|
97767
98152
|
var fs$writeFile = fs3.writeFile;
|
|
97768
|
-
fs3.writeFile =
|
|
97769
|
-
function
|
|
98153
|
+
fs3.writeFile = writeFile18;
|
|
98154
|
+
function writeFile18(path5, data, options, cb) {
|
|
97770
98155
|
if (typeof options === "function")
|
|
97771
98156
|
cb = options, options = null;
|
|
97772
98157
|
return go$writeFile(path5, data, options, cb);
|
|
@@ -97955,7 +98340,7 @@ var require_graceful_fs = __commonJS({
|
|
|
97955
98340
|
}
|
|
97956
98341
|
});
|
|
97957
98342
|
}
|
|
97958
|
-
function
|
|
98343
|
+
function createReadStream4(path5, options) {
|
|
97959
98344
|
return new fs3.ReadStream(path5, options);
|
|
97960
98345
|
}
|
|
97961
98346
|
function createWriteStream2(path5, options) {
|
|
@@ -102090,25 +102475,25 @@ var require_util2 = __commonJS({
|
|
|
102090
102475
|
};
|
|
102091
102476
|
},
|
|
102092
102477
|
createDeferredPromise: function() {
|
|
102093
|
-
let
|
|
102478
|
+
let resolve39;
|
|
102094
102479
|
let reject2;
|
|
102095
102480
|
const promise = new Promise((res, rej) => {
|
|
102096
|
-
|
|
102481
|
+
resolve39 = res;
|
|
102097
102482
|
reject2 = rej;
|
|
102098
102483
|
});
|
|
102099
102484
|
return {
|
|
102100
102485
|
promise,
|
|
102101
|
-
resolve:
|
|
102486
|
+
resolve: resolve39,
|
|
102102
102487
|
reject: reject2
|
|
102103
102488
|
};
|
|
102104
102489
|
},
|
|
102105
102490
|
promisify(fn) {
|
|
102106
|
-
return new Promise((
|
|
102491
|
+
return new Promise((resolve39, reject2) => {
|
|
102107
102492
|
fn((err, ...args) => {
|
|
102108
102493
|
if (err) {
|
|
102109
102494
|
return reject2(err);
|
|
102110
102495
|
}
|
|
102111
|
-
return
|
|
102496
|
+
return resolve39(...args);
|
|
102112
102497
|
});
|
|
102113
102498
|
});
|
|
102114
102499
|
},
|
|
@@ -102900,7 +103285,7 @@ var require_end_of_stream2 = __commonJS({
|
|
|
102900
103285
|
validateBoolean3(opts.cleanup, "cleanup");
|
|
102901
103286
|
autoCleanup = opts.cleanup;
|
|
102902
103287
|
}
|
|
102903
|
-
return new Promise2((
|
|
103288
|
+
return new Promise2((resolve39, reject2) => {
|
|
102904
103289
|
const cleanup = eos(stream, opts, (err) => {
|
|
102905
103290
|
if (autoCleanup) {
|
|
102906
103291
|
cleanup();
|
|
@@ -102908,7 +103293,7 @@ var require_end_of_stream2 = __commonJS({
|
|
|
102908
103293
|
if (err) {
|
|
102909
103294
|
reject2(err);
|
|
102910
103295
|
} else {
|
|
102911
|
-
|
|
103296
|
+
resolve39();
|
|
102912
103297
|
}
|
|
102913
103298
|
});
|
|
102914
103299
|
});
|
|
@@ -104075,7 +104460,7 @@ var require_readable2 = __commonJS({
|
|
|
104075
104460
|
error = this.readableEnded ? null : new AbortError();
|
|
104076
104461
|
this.destroy(error);
|
|
104077
104462
|
}
|
|
104078
|
-
return new Promise2((
|
|
104463
|
+
return new Promise2((resolve39, reject2) => eos(this, (err) => err && err !== error ? reject2(err) : resolve39(null)));
|
|
104079
104464
|
};
|
|
104080
104465
|
Readable2.prototype.push = function(chunk, encoding) {
|
|
104081
104466
|
return readableAddChunk(this, chunk, encoding, false);
|
|
@@ -104619,12 +105004,12 @@ var require_readable2 = __commonJS({
|
|
|
104619
105004
|
}
|
|
104620
105005
|
async function* createAsyncIterator(stream, options) {
|
|
104621
105006
|
let callback = nop;
|
|
104622
|
-
function next(
|
|
105007
|
+
function next(resolve39) {
|
|
104623
105008
|
if (this === stream) {
|
|
104624
105009
|
callback();
|
|
104625
105010
|
callback = nop;
|
|
104626
105011
|
} else {
|
|
104627
|
-
callback =
|
|
105012
|
+
callback = resolve39;
|
|
104628
105013
|
}
|
|
104629
105014
|
}
|
|
104630
105015
|
stream.on("readable", next);
|
|
@@ -105677,7 +106062,7 @@ var require_duplexify = __commonJS({
|
|
|
105677
106062
|
);
|
|
105678
106063
|
};
|
|
105679
106064
|
function fromAsyncGen(fn) {
|
|
105680
|
-
let { promise, resolve:
|
|
106065
|
+
let { promise, resolve: resolve39 } = createDeferredPromise();
|
|
105681
106066
|
const ac = new AbortController2();
|
|
105682
106067
|
const signal = ac.signal;
|
|
105683
106068
|
const value = fn(
|
|
@@ -105692,7 +106077,7 @@ var require_duplexify = __commonJS({
|
|
|
105692
106077
|
throw new AbortError(void 0, {
|
|
105693
106078
|
cause: signal.reason
|
|
105694
106079
|
});
|
|
105695
|
-
({ promise, resolve:
|
|
106080
|
+
({ promise, resolve: resolve39 } = createDeferredPromise());
|
|
105696
106081
|
yield chunk;
|
|
105697
106082
|
}
|
|
105698
106083
|
})(),
|
|
@@ -105703,8 +106088,8 @@ var require_duplexify = __commonJS({
|
|
|
105703
106088
|
return {
|
|
105704
106089
|
value,
|
|
105705
106090
|
write(chunk, encoding, cb) {
|
|
105706
|
-
const _resolve =
|
|
105707
|
-
|
|
106091
|
+
const _resolve = resolve39;
|
|
106092
|
+
resolve39 = null;
|
|
105708
106093
|
_resolve({
|
|
105709
106094
|
chunk,
|
|
105710
106095
|
done: false,
|
|
@@ -105712,8 +106097,8 @@ var require_duplexify = __commonJS({
|
|
|
105712
106097
|
});
|
|
105713
106098
|
},
|
|
105714
106099
|
final(cb) {
|
|
105715
|
-
const _resolve =
|
|
105716
|
-
|
|
106100
|
+
const _resolve = resolve39;
|
|
106101
|
+
resolve39 = null;
|
|
105717
106102
|
_resolve({
|
|
105718
106103
|
done: true,
|
|
105719
106104
|
cb
|
|
@@ -106165,7 +106550,7 @@ var require_pipeline = __commonJS({
|
|
|
106165
106550
|
callback();
|
|
106166
106551
|
}
|
|
106167
106552
|
};
|
|
106168
|
-
const wait = () => new Promise2((
|
|
106553
|
+
const wait = () => new Promise2((resolve39, reject2) => {
|
|
106169
106554
|
if (error) {
|
|
106170
106555
|
reject2(error);
|
|
106171
106556
|
} else {
|
|
@@ -106173,7 +106558,7 @@ var require_pipeline = __commonJS({
|
|
|
106173
106558
|
if (error) {
|
|
106174
106559
|
reject2(error);
|
|
106175
106560
|
} else {
|
|
106176
|
-
|
|
106561
|
+
resolve39();
|
|
106177
106562
|
}
|
|
106178
106563
|
};
|
|
106179
106564
|
}
|
|
@@ -106817,8 +107202,8 @@ var require_operators = __commonJS({
|
|
|
106817
107202
|
next = null;
|
|
106818
107203
|
}
|
|
106819
107204
|
if (!done && (queue2.length >= highWaterMark2 || cnt >= concurrency)) {
|
|
106820
|
-
await new Promise2((
|
|
106821
|
-
resume =
|
|
107205
|
+
await new Promise2((resolve39) => {
|
|
107206
|
+
resume = resolve39;
|
|
106822
107207
|
});
|
|
106823
107208
|
}
|
|
106824
107209
|
}
|
|
@@ -106852,8 +107237,8 @@ var require_operators = __commonJS({
|
|
|
106852
107237
|
queue2.shift();
|
|
106853
107238
|
maybeResume();
|
|
106854
107239
|
}
|
|
106855
|
-
await new Promise2((
|
|
106856
|
-
next =
|
|
107240
|
+
await new Promise2((resolve39) => {
|
|
107241
|
+
next = resolve39;
|
|
106857
107242
|
});
|
|
106858
107243
|
}
|
|
106859
107244
|
} finally {
|
|
@@ -107111,7 +107496,7 @@ var require_promises = __commonJS({
|
|
|
107111
107496
|
var { finished } = require_end_of_stream2();
|
|
107112
107497
|
require_stream2();
|
|
107113
107498
|
function pipeline(...streams) {
|
|
107114
|
-
return new Promise2((
|
|
107499
|
+
return new Promise2((resolve39, reject2) => {
|
|
107115
107500
|
let signal;
|
|
107116
107501
|
let end;
|
|
107117
107502
|
const lastArg = streams[streams.length - 1];
|
|
@@ -107126,7 +107511,7 @@ var require_promises = __commonJS({
|
|
|
107126
107511
|
if (err) {
|
|
107127
107512
|
reject2(err);
|
|
107128
107513
|
} else {
|
|
107129
|
-
|
|
107514
|
+
resolve39(value);
|
|
107130
107515
|
}
|
|
107131
107516
|
},
|
|
107132
107517
|
{
|
|
@@ -111899,10 +112284,10 @@ var require_commonjs3 = __commonJS({
|
|
|
111899
112284
|
* Return a void Promise that resolves once the stream ends.
|
|
111900
112285
|
*/
|
|
111901
112286
|
async promise() {
|
|
111902
|
-
return new Promise((
|
|
112287
|
+
return new Promise((resolve39, reject2) => {
|
|
111903
112288
|
this.on(DESTROYED, () => reject2(new Error("stream destroyed")));
|
|
111904
112289
|
this.on("error", (er) => reject2(er));
|
|
111905
|
-
this.on("end", () =>
|
|
112290
|
+
this.on("end", () => resolve39());
|
|
111906
112291
|
});
|
|
111907
112292
|
}
|
|
111908
112293
|
/**
|
|
@@ -111926,7 +112311,7 @@ var require_commonjs3 = __commonJS({
|
|
|
111926
112311
|
return Promise.resolve({ done: false, value: res });
|
|
111927
112312
|
if (this[EOF])
|
|
111928
112313
|
return stop();
|
|
111929
|
-
let
|
|
112314
|
+
let resolve39;
|
|
111930
112315
|
let reject2;
|
|
111931
112316
|
const onerr = (er) => {
|
|
111932
112317
|
this.off("data", ondata);
|
|
@@ -111940,19 +112325,19 @@ var require_commonjs3 = __commonJS({
|
|
|
111940
112325
|
this.off("end", onend);
|
|
111941
112326
|
this.off(DESTROYED, ondestroy);
|
|
111942
112327
|
this.pause();
|
|
111943
|
-
|
|
112328
|
+
resolve39({ value, done: !!this[EOF] });
|
|
111944
112329
|
};
|
|
111945
112330
|
const onend = () => {
|
|
111946
112331
|
this.off("error", onerr);
|
|
111947
112332
|
this.off("data", ondata);
|
|
111948
112333
|
this.off(DESTROYED, ondestroy);
|
|
111949
112334
|
stop();
|
|
111950
|
-
|
|
112335
|
+
resolve39({ done: true, value: void 0 });
|
|
111951
112336
|
};
|
|
111952
112337
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
111953
112338
|
return new Promise((res2, rej) => {
|
|
111954
112339
|
reject2 = rej;
|
|
111955
|
-
|
|
112340
|
+
resolve39 = res2;
|
|
111956
112341
|
this.once(DESTROYED, ondestroy);
|
|
111957
112342
|
this.once("error", onerr);
|
|
111958
112343
|
this.once("end", onend);
|
|
@@ -112968,9 +113353,9 @@ var require_commonjs4 = __commonJS({
|
|
|
112968
113353
|
if (this.#asyncReaddirInFlight) {
|
|
112969
113354
|
await this.#asyncReaddirInFlight;
|
|
112970
113355
|
} else {
|
|
112971
|
-
let
|
|
113356
|
+
let resolve39 = () => {
|
|
112972
113357
|
};
|
|
112973
|
-
this.#asyncReaddirInFlight = new Promise((res) =>
|
|
113358
|
+
this.#asyncReaddirInFlight = new Promise((res) => resolve39 = res);
|
|
112974
113359
|
try {
|
|
112975
113360
|
for (const e of await this.#fs.promises.readdir(fullpath, {
|
|
112976
113361
|
withFileTypes: true
|
|
@@ -112983,7 +113368,7 @@ var require_commonjs4 = __commonJS({
|
|
|
112983
113368
|
children.provisional = 0;
|
|
112984
113369
|
}
|
|
112985
113370
|
this.#asyncReaddirInFlight = void 0;
|
|
112986
|
-
|
|
113371
|
+
resolve39();
|
|
112987
113372
|
}
|
|
112988
113373
|
return children.slice(0, children.provisional);
|
|
112989
113374
|
}
|
|
@@ -115756,11 +116141,11 @@ var require_core = __commonJS({
|
|
|
115756
116141
|
this._finalize();
|
|
115757
116142
|
}
|
|
115758
116143
|
var self2 = this;
|
|
115759
|
-
return new Promise(function(
|
|
116144
|
+
return new Promise(function(resolve39, reject2) {
|
|
115760
116145
|
var errored;
|
|
115761
116146
|
self2._module.on("end", function() {
|
|
115762
116147
|
if (!errored) {
|
|
115763
|
-
|
|
116148
|
+
resolve39();
|
|
115764
116149
|
}
|
|
115765
116150
|
});
|
|
115766
116151
|
self2._module.on("error", function(err) {
|
|
@@ -118200,8 +118585,8 @@ var require_streamx = __commonJS({
|
|
|
118200
118585
|
return this;
|
|
118201
118586
|
},
|
|
118202
118587
|
next() {
|
|
118203
|
-
return new Promise(function(
|
|
118204
|
-
promiseResolve =
|
|
118588
|
+
return new Promise(function(resolve39, reject2) {
|
|
118589
|
+
promiseResolve = resolve39;
|
|
118205
118590
|
promiseReject = reject2;
|
|
118206
118591
|
const data = stream.read();
|
|
118207
118592
|
if (data !== null) ondata(data);
|
|
@@ -118231,11 +118616,11 @@ var require_streamx = __commonJS({
|
|
|
118231
118616
|
}
|
|
118232
118617
|
function destroy(err) {
|
|
118233
118618
|
stream.destroy(err);
|
|
118234
|
-
return new Promise((
|
|
118235
|
-
if (stream._duplexState & DESTROYED) return
|
|
118619
|
+
return new Promise((resolve39, reject2) => {
|
|
118620
|
+
if (stream._duplexState & DESTROYED) return resolve39({ value: void 0, done: true });
|
|
118236
118621
|
stream.once("close", function() {
|
|
118237
118622
|
if (err) reject2(err);
|
|
118238
|
-
else
|
|
118623
|
+
else resolve39({ value: void 0, done: true });
|
|
118239
118624
|
});
|
|
118240
118625
|
});
|
|
118241
118626
|
}
|
|
@@ -118279,8 +118664,8 @@ var require_streamx = __commonJS({
|
|
|
118279
118664
|
const writes = pending + (ws._duplexState & WRITE_WRITING ? 1 : 0);
|
|
118280
118665
|
if (writes === 0) return Promise.resolve(true);
|
|
118281
118666
|
if (state.drains === null) state.drains = [];
|
|
118282
|
-
return new Promise((
|
|
118283
|
-
state.drains.push({ writes, resolve:
|
|
118667
|
+
return new Promise((resolve39) => {
|
|
118668
|
+
state.drains.push({ writes, resolve: resolve39 });
|
|
118284
118669
|
});
|
|
118285
118670
|
}
|
|
118286
118671
|
write(data) {
|
|
@@ -118385,10 +118770,10 @@ var require_streamx = __commonJS({
|
|
|
118385
118770
|
cb(null);
|
|
118386
118771
|
}
|
|
118387
118772
|
function pipelinePromise(...streams) {
|
|
118388
|
-
return new Promise((
|
|
118773
|
+
return new Promise((resolve39, reject2) => {
|
|
118389
118774
|
return pipeline(...streams, (err) => {
|
|
118390
118775
|
if (err) return reject2(err);
|
|
118391
|
-
|
|
118776
|
+
resolve39();
|
|
118392
118777
|
});
|
|
118393
118778
|
});
|
|
118394
118779
|
}
|
|
@@ -119045,16 +119430,16 @@ var require_extract = __commonJS({
|
|
|
119045
119430
|
entryCallback = null;
|
|
119046
119431
|
cb(err);
|
|
119047
119432
|
}
|
|
119048
|
-
function onnext(
|
|
119433
|
+
function onnext(resolve39, reject2) {
|
|
119049
119434
|
if (error) {
|
|
119050
119435
|
return reject2(error);
|
|
119051
119436
|
}
|
|
119052
119437
|
if (entryStream) {
|
|
119053
|
-
|
|
119438
|
+
resolve39({ value: entryStream, done: false });
|
|
119054
119439
|
entryStream = null;
|
|
119055
119440
|
return;
|
|
119056
119441
|
}
|
|
119057
|
-
promiseResolve =
|
|
119442
|
+
promiseResolve = resolve39;
|
|
119058
119443
|
promiseReject = reject2;
|
|
119059
119444
|
consumeCallback(null);
|
|
119060
119445
|
if (extract._finished && promiseResolve) {
|
|
@@ -119082,11 +119467,11 @@ var require_extract = __commonJS({
|
|
|
119082
119467
|
function destroy(err) {
|
|
119083
119468
|
extract.destroy(err);
|
|
119084
119469
|
consumeCallback(err);
|
|
119085
|
-
return new Promise((
|
|
119086
|
-
if (extract.destroyed) return
|
|
119470
|
+
return new Promise((resolve39, reject2) => {
|
|
119471
|
+
if (extract.destroyed) return resolve39({ value: void 0, done: true });
|
|
119087
119472
|
extract.once("close", function() {
|
|
119088
119473
|
if (err) reject2(err);
|
|
119089
|
-
else
|
|
119474
|
+
else resolve39({ value: void 0, done: true });
|
|
119090
119475
|
});
|
|
119091
119476
|
});
|
|
119092
119477
|
}
|
|
@@ -119857,7 +120242,7 @@ var require_archiver = __commonJS({
|
|
|
119857
120242
|
|
|
119858
120243
|
// ../dashboard/src/routes/register-file-workspace-routes.ts
|
|
119859
120244
|
import { access as access5 } from "node:fs/promises";
|
|
119860
|
-
import { createReadStream as
|
|
120245
|
+
import { createReadStream as createReadStream3 } from "node:fs";
|
|
119861
120246
|
function extractFileParams(req) {
|
|
119862
120247
|
const filePath = Array.isArray(req.params.filepath) ? req.params.filepath[0] : req.params.filepath ?? "";
|
|
119863
120248
|
const workspace = typeof req.query.workspace === "string" && req.query.workspace.length > 0 ? req.query.workspace : "project";
|
|
@@ -119908,7 +120293,7 @@ function registerFileWorkspaceRoutes(ctx) {
|
|
|
119908
120293
|
if (typeof content !== "string") {
|
|
119909
120294
|
throw badRequest("content is required and must be a string");
|
|
119910
120295
|
}
|
|
119911
|
-
const result = await
|
|
120296
|
+
const result = await writeFile13(scopedStore, req.params.id, filePath, content);
|
|
119912
120297
|
res.json(result);
|
|
119913
120298
|
} catch (err) {
|
|
119914
120299
|
if (err instanceof ApiError) {
|
|
@@ -120119,7 +120504,7 @@ function registerFileWorkspaceRoutes(ctx) {
|
|
|
120119
120504
|
res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`);
|
|
120120
120505
|
res.setHeader("Content-Length", stats.size);
|
|
120121
120506
|
res.setHeader("Last-Modified", stats.mtime.toUTCString());
|
|
120122
|
-
const stream =
|
|
120507
|
+
const stream = createReadStream3(absolutePath);
|
|
120123
120508
|
stream.pipe(res);
|
|
120124
120509
|
} catch (err) {
|
|
120125
120510
|
if (err instanceof ApiError) {
|
|
@@ -120866,8 +121251,8 @@ var init_exec_file = __esm({
|
|
|
120866
121251
|
|
|
120867
121252
|
// ../dashboard/src/routes/register-project-routes.ts
|
|
120868
121253
|
import * as fsPromises from "node:fs/promises";
|
|
120869
|
-
import { dirname as dirname12, isAbsolute as isAbsolute14, join as
|
|
120870
|
-
var access7, stat8,
|
|
121254
|
+
import { dirname as dirname12, isAbsolute as isAbsolute14, join as join40 } from "node:path";
|
|
121255
|
+
var access7, stat8, mkdir14, readdir9, rm3, registerProjectRoutes;
|
|
120871
121256
|
var init_register_project_routes = __esm({
|
|
120872
121257
|
"../dashboard/src/routes/register-project-routes.ts"() {
|
|
120873
121258
|
"use strict";
|
|
@@ -120878,9 +121263,9 @@ var init_register_project_routes = __esm({
|
|
|
120878
121263
|
({
|
|
120879
121264
|
access: access7,
|
|
120880
121265
|
stat: stat8,
|
|
120881
|
-
mkdir:
|
|
121266
|
+
mkdir: mkdir14,
|
|
120882
121267
|
readdir: readdir9,
|
|
120883
|
-
rm:
|
|
121268
|
+
rm: rm3
|
|
120884
121269
|
} = fsPromises);
|
|
120885
121270
|
registerProjectRoutes = (ctx) => {
|
|
120886
121271
|
const { router, options, runtimeLogger, prioritizeProjectsForCurrentDirectory, rethrowAsApiError: rethrowAsApiError7 } = ctx;
|
|
@@ -121031,7 +121416,7 @@ var init_register_project_routes = __esm({
|
|
|
121031
121416
|
throw badRequest("Clone destination must be empty");
|
|
121032
121417
|
}
|
|
121033
121418
|
} else {
|
|
121034
|
-
await
|
|
121419
|
+
await mkdir14(normalizedPath, { recursive: false });
|
|
121035
121420
|
destinationCreatedForClone = true;
|
|
121036
121421
|
}
|
|
121037
121422
|
const cloneSource = normalizedCloneUrl;
|
|
@@ -121047,7 +121432,7 @@ var init_register_project_routes = __esm({
|
|
|
121047
121432
|
} catch (cloneError) {
|
|
121048
121433
|
if (destinationCreatedForClone) {
|
|
121049
121434
|
try {
|
|
121050
|
-
await
|
|
121435
|
+
await rm3(normalizedPath, { recursive: true, force: true });
|
|
121051
121436
|
} catch {
|
|
121052
121437
|
}
|
|
121053
121438
|
}
|
|
@@ -121057,7 +121442,7 @@ var init_register_project_routes = __esm({
|
|
|
121057
121442
|
}
|
|
121058
121443
|
}
|
|
121059
121444
|
let hasFusionDir = false;
|
|
121060
|
-
const fusionDirPath =
|
|
121445
|
+
const fusionDirPath = join40(normalizedPath, ".fusion");
|
|
121061
121446
|
try {
|
|
121062
121447
|
await access7(fusionDirPath);
|
|
121063
121448
|
hasFusionDir = true;
|
|
@@ -121119,18 +121504,18 @@ var init_register_project_routes = __esm({
|
|
|
121119
121504
|
const entries = await readdir9(searchPath, { withFileTypes: true });
|
|
121120
121505
|
for (const entry of entries) {
|
|
121121
121506
|
if (!entry.isDirectory()) continue;
|
|
121122
|
-
const dirPath =
|
|
121507
|
+
const dirPath = join40(searchPath, entry.name);
|
|
121123
121508
|
let hasKbDb = false;
|
|
121124
121509
|
let hasFusionDir = false;
|
|
121125
121510
|
try {
|
|
121126
|
-
await access7(
|
|
121511
|
+
await access7(join40(dirPath, ".fusion", "fusion.db"));
|
|
121127
121512
|
hasKbDb = true;
|
|
121128
121513
|
} catch {
|
|
121129
121514
|
hasKbDb = false;
|
|
121130
121515
|
}
|
|
121131
121516
|
if (!hasKbDb) {
|
|
121132
121517
|
try {
|
|
121133
|
-
await access7(
|
|
121518
|
+
await access7(join40(dirPath, ".fusion"));
|
|
121134
121519
|
hasFusionDir = true;
|
|
121135
121520
|
} catch {
|
|
121136
121521
|
hasFusionDir = false;
|
|
@@ -124134,7 +124519,7 @@ var init_register_agent_reflection_rating_routes = __esm({
|
|
|
124134
124519
|
});
|
|
124135
124520
|
|
|
124136
124521
|
// ../dashboard/src/agent-generation.ts
|
|
124137
|
-
import { randomUUID as
|
|
124522
|
+
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
124138
124523
|
async function initPromptCatalog() {
|
|
124139
124524
|
if (promptCatalogReady) return;
|
|
124140
124525
|
try {
|
|
@@ -124340,7 +124725,7 @@ async function startAgentGeneration(ip, roleDescription) {
|
|
|
124340
124725
|
`Rate limit exceeded. Maximum ${MAX_SESSIONS_PER_IP_PER_HOUR4} generation sessions per hour. Reset at ${resetTime?.toISOString() || "unknown"}`
|
|
124341
124726
|
);
|
|
124342
124727
|
}
|
|
124343
|
-
const sessionId =
|
|
124728
|
+
const sessionId = randomUUID17();
|
|
124344
124729
|
const session = {
|
|
124345
124730
|
id: sessionId,
|
|
124346
124731
|
ip,
|
|
@@ -124518,7 +124903,7 @@ You MUST respond with ONLY valid JSON (no markdown, no explanation):
|
|
|
124518
124903
|
import { createWriteStream } from "node:fs";
|
|
124519
124904
|
import * as fsPromises2 from "node:fs/promises";
|
|
124520
124905
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
124521
|
-
import { join as
|
|
124906
|
+
import { join as join41, resolve as resolve20 } from "node:path";
|
|
124522
124907
|
import { Readable } from "node:stream";
|
|
124523
124908
|
import { pipeline as streamPipeline } from "node:stream/promises";
|
|
124524
124909
|
function registerAgentImportExportRoutes(ctx) {
|
|
@@ -124555,11 +124940,11 @@ function registerAgentImportExportRoutes(ctx) {
|
|
|
124555
124940
|
}
|
|
124556
124941
|
let resolvedOutputDir;
|
|
124557
124942
|
if (typeof outputDir === "string" && outputDir.trim().length > 0) {
|
|
124558
|
-
resolvedOutputDir =
|
|
124943
|
+
resolvedOutputDir = resolve20(outputDir.trim());
|
|
124559
124944
|
} else if (typeof outputDir === "string") {
|
|
124560
124945
|
throw badRequest("outputDir cannot be empty");
|
|
124561
124946
|
} else {
|
|
124562
|
-
resolvedOutputDir = await mkdtemp(
|
|
124947
|
+
resolvedOutputDir = await mkdtemp(join41(tmpdir3(), "fusion-agent-export-"));
|
|
124563
124948
|
}
|
|
124564
124949
|
const result = await exportAgentsToDirectory2(agentsToExport, resolvedOutputDir, {
|
|
124565
124950
|
companyName: typeof companyName === "string" ? companyName : void 0,
|
|
@@ -124686,7 +125071,7 @@ ${body}`;
|
|
|
124686
125071
|
return result;
|
|
124687
125072
|
}
|
|
124688
125073
|
const safeCompanySlug = companySlug ? slugifyPathSegment2(companySlug, "unknown-company") : "unknown-company";
|
|
124689
|
-
const skillsBaseDir =
|
|
125074
|
+
const skillsBaseDir = join41(projectRoot, "skills", "imported", safeCompanySlug);
|
|
124690
125075
|
const usedSlugs = /* @__PURE__ */ new Set();
|
|
124691
125076
|
for (const skill of skills) {
|
|
124692
125077
|
const name = typeof skill.name === "string" && skill.name.trim().length > 0 ? skill.name.trim() : null;
|
|
@@ -124703,8 +125088,8 @@ ${body}`;
|
|
|
124703
125088
|
skillSlug = `${skillSlug}-${counter}`;
|
|
124704
125089
|
}
|
|
124705
125090
|
usedSlugs.add(skillSlug);
|
|
124706
|
-
const skillDir =
|
|
124707
|
-
const skillPath =
|
|
125091
|
+
const skillDir = join41(skillsBaseDir, skillSlug);
|
|
125092
|
+
const skillPath = join41(skillDir, "SKILL.md");
|
|
124708
125093
|
try {
|
|
124709
125094
|
await access8(skillPath);
|
|
124710
125095
|
result.skipped.push(name);
|
|
@@ -124740,7 +125125,7 @@ ${body}`;
|
|
|
124740
125125
|
|
|
124741
125126
|
<!-- Add skill instructions here. -->`;
|
|
124742
125127
|
try {
|
|
124743
|
-
await
|
|
125128
|
+
await mkdir15(skillDir, { recursive: true });
|
|
124744
125129
|
const content = toSkillMarkdown2(frontmatter, body);
|
|
124745
125130
|
await fsWriteFile2(skillPath, content, "utf-8");
|
|
124746
125131
|
result.imported.push({ name, path: `skills/imported/${safeCompanySlug}/${skillSlug}/SKILL.md` });
|
|
@@ -124790,7 +125175,7 @@ ${body}`;
|
|
|
124790
125175
|
tasks: []
|
|
124791
125176
|
};
|
|
124792
125177
|
} else if (typeof source === "string" && source.trim()) {
|
|
124793
|
-
const sourcePath =
|
|
125178
|
+
const sourcePath = resolve20(source);
|
|
124794
125179
|
const isArchive = sourcePath.endsWith(".tar.gz") || sourcePath.endsWith(".tgz") || sourcePath.endsWith(".zip");
|
|
124795
125180
|
if (isArchive) {
|
|
124796
125181
|
try {
|
|
@@ -124874,8 +125259,8 @@ ${body}`;
|
|
|
124874
125259
|
const archiveUrl = `https://github.com/${repoOwner}/${repoName}/archive/refs/heads/main.tar.gz`;
|
|
124875
125260
|
let tempDir = null;
|
|
124876
125261
|
try {
|
|
124877
|
-
tempDir = await mkdtemp(
|
|
124878
|
-
const archivePath =
|
|
125262
|
+
tempDir = await mkdtemp(join41(tmpdir3(), `fn-agent-import-${importCompanySlug}-`));
|
|
125263
|
+
const archivePath = join41(tempDir, "archive.tar.gz");
|
|
124879
125264
|
const downloadController = new AbortController();
|
|
124880
125265
|
const downloadTimeout = setTimeout(() => downloadController.abort(), 3e4);
|
|
124881
125266
|
let archiveResponse;
|
|
@@ -124919,7 +125304,7 @@ ${body}`;
|
|
|
124919
125304
|
} finally {
|
|
124920
125305
|
if (tempDir) {
|
|
124921
125306
|
try {
|
|
124922
|
-
await
|
|
125307
|
+
await rm4(tempDir, { recursive: true, force: true });
|
|
124923
125308
|
} catch {
|
|
124924
125309
|
}
|
|
124925
125310
|
}
|
|
@@ -125127,14 +125512,14 @@ function registerAgentGenerationRoutes(ctx) {
|
|
|
125127
125512
|
}
|
|
125128
125513
|
});
|
|
125129
125514
|
}
|
|
125130
|
-
var mkdtemp, access8, stat9,
|
|
125515
|
+
var mkdtemp, access8, stat9, mkdir15, rm4, fsWriteFile2;
|
|
125131
125516
|
var init_register_agent_import_export_generation_routes = __esm({
|
|
125132
125517
|
"../dashboard/src/routes/register-agent-import-export-generation-routes.ts"() {
|
|
125133
125518
|
"use strict";
|
|
125134
125519
|
init_api_error();
|
|
125135
125520
|
init_ai_session_diagnostics();
|
|
125136
125521
|
init_agent_generation();
|
|
125137
|
-
({ mkdtemp, access: access8, stat: stat9, mkdir:
|
|
125522
|
+
({ mkdtemp, access: access8, stat: stat9, mkdir: mkdir15, rm: rm4, writeFile: fsWriteFile2 } = fsPromises2);
|
|
125138
125523
|
}
|
|
125139
125524
|
});
|
|
125140
125525
|
|
|
@@ -125591,9 +125976,9 @@ function registerProxyRoutes(router, deps) {
|
|
|
125591
125976
|
if (req.rawBody && req.rawBody.length > 0) {
|
|
125592
125977
|
body = req.rawBody;
|
|
125593
125978
|
} else {
|
|
125594
|
-
await new Promise((
|
|
125979
|
+
await new Promise((resolve39, reject2) => {
|
|
125595
125980
|
req.on("data", (chunk) => chunks.push(chunk));
|
|
125596
|
-
req.on("end",
|
|
125981
|
+
req.on("end", resolve39);
|
|
125597
125982
|
req.on("error", reject2);
|
|
125598
125983
|
});
|
|
125599
125984
|
if (chunks.length > 0) {
|
|
@@ -125789,13 +126174,13 @@ import { readFile as readFile19 } from "node:fs/promises";
|
|
|
125789
126174
|
import * as https from "node:https";
|
|
125790
126175
|
import * as child_process from "node:child_process";
|
|
125791
126176
|
function execFileAsync4(file, args, options) {
|
|
125792
|
-
return new Promise((
|
|
126177
|
+
return new Promise((resolve39, reject2) => {
|
|
125793
126178
|
child_process.execFile(file, args, options, (error, stdout, stderr) => {
|
|
125794
126179
|
if (error) {
|
|
125795
126180
|
reject2(error);
|
|
125796
126181
|
return;
|
|
125797
126182
|
}
|
|
125798
|
-
|
|
126183
|
+
resolve39({ stdout: String(stdout), stderr: String(stderr) });
|
|
125799
126184
|
});
|
|
125800
126185
|
});
|
|
125801
126186
|
}
|
|
@@ -125854,7 +126239,7 @@ function formatDuration(ms) {
|
|
|
125854
126239
|
return remHours > 0 ? `${days}d ${remHours}h` : `${days}d`;
|
|
125855
126240
|
}
|
|
125856
126241
|
function httpsRequest(url, options) {
|
|
125857
|
-
return new Promise((
|
|
126242
|
+
return new Promise((resolve39, reject2) => {
|
|
125858
126243
|
const parsed = new URL(url);
|
|
125859
126244
|
const req = https.request(
|
|
125860
126245
|
{
|
|
@@ -125874,7 +126259,7 @@ function httpsRequest(url, options) {
|
|
|
125874
126259
|
if (typeof v === "string") hdrs[k.toLowerCase()] = v;
|
|
125875
126260
|
else if (Array.isArray(v)) hdrs[k.toLowerCase()] = v.join(", ");
|
|
125876
126261
|
}
|
|
125877
|
-
|
|
126262
|
+
resolve39({
|
|
125878
126263
|
status: res.statusCode || 0,
|
|
125879
126264
|
headers: hdrs,
|
|
125880
126265
|
body: Buffer.concat(chunks).toString("utf-8")
|
|
@@ -126121,7 +126506,7 @@ async function fetchClaudeUsageViaCli() {
|
|
|
126121
126506
|
env: { ...process.env, TERM: "xterm-256color" }
|
|
126122
126507
|
};
|
|
126123
126508
|
if (isWindows) ptyOptions.useConpty = false;
|
|
126124
|
-
const output = await new Promise((
|
|
126509
|
+
const output = await new Promise((resolve39, reject2) => {
|
|
126125
126510
|
let buf = "";
|
|
126126
126511
|
let settled = false;
|
|
126127
126512
|
let sentCommand = false;
|
|
@@ -126137,7 +126522,7 @@ async function fetchClaudeUsageViaCli() {
|
|
|
126137
126522
|
}
|
|
126138
126523
|
const clean = _stripClaudeAnsi(buf);
|
|
126139
126524
|
if (clean.includes("Current session") || clean.includes("% left") || clean.includes("% used")) {
|
|
126140
|
-
|
|
126525
|
+
resolve39(buf);
|
|
126141
126526
|
} else {
|
|
126142
126527
|
reject2(new Error("Claude CLI timed out after 60s \u2014 got output but no usage data. Try running `claude /usage` manually."));
|
|
126143
126528
|
}
|
|
@@ -126188,7 +126573,7 @@ async function fetchClaudeUsageViaCli() {
|
|
|
126188
126573
|
ptyProcess.kill();
|
|
126189
126574
|
} catch {
|
|
126190
126575
|
}
|
|
126191
|
-
|
|
126576
|
+
resolve39(buf);
|
|
126192
126577
|
}
|
|
126193
126578
|
}, 2e3);
|
|
126194
126579
|
}
|
|
@@ -126199,7 +126584,7 @@ async function fetchClaudeUsageViaCli() {
|
|
|
126199
126584
|
if (settled) return;
|
|
126200
126585
|
settled = true;
|
|
126201
126586
|
clearTimeout(timeout2);
|
|
126202
|
-
|
|
126587
|
+
resolve39(buf);
|
|
126203
126588
|
});
|
|
126204
126589
|
});
|
|
126205
126590
|
const cleanOutput = _stripClaudeAnsi(output);
|
|
@@ -126867,9 +127252,9 @@ async function fetchGitHubCopilotUsage() {
|
|
|
126867
127252
|
return usage;
|
|
126868
127253
|
}
|
|
126869
127254
|
function withTimeout(providerPromise, providerName, timeoutMs = PROVIDER_FETCH_TIMEOUT_MS) {
|
|
126870
|
-
return new Promise((
|
|
127255
|
+
return new Promise((resolve39) => {
|
|
126871
127256
|
const timer = setTimeout(() => {
|
|
126872
|
-
|
|
127257
|
+
resolve39({
|
|
126873
127258
|
name: providerName,
|
|
126874
127259
|
icon: "\u23F1\uFE0F",
|
|
126875
127260
|
status: "error",
|
|
@@ -126879,10 +127264,10 @@ function withTimeout(providerPromise, providerName, timeoutMs = PROVIDER_FETCH_T
|
|
|
126879
127264
|
}, timeoutMs);
|
|
126880
127265
|
providerPromise.then((result) => {
|
|
126881
127266
|
clearTimeout(timer);
|
|
126882
|
-
|
|
127267
|
+
resolve39(result);
|
|
126883
127268
|
}).catch((err) => {
|
|
126884
127269
|
clearTimeout(timer);
|
|
126885
|
-
|
|
127270
|
+
resolve39({
|
|
126886
127271
|
name: providerName,
|
|
126887
127272
|
icon: "\u23F1\uFE0F",
|
|
126888
127273
|
status: "error",
|
|
@@ -126937,7 +127322,7 @@ var init_usage = __esm({
|
|
|
126937
127322
|
ANTHROPIC_OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
126938
127323
|
ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
|
|
126939
127324
|
CLAUDE_USAGE_USER_AGENT = "claude-code-fusion-dashboard";
|
|
126940
|
-
_sleep = (ms) => new Promise((
|
|
127325
|
+
_sleep = (ms) => new Promise((resolve39) => setTimeout(resolve39, ms));
|
|
126941
127326
|
sleepFn = _sleep;
|
|
126942
127327
|
PROVIDER_FETCH_TIMEOUT_MS = 1e4;
|
|
126943
127328
|
CLAUDE_FETCH_TIMEOUT_MS = 75e3;
|
|
@@ -127251,8 +127636,8 @@ var init_register_auth_routes = __esm({
|
|
|
127251
127636
|
loginInProgress.set(provider, abortController);
|
|
127252
127637
|
let authResolve;
|
|
127253
127638
|
let authReject;
|
|
127254
|
-
const authUrlPromise = new Promise((
|
|
127255
|
-
authResolve =
|
|
127639
|
+
const authUrlPromise = new Promise((resolve39, reject2) => {
|
|
127640
|
+
authResolve = resolve39;
|
|
127256
127641
|
authReject = reject2;
|
|
127257
127642
|
});
|
|
127258
127643
|
const loginPromise = storage.login(provider, {
|
|
@@ -127678,7 +128063,7 @@ async function mintAgentApiKeyViaCli(opts) {
|
|
|
127678
128063
|
args.push("--data-dir", opts.dataDir);
|
|
127679
128064
|
}
|
|
127680
128065
|
const timeoutMs = opts.cliTimeoutMs ?? 3e4;
|
|
127681
|
-
return new Promise((
|
|
128066
|
+
return new Promise((resolve39, reject2) => {
|
|
127682
128067
|
let child;
|
|
127683
128068
|
try {
|
|
127684
128069
|
child = spawn15(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -127752,7 +128137,7 @@ async function mintAgentApiKeyViaCli(opts) {
|
|
|
127752
128137
|
const apiBase = (typeof r.apiBase === "string" ? r.apiBase : void 0) ?? (typeof r.api_base === "string" ? r.api_base : void 0);
|
|
127753
128138
|
const agentId = (typeof r.agentId === "string" ? r.agentId : void 0) ?? (typeof r.id === "string" ? r.id : void 0);
|
|
127754
128139
|
const companyId = typeof r.companyId === "string" ? r.companyId : void 0;
|
|
127755
|
-
|
|
128140
|
+
resolve39({ apiKey, apiBase, agentId, companyId, raw: parsed });
|
|
127756
128141
|
});
|
|
127757
128142
|
});
|
|
127758
128143
|
}
|
|
@@ -127772,7 +128157,7 @@ async function spawnPaperclipCliJson(args, opts) {
|
|
|
127772
128157
|
}
|
|
127773
128158
|
const timeoutMs = opts.cliTimeoutMs ?? 15e3;
|
|
127774
128159
|
const label = ["paperclipai", ...args].join(" ");
|
|
127775
|
-
return new Promise((
|
|
128160
|
+
return new Promise((resolve39, reject2) => {
|
|
127776
128161
|
let child;
|
|
127777
128162
|
try {
|
|
127778
128163
|
child = spawn15(bin, fullArgs, { stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -127818,7 +128203,7 @@ async function spawnPaperclipCliJson(args, opts) {
|
|
|
127818
128203
|
return;
|
|
127819
128204
|
}
|
|
127820
128205
|
try {
|
|
127821
|
-
|
|
128206
|
+
resolve39(JSON.parse(cleaned));
|
|
127822
128207
|
} catch {
|
|
127823
128208
|
reject2(new Error(`${label} returned non-JSON output: ${cleaned.slice(0, 200)}`));
|
|
127824
128209
|
}
|
|
@@ -127945,9 +128330,9 @@ var init_paperclip_client = __esm({
|
|
|
127945
128330
|
});
|
|
127946
128331
|
|
|
127947
128332
|
// ../../plugins/fusion-plugin-paperclip-runtime/dist/runtime-adapter.js
|
|
127948
|
-
import { randomUUID as
|
|
128333
|
+
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
127949
128334
|
function sleep3(ms) {
|
|
127950
|
-
return new Promise((
|
|
128335
|
+
return new Promise((resolve39) => setTimeout(resolve39, ms));
|
|
127951
128336
|
}
|
|
127952
128337
|
function asString2(value) {
|
|
127953
128338
|
return typeof value === "string" ? value : void 0;
|
|
@@ -128064,7 +128449,7 @@ var init_runtime_adapter3 = __esm({
|
|
|
128064
128449
|
apiKey: effectiveApiKey,
|
|
128065
128450
|
agentId,
|
|
128066
128451
|
companyId,
|
|
128067
|
-
sessionId:
|
|
128452
|
+
sessionId: randomUUID18(),
|
|
128068
128453
|
systemPrompt: options.systemPrompt,
|
|
128069
128454
|
cwd: options.cwd,
|
|
128070
128455
|
mode: normalizeMode(this.config.mode),
|
|
@@ -128590,8 +128975,8 @@ var init_register_runtime_provider_routes = __esm({
|
|
|
128590
128975
|
|
|
128591
128976
|
// ../dashboard/src/update-check.ts
|
|
128592
128977
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
128593
|
-
import { mkdir as
|
|
128594
|
-
import { join as
|
|
128978
|
+
import { mkdir as mkdir16, rm as rm5, writeFile as writeFile14 } from "node:fs/promises";
|
|
128979
|
+
import { join as join43 } from "node:path";
|
|
128595
128980
|
function ttlForFrequency(frequency) {
|
|
128596
128981
|
switch (frequency) {
|
|
128597
128982
|
case "manual":
|
|
@@ -128605,7 +128990,7 @@ function ttlForFrequency(frequency) {
|
|
|
128605
128990
|
}
|
|
128606
128991
|
}
|
|
128607
128992
|
function getCachePath(fusionDir) {
|
|
128608
|
-
return
|
|
128993
|
+
return join43(fusionDir, CACHE_FILENAME);
|
|
128609
128994
|
}
|
|
128610
128995
|
function parseVersion(version) {
|
|
128611
128996
|
return version.split(".").slice(0, 3).map((part) => Number.parseInt(part, 10)).map((value) => Number.isFinite(value) ? value : 0);
|
|
@@ -128637,7 +129022,7 @@ function readCachedUpdateCheck(fusionDir) {
|
|
|
128637
129022
|
}
|
|
128638
129023
|
}
|
|
128639
129024
|
async function clearUpdateCheckCache(fusionDir) {
|
|
128640
|
-
await
|
|
129025
|
+
await rm5(getCachePath(fusionDir), { force: true });
|
|
128641
129026
|
}
|
|
128642
129027
|
async function performUpdateCheck(fusionDir, currentVersion, options = {}) {
|
|
128643
129028
|
const now = Date.now();
|
|
@@ -128669,8 +129054,8 @@ async function performUpdateCheck(fusionDir, currentVersion, options = {}) {
|
|
|
128669
129054
|
updateAvailable,
|
|
128670
129055
|
lastChecked: now
|
|
128671
129056
|
};
|
|
128672
|
-
await
|
|
128673
|
-
await
|
|
129057
|
+
await mkdir16(fusionDir, { recursive: true });
|
|
129058
|
+
await writeFile14(getCachePath(fusionDir), JSON.stringify(result, null, 2), "utf-8");
|
|
128674
129059
|
hasRefreshedThisProcess = true;
|
|
128675
129060
|
return result;
|
|
128676
129061
|
} catch (error) {
|
|
@@ -128696,22 +129081,29 @@ var init_update_check = __esm({
|
|
|
128696
129081
|
});
|
|
128697
129082
|
|
|
128698
129083
|
// ../dashboard/src/routes/register-update-check-routes.ts
|
|
128699
|
-
import { readFileSync as readFileSync9 } from "node:fs";
|
|
128700
|
-
import { dirname as dirname13,
|
|
129084
|
+
import { existsSync as existsSync29, readFileSync as readFileSync9 } from "node:fs";
|
|
129085
|
+
import { dirname as dirname13, resolve as resolve21 } from "node:path";
|
|
128701
129086
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
128702
|
-
var
|
|
129087
|
+
var CLI_PACKAGE_VERSION, registerUpdateCheckRoutes;
|
|
128703
129088
|
var init_register_update_check_routes = __esm({
|
|
128704
129089
|
"../dashboard/src/routes/register-update-check-routes.ts"() {
|
|
128705
129090
|
"use strict";
|
|
128706
129091
|
init_src();
|
|
128707
129092
|
init_update_check();
|
|
128708
|
-
__dirname = dirname13(fileURLToPath3(import.meta.url));
|
|
128709
129093
|
CLI_PACKAGE_VERSION = (() => {
|
|
128710
129094
|
try {
|
|
128711
|
-
|
|
128712
|
-
|
|
128713
|
-
|
|
128714
|
-
|
|
129095
|
+
let cur = dirname13(fileURLToPath3(import.meta.url));
|
|
129096
|
+
for (let i = 0; i < 8; i++) {
|
|
129097
|
+
const pkgPath = resolve21(cur, "package.json");
|
|
129098
|
+
if (existsSync29(pkgPath)) {
|
|
129099
|
+
const parsed = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
129100
|
+
if (parsed.name === "@runfusion/fusion" && typeof parsed.version === "string" && parsed.version.length > 0) {
|
|
129101
|
+
return parsed.version;
|
|
129102
|
+
}
|
|
129103
|
+
}
|
|
129104
|
+
const parent2 = resolve21(cur, "..");
|
|
129105
|
+
if (parent2 === cur) break;
|
|
129106
|
+
cur = parent2;
|
|
128715
129107
|
}
|
|
128716
129108
|
} catch {
|
|
128717
129109
|
}
|
|
@@ -132693,7 +133085,7 @@ var init_todo_routes = __esm({
|
|
|
132693
133085
|
|
|
132694
133086
|
// ../dashboard/src/dev-server-detect.ts
|
|
132695
133087
|
import { glob, readFile as readFile20 } from "node:fs/promises";
|
|
132696
|
-
import { dirname as dirname14, join as join44, relative as relative10, resolve as
|
|
133088
|
+
import { dirname as dirname14, join as join44, relative as relative10, resolve as resolve22 } from "node:path";
|
|
132697
133089
|
async function readPackageJson(filePath) {
|
|
132698
133090
|
try {
|
|
132699
133091
|
const raw = await readFile20(filePath, "utf-8");
|
|
@@ -132743,7 +133135,7 @@ async function collectWorkspacePackageJsons(projectRoot) {
|
|
|
132743
133135
|
try {
|
|
132744
133136
|
for await (const match of glob(pattern, { cwd: projectRoot })) {
|
|
132745
133137
|
if (typeof match === "string") {
|
|
132746
|
-
discovered.add(
|
|
133138
|
+
discovered.add(resolve22(projectRoot, match));
|
|
132747
133139
|
}
|
|
132748
133140
|
}
|
|
132749
133141
|
} catch {
|
|
@@ -132768,7 +133160,7 @@ function toSource(projectRoot, packageJsonPath) {
|
|
|
132768
133160
|
return rel.length > 0 ? rel : "root";
|
|
132769
133161
|
}
|
|
132770
133162
|
async function detectDevServerScripts(projectRoot) {
|
|
132771
|
-
const root =
|
|
133163
|
+
const root = resolve22(projectRoot);
|
|
132772
133164
|
const candidates = [];
|
|
132773
133165
|
const rootPackagePath = join44(root, "package.json");
|
|
132774
133166
|
const rootPackage = await readPackageJson(rootPackagePath);
|
|
@@ -132836,10 +133228,10 @@ var init_dev_server_detect = __esm({
|
|
|
132836
133228
|
});
|
|
132837
133229
|
|
|
132838
133230
|
// ../dashboard/src/dev-server-store.ts
|
|
132839
|
-
import { mkdir as
|
|
132840
|
-
import { dirname as dirname15, join as join45, resolve as
|
|
133231
|
+
import { mkdir as mkdir17, readFile as readFile21, writeFile as writeFile15 } from "node:fs/promises";
|
|
133232
|
+
import { dirname as dirname15, join as join45, resolve as resolve23 } from "node:path";
|
|
132841
133233
|
function devServerFilePath(projectDir) {
|
|
132842
|
-
return join45(
|
|
133234
|
+
return join45(resolve23(projectDir), ".fusion", "dev-server.json");
|
|
132843
133235
|
}
|
|
132844
133236
|
function normalizeState(candidate) {
|
|
132845
133237
|
const defaults = DEV_SERVER_DEFAULT_STATE();
|
|
@@ -132874,7 +133266,7 @@ function normalizeConfig(candidate) {
|
|
|
132874
133266
|
};
|
|
132875
133267
|
}
|
|
132876
133268
|
async function loadDevServerStore(projectDir) {
|
|
132877
|
-
const storeKey =
|
|
133269
|
+
const storeKey = resolve23(projectDir);
|
|
132878
133270
|
let store = storeInstances.get(storeKey);
|
|
132879
133271
|
if (!store) {
|
|
132880
133272
|
store = new DevServerStore(projectDir);
|
|
@@ -132933,7 +133325,7 @@ var init_dev_server_store = __esm({
|
|
|
132933
133325
|
return error.code === "ENOENT";
|
|
132934
133326
|
};
|
|
132935
133327
|
try {
|
|
132936
|
-
await
|
|
133328
|
+
await mkdir17(dir2, { recursive: true });
|
|
132937
133329
|
} catch (error) {
|
|
132938
133330
|
if (isMissingPathError(error)) {
|
|
132939
133331
|
return;
|
|
@@ -132941,13 +133333,13 @@ var init_dev_server_store = __esm({
|
|
|
132941
133333
|
throw error;
|
|
132942
133334
|
}
|
|
132943
133335
|
try {
|
|
132944
|
-
await
|
|
133336
|
+
await writeFile15(this.filePath, serializedPayload, "utf-8");
|
|
132945
133337
|
} catch (error) {
|
|
132946
133338
|
if (!isMissingPathError(error)) {
|
|
132947
133339
|
throw error;
|
|
132948
133340
|
}
|
|
132949
133341
|
try {
|
|
132950
|
-
await
|
|
133342
|
+
await mkdir17(dir2, { recursive: true });
|
|
132951
133343
|
} catch (retryMkdirError) {
|
|
132952
133344
|
if (isMissingPathError(retryMkdirError)) {
|
|
132953
133345
|
return;
|
|
@@ -132955,7 +133347,7 @@ var init_dev_server_store = __esm({
|
|
|
132955
133347
|
throw retryMkdirError;
|
|
132956
133348
|
}
|
|
132957
133349
|
try {
|
|
132958
|
-
await
|
|
133350
|
+
await writeFile15(this.filePath, serializedPayload, "utf-8");
|
|
132959
133351
|
} catch (retryWriteError) {
|
|
132960
133352
|
if (isMissingPathError(retryWriteError)) {
|
|
132961
133353
|
return;
|
|
@@ -133152,7 +133544,7 @@ function detectPortFromLogLine(line) {
|
|
|
133152
133544
|
return detectViteLine(cleanLine) ?? detectNextLine(cleanLine) ?? detectStorybookLine(cleanLine) ?? detectAngularLine(cleanLine) ?? detectGenericUrl(cleanLine) ?? detectGenericPortLine(cleanLine);
|
|
133153
133545
|
}
|
|
133154
133546
|
function probePort(host, port, timeoutMs) {
|
|
133155
|
-
return new Promise((
|
|
133547
|
+
return new Promise((resolve39) => {
|
|
133156
133548
|
let settled = false;
|
|
133157
133549
|
const socket = createConnection({ host, port });
|
|
133158
133550
|
const settle = (isOpen) => {
|
|
@@ -133166,7 +133558,7 @@ function probePort(host, port, timeoutMs) {
|
|
|
133166
133558
|
} else {
|
|
133167
133559
|
socket.destroy();
|
|
133168
133560
|
}
|
|
133169
|
-
|
|
133561
|
+
resolve39(isOpen);
|
|
133170
133562
|
};
|
|
133171
133563
|
socket.setTimeout(timeoutMs);
|
|
133172
133564
|
socket.once("connect", () => settle(true));
|
|
@@ -133293,8 +133685,8 @@ var init_dev_server_process = __esm({
|
|
|
133293
133685
|
stdio: ["pipe", "pipe", "pipe"]
|
|
133294
133686
|
});
|
|
133295
133687
|
this.childProcess = child;
|
|
133296
|
-
this.closePromise = new Promise((
|
|
133297
|
-
this.resolveClosePromise =
|
|
133688
|
+
this.closePromise = new Promise((resolve39) => {
|
|
133689
|
+
this.resolveClosePromise = resolve39;
|
|
133298
133690
|
});
|
|
133299
133691
|
const runningState = await this.store.updateState({
|
|
133300
133692
|
pid: child.pid,
|
|
@@ -134091,7 +134483,7 @@ Your job is to refine task descriptions based on the user's selected refinement
|
|
|
134091
134483
|
|
|
134092
134484
|
// ../dashboard/src/routes.ts
|
|
134093
134485
|
import multer from "multer";
|
|
134094
|
-
import { resolve as
|
|
134486
|
+
import { resolve as resolve24, sep as sep6, join as join46, isAbsolute as isAbsolute15 } from "node:path";
|
|
134095
134487
|
import * as nodeFs from "node:fs";
|
|
134096
134488
|
import os5 from "node:os";
|
|
134097
134489
|
import v8 from "node:v8";
|
|
@@ -134123,7 +134515,7 @@ function getPiPackageManagerAgentDir() {
|
|
|
134123
134515
|
return nodeFs.existsSync(fusionAgentDir) ? fusionAgentDir : legacyAgentDir;
|
|
134124
134516
|
}
|
|
134125
134517
|
function packageExtensionName(extensionPath, source) {
|
|
134126
|
-
const base =
|
|
134518
|
+
const base = resolve24(extensionPath).split(sep6).pop()?.replace(/\.(ts|js)$/i, "") || source;
|
|
134127
134519
|
if (base !== "index") {
|
|
134128
134520
|
return base;
|
|
134129
134521
|
}
|
|
@@ -134131,7 +134523,7 @@ function packageExtensionName(extensionPath, source) {
|
|
|
134131
134523
|
}
|
|
134132
134524
|
async function discoverDashboardPiExtensions(cwd) {
|
|
134133
134525
|
const settings = discoverPiExtensions(cwd);
|
|
134134
|
-
const disabled = new Set(settings.disabledIds.map((id) =>
|
|
134526
|
+
const disabled = new Set(settings.disabledIds.map((id) => resolve24(id)));
|
|
134135
134527
|
const byPath = new Map(settings.extensions.map((entry) => [entry.id, entry]));
|
|
134136
134528
|
try {
|
|
134137
134529
|
const { DefaultPackageManager: DefaultPackageManager5 } = await import("@mariozechner/pi-coding-agent");
|
|
@@ -134153,7 +134545,7 @@ async function discoverDashboardPiExtensions(cwd) {
|
|
|
134153
134545
|
});
|
|
134154
134546
|
const resolved = await packageManager.resolve(async () => "skip");
|
|
134155
134547
|
for (const extension2 of resolved.extensions) {
|
|
134156
|
-
const id =
|
|
134548
|
+
const id = resolve24(extension2.path);
|
|
134157
134549
|
const source = extension2.metadata?.source || "package";
|
|
134158
134550
|
byPath.set(id, {
|
|
134159
134551
|
id,
|
|
@@ -134543,7 +134935,8 @@ function createApiRoutes(store, options) {
|
|
|
134543
134935
|
});
|
|
134544
134936
|
registerChatRoutes(routeContext, {
|
|
134545
134937
|
parseLastEventId: parseLastEventId2,
|
|
134546
|
-
validateOptionalModelField
|
|
134938
|
+
validateOptionalModelField,
|
|
134939
|
+
upload
|
|
134547
134940
|
});
|
|
134548
134941
|
registerMessagingScriptRoutes(routeContext);
|
|
134549
134942
|
registerGitGitHubRoutes(routeContext);
|
|
@@ -134555,8 +134948,8 @@ function createApiRoutes(store, options) {
|
|
|
134555
134948
|
function isHeartbeatMonitorForProject(scopedStore) {
|
|
134556
134949
|
if (!heartbeatMonitor?.rootDir) return true;
|
|
134557
134950
|
try {
|
|
134558
|
-
const monitorRoot =
|
|
134559
|
-
const storeRoot =
|
|
134951
|
+
const monitorRoot = resolve24(heartbeatMonitor.rootDir);
|
|
134952
|
+
const storeRoot = resolve24(scopedStore.getRootDir());
|
|
134560
134953
|
return monitorRoot === storeRoot;
|
|
134561
134954
|
} catch {
|
|
134562
134955
|
return true;
|
|
@@ -136478,15 +136871,15 @@ Description: ${step.description}`
|
|
|
136478
136871
|
return;
|
|
136479
136872
|
}
|
|
136480
136873
|
}
|
|
136481
|
-
const { resolve:
|
|
136874
|
+
const { resolve: resolve39, dirname: dirname28, join: join65 } = await import("node:path");
|
|
136482
136875
|
const { readdir: readdir12, stat: stat12 } = await import("node:fs/promises");
|
|
136483
136876
|
const rawPath = req.query.path || process.env.HOME || process.env.USERPROFILE || "/";
|
|
136484
136877
|
const showHidden = req.query.showHidden === "true";
|
|
136485
|
-
const resolvedPath =
|
|
136878
|
+
const resolvedPath = resolve39(rawPath);
|
|
136486
136879
|
if (rawPath.includes("..")) {
|
|
136487
136880
|
throw badRequest("Path must not contain '..' traversal");
|
|
136488
136881
|
}
|
|
136489
|
-
if (resolvedPath !==
|
|
136882
|
+
if (resolvedPath !== resolve39(resolvedPath)) {
|
|
136490
136883
|
throw badRequest("Path must be absolute");
|
|
136491
136884
|
}
|
|
136492
136885
|
let pathStat;
|
|
@@ -141813,7 +142206,7 @@ var init_badge_pubsub = __esm({
|
|
|
141813
142206
|
});
|
|
141814
142207
|
|
|
141815
142208
|
// ../dashboard/src/terminal-websocket-diagnostics.ts
|
|
141816
|
-
import { basename as
|
|
142209
|
+
import { basename as basename12, normalize as normalize4, sep as sep7 } from "node:path";
|
|
141817
142210
|
function toSessionTag(sessionId) {
|
|
141818
142211
|
const normalized = sessionId.trim();
|
|
141819
142212
|
if (normalized.length <= 8) {
|
|
@@ -141860,8 +142253,8 @@ function createTerminalWebSocketDiagnostics(runtimeLogger) {
|
|
|
141860
142253
|
projectId,
|
|
141861
142254
|
sessionCwdHint: toRedactedPathHint(sessionCwd),
|
|
141862
142255
|
scopedRootHint: toRedactedPathHint(scopedRootDir),
|
|
141863
|
-
sessionCwdBase:
|
|
141864
|
-
scopedRootBase:
|
|
142256
|
+
sessionCwdBase: basename12(sessionCwd),
|
|
142257
|
+
scopedRootBase: basename12(scopedRootDir)
|
|
141865
142258
|
});
|
|
141866
142259
|
},
|
|
141867
142260
|
staleReconnect({ sessionId, idleMs, staleThresholdMs }) {
|
|
@@ -142003,9 +142396,9 @@ var init_auth_middleware = __esm({
|
|
|
142003
142396
|
|
|
142004
142397
|
// ../dashboard/src/server.ts
|
|
142005
142398
|
import express from "express";
|
|
142006
|
-
import { randomUUID as
|
|
142007
|
-
import { join as join47, dirname as dirname16 } from "node:path";
|
|
142008
|
-
import { existsSync as
|
|
142399
|
+
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
142400
|
+
import { join as join47, dirname as dirname16, resolve as resolve25 } from "node:path";
|
|
142401
|
+
import { existsSync as existsSync31, readFileSync as readFileSync11 } from "node:fs";
|
|
142009
142402
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
142010
142403
|
import { createSecureServer as createHttp2SecureServer } from "node:http2";
|
|
142011
142404
|
function parseVersion2(version) {
|
|
@@ -142186,7 +142579,7 @@ function createServer(store, options) {
|
|
|
142186
142579
|
getTerminalService(store.getRootDir());
|
|
142187
142580
|
const isHeadless = options?.headless === true;
|
|
142188
142581
|
const execDir = dirname16(process.execPath);
|
|
142189
|
-
const clientDir = process.env.FUSION_CLIENT_DIR ? process.env.FUSION_CLIENT_DIR :
|
|
142582
|
+
const clientDir = process.env.FUSION_CLIENT_DIR ? process.env.FUSION_CLIENT_DIR : existsSync31(join47(execDir, "client", "index.html")) ? join47(execDir, "client") : existsSync31(join47(__dirname, "..", "dist", "client")) ? join47(__dirname, "..", "dist", "client") : join47(__dirname, "..", "client");
|
|
142190
142583
|
if (!isHeadless) {
|
|
142191
142584
|
app.get("/version.json", (_req, res) => {
|
|
142192
142585
|
res.setHeader("Cache-Control", "no-store, max-age=0");
|
|
@@ -142849,7 +143242,7 @@ function setupBadgeWebSocket(app, server, store, options) {
|
|
|
142849
143242
|
const dashboardApp = app;
|
|
142850
143243
|
const wsManager = new WebSocketManager();
|
|
142851
143244
|
const badgeSnapshots = /* @__PURE__ */ new Map();
|
|
142852
|
-
const serverId =
|
|
143245
|
+
const serverId = randomUUID19();
|
|
142853
143246
|
const badgePubSub = options?.badgePubSub ?? createBadgePubSub({ sourceId: serverId });
|
|
142854
143247
|
void badgePubSub.start();
|
|
142855
143248
|
const scopedStores = /* @__PURE__ */ new Map();
|
|
@@ -142983,7 +143376,7 @@ function setupBadgeWebSocket(app, server, store, options) {
|
|
|
142983
143376
|
const url = new URL(req.url || "", `http://${req.headers.host}`);
|
|
142984
143377
|
const projectId = url.searchParams.get("projectId") ?? "default";
|
|
142985
143378
|
void ensureScopedListeners(projectId);
|
|
142986
|
-
wsManager.addClient(ws,
|
|
143379
|
+
wsManager.addClient(ws, randomUUID19(), projectId);
|
|
142987
143380
|
});
|
|
142988
143381
|
server.once("close", () => {
|
|
142989
143382
|
for (const cleanup of scopedCleanups.values()) {
|
|
@@ -143023,7 +143416,7 @@ function snapshotsEqual(a, b) {
|
|
|
143023
143416
|
if (a.issueInfo?.title !== b.issueInfo?.title) return false;
|
|
143024
143417
|
return true;
|
|
143025
143418
|
}
|
|
143026
|
-
var
|
|
143419
|
+
var __dirname, PACKAGE_VERSION, CLI_PACKAGE_VERSION2, DEFAULT_AI_SESSION_TTL_MS, MIN_AI_SESSION_TTL_MS, MAX_AI_SESSION_TTL_MS, DEFAULT_AI_SESSION_CLEANUP_INTERVAL_MS, MIN_AI_SESSION_CLEANUP_INTERVAL_MS, MAX_AI_SESSION_CLEANUP_INTERVAL_MS, aiSessionCleanupIntervalHandle;
|
|
143027
143420
|
var init_server = __esm({
|
|
143028
143421
|
"../dashboard/src/server.ts"() {
|
|
143029
143422
|
"use strict";
|
|
@@ -143049,10 +143442,10 @@ var init_server = __esm({
|
|
|
143049
143442
|
init_dev_server_routes();
|
|
143050
143443
|
init_auth_middleware();
|
|
143051
143444
|
init_remote_auth();
|
|
143052
|
-
|
|
143445
|
+
__dirname = dirname16(fileURLToPath4(import.meta.url));
|
|
143053
143446
|
PACKAGE_VERSION = (() => {
|
|
143054
143447
|
try {
|
|
143055
|
-
const packageJsonPath = join47(
|
|
143448
|
+
const packageJsonPath = join47(__dirname, "..", "package.json");
|
|
143056
143449
|
const packageJson = JSON.parse(readFileSync11(packageJsonPath, "utf-8"));
|
|
143057
143450
|
if (typeof packageJson.version === "string" && packageJson.version.length > 0) {
|
|
143058
143451
|
return packageJson.version;
|
|
@@ -143063,10 +143456,18 @@ var init_server = __esm({
|
|
|
143063
143456
|
})();
|
|
143064
143457
|
CLI_PACKAGE_VERSION2 = (() => {
|
|
143065
143458
|
try {
|
|
143066
|
-
|
|
143067
|
-
|
|
143068
|
-
|
|
143069
|
-
|
|
143459
|
+
let cur = __dirname;
|
|
143460
|
+
for (let i = 0; i < 8; i++) {
|
|
143461
|
+
const pkgPath = resolve25(cur, "package.json");
|
|
143462
|
+
if (existsSync31(pkgPath)) {
|
|
143463
|
+
const parsed = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
143464
|
+
if (parsed.name === "@runfusion/fusion" && typeof parsed.version === "string" && parsed.version.length > 0) {
|
|
143465
|
+
return parsed.version;
|
|
143466
|
+
}
|
|
143467
|
+
}
|
|
143468
|
+
const parent2 = resolve25(cur, "..");
|
|
143469
|
+
if (parent2 === cur) break;
|
|
143470
|
+
cur = parent2;
|
|
143070
143471
|
}
|
|
143071
143472
|
} catch {
|
|
143072
143473
|
}
|
|
@@ -143085,7 +143486,7 @@ var init_server = __esm({
|
|
|
143085
143486
|
});
|
|
143086
143487
|
|
|
143087
143488
|
// ../dashboard/src/skills-adapter.ts
|
|
143088
|
-
import { access as access9, readFile as readFile22, writeFile as
|
|
143489
|
+
import { access as access9, readFile as readFile22, writeFile as writeFile16, mkdir as mkdir18, readdir as readdir10, stat as stat10 } from "node:fs/promises";
|
|
143089
143490
|
import { join as join48, relative as relative11, dirname as dirname17 } from "node:path";
|
|
143090
143491
|
async function pathExists(path5) {
|
|
143091
143492
|
try {
|
|
@@ -143184,7 +143585,7 @@ function createSkillsAdapter(options) {
|
|
|
143184
143585
|
const settingsPath = options.getSettingsPath(rootDir);
|
|
143185
143586
|
const settingsDir = dirname17(settingsPath);
|
|
143186
143587
|
if (!await pathExists(settingsDir)) {
|
|
143187
|
-
await
|
|
143588
|
+
await mkdir18(settingsDir, { recursive: true });
|
|
143188
143589
|
}
|
|
143189
143590
|
let settings = {};
|
|
143190
143591
|
if (await pathExists(settingsPath)) {
|
|
@@ -143213,7 +143614,7 @@ function createSkillsAdapter(options) {
|
|
|
143213
143614
|
}
|
|
143214
143615
|
skills.push(`${prefix}${skillPath}`);
|
|
143215
143616
|
settings.skills = skills;
|
|
143216
|
-
await
|
|
143617
|
+
await writeFile16(settingsPath, JSON.stringify(settings, null, 2));
|
|
143217
143618
|
return {
|
|
143218
143619
|
settingsPath: "skills",
|
|
143219
143620
|
pattern: `${prefix}${skillPath}`,
|
|
@@ -143250,7 +143651,7 @@ function createSkillsAdapter(options) {
|
|
|
143250
143651
|
}
|
|
143251
143652
|
pkgEntry.skills.push(`${prefix}${skillPath}`);
|
|
143252
143653
|
settings.packages = packages;
|
|
143253
|
-
await
|
|
143654
|
+
await writeFile16(settingsPath, JSON.stringify(settings, null, 2));
|
|
143254
143655
|
return {
|
|
143255
143656
|
settingsPath: "packages[].skills",
|
|
143256
143657
|
pattern: `${prefix}${skillPath}`,
|
|
@@ -143725,7 +144126,7 @@ var init_task_lifecycle = __esm({
|
|
|
143725
144126
|
// src/commands/port-prompt.ts
|
|
143726
144127
|
import { createInterface } from "node:readline";
|
|
143727
144128
|
function promptForPort(defaultPort = 4040, input = process.stdin) {
|
|
143728
|
-
return new Promise((
|
|
144129
|
+
return new Promise((resolve39, reject2) => {
|
|
143729
144130
|
const rl = createInterface({
|
|
143730
144131
|
input,
|
|
143731
144132
|
output: process.stdout
|
|
@@ -143742,7 +144143,7 @@ function promptForPort(defaultPort = 4040, input = process.stdin) {
|
|
|
143742
144143
|
if (trimmed === "") {
|
|
143743
144144
|
process.removeListener("SIGINT", sigintHandler);
|
|
143744
144145
|
rl.close();
|
|
143745
|
-
|
|
144146
|
+
resolve39(defaultPort);
|
|
143746
144147
|
return;
|
|
143747
144148
|
}
|
|
143748
144149
|
const port = parseInt(trimmed, 10);
|
|
@@ -143758,7 +144159,7 @@ function promptForPort(defaultPort = 4040, input = process.stdin) {
|
|
|
143758
144159
|
}
|
|
143759
144160
|
process.removeListener("SIGINT", sigintHandler);
|
|
143760
144161
|
rl.close();
|
|
143761
|
-
|
|
144162
|
+
resolve39(port);
|
|
143762
144163
|
});
|
|
143763
144164
|
};
|
|
143764
144165
|
ask();
|
|
@@ -143771,16 +144172,16 @@ var init_port_prompt = __esm({
|
|
|
143771
144172
|
});
|
|
143772
144173
|
|
|
143773
144174
|
// src/commands/provider-settings.ts
|
|
143774
|
-
import { existsSync as
|
|
143775
|
-
import { join as join49, dirname as dirname18, basename as
|
|
144175
|
+
import { existsSync as existsSync32, readFileSync as readFileSync12, writeFileSync as writeFileSync2, mkdirSync as mkdirSync6 } from "node:fs";
|
|
144176
|
+
import { join as join49, dirname as dirname18, basename as basename13 } from "node:path";
|
|
143776
144177
|
function siblingAgentDir2(agentDir, siblingRoot) {
|
|
143777
|
-
if (
|
|
144178
|
+
if (basename13(agentDir) !== "agent") {
|
|
143778
144179
|
return void 0;
|
|
143779
144180
|
}
|
|
143780
144181
|
return join49(dirname18(dirname18(agentDir)), siblingRoot, "agent");
|
|
143781
144182
|
}
|
|
143782
144183
|
function readJsonObject4(path5) {
|
|
143783
|
-
if (!
|
|
144184
|
+
if (!existsSync32(path5)) {
|
|
143784
144185
|
return {};
|
|
143785
144186
|
}
|
|
143786
144187
|
try {
|
|
@@ -143812,7 +144213,7 @@ var init_provider_settings = __esm({
|
|
|
143812
144213
|
});
|
|
143813
144214
|
|
|
143814
144215
|
// src/commands/provider-auth.ts
|
|
143815
|
-
import { existsSync as
|
|
144216
|
+
import { existsSync as existsSync33, readFileSync as readFileSync13 } from "node:fs";
|
|
143816
144217
|
import { getOAuthProvider as getOAuthProvider2 } from "@mariozechner/pi-ai/oauth";
|
|
143817
144218
|
function getProviderDisplayName(providerId) {
|
|
143818
144219
|
const knownProviderNames = new Map(
|
|
@@ -143941,7 +144342,7 @@ function createReadOnlyAuthFileStorage(authPaths) {
|
|
|
143941
144342
|
const reload = () => {
|
|
143942
144343
|
const nextCredentials = {};
|
|
143943
144344
|
for (const authPath of authPaths) {
|
|
143944
|
-
if (!
|
|
144345
|
+
if (!existsSync33(authPath)) {
|
|
143945
144346
|
continue;
|
|
143946
144347
|
}
|
|
143947
144348
|
try {
|
|
@@ -143982,7 +144383,7 @@ var init_provider_auth = __esm({
|
|
|
143982
144383
|
|
|
143983
144384
|
// src/commands/auth-paths.ts
|
|
143984
144385
|
import { homedir as homedir7 } from "node:os";
|
|
143985
|
-
import { existsSync as
|
|
144386
|
+
import { existsSync as existsSync34, readFileSync as readFileSync14 } from "node:fs";
|
|
143986
144387
|
import { join as join50 } from "node:path";
|
|
143987
144388
|
function getFusionAgentDir3(home = process.env.HOME || process.env.USERPROFILE || homedir7()) {
|
|
143988
144389
|
return join50(home, ".fusion", "agent");
|
|
@@ -144010,13 +144411,13 @@ function getLegacyModelsPaths2(home = process.env.HOME || process.env.USERPROFIL
|
|
|
144010
144411
|
}
|
|
144011
144412
|
function getModelRegistryModelsPath2(home = process.env.HOME || process.env.USERPROFILE || homedir7()) {
|
|
144012
144413
|
const fusionModelsPath = getFusionModelsPath2(home);
|
|
144013
|
-
if (
|
|
144414
|
+
if (existsSync34(fusionModelsPath)) {
|
|
144014
144415
|
return fusionModelsPath;
|
|
144015
144416
|
}
|
|
144016
|
-
return getLegacyModelsPaths2(home).find((modelsPath) =>
|
|
144417
|
+
return getLegacyModelsPaths2(home).find((modelsPath) => existsSync34(modelsPath)) ?? fusionModelsPath;
|
|
144017
144418
|
}
|
|
144018
144419
|
function readJsonObject5(path5) {
|
|
144019
|
-
if (!
|
|
144420
|
+
if (!existsSync34(path5)) {
|
|
144020
144421
|
return {};
|
|
144021
144422
|
}
|
|
144022
144423
|
try {
|
|
@@ -144034,13 +144435,13 @@ function getPackageManagerAgentDir2(home = process.env.HOME || process.env.USERP
|
|
|
144034
144435
|
const legacyAgentDir = getLegacyAgentDir(home);
|
|
144035
144436
|
const fusionSettings = readJsonObject5(join50(fusionAgentDir, "settings.json"));
|
|
144036
144437
|
const legacySettings = readJsonObject5(join50(legacyAgentDir, "settings.json"));
|
|
144037
|
-
if (hasPackageManagerSettings3(fusionSettings) || !
|
|
144438
|
+
if (hasPackageManagerSettings3(fusionSettings) || !existsSync34(legacyAgentDir)) {
|
|
144038
144439
|
return fusionAgentDir;
|
|
144039
144440
|
}
|
|
144040
144441
|
if (hasPackageManagerSettings3(legacySettings)) {
|
|
144041
144442
|
return legacyAgentDir;
|
|
144042
144443
|
}
|
|
144043
|
-
return
|
|
144444
|
+
return existsSync34(fusionAgentDir) ? fusionAgentDir : legacyAgentDir;
|
|
144044
144445
|
}
|
|
144045
144446
|
var init_auth_paths2 = __esm({
|
|
144046
144447
|
"src/commands/auth-paths.ts"() {
|
|
@@ -144049,8 +144450,8 @@ var init_auth_paths2 = __esm({
|
|
|
144049
144450
|
});
|
|
144050
144451
|
|
|
144051
144452
|
// src/project-context.ts
|
|
144052
|
-
import { resolve as
|
|
144053
|
-
import { existsSync as
|
|
144453
|
+
import { resolve as resolve26, dirname as dirname19 } from "node:path";
|
|
144454
|
+
import { existsSync as existsSync35 } from "node:fs";
|
|
144054
144455
|
async function resolveProject(projectNameFlag, cwd = process.cwd(), globalDir) {
|
|
144055
144456
|
const central = new CentralCore(globalDir);
|
|
144056
144457
|
await central.init();
|
|
@@ -144141,10 +144542,10 @@ async function clearDefaultProject(globalDir) {
|
|
|
144141
144542
|
await globalStore.updateSettings(rest);
|
|
144142
144543
|
}
|
|
144143
144544
|
async function detectProjectFromCwd(cwd, central) {
|
|
144144
|
-
let currentDir =
|
|
144545
|
+
let currentDir = resolve26(cwd);
|
|
144145
144546
|
while (true) {
|
|
144146
|
-
const kbPath =
|
|
144147
|
-
if (
|
|
144547
|
+
const kbPath = resolve26(currentDir, ".fusion", "fusion.db");
|
|
144548
|
+
if (existsSync35(kbPath)) {
|
|
144148
144549
|
const project = await central.getProjectByPath(currentDir);
|
|
144149
144550
|
if (project) {
|
|
144150
144551
|
return project;
|
|
@@ -144199,7 +144600,7 @@ var init_project_context = __esm({
|
|
|
144199
144600
|
// src/commands/claude-skills.ts
|
|
144200
144601
|
import {
|
|
144201
144602
|
cpSync,
|
|
144202
|
-
existsSync as
|
|
144603
|
+
existsSync as existsSync36,
|
|
144203
144604
|
lstatSync as lstatSync2,
|
|
144204
144605
|
mkdirSync as mkdirSync7,
|
|
144205
144606
|
readlinkSync,
|
|
@@ -144207,7 +144608,7 @@ import {
|
|
|
144207
144608
|
symlinkSync,
|
|
144208
144609
|
unlinkSync
|
|
144209
144610
|
} from "node:fs";
|
|
144210
|
-
import { dirname as dirname20, join as join51, resolve as
|
|
144611
|
+
import { dirname as dirname20, join as join51, resolve as resolve27 } from "node:path";
|
|
144211
144612
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
144212
144613
|
function isPiClaudeCliConfigured(globalSettings) {
|
|
144213
144614
|
if (!globalSettings || typeof globalSettings !== "object") {
|
|
@@ -144227,8 +144628,8 @@ function isPiClaudeCliConfigured(globalSettings) {
|
|
|
144227
144628
|
}
|
|
144228
144629
|
function resolveFusionSkillSource() {
|
|
144229
144630
|
const here = fileURLToPath5(import.meta.url);
|
|
144230
|
-
const candidate =
|
|
144231
|
-
return
|
|
144631
|
+
const candidate = resolve27(dirname20(here), "..", "..", "skill", FUSION_SKILL_NAME);
|
|
144632
|
+
return existsSync36(candidate) ? candidate : null;
|
|
144232
144633
|
}
|
|
144233
144634
|
function installFusionSkillIntoProject(projectPath, options = {}) {
|
|
144234
144635
|
const target = join51(projectPath, ".claude", "skills", FUSION_SKILL_NAME);
|
|
@@ -144246,18 +144647,18 @@ function installFusionSkillIntoProject(projectPath, options = {}) {
|
|
|
144246
144647
|
try {
|
|
144247
144648
|
mkdirSync7(dirname20(target), { recursive: true });
|
|
144248
144649
|
let replaced = false;
|
|
144249
|
-
if (
|
|
144650
|
+
if (existsSync36(target) || isBrokenSymlink(target)) {
|
|
144250
144651
|
const stat12 = lstatSync2(target);
|
|
144251
144652
|
if (stat12.isSymbolicLink()) {
|
|
144252
144653
|
const current = safeReadlink(target);
|
|
144253
|
-
if (current &&
|
|
144654
|
+
if (current && resolve27(dirname20(target), current) === resolve27(source)) {
|
|
144254
144655
|
return { outcome: "already-installed", target, source };
|
|
144255
144656
|
}
|
|
144256
144657
|
unlinkSync(target);
|
|
144257
144658
|
replaced = true;
|
|
144258
144659
|
} else {
|
|
144259
144660
|
const skillMd = join51(target, "SKILL.md");
|
|
144260
|
-
if (!
|
|
144661
|
+
if (!existsSync36(skillMd)) {
|
|
144261
144662
|
return {
|
|
144262
144663
|
outcome: "failed",
|
|
144263
144664
|
target,
|
|
@@ -144316,7 +144717,7 @@ function isBrokenSymlink(path5) {
|
|
|
144316
144717
|
try {
|
|
144317
144718
|
const stat12 = lstatSync2(path5);
|
|
144318
144719
|
if (!stat12.isSymbolicLink()) return false;
|
|
144319
|
-
return !
|
|
144720
|
+
return !existsSync36(path5);
|
|
144320
144721
|
} catch {
|
|
144321
144722
|
return false;
|
|
144322
144723
|
}
|
|
@@ -144413,16 +144814,16 @@ var init_claude_skills_runner = __esm({
|
|
|
144413
144814
|
});
|
|
144414
144815
|
|
|
144415
144816
|
// src/commands/claude-cli-extension.ts
|
|
144416
|
-
import { existsSync as
|
|
144817
|
+
import { existsSync as existsSync37, readFileSync as readFileSync15 } from "node:fs";
|
|
144417
144818
|
import { createRequire as createRequire4 } from "node:module";
|
|
144418
|
-
import { dirname as dirname21, resolve as
|
|
144819
|
+
import { dirname as dirname21, resolve as resolve28 } from "node:path";
|
|
144419
144820
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
144420
144821
|
function resolveClaudeCliExtensionFromModuleUrl(moduleUrl) {
|
|
144421
144822
|
let pkgJsonPath;
|
|
144422
144823
|
const here = dirname21(fileURLToPath6(moduleUrl));
|
|
144423
144824
|
for (const rel of ["pi-claude-cli", "../pi-claude-cli", "../../pi-claude-cli"]) {
|
|
144424
|
-
const candidate =
|
|
144425
|
-
if (
|
|
144825
|
+
const candidate = resolve28(here, rel, "package.json");
|
|
144826
|
+
if (existsSync37(candidate)) {
|
|
144426
144827
|
pkgJsonPath = candidate;
|
|
144427
144828
|
break;
|
|
144428
144829
|
}
|
|
@@ -144457,8 +144858,8 @@ function resolveClaudeCliExtensionFromModuleUrl(moduleUrl) {
|
|
|
144457
144858
|
reason: "@fusion/pi-claude-cli pi.extensions[0] is not a valid path string"
|
|
144458
144859
|
};
|
|
144459
144860
|
}
|
|
144460
|
-
const entryPath =
|
|
144461
|
-
if (!
|
|
144861
|
+
const entryPath = resolve28(dirname21(pkgJsonPath), rawEntry);
|
|
144862
|
+
if (!existsSync37(entryPath)) {
|
|
144462
144863
|
return {
|
|
144463
144864
|
status: "missing-entry",
|
|
144464
144865
|
reason: `@fusion/pi-claude-cli extension file not found at ${entryPath}`
|
|
@@ -144542,17 +144943,17 @@ var init_update_cache = __esm({
|
|
|
144542
144943
|
});
|
|
144543
144944
|
|
|
144544
144945
|
// src/commands/self-extension.ts
|
|
144545
|
-
import { existsSync as
|
|
144546
|
-
import { dirname as dirname22, resolve as
|
|
144946
|
+
import { existsSync as existsSync38, readFileSync as readFileSync17 } from "node:fs";
|
|
144947
|
+
import { dirname as dirname22, resolve as resolve29 } from "node:path";
|
|
144547
144948
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
144548
144949
|
function resolveSelfExtension() {
|
|
144549
144950
|
const here = dirname22(fileURLToPath7(import.meta.url));
|
|
144550
144951
|
let pkgDir;
|
|
144551
144952
|
let cur = here;
|
|
144552
144953
|
for (let i = 0; i < 5; i++) {
|
|
144553
|
-
if (
|
|
144954
|
+
if (existsSync38(resolve29(cur, "package.json"))) {
|
|
144554
144955
|
try {
|
|
144555
|
-
const parsed = JSON.parse(readFileSync17(
|
|
144956
|
+
const parsed = JSON.parse(readFileSync17(resolve29(cur, "package.json"), "utf-8"));
|
|
144556
144957
|
if (parsed.name === "@runfusion/fusion") {
|
|
144557
144958
|
pkgDir = cur;
|
|
144558
144959
|
break;
|
|
@@ -144560,7 +144961,7 @@ function resolveSelfExtension() {
|
|
|
144560
144961
|
} catch {
|
|
144561
144962
|
}
|
|
144562
144963
|
}
|
|
144563
|
-
const parent2 =
|
|
144964
|
+
const parent2 = resolve29(cur, "..");
|
|
144564
144965
|
if (parent2 === cur) break;
|
|
144565
144966
|
cur = parent2;
|
|
144566
144967
|
}
|
|
@@ -144569,12 +144970,12 @@ function resolveSelfExtension() {
|
|
|
144569
144970
|
}
|
|
144570
144971
|
let pkgJson;
|
|
144571
144972
|
try {
|
|
144572
|
-
pkgJson = JSON.parse(readFileSync17(
|
|
144973
|
+
pkgJson = JSON.parse(readFileSync17(resolve29(pkgDir, "package.json"), "utf-8"));
|
|
144573
144974
|
} catch (err) {
|
|
144574
144975
|
return { status: "missing", reason: `Failed to read @runfusion/fusion package.json: ${err instanceof Error ? err.message : String(err)}` };
|
|
144575
144976
|
}
|
|
144576
|
-
const srcEntry =
|
|
144577
|
-
if (
|
|
144977
|
+
const srcEntry = resolve29(pkgDir, "src", "extension.ts");
|
|
144978
|
+
if (existsSync38(srcEntry)) {
|
|
144578
144979
|
return { status: "ok", path: srcEntry, packageVersion: pkgJson.version ?? "unknown" };
|
|
144579
144980
|
}
|
|
144580
144981
|
const extensions = pkgJson.pi?.extensions;
|
|
@@ -144585,8 +144986,8 @@ function resolveSelfExtension() {
|
|
|
144585
144986
|
if (typeof rawEntry !== "string" || rawEntry.length === 0) {
|
|
144586
144987
|
return { status: "missing", reason: "@runfusion/fusion pi.extensions[0] is not a valid path string" };
|
|
144587
144988
|
}
|
|
144588
|
-
const entryPath =
|
|
144589
|
-
if (!
|
|
144989
|
+
const entryPath = resolve29(pkgDir, rawEntry);
|
|
144990
|
+
if (!existsSync38(entryPath)) {
|
|
144590
144991
|
return { status: "missing", reason: `@runfusion/fusion extension file not found at ${entryPath}` };
|
|
144591
144992
|
}
|
|
144592
144993
|
return { status: "ok", path: entryPath, packageVersion: pkgJson.version ?? "unknown" };
|
|
@@ -144645,21 +145046,21 @@ var init_state = __esm({
|
|
|
144645
145046
|
});
|
|
144646
145047
|
|
|
144647
145048
|
// src/commands/dashboard-tui/logo.ts
|
|
144648
|
-
import { existsSync as
|
|
144649
|
-
import { dirname as dirname23, resolve as
|
|
145049
|
+
import { existsSync as existsSync39, readFileSync as readFileSync18 } from "node:fs";
|
|
145050
|
+
import { dirname as dirname23, resolve as resolve30 } from "node:path";
|
|
144650
145051
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
144651
145052
|
function readFusionVersion() {
|
|
144652
145053
|
try {
|
|
144653
145054
|
let cur = dirname23(fileURLToPath8(import.meta.url));
|
|
144654
145055
|
for (let i = 0; i < 6; i++) {
|
|
144655
|
-
const pkgPath =
|
|
144656
|
-
if (
|
|
145056
|
+
const pkgPath = resolve30(cur, "package.json");
|
|
145057
|
+
if (existsSync39(pkgPath)) {
|
|
144657
145058
|
const parsed = JSON.parse(readFileSync18(pkgPath, "utf-8"));
|
|
144658
145059
|
if (parsed.name === "@runfusion/fusion" && typeof parsed.version === "string") {
|
|
144659
145060
|
return parsed.version;
|
|
144660
145061
|
}
|
|
144661
145062
|
}
|
|
144662
|
-
const parent2 =
|
|
145063
|
+
const parent2 = resolve30(cur, "..");
|
|
144663
145064
|
if (parent2 === cur) break;
|
|
144664
145065
|
cur = parent2;
|
|
144665
145066
|
}
|
|
@@ -144764,14 +145165,14 @@ async function copyToClipboard(text) {
|
|
|
144764
145165
|
{ cmd: "xsel", args: ["--clipboard", "--input"] }
|
|
144765
145166
|
];
|
|
144766
145167
|
for (const { cmd, args } of candidates) {
|
|
144767
|
-
const ok = await new Promise((
|
|
145168
|
+
const ok = await new Promise((resolve39) => {
|
|
144768
145169
|
try {
|
|
144769
145170
|
const child = spawn11(cmd, args, { stdio: ["pipe", "ignore", "ignore"] });
|
|
144770
|
-
child.once("error", () =>
|
|
144771
|
-
child.once("close", (code) =>
|
|
145171
|
+
child.once("error", () => resolve39(false));
|
|
145172
|
+
child.once("close", (code) => resolve39(code === 0));
|
|
144772
145173
|
child.stdin.end(text);
|
|
144773
145174
|
} catch {
|
|
144774
|
-
|
|
145175
|
+
resolve39(false);
|
|
144775
145176
|
}
|
|
144776
145177
|
});
|
|
144777
145178
|
if (ok) return true;
|
|
@@ -144932,9 +145333,9 @@ function SystemPanel({ state, isFocused }) {
|
|
|
144932
145333
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Uptime" }),
|
|
144933
145334
|
/* @__PURE__ */ jsx(Text, { children: formatUptime(Date.now() - info.startTimeMs) })
|
|
144934
145335
|
] }),
|
|
144935
|
-
info.authToken && /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, flexShrink:
|
|
145336
|
+
info.authToken && /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, flexShrink: 0, children: [
|
|
144936
145337
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Token" }),
|
|
144937
|
-
/* @__PURE__ */ jsx(Text, {
|
|
145338
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: info.authToken })
|
|
144938
145339
|
] })
|
|
144939
145340
|
] }) });
|
|
144940
145341
|
}
|
|
@@ -145275,7 +145676,7 @@ function StatusModeGrid({
|
|
|
145275
145676
|
const rows = stdout?.rows ?? 24;
|
|
145276
145677
|
const cols = stdout?.columns ?? 80;
|
|
145277
145678
|
const middleHeight = Math.max(1, rows - 2);
|
|
145278
|
-
const SYSTEM_HEIGHT = 4;
|
|
145679
|
+
const SYSTEM_HEIGHT = state.systemInfo?.authToken ? 5 : 4;
|
|
145279
145680
|
const bottomShare = Math.min(10, Math.max(6, Math.floor(middleHeight * 0.35)));
|
|
145280
145681
|
const logsShare = Math.max(1, middleHeight - SYSTEM_HEIGHT - bottomShare);
|
|
145281
145682
|
const logsAvailableRows = Math.max(1, logsShare - 4);
|
|
@@ -145284,7 +145685,7 @@ function StatusModeGrid({
|
|
|
145284
145685
|
tuiDebug("StatusModeGrid", { cols, rows, middleHeight, logsShare, bottomShare, focused, wideLayout });
|
|
145285
145686
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
|
|
145286
145687
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: [
|
|
145287
|
-
/* @__PURE__ */ jsx(Box, { height:
|
|
145688
|
+
/* @__PURE__ */ jsx(Box, { height: SYSTEM_HEIGHT, flexShrink: 0, overflow: "hidden", children: /* @__PURE__ */ jsx(SystemPanel, { state, isFocused: focused === "system" }) }),
|
|
145288
145689
|
wideLayout ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
145289
145690
|
/* @__PURE__ */ jsxs(Box, { flexGrow: 1, flexShrink: 0, flexDirection: "row", overflow: "hidden", children: [
|
|
145290
145691
|
/* @__PURE__ */ jsx(Box, { flexDirection: "column", width: "30%", flexShrink: 0, overflow: "hidden", children: /* @__PURE__ */ jsx(StatsPanel, { state, isFocused: focused === "stats" }) }),
|
|
@@ -149904,8 +150305,8 @@ async function runDashboard(port, opts = {}) {
|
|
|
149904
150305
|
try {
|
|
149905
150306
|
const updateCheckEnabled = await Promise.race([
|
|
149906
150307
|
isUpdateCheckEnabled(),
|
|
149907
|
-
new Promise((
|
|
149908
|
-
setTimeout(() =>
|
|
150308
|
+
new Promise((resolve39) => {
|
|
150309
|
+
setTimeout(() => resolve39(false), 3e3);
|
|
149909
150310
|
})
|
|
149910
150311
|
]);
|
|
149911
150312
|
if (!updateCheckEnabled) {
|
|
@@ -151300,8 +151701,8 @@ async function runServe(port, opts = {}) {
|
|
|
151300
151701
|
https: loadTlsCredentialsFromEnv()
|
|
151301
151702
|
});
|
|
151302
151703
|
const server = app.listen(selectedPort, selectedHost);
|
|
151303
|
-
await new Promise((
|
|
151304
|
-
server.once("listening",
|
|
151704
|
+
await new Promise((resolve39, reject2) => {
|
|
151705
|
+
server.once("listening", resolve39);
|
|
151305
151706
|
server.once("error", reject2);
|
|
151306
151707
|
});
|
|
151307
151708
|
const actualPort = server.address().port;
|
|
@@ -151819,8 +152220,8 @@ async function runDaemon(opts = {}) {
|
|
|
151819
152220
|
https: loadTlsCredentialsFromEnv()
|
|
151820
152221
|
});
|
|
151821
152222
|
const server = app.listen(selectedPort, selectedHost);
|
|
151822
|
-
await new Promise((
|
|
151823
|
-
server.once("listening",
|
|
152223
|
+
await new Promise((resolve39, reject2) => {
|
|
152224
|
+
server.once("listening", resolve39);
|
|
151824
152225
|
server.once("error", reject2);
|
|
151825
152226
|
});
|
|
151826
152227
|
const actualPort = server.address().port;
|
|
@@ -151934,7 +152335,7 @@ import { once as once2 } from "node:events";
|
|
|
151934
152335
|
import { join as join56 } from "node:path";
|
|
151935
152336
|
import { createRequire as createRequire5 } from "node:module";
|
|
151936
152337
|
function runCommand(command, args, cwd) {
|
|
151937
|
-
return new Promise((
|
|
152338
|
+
return new Promise((resolve39, reject2) => {
|
|
151938
152339
|
const child = spawn13(command, args, {
|
|
151939
152340
|
cwd,
|
|
151940
152341
|
stdio: "inherit",
|
|
@@ -151943,7 +152344,7 @@ function runCommand(command, args, cwd) {
|
|
|
151943
152344
|
child.on("error", (error) => reject2(error));
|
|
151944
152345
|
child.on("exit", (code) => {
|
|
151945
152346
|
if (code === 0) {
|
|
151946
|
-
|
|
152347
|
+
resolve39();
|
|
151947
152348
|
return;
|
|
151948
152349
|
}
|
|
151949
152350
|
reject2(new Error(`${command} ${args.join(" ")} exited with code ${code ?? "unknown"}`));
|
|
@@ -151986,8 +152387,8 @@ async function startDashboardRuntime(rootDir, paused) {
|
|
|
151986
152387
|
};
|
|
151987
152388
|
}
|
|
151988
152389
|
async function closeDashboardRuntime(runtime) {
|
|
151989
|
-
await new Promise((
|
|
151990
|
-
runtime.server.close(() =>
|
|
152390
|
+
await new Promise((resolve39) => {
|
|
152391
|
+
runtime.server.close(() => resolve39());
|
|
151991
152392
|
});
|
|
151992
152393
|
runtime.store.close();
|
|
151993
152394
|
}
|
|
@@ -152095,7 +152496,7 @@ __export(task_exports, {
|
|
|
152095
152496
|
runTaskUpdate: () => runTaskUpdate
|
|
152096
152497
|
});
|
|
152097
152498
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
152098
|
-
import { watchFile, unwatchFile, statSync as statSync6, existsSync as
|
|
152499
|
+
import { watchFile, unwatchFile, statSync as statSync6, existsSync as existsSync40, readFileSync as readFileSync19 } from "node:fs";
|
|
152099
152500
|
import { join as join57 } from "node:path";
|
|
152100
152501
|
function asLocalProjectContext(store) {
|
|
152101
152502
|
const cwd = process.cwd();
|
|
@@ -152216,10 +152617,10 @@ async function runTaskCreate(descriptionArg, attachFiles, depends, projectName,
|
|
|
152216
152617
|
console.log(` Path: .fusion/tasks/${task.id}/`);
|
|
152217
152618
|
if (attachFiles && attachFiles.length > 0) {
|
|
152218
152619
|
const { readFile: readFile24 } = await import("node:fs/promises");
|
|
152219
|
-
const { basename:
|
|
152620
|
+
const { basename: basename17, extname: extname2, resolve: resolve39 } = await import("node:path");
|
|
152220
152621
|
for (const filePath of attachFiles) {
|
|
152221
|
-
const resolvedPath =
|
|
152222
|
-
const filename =
|
|
152622
|
+
const resolvedPath = resolve39(filePath);
|
|
152623
|
+
const filename = basename17(resolvedPath);
|
|
152223
152624
|
const ext = extname2(filename).toLowerCase();
|
|
152224
152625
|
const mimeType = MIME_TYPES[ext];
|
|
152225
152626
|
if (!mimeType) {
|
|
@@ -152353,7 +152754,7 @@ async function runTaskLogs(id, options = {}, projectName) {
|
|
|
152353
152754
|
if (options.follow) {
|
|
152354
152755
|
const projectPath = projectContext?.projectPath ?? process.cwd();
|
|
152355
152756
|
const logPath = join57(projectPath, ".fusion", "tasks", id, "agent.log");
|
|
152356
|
-
if (!
|
|
152757
|
+
if (!existsSync40(logPath)) {
|
|
152357
152758
|
console.log(`
|
|
152358
152759
|
Waiting for log file to be created...`);
|
|
152359
152760
|
}
|
|
@@ -152511,10 +152912,10 @@ async function runTaskMerge(id, projectName) {
|
|
|
152511
152912
|
}
|
|
152512
152913
|
async function runTaskAttach(id, filePath, projectName) {
|
|
152513
152914
|
const { readFile: readFile24 } = await import("node:fs/promises");
|
|
152514
|
-
const { basename:
|
|
152515
|
-
const { resolve:
|
|
152516
|
-
const resolvedPath =
|
|
152517
|
-
const filename =
|
|
152915
|
+
const { basename: basename17, extname: extname2 } = await import("node:path");
|
|
152916
|
+
const { resolve: resolve39 } = await import("node:path");
|
|
152917
|
+
const resolvedPath = resolve39(filePath);
|
|
152918
|
+
const filename = basename17(resolvedPath);
|
|
152518
152919
|
const ext = extname2(filename).toLowerCase();
|
|
152519
152920
|
const mimeType = MIME_TYPES[ext];
|
|
152520
152921
|
if (!mimeType) {
|
|
@@ -153044,12 +153445,12 @@ async function promptText(question) {
|
|
|
153044
153445
|
console.log(" (Enter your response. Type DONE on its own line when finished):\n");
|
|
153045
153446
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
153046
153447
|
const lines = [];
|
|
153047
|
-
return new Promise((
|
|
153448
|
+
return new Promise((resolve39) => {
|
|
153048
153449
|
const askLine = () => {
|
|
153049
153450
|
rl.question(" ").then((line) => {
|
|
153050
153451
|
if (line.trim() === "DONE") {
|
|
153051
153452
|
rl.close();
|
|
153052
|
-
|
|
153453
|
+
resolve39(lines.join("\n"));
|
|
153053
153454
|
} else {
|
|
153054
153455
|
lines.push(line);
|
|
153055
153456
|
askLine();
|
|
@@ -153616,8 +154017,8 @@ var settings_export_exports = {};
|
|
|
153616
154017
|
__export(settings_export_exports, {
|
|
153617
154018
|
runSettingsExport: () => runSettingsExport
|
|
153618
154019
|
});
|
|
153619
|
-
import { writeFile as
|
|
153620
|
-
import { resolve as
|
|
154020
|
+
import { writeFile as writeFile17 } from "node:fs/promises";
|
|
154021
|
+
import { resolve as resolve31, join as join58 } from "node:path";
|
|
153621
154022
|
async function runSettingsExport(options = {}) {
|
|
153622
154023
|
const scope = options.scope ?? "both";
|
|
153623
154024
|
const project = options.projectName ? await resolveProject(options.projectName) : void 0;
|
|
@@ -153628,13 +154029,13 @@ async function runSettingsExport(options = {}) {
|
|
|
153628
154029
|
const exportData = await exportSettings(store, { scope });
|
|
153629
154030
|
let targetPath;
|
|
153630
154031
|
if (outputPath) {
|
|
153631
|
-
targetPath =
|
|
154032
|
+
targetPath = resolve31(outputPath);
|
|
153632
154033
|
} else {
|
|
153633
154034
|
const filename = generateExportFilename();
|
|
153634
154035
|
targetPath = join58(process.cwd(), filename);
|
|
153635
154036
|
}
|
|
153636
154037
|
const jsonContent = JSON.stringify(exportData, null, 2);
|
|
153637
|
-
await
|
|
154038
|
+
await writeFile17(targetPath, jsonContent);
|
|
153638
154039
|
console.log();
|
|
153639
154040
|
console.log(` \u2713 Settings exported to ${targetPath}`);
|
|
153640
154041
|
const parts = [];
|
|
@@ -153677,8 +154078,8 @@ var settings_import_exports = {};
|
|
|
153677
154078
|
__export(settings_import_exports, {
|
|
153678
154079
|
runSettingsImport: () => runSettingsImport
|
|
153679
154080
|
});
|
|
153680
|
-
import { existsSync as
|
|
153681
|
-
import { resolve as
|
|
154081
|
+
import { existsSync as existsSync41 } from "node:fs";
|
|
154082
|
+
import { resolve as resolve32 } from "node:path";
|
|
153682
154083
|
async function runSettingsImport(filePath, options = {}) {
|
|
153683
154084
|
const scope = options.scope ?? "both";
|
|
153684
154085
|
const project = options.projectName ? await resolveProject(options.projectName) : void 0;
|
|
@@ -153687,8 +154088,8 @@ async function runSettingsImport(filePath, options = {}) {
|
|
|
153687
154088
|
const merge = options.merge ?? true;
|
|
153688
154089
|
const skipConfirm = options.yes ?? false;
|
|
153689
154090
|
try {
|
|
153690
|
-
const resolvedPath =
|
|
153691
|
-
if (!
|
|
154091
|
+
const resolvedPath = resolve32(filePath);
|
|
154092
|
+
if (!existsSync41(resolvedPath)) {
|
|
153692
154093
|
console.error(`Error: File not found: ${filePath}`);
|
|
153693
154094
|
process.exit(1);
|
|
153694
154095
|
}
|
|
@@ -154161,8 +154562,8 @@ var init_backup2 = __esm({
|
|
|
154161
154562
|
});
|
|
154162
154563
|
|
|
154163
154564
|
// src/project-resolver.ts
|
|
154164
|
-
import { existsSync as
|
|
154165
|
-
import { dirname as dirname24, resolve as
|
|
154565
|
+
import { existsSync as existsSync42, statSync as statSync7 } from "node:fs";
|
|
154566
|
+
import { dirname as dirname24, resolve as resolve33, normalize as normalize5 } from "node:path";
|
|
154166
154567
|
import { createInterface as createInterface5 } from "node:readline/promises";
|
|
154167
154568
|
async function getCentralCore() {
|
|
154168
154569
|
if (!centralCoreInstance) {
|
|
@@ -154179,10 +154580,10 @@ async function getProjectManager() {
|
|
|
154179
154580
|
return projectManagerInstance;
|
|
154180
154581
|
}
|
|
154181
154582
|
function findKbDir(startPath) {
|
|
154182
|
-
let current =
|
|
154583
|
+
let current = resolve33(startPath);
|
|
154183
154584
|
for (let i = 0; i < 100; i++) {
|
|
154184
|
-
const kbPath =
|
|
154185
|
-
if (
|
|
154585
|
+
const kbPath = resolve33(current, ".fusion");
|
|
154586
|
+
if (existsSync42(kbPath) && statSync7(kbPath).isDirectory()) {
|
|
154186
154587
|
return current;
|
|
154187
154588
|
}
|
|
154188
154589
|
const parent2 = dirname24(current);
|
|
@@ -154237,7 +154638,7 @@ async function resolveProject2(options = {}) {
|
|
|
154237
154638
|
{ searchedName: options.project, availableProjects: projects.map((p) => p.name) }
|
|
154238
154639
|
);
|
|
154239
154640
|
}
|
|
154240
|
-
if (!
|
|
154641
|
+
if (!existsSync42(match.path)) {
|
|
154241
154642
|
throw new ProjectResolutionError(
|
|
154242
154643
|
`Project "${match.name}" is registered but the directory no longer exists: ${match.path}
|
|
154243
154644
|
|
|
@@ -154248,14 +154649,14 @@ Run \`fn project remove ` + match.name + "` to clean up the registry entry.",
|
|
|
154248
154649
|
}
|
|
154249
154650
|
return createResolvedProject(match);
|
|
154250
154651
|
}
|
|
154251
|
-
const cwd = options.cwd ?
|
|
154652
|
+
const cwd = options.cwd ? resolve33(options.cwd) : process.cwd();
|
|
154252
154653
|
const fusionDir = findKbDir(cwd);
|
|
154253
154654
|
if (fusionDir) {
|
|
154254
154655
|
const allProjects2 = await central.listProjects();
|
|
154255
154656
|
const normalizedKbDir = normalize5(fusionDir);
|
|
154256
154657
|
const match = allProjects2.find((p) => normalize5(p.path) === normalizedKbDir);
|
|
154257
154658
|
if (match) {
|
|
154258
|
-
if (!
|
|
154659
|
+
if (!existsSync42(match.path)) {
|
|
154259
154660
|
throw new ProjectResolutionError(
|
|
154260
154661
|
`Project "${match.name}" is registered but the directory no longer exists: ${match.path}
|
|
154261
154662
|
|
|
@@ -154320,7 +154721,7 @@ Run \`fn project add ` + fusionDir + "` to register it, or use --project <name>.
|
|
|
154320
154721
|
}
|
|
154321
154722
|
if (allProjects.length === 1) {
|
|
154322
154723
|
const project = allProjects[0];
|
|
154323
|
-
if (!
|
|
154724
|
+
if (!existsSync42(project.path)) {
|
|
154324
154725
|
throw new ProjectResolutionError(
|
|
154325
154726
|
`The only registered project "${project.name}" has a missing directory: ${project.path}
|
|
154326
154727
|
|
|
@@ -154760,15 +155161,15 @@ __export(project_exports, {
|
|
|
154760
155161
|
runProjectSetDefault: () => runProjectSetDefault,
|
|
154761
155162
|
runProjectShow: () => runProjectShow
|
|
154762
155163
|
});
|
|
154763
|
-
import { resolve as
|
|
154764
|
-
import { existsSync as
|
|
155164
|
+
import { resolve as resolve34, isAbsolute as isAbsolute16, relative as relative12, basename as basename14 } from "node:path";
|
|
155165
|
+
import { existsSync as existsSync43, statSync as statSync8 } from "node:fs";
|
|
154765
155166
|
import { createInterface as createInterface7 } from "node:readline/promises";
|
|
154766
155167
|
function formatDisplayPath(projectPath) {
|
|
154767
155168
|
const rel = relative12(process.cwd(), projectPath);
|
|
154768
155169
|
if (rel && !rel.startsWith("..") && rel !== "") {
|
|
154769
155170
|
return rel;
|
|
154770
155171
|
}
|
|
154771
|
-
return
|
|
155172
|
+
return basename14(projectPath) || ".";
|
|
154772
155173
|
}
|
|
154773
155174
|
function formatLastActivity2(timestamp) {
|
|
154774
155175
|
if (!timestamp) return "never";
|
|
@@ -154889,8 +155290,8 @@ async function runProjectAdd(name, path5, options = {}) {
|
|
|
154889
155290
|
const pathInput = await rl.question(` Project path [${defaultPath}]: `);
|
|
154890
155291
|
projectPath = pathInput.trim() || defaultPath;
|
|
154891
155292
|
}
|
|
154892
|
-
const absolutePath2 = isAbsolute16(projectPath) ? projectPath :
|
|
154893
|
-
if (!
|
|
155293
|
+
const absolutePath2 = isAbsolute16(projectPath) ? projectPath : resolve34(process.cwd(), projectPath);
|
|
155294
|
+
if (!existsSync43(absolutePath2)) {
|
|
154894
155295
|
console.error(`
|
|
154895
155296
|
\u2717 Path does not exist: ${projectPath}`);
|
|
154896
155297
|
rl.close();
|
|
@@ -154902,8 +155303,8 @@ async function runProjectAdd(name, path5, options = {}) {
|
|
|
154902
155303
|
rl.close();
|
|
154903
155304
|
process.exit(1);
|
|
154904
155305
|
}
|
|
154905
|
-
const kbDbPath2 =
|
|
154906
|
-
if (!
|
|
155306
|
+
const kbDbPath2 = resolve34(absolutePath2, ".fusion", "fusion.db");
|
|
155307
|
+
if (!existsSync43(kbDbPath2) && !options.force) {
|
|
154907
155308
|
console.log(`
|
|
154908
155309
|
No fn project found at ${formatDisplayPath(absolutePath2)}`);
|
|
154909
155310
|
const init = await rl.question(" Initialize fn here first? [Y/n] ");
|
|
@@ -154918,7 +155319,7 @@ async function runProjectAdd(name, path5, options = {}) {
|
|
|
154918
155319
|
}
|
|
154919
155320
|
}
|
|
154920
155321
|
if (!projectName) {
|
|
154921
|
-
const suggested =
|
|
155322
|
+
const suggested = basename14(absolutePath2);
|
|
154922
155323
|
projectName = await rl.question(` Project name [${suggested}]: `);
|
|
154923
155324
|
projectName = projectName.trim() || suggested;
|
|
154924
155325
|
}
|
|
@@ -154934,8 +155335,8 @@ async function runProjectAdd(name, path5, options = {}) {
|
|
|
154934
155335
|
console.error(" Name must be 1-64 characters and contain only: a-z, A-Z, 0-9, _, -\n");
|
|
154935
155336
|
process.exit(1);
|
|
154936
155337
|
}
|
|
154937
|
-
const absolutePath = isAbsolute16(projectPath) ? projectPath :
|
|
154938
|
-
if (!
|
|
155338
|
+
const absolutePath = isAbsolute16(projectPath) ? projectPath : resolve34(process.cwd(), projectPath);
|
|
155339
|
+
if (!existsSync43(absolutePath)) {
|
|
154939
155340
|
console.error(`
|
|
154940
155341
|
\u2717 Path does not exist: ${projectPath}
|
|
154941
155342
|
`);
|
|
@@ -154947,8 +155348,8 @@ async function runProjectAdd(name, path5, options = {}) {
|
|
|
154947
155348
|
`);
|
|
154948
155349
|
process.exit(1);
|
|
154949
155350
|
}
|
|
154950
|
-
const kbDbPath =
|
|
154951
|
-
if (!
|
|
155351
|
+
const kbDbPath = resolve34(absolutePath, ".fusion", "fusion.db");
|
|
155352
|
+
if (!existsSync43(kbDbPath) && !options.force) {
|
|
154952
155353
|
console.error(`
|
|
154953
155354
|
\u2717 No fn project found at ${formatDisplayPath(absolutePath)}`);
|
|
154954
155355
|
console.error(" Run `fn init` first to initialize the project.\n");
|
|
@@ -155204,9 +155605,9 @@ var init_project = __esm({
|
|
|
155204
155605
|
});
|
|
155205
155606
|
|
|
155206
155607
|
// src/commands/skill-installation.ts
|
|
155207
|
-
import { cpSync as cpSync2, existsSync as
|
|
155608
|
+
import { cpSync as cpSync2, existsSync as existsSync44, mkdirSync as mkdirSync8 } from "node:fs";
|
|
155208
155609
|
import { homedir as homedir8 } from "node:os";
|
|
155209
|
-
import { dirname as dirname25, join as join59, resolve as
|
|
155610
|
+
import { dirname as dirname25, join as join59, resolve as resolve35 } from "node:path";
|
|
155210
155611
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
155211
155612
|
function getSupportedSkillInstallTargets(homeDir = process.env.HOME || process.env.USERPROFILE || homedir8()) {
|
|
155212
155613
|
return [
|
|
@@ -155217,8 +155618,8 @@ function getSupportedSkillInstallTargets(homeDir = process.env.HOME || process.e
|
|
|
155217
155618
|
}
|
|
155218
155619
|
function resolveBundledFusionSkillSource() {
|
|
155219
155620
|
const here = fileURLToPath9(import.meta.url);
|
|
155220
|
-
const source =
|
|
155221
|
-
return
|
|
155621
|
+
const source = resolve35(dirname25(here), "..", "..", "skill", FUSION_SKILL_NAME2);
|
|
155622
|
+
return existsSync44(source) ? source : null;
|
|
155222
155623
|
}
|
|
155223
155624
|
function installBundledFusionSkill(options = {}) {
|
|
155224
155625
|
const sourceDir = options.sourceDir ?? resolveBundledFusionSkillSource();
|
|
@@ -155236,7 +155637,7 @@ function installBundledFusionSkill(options = {}) {
|
|
|
155236
155637
|
}
|
|
155237
155638
|
const results = targets.map((target) => {
|
|
155238
155639
|
try {
|
|
155239
|
-
if (
|
|
155640
|
+
if (existsSync44(target.targetDir)) {
|
|
155240
155641
|
return {
|
|
155241
155642
|
client: target.client,
|
|
155242
155643
|
targetDir: target.targetDir,
|
|
@@ -155275,15 +155676,15 @@ var init_exports = {};
|
|
|
155275
155676
|
__export(init_exports, {
|
|
155276
155677
|
runInit: () => runInit
|
|
155277
155678
|
});
|
|
155278
|
-
import { existsSync as
|
|
155279
|
-
import { join as join60, resolve as
|
|
155679
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync9, writeFileSync as writeFileSync3, readFileSync as readFileSync20 } from "node:fs";
|
|
155680
|
+
import { join as join60, resolve as resolve36, basename as basename15 } from "node:path";
|
|
155280
155681
|
import { exec as exec11 } from "node:child_process";
|
|
155281
155682
|
import { promisify as promisify16 } from "node:util";
|
|
155282
155683
|
async function runInit(options = {}) {
|
|
155283
|
-
const cwd = options.path ?
|
|
155684
|
+
const cwd = options.path ? resolve36(options.path) : process.cwd();
|
|
155284
155685
|
const fusionDir = join60(cwd, ".fusion");
|
|
155285
155686
|
const dbPath = join60(fusionDir, "fusion.db");
|
|
155286
|
-
if (
|
|
155687
|
+
if (existsSync45(fusionDir) && existsSync45(dbPath)) {
|
|
155287
155688
|
const central2 = new CentralCore();
|
|
155288
155689
|
await central2.init();
|
|
155289
155690
|
const existing = await central2.getProjectByPath(cwd);
|
|
@@ -155308,7 +155709,7 @@ async function runInit(options = {}) {
|
|
|
155308
155709
|
const projectName = options.name ?? await detectProjectName(cwd);
|
|
155309
155710
|
console.log(`Initializing fn project: "${projectName}"`);
|
|
155310
155711
|
console.log(` Path: ${cwd}`);
|
|
155311
|
-
if (!
|
|
155712
|
+
if (!existsSync45(fusionDir)) {
|
|
155312
155713
|
mkdirSync9(fusionDir, { recursive: true });
|
|
155313
155714
|
console.log(` \u2713 Created .fusion/ directory`);
|
|
155314
155715
|
}
|
|
@@ -155321,7 +155722,7 @@ async function runInit(options = {}) {
|
|
|
155321
155722
|
}
|
|
155322
155723
|
await addLocalStorageToGitignore(cwd);
|
|
155323
155724
|
await warnIfQmdMissing();
|
|
155324
|
-
if (!
|
|
155725
|
+
if (!existsSync45(dbPath)) {
|
|
155325
155726
|
const sqliteHeader = Buffer.from([
|
|
155326
155727
|
83,
|
|
155327
155728
|
81,
|
|
@@ -155389,8 +155790,8 @@ async function runInit(options = {}) {
|
|
|
155389
155790
|
}
|
|
155390
155791
|
}
|
|
155391
155792
|
async function detectProjectName(dir2) {
|
|
155392
|
-
if (!
|
|
155393
|
-
return
|
|
155793
|
+
if (!existsSync45(join60(dir2, ".git"))) {
|
|
155794
|
+
return basename15(dir2) || "my-project";
|
|
155394
155795
|
}
|
|
155395
155796
|
try {
|
|
155396
155797
|
const { stdout: remoteUrl } = await execAsync11("git remote get-url origin", {
|
|
@@ -155406,12 +155807,12 @@ async function detectProjectName(dir2) {
|
|
|
155406
155807
|
}
|
|
155407
155808
|
} catch {
|
|
155408
155809
|
}
|
|
155409
|
-
return
|
|
155810
|
+
return basename15(dir2) || "my-project";
|
|
155410
155811
|
}
|
|
155411
155812
|
async function addLocalStorageToGitignore(cwd) {
|
|
155412
155813
|
const gitignorePath = join60(cwd, ".gitignore");
|
|
155413
155814
|
let content = "";
|
|
155414
|
-
if (
|
|
155815
|
+
if (existsSync45(gitignorePath)) {
|
|
155415
155816
|
try {
|
|
155416
155817
|
content = readFileSync20(gitignorePath, "utf-8");
|
|
155417
155818
|
} catch {
|
|
@@ -155453,7 +155854,7 @@ async function initializeGitRepo(cwd) {
|
|
|
155453
155854
|
await ensureGitConfig(cwd, "user.name", "Fusion");
|
|
155454
155855
|
await ensureGitConfig(cwd, "user.email", "noreply@runfusion.ai");
|
|
155455
155856
|
const gitkeepPath = join60(cwd, ".gitkeep");
|
|
155456
|
-
if (!
|
|
155857
|
+
if (!existsSync45(gitkeepPath)) {
|
|
155457
155858
|
writeFileSync3(gitkeepPath, "\n");
|
|
155458
155859
|
}
|
|
155459
155860
|
await execAsync11("git add .gitkeep", { cwd, timeout: 1e4 });
|
|
@@ -155591,8 +155992,8 @@ var agent_import_exports = {};
|
|
|
155591
155992
|
__export(agent_import_exports, {
|
|
155592
155993
|
runAgentImport: () => runAgentImport
|
|
155593
155994
|
});
|
|
155594
|
-
import { existsSync as
|
|
155595
|
-
import { resolve as
|
|
155995
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync10, readFileSync as readFileSync21, statSync as statSync9, writeFileSync as writeFileSync4 } from "node:fs";
|
|
155996
|
+
import { resolve as resolve37 } from "node:path";
|
|
155596
155997
|
function slugifyPathSegment(input) {
|
|
155597
155998
|
if (!input || typeof input !== "string") {
|
|
155598
155999
|
return "unnamed";
|
|
@@ -155641,16 +156042,16 @@ async function importSkillsToProject(projectPath, skills, companySlug, dryRun) {
|
|
|
155641
156042
|
errors: []
|
|
155642
156043
|
};
|
|
155643
156044
|
const companyDir = slugifyPathSegment(companySlug ?? "unknown-company");
|
|
155644
|
-
const baseSkillsDir =
|
|
156045
|
+
const baseSkillsDir = resolve37(projectPath, "skills", "imported", companyDir);
|
|
155645
156046
|
for (const skill of skills) {
|
|
155646
156047
|
if (!skill.name || typeof skill.name !== "string" || skill.name.trim().length === 0) {
|
|
155647
156048
|
result.errors.push({ name: "(unnamed)", error: "Skill is missing required 'name' field" });
|
|
155648
156049
|
continue;
|
|
155649
156050
|
}
|
|
155650
156051
|
const skillSlug = slugifyPathSegment(skill.name);
|
|
155651
|
-
const skillDir =
|
|
155652
|
-
const skillPath =
|
|
155653
|
-
if (
|
|
156052
|
+
const skillDir = resolve37(baseSkillsDir, skillSlug);
|
|
156053
|
+
const skillPath = resolve37(skillDir, "SKILL.md");
|
|
156054
|
+
if (existsSync46(skillPath)) {
|
|
155654
156055
|
result.skipped.push(skill.name);
|
|
155655
156056
|
continue;
|
|
155656
156057
|
}
|
|
@@ -155722,8 +156123,8 @@ function isArchivePath(path5) {
|
|
|
155722
156123
|
async function runAgentImport(source, options) {
|
|
155723
156124
|
const dryRun = options?.dryRun ?? false;
|
|
155724
156125
|
const skipExisting = options?.skipExisting ?? false;
|
|
155725
|
-
const sourcePath =
|
|
155726
|
-
if (!
|
|
156126
|
+
const sourcePath = resolve37(source);
|
|
156127
|
+
if (!existsSync46(sourcePath)) {
|
|
155727
156128
|
console.error(`Path not found: ${sourcePath}`);
|
|
155728
156129
|
process.exit(1);
|
|
155729
156130
|
}
|
|
@@ -155861,7 +156262,7 @@ var agent_export_exports = {};
|
|
|
155861
156262
|
__export(agent_export_exports, {
|
|
155862
156263
|
runAgentExport: () => runAgentExport
|
|
155863
156264
|
});
|
|
155864
|
-
import { resolve as
|
|
156265
|
+
import { resolve as resolve38 } from "node:path";
|
|
155865
156266
|
async function getProjectPath4(projectName) {
|
|
155866
156267
|
if (projectName) {
|
|
155867
156268
|
const context = await resolveProject(projectName);
|
|
@@ -155899,7 +156300,7 @@ async function runAgentExport(outputDir, options) {
|
|
|
155899
156300
|
console.error("No agents found to export");
|
|
155900
156301
|
process.exit(1);
|
|
155901
156302
|
}
|
|
155902
|
-
const result = await exportAgentsToDirectory(agents,
|
|
156303
|
+
const result = await exportAgentsToDirectory(agents, resolve38(outputDir), {
|
|
155903
156304
|
companyName: options?.companyName,
|
|
155904
156305
|
companySlug: options?.companySlug
|
|
155905
156306
|
});
|
|
@@ -156118,7 +156519,7 @@ __export(plugin_exports, {
|
|
|
156118
156519
|
runPluginList: () => runPluginList,
|
|
156119
156520
|
runPluginUninstall: () => runPluginUninstall
|
|
156120
156521
|
});
|
|
156121
|
-
import { existsSync as
|
|
156522
|
+
import { existsSync as existsSync47 } from "node:fs";
|
|
156122
156523
|
import { join as join61 } from "node:path";
|
|
156123
156524
|
import { readFile as readFile23 } from "node:fs/promises";
|
|
156124
156525
|
import * as readline from "node:readline";
|
|
@@ -156158,7 +156559,7 @@ async function createPluginLoader(pluginStore, projectName) {
|
|
|
156158
156559
|
}
|
|
156159
156560
|
async function loadManifestFromPath(pluginPath) {
|
|
156160
156561
|
const manifestPath = join61(pluginPath, "manifest.json");
|
|
156161
|
-
if (!
|
|
156562
|
+
if (!existsSync47(manifestPath)) {
|
|
156162
156563
|
throw new Error(`Plugin manifest not found at: ${manifestPath}`);
|
|
156163
156564
|
}
|
|
156164
156565
|
const content = await readFile23(manifestPath, "utf-8");
|
|
@@ -156216,7 +156617,7 @@ async function runPluginInstall(source, options) {
|
|
|
156216
156617
|
console.error("Please provide a local path to the plugin directory.");
|
|
156217
156618
|
process.exit(1);
|
|
156218
156619
|
}
|
|
156219
|
-
if (!
|
|
156620
|
+
if (!existsSync47(source)) {
|
|
156220
156621
|
console.error(`Plugin path does not exist: ${source}`);
|
|
156221
156622
|
process.exit(1);
|
|
156222
156623
|
}
|
|
@@ -156261,14 +156662,14 @@ async function runPluginUninstall(id, options) {
|
|
|
156261
156662
|
console.log(` Uninstall "${plugin4.name}"?`);
|
|
156262
156663
|
console.log(` This will stop and remove the plugin.`);
|
|
156263
156664
|
console.log();
|
|
156264
|
-
const response = await new Promise((
|
|
156665
|
+
const response = await new Promise((resolve39) => {
|
|
156265
156666
|
const rl = readline.createInterface({
|
|
156266
156667
|
input: process.stdin,
|
|
156267
156668
|
output: process.stdout
|
|
156268
156669
|
});
|
|
156269
156670
|
rl.question(" Continue? [y/N] ", (answer) => {
|
|
156270
156671
|
rl.close();
|
|
156271
|
-
|
|
156672
|
+
resolve39(answer.toLowerCase());
|
|
156272
156673
|
});
|
|
156273
156674
|
});
|
|
156274
156675
|
if (response !== "y" && response !== "yes") {
|
|
@@ -156348,7 +156749,7 @@ var plugin_scaffold_exports = {};
|
|
|
156348
156749
|
__export(plugin_scaffold_exports, {
|
|
156349
156750
|
runPluginCreate: () => runPluginCreate
|
|
156350
156751
|
});
|
|
156351
|
-
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync5, existsSync as
|
|
156752
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync5, existsSync as existsSync48 } from "node:fs";
|
|
156352
156753
|
import { join as join62 } from "node:path";
|
|
156353
156754
|
function toTitleCase(str) {
|
|
156354
156755
|
return str.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
@@ -156483,7 +156884,7 @@ async function runPluginCreate(name, options) {
|
|
|
156483
156884
|
}
|
|
156484
156885
|
const targetDir = options?.output ?? name;
|
|
156485
156886
|
const targetPath = join62(process.cwd(), targetDir);
|
|
156486
|
-
if (
|
|
156887
|
+
if (existsSync48(targetPath)) {
|
|
156487
156888
|
console.error(`Error: Directory '${targetDir}' already exists.`);
|
|
156488
156889
|
console.error("Please choose a different name or remove the existing directory.");
|
|
156489
156890
|
process.exit(1);
|
|
@@ -156616,9 +157017,9 @@ async function runSkillsInstall(args, options) {
|
|
|
156616
157017
|
stdio: "inherit",
|
|
156617
157018
|
shell: true
|
|
156618
157019
|
});
|
|
156619
|
-
const exitCode = await new Promise((
|
|
157020
|
+
const exitCode = await new Promise((resolve39, reject2) => {
|
|
156620
157021
|
child.on("exit", (code) => {
|
|
156621
|
-
|
|
157022
|
+
resolve39(code ?? 1);
|
|
156622
157023
|
});
|
|
156623
157024
|
child.on("error", (err) => {
|
|
156624
157025
|
reject2(err);
|
|
@@ -156649,8 +157050,8 @@ __export(native_patch_exports, {
|
|
|
156649
157050
|
isTerminalAvailable: () => isTerminalAvailable,
|
|
156650
157051
|
setupNativeResolution: () => setupNativeResolution
|
|
156651
157052
|
});
|
|
156652
|
-
import { join as join63, basename as
|
|
156653
|
-
import { existsSync as
|
|
157053
|
+
import { join as join63, basename as basename16, dirname as dirname26 } from "node:path";
|
|
157054
|
+
import { existsSync as existsSync49, copyFileSync, mkdirSync as mkdirSync12, symlinkSync as symlinkSync2, rmSync as rmSync5, lstatSync as lstatSync3, readlinkSync as readlinkSync2 } from "node:fs";
|
|
156654
157055
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
156655
157056
|
function findStagedNativeDir2() {
|
|
156656
157057
|
const platform3 = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : process.platform === "win32" ? "win32" : "unknown";
|
|
@@ -156658,12 +157059,12 @@ function findStagedNativeDir2() {
|
|
|
156658
157059
|
const prebuildName = `${platform3}-${arch}`;
|
|
156659
157060
|
const execDir = dirname26(process.execPath);
|
|
156660
157061
|
const nextToBinary = join63(execDir, "runtime", prebuildName);
|
|
156661
|
-
if (
|
|
157062
|
+
if (existsSync49(join63(nextToBinary, "pty.node"))) {
|
|
156662
157063
|
return nextToBinary;
|
|
156663
157064
|
}
|
|
156664
157065
|
if (process.env.FUSION_RUNTIME_DIR) {
|
|
156665
157066
|
const envPath = join63(process.env.FUSION_RUNTIME_DIR, prebuildName);
|
|
156666
|
-
if (
|
|
157067
|
+
if (existsSync49(join63(envPath, "pty.node"))) {
|
|
156667
157068
|
return envPath;
|
|
156668
157069
|
}
|
|
156669
157070
|
}
|
|
@@ -156673,11 +157074,11 @@ function cleanupStaleBunfsLinks() {
|
|
|
156673
157074
|
if (process.platform === "win32") return;
|
|
156674
157075
|
const bunfsRoot = "/$bunfs/root";
|
|
156675
157076
|
try {
|
|
156676
|
-
if (
|
|
157077
|
+
if (existsSync49(bunfsRoot)) {
|
|
156677
157078
|
const stats = lstatSync3(bunfsRoot);
|
|
156678
157079
|
if (stats.isSymbolicLink()) {
|
|
156679
157080
|
const target = readlinkSync2(bunfsRoot);
|
|
156680
|
-
if (target.includes("fn-bunfs-") && !
|
|
157081
|
+
if (target.includes("fn-bunfs-") && !existsSync49(target)) {
|
|
156681
157082
|
rmSync5(bunfsRoot);
|
|
156682
157083
|
console.log("[fn-native-patch] Cleaned up stale /$bunfs/root symlink");
|
|
156683
157084
|
}
|
|
@@ -156699,20 +157100,20 @@ function setupNativeResolution() {
|
|
|
156699
157100
|
const tmpRoot = join63(tmpdir4(), `fn-bunfs-${process.pid}`);
|
|
156700
157101
|
const fnDir = join63(tmpRoot, "fn");
|
|
156701
157102
|
const prebuildsDir = join63(fnDir, "prebuilds");
|
|
156702
|
-
const platformDir = join63(prebuildsDir,
|
|
157103
|
+
const platformDir = join63(prebuildsDir, basename16(nativeDir));
|
|
156703
157104
|
try {
|
|
156704
157105
|
cleanupStaleBunfsLinks();
|
|
156705
157106
|
mkdirSync12(platformDir, { recursive: true });
|
|
156706
157107
|
const ptyNodeDest = join63(platformDir, "pty.node");
|
|
156707
157108
|
copyFileSync(join63(nativeDir, "pty.node"), ptyNodeDest);
|
|
156708
|
-
if (
|
|
157109
|
+
if (existsSync49(join63(nativeDir, "spawn-helper"))) {
|
|
156709
157110
|
copyFileSync(join63(nativeDir, "spawn-helper"), join63(platformDir, "spawn-helper"));
|
|
156710
157111
|
}
|
|
156711
157112
|
process.env.FUSION_FAKE_BUNFS_ROOT = tmpRoot;
|
|
156712
157113
|
if (process.platform !== "win32") {
|
|
156713
157114
|
const bunfsRoot = "/$bunfs/root";
|
|
156714
157115
|
try {
|
|
156715
|
-
if (
|
|
157116
|
+
if (existsSync49(bunfsRoot)) {
|
|
156716
157117
|
const stats = lstatSync3(bunfsRoot);
|
|
156717
157118
|
if (stats.isSymbolicLink()) {
|
|
156718
157119
|
rmSync5(bunfsRoot);
|
|
@@ -156735,7 +157136,7 @@ function setupNativeResolution() {
|
|
|
156735
157136
|
function cleanupNativeResolution() {
|
|
156736
157137
|
if (bunfsSymlinkPath && process.platform !== "win32") {
|
|
156737
157138
|
try {
|
|
156738
|
-
if (
|
|
157139
|
+
if (existsSync49(bunfsSymlinkPath)) {
|
|
156739
157140
|
const stats = lstatSync3(bunfsSymlinkPath);
|
|
156740
157141
|
if (stats.isSymbolicLink()) {
|
|
156741
157142
|
rmSync5(bunfsSymlinkPath);
|
|
@@ -156781,7 +157182,7 @@ var init_native_patch = __esm({
|
|
|
156781
157182
|
});
|
|
156782
157183
|
|
|
156783
157184
|
// src/bin.ts
|
|
156784
|
-
import { existsSync as
|
|
157185
|
+
import { existsSync as existsSync50, mkdtempSync as mkdtempSync2, readFileSync as readFileSync22, symlinkSync as symlinkSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
156785
157186
|
import { createRequire as createRequire6 } from "node:module";
|
|
156786
157187
|
import { join as join64, dirname as dirname27 } from "node:path";
|
|
156787
157188
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
@@ -156804,7 +157205,7 @@ function configurePiPackage() {
|
|
|
156804
157205
|
packageJson = JSON.parse(readFileSync22(piPackagePath, "utf-8"));
|
|
156805
157206
|
for (const entry of ["dist", "docs", "examples", "README.md", "CHANGELOG.md"]) {
|
|
156806
157207
|
const source = join64(piPackageDir, entry);
|
|
156807
|
-
if (
|
|
157208
|
+
if (existsSync50(source)) {
|
|
156808
157209
|
symlinkSync3(source, join64(tmp, entry));
|
|
156809
157210
|
}
|
|
156810
157211
|
}
|
|
@@ -156823,7 +157224,7 @@ setInterval(() => {
|
|
|
156823
157224
|
performance3.clearMarks();
|
|
156824
157225
|
}, 3e4).unref();
|
|
156825
157226
|
function loadEnvFile(path5) {
|
|
156826
|
-
if (!
|
|
157227
|
+
if (!existsSync50(path5)) return;
|
|
156827
157228
|
const contents = readFileSync22(path5, "utf-8");
|
|
156828
157229
|
for (const rawLine of contents.split(/\r?\n/)) {
|
|
156829
157230
|
const line = rawLine.trim();
|
|
@@ -157076,9 +157477,6 @@ Options:
|
|
|
157076
157477
|
|
|
157077
157478
|
Columns: triage, todo, in-progress, in-review, done, archived
|
|
157078
157479
|
Supported file types: png, jpg, gif, webp, txt, log, json, yaml, yml, toml, csv, xml
|
|
157079
|
-
|
|
157080
|
-
The AI engine uses pi (github.com/badlogic/pi-mono) for agent sessions.
|
|
157081
|
-
Requires configured API keys \u2014 run "pi" first to set up authentication.
|
|
157082
157480
|
`.trim();
|
|
157083
157481
|
function extractGlobalProjectFlag(argv) {
|
|
157084
157482
|
const cleanedArgs = [];
|
|
@@ -157126,10 +157524,8 @@ async function main() {
|
|
|
157126
157524
|
console.log(HELP);
|
|
157127
157525
|
process.exit(0);
|
|
157128
157526
|
}
|
|
157129
|
-
if (args.length === 0) {
|
|
157130
|
-
|
|
157131
|
-
await runDashboard3(4040);
|
|
157132
|
-
return;
|
|
157527
|
+
if (args.length === 0 || args[0].startsWith("-")) {
|
|
157528
|
+
args.unshift("dashboard");
|
|
157133
157529
|
}
|
|
157134
157530
|
const command = args[0];
|
|
157135
157531
|
const {
|