@runfusion/fusion 0.4.0 → 0.4.1
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/LICENSE +21 -0
- package/dist/bin.js +825 -749
- package/dist/client/assets/{AgentDetailView-DJwWfkpv.js → AgentDetailView-sy6Hg1Xr.js} +1 -1
- package/dist/client/assets/{AgentsView-DegK8aw-.js → AgentsView-DpEpW88a.js} +3 -3
- package/dist/client/assets/{ChatView-CYpEShLS.js → ChatView-BUt3C4cf.js} +1 -1
- package/dist/client/assets/{DevServerView-DfCTA9fx.js → DevServerView-BOyWtQJM.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-B0qNpfLW.js → DirectoryPicker-BJyEEso5.js} +1 -1
- package/dist/client/assets/{DocumentsView-CsQxuyz3.js → DocumentsView-Dx0M1YHw.js} +1 -1
- package/dist/client/assets/{InsightsView-Bzs7A2jv.js → InsightsView-BtXdAo7D.js} +1 -1
- package/dist/client/assets/{MemoryView-Cl5ASqjW.js → MemoryView-kKPuqmwf.js} +1 -1
- package/dist/client/assets/{NodesView-BpiqRlvc.js → NodesView-B_ZwUORz.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-Cr6EoC7S.js → PiExtensionsManager-Db0EGr0Q.js} +1 -1
- package/dist/client/assets/{PluginManager-DXtQdfns.js → PluginManager-mOwWndfg.js} +1 -1
- package/dist/client/assets/{RoadmapsView-CYPLTTB0.js → RoadmapsView-DbUzBLeF.js} +1 -1
- package/dist/client/assets/SettingsModal-Bs_lNs5B.js +31 -0
- package/dist/client/assets/{SettingsModal-CNdVTVqD.js → SettingsModal-TRJu_mTn.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-BLiljNn7.js → SetupWizardModal-D1bmCQrf.js} +1 -1
- package/dist/client/assets/{SkillsView-Dlpw5LKI.js → SkillsView-Dzzpd5Md.js} +1 -1
- package/dist/client/assets/{folder-open-B_38R5AA.js → folder-open-BcuByk6U.js} +1 -1
- package/dist/client/assets/index-BipedNj4.css +1 -0
- package/dist/client/assets/{index-DQKtk17v.js → index-k2c4LrUr.js} +5 -5
- package/dist/client/assets/{upload-DNQF7XCK.js → upload-BzNbXYEj.js} +1 -1
- package/dist/client/assets/{users-CG2_rCdk.js → users-BvIqhSXp.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/extension.js +68 -12
- package/dist/pi-claude-cli/package.json +1 -1
- package/package.json +17 -17
- package/dist/client/assets/SettingsModal-CyCC7MzL.js +0 -31
- package/dist/client/assets/index-DjOxzdj3.css +0 -1
package/dist/bin.js
CHANGED
|
@@ -205,6 +205,7 @@ var init_settings_schema = __esm({
|
|
|
205
205
|
},
|
|
206
206
|
cloudflare: {
|
|
207
207
|
enabled: false,
|
|
208
|
+
quickTunnel: false,
|
|
208
209
|
tunnelName: "",
|
|
209
210
|
tunnelToken: null,
|
|
210
211
|
ingressUrl: ""
|
|
@@ -388,18 +389,18 @@ Call \`task_done()\` to signal completion.
|
|
|
388
389
|
},
|
|
389
390
|
"triage-welcome": {
|
|
390
391
|
key: "triage-welcome",
|
|
391
|
-
name: "
|
|
392
|
+
name: "Planning Welcome",
|
|
392
393
|
roles: ["triage"],
|
|
393
|
-
description: "Introductory section for the
|
|
394
|
+
description: "Introductory section for the planning agent",
|
|
394
395
|
defaultContent: `You are a task specification agent for "fn", an AI-orchestrated task board.
|
|
395
396
|
|
|
396
397
|
Your job: take a rough task description and produce a fully specified PROMPT.md that another AI agent can execute autonomously in a fresh context with zero memory of this conversation.`
|
|
397
398
|
},
|
|
398
399
|
"triage-context": {
|
|
399
400
|
key: "triage-context",
|
|
400
|
-
name: "
|
|
401
|
+
name: "Planning Context",
|
|
401
402
|
roles: ["triage"],
|
|
402
|
-
description: "Context-gathering instructions for
|
|
403
|
+
description: "Context-gathering instructions for planning",
|
|
403
404
|
defaultContent: `## What you receive
|
|
404
405
|
- A raw task title and optional description (the user's rough idea)
|
|
405
406
|
- Access to the project's files so you can understand context`
|
|
@@ -1088,7 +1089,7 @@ Output Requirements:
|
|
|
1088
1089
|
}
|
|
1089
1090
|
};
|
|
1090
1091
|
COLUMN_LABELS = {
|
|
1091
|
-
triage: "
|
|
1092
|
+
triage: "Planning",
|
|
1092
1093
|
todo: "Todo",
|
|
1093
1094
|
"in-progress": "In Progress",
|
|
1094
1095
|
"in-review": "In Review",
|
|
@@ -1096,7 +1097,7 @@ Output Requirements:
|
|
|
1096
1097
|
archived: "Archived"
|
|
1097
1098
|
};
|
|
1098
1099
|
COLUMN_DESCRIPTIONS = {
|
|
1099
|
-
triage: "Raw ideas \u2014 AI will
|
|
1100
|
+
triage: "Raw ideas \u2014 AI will plan these",
|
|
1100
1101
|
todo: "Specified and ready to start",
|
|
1101
1102
|
"in-progress": "AI is working on this in a worktree",
|
|
1102
1103
|
"in-review": "Complete \u2014 ready to merge",
|
|
@@ -2222,7 +2223,7 @@ var init_db = __esm({
|
|
|
2222
2223
|
"../core/src/db.ts"() {
|
|
2223
2224
|
"use strict";
|
|
2224
2225
|
init_types();
|
|
2225
|
-
SCHEMA_VERSION =
|
|
2226
|
+
SCHEMA_VERSION = 47;
|
|
2226
2227
|
SCHEMA_SQL = `
|
|
2227
2228
|
-- Tasks table with JSON columns for nested data
|
|
2228
2229
|
CREATE TABLE IF NOT EXISTS tasks (
|
|
@@ -3660,6 +3661,14 @@ CREATE INDEX IF NOT EXISTS idxTodoItemsSortOrder ON todo_items(listId, sortOrder
|
|
|
3660
3661
|
this.db.exec("CREATE INDEX IF NOT EXISTS idxTodoItemsSortOrder ON todo_items(listId, sortOrder)");
|
|
3661
3662
|
});
|
|
3662
3663
|
}
|
|
3664
|
+
if (version < 47) {
|
|
3665
|
+
this.applyMigration(47, () => {
|
|
3666
|
+
if (this.hasTable("tasks") && this.hasColumn("tasks", "status")) {
|
|
3667
|
+
this.db.exec("UPDATE tasks SET status = 'planning' WHERE status = 'specifying'");
|
|
3668
|
+
this.db.exec("UPDATE tasks SET status = 'needs-replan' WHERE status = 'needs-respecify'");
|
|
3669
|
+
}
|
|
3670
|
+
});
|
|
3671
|
+
}
|
|
3663
3672
|
}
|
|
3664
3673
|
/**
|
|
3665
3674
|
* Run a single migration step inside a transaction and bump the version.
|
|
@@ -32830,7 +32839,7 @@ ${task.description}
|
|
|
32830
32839
|
let invalidatedStatus = false;
|
|
32831
32840
|
try {
|
|
32832
32841
|
await this.updateTask(id, {
|
|
32833
|
-
status: "needs-
|
|
32842
|
+
status: "needs-replan"
|
|
32834
32843
|
});
|
|
32835
32844
|
invalidatedStatus = true;
|
|
32836
32845
|
} catch (err) {
|
|
@@ -32838,7 +32847,7 @@ ${task.description}
|
|
|
32838
32847
|
...commentContextBase,
|
|
32839
32848
|
phase: "addComment:awaiting-approval-invalidation",
|
|
32840
32849
|
stage: "status-update",
|
|
32841
|
-
nextStatus: "needs-
|
|
32850
|
+
nextStatus: "needs-replan",
|
|
32842
32851
|
error: err instanceof Error ? err.message : String(err)
|
|
32843
32852
|
});
|
|
32844
32853
|
}
|
|
@@ -32855,7 +32864,7 @@ ${task.description}
|
|
|
32855
32864
|
...commentContextBase,
|
|
32856
32865
|
phase: "addComment:awaiting-approval-invalidation",
|
|
32857
32866
|
stage: "post-invalidation-log-entry",
|
|
32858
|
-
nextStatus: "needs-
|
|
32867
|
+
nextStatus: "needs-replan",
|
|
32859
32868
|
error: err instanceof Error ? err.message : String(err)
|
|
32860
32869
|
});
|
|
32861
32870
|
}
|
|
@@ -55219,6 +55228,15 @@ function rateLimited(message, retryAfter) {
|
|
|
55219
55228
|
function internalError(message) {
|
|
55220
55229
|
return new ApiError(500, message);
|
|
55221
55230
|
}
|
|
55231
|
+
function rethrowAsApiError(error, fallbackMessage = "Internal server error") {
|
|
55232
|
+
if (error instanceof ApiError) {
|
|
55233
|
+
throw error;
|
|
55234
|
+
}
|
|
55235
|
+
if (error instanceof Error && error.message) {
|
|
55236
|
+
throw internalError(error.message);
|
|
55237
|
+
}
|
|
55238
|
+
throw internalError(fallbackMessage);
|
|
55239
|
+
}
|
|
55222
55240
|
var ApiError;
|
|
55223
55241
|
var init_api_error = __esm({
|
|
55224
55242
|
"../dashboard/src/api-error.ts"() {
|
|
@@ -55383,7 +55401,7 @@ var init_project_store_resolver = __esm({
|
|
|
55383
55401
|
// ../dashboard/src/routes/context.ts
|
|
55384
55402
|
import { Router as Router2 } from "express";
|
|
55385
55403
|
import { resolve as resolve11, sep as sep4 } from "node:path";
|
|
55386
|
-
function
|
|
55404
|
+
function rethrowAsApiError2(error, fallbackMessage = "Internal server error") {
|
|
55387
55405
|
if (error instanceof ApiError) {
|
|
55388
55406
|
throw error;
|
|
55389
55407
|
}
|
|
@@ -55700,7 +55718,7 @@ function createApiRoutesContext(store, options) {
|
|
|
55700
55718
|
resolveAutomationStore,
|
|
55701
55719
|
resolveRoutineStore,
|
|
55702
55720
|
resolveRoutineRunner,
|
|
55703
|
-
rethrowAsApiError
|
|
55721
|
+
rethrowAsApiError: rethrowAsApiError2
|
|
55704
55722
|
};
|
|
55705
55723
|
}
|
|
55706
55724
|
var init_context = __esm({
|
|
@@ -55714,7 +55732,6 @@ var init_context = __esm({
|
|
|
55714
55732
|
|
|
55715
55733
|
// ../dashboard/src/routes/register-task-workflow-routes.ts
|
|
55716
55734
|
import { createReadStream } from "node:fs";
|
|
55717
|
-
import { access as access4 } from "node:fs/promises";
|
|
55718
55735
|
function registerTaskWorkflowRoutes(ctx, deps) {
|
|
55719
55736
|
const { router, options, getProjectContext: getProjectContext3, rethrowAsApiError: rethrowAsApiError5 } = ctx;
|
|
55720
55737
|
const {
|
|
@@ -55724,7 +55741,6 @@ function registerTaskWorkflowRoutes(ctx, deps) {
|
|
|
55724
55741
|
validateOptionalModelField: validateOptionalModelField2,
|
|
55725
55742
|
normalizeModelSelectionPair: normalizeModelSelectionPair2,
|
|
55726
55743
|
runGitCommand: runGitCommand2,
|
|
55727
|
-
resolveDiffBase: resolveDiffBase2,
|
|
55728
55744
|
trimTaskDetailActivityLog: trimTaskDetailActivityLog2,
|
|
55729
55745
|
triggerCommentWakeForAssignedAgent
|
|
55730
55746
|
} = deps;
|
|
@@ -56978,156 +56994,6 @@ function registerTaskWorkflowRoutes(ctx, deps) {
|
|
|
56978
56994
|
rethrowAsApiError5(err);
|
|
56979
56995
|
}
|
|
56980
56996
|
});
|
|
56981
|
-
router.get("/tasks/:id/diff", async (req, res) => {
|
|
56982
|
-
try {
|
|
56983
|
-
const { store: scopedStore } = await getProjectContext3(req);
|
|
56984
|
-
const task = await scopedStore.getTask(req.params.id);
|
|
56985
|
-
if (!task) {
|
|
56986
|
-
res.status(404).json({ error: "Task not found" });
|
|
56987
|
-
return;
|
|
56988
|
-
}
|
|
56989
|
-
if (task.column === "done" && task.mergeDetails?.commitSha) {
|
|
56990
|
-
const rootDir = scopedStore.getRootDir();
|
|
56991
|
-
const sha = task.mergeDetails.commitSha;
|
|
56992
|
-
let mergeBase;
|
|
56993
|
-
try {
|
|
56994
|
-
mergeBase = (await runGitCommand2(["rev-parse", `${sha}^`], rootDir, 5e3)).trim();
|
|
56995
|
-
} catch {
|
|
56996
|
-
res.json({ files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 } });
|
|
56997
|
-
return;
|
|
56998
|
-
}
|
|
56999
|
-
const nameStatus = (await runGitCommand2(["diff", "--name-status", `${mergeBase}..${sha}`], rootDir, 1e4)).trim();
|
|
57000
|
-
const doneFiles = [];
|
|
57001
|
-
for (const line of nameStatus.split("\n").filter(Boolean)) {
|
|
57002
|
-
const parts = line.split(" ");
|
|
57003
|
-
const statusCode = parts[0] ?? "M";
|
|
57004
|
-
const filePath = parts[1] ?? "";
|
|
57005
|
-
if (!filePath) continue;
|
|
57006
|
-
let status = "modified";
|
|
57007
|
-
if (statusCode.startsWith("A")) status = "added";
|
|
57008
|
-
else if (statusCode.startsWith("D")) status = "deleted";
|
|
57009
|
-
let patch = "";
|
|
57010
|
-
try {
|
|
57011
|
-
patch = await runGitCommand2(["diff", `${mergeBase}..${sha}`, "--", filePath], rootDir, 1e4);
|
|
57012
|
-
} catch {
|
|
57013
|
-
}
|
|
57014
|
-
const additions = (patch.match(/^\+[^+]/gm) || []).length;
|
|
57015
|
-
const deletions = (patch.match(/^-[^-]/gm) || []).length;
|
|
57016
|
-
doneFiles.push({ path: filePath, status, additions, deletions, patch });
|
|
57017
|
-
}
|
|
57018
|
-
const doneStats = {
|
|
57019
|
-
filesChanged: doneFiles.length,
|
|
57020
|
-
additions: doneFiles.reduce((s, f) => s + f.additions, 0),
|
|
57021
|
-
deletions: doneFiles.reduce((s, f) => s + f.deletions, 0)
|
|
57022
|
-
};
|
|
57023
|
-
res.json({ files: doneFiles, stats: doneStats });
|
|
57024
|
-
return;
|
|
57025
|
-
}
|
|
57026
|
-
if (task.column === "done") {
|
|
57027
|
-
const md = task.mergeDetails;
|
|
57028
|
-
res.json({
|
|
57029
|
-
files: [],
|
|
57030
|
-
stats: {
|
|
57031
|
-
filesChanged: md?.filesChanged ?? 0,
|
|
57032
|
-
additions: md?.insertions ?? 0,
|
|
57033
|
-
deletions: md?.deletions ?? 0
|
|
57034
|
-
}
|
|
57035
|
-
});
|
|
57036
|
-
return;
|
|
57037
|
-
}
|
|
57038
|
-
const worktree = typeof req.query.worktree === "string" ? req.query.worktree : void 0;
|
|
57039
|
-
const resolvedWorktree = worktree || task.worktree;
|
|
57040
|
-
if (!resolvedWorktree) {
|
|
57041
|
-
res.json({ files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 } });
|
|
57042
|
-
return;
|
|
57043
|
-
}
|
|
57044
|
-
let worktreeExists = false;
|
|
57045
|
-
try {
|
|
57046
|
-
await access4(resolvedWorktree);
|
|
57047
|
-
worktreeExists = true;
|
|
57048
|
-
} catch {
|
|
57049
|
-
worktreeExists = false;
|
|
57050
|
-
}
|
|
57051
|
-
if (!worktreeExists) {
|
|
57052
|
-
res.json({ files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 } });
|
|
57053
|
-
return;
|
|
57054
|
-
}
|
|
57055
|
-
const cwd = resolvedWorktree;
|
|
57056
|
-
const diffBase = await resolveDiffBase2(task, cwd);
|
|
57057
|
-
const diffRange = diffBase ? `${diffBase}..HEAD` : "HEAD";
|
|
57058
|
-
const fileMap = /* @__PURE__ */ new Map();
|
|
57059
|
-
if (diffBase) {
|
|
57060
|
-
try {
|
|
57061
|
-
const committedOutput = (await runGitCommand2(["diff", "--name-status", `${diffBase}..HEAD`], cwd, 1e4)).trim();
|
|
57062
|
-
for (const line of committedOutput.split("\n").filter(Boolean)) {
|
|
57063
|
-
const parts = line.split(" ");
|
|
57064
|
-
fileMap.set(parts[1] ?? "", parts[0] ?? "M");
|
|
57065
|
-
}
|
|
57066
|
-
} catch {
|
|
57067
|
-
}
|
|
57068
|
-
}
|
|
57069
|
-
try {
|
|
57070
|
-
const stagedOutput = (await runGitCommand2(["diff", "--cached", "--name-status"], cwd, 1e4)).trim();
|
|
57071
|
-
for (const line of stagedOutput.split("\n").filter(Boolean)) {
|
|
57072
|
-
const parts = line.split(" ");
|
|
57073
|
-
const filePath = parts[1] ?? "";
|
|
57074
|
-
if (filePath && !fileMap.has(filePath)) {
|
|
57075
|
-
fileMap.set(filePath, parts[0] ?? "M");
|
|
57076
|
-
}
|
|
57077
|
-
}
|
|
57078
|
-
} catch {
|
|
57079
|
-
}
|
|
57080
|
-
try {
|
|
57081
|
-
const workingTreeOutput = (await runGitCommand2(["diff", "--name-status"], cwd, 1e4)).trim();
|
|
57082
|
-
for (const line of workingTreeOutput.split("\n").filter(Boolean)) {
|
|
57083
|
-
const parts = line.split(" ");
|
|
57084
|
-
const filePath = parts[1] ?? "";
|
|
57085
|
-
if (filePath && !fileMap.has(filePath)) {
|
|
57086
|
-
fileMap.set(filePath, parts[0] ?? "M");
|
|
57087
|
-
}
|
|
57088
|
-
}
|
|
57089
|
-
} catch {
|
|
57090
|
-
}
|
|
57091
|
-
try {
|
|
57092
|
-
const untrackedOutput = (await runGitCommand2(["ls-files", "--others", "--exclude-standard"], cwd, 1e4)).trim();
|
|
57093
|
-
for (const line of untrackedOutput.split("\n").filter(Boolean)) {
|
|
57094
|
-
fileMap.set(line, "U");
|
|
57095
|
-
}
|
|
57096
|
-
} catch {
|
|
57097
|
-
}
|
|
57098
|
-
const files = [];
|
|
57099
|
-
for (const [filePath, statusCode] of fileMap) {
|
|
57100
|
-
if (!filePath) continue;
|
|
57101
|
-
let status;
|
|
57102
|
-
if (statusCode.startsWith("A") || statusCode === "U") status = "added";
|
|
57103
|
-
else if (statusCode.startsWith("D")) status = "deleted";
|
|
57104
|
-
else status = "modified";
|
|
57105
|
-
let patch = "";
|
|
57106
|
-
try {
|
|
57107
|
-
if (statusCode === "U") {
|
|
57108
|
-
patch = await runGitCommand2(["diff", "--no-index", "/dev/null", filePath], cwd, 1e4).catch(() => "");
|
|
57109
|
-
} else {
|
|
57110
|
-
patch = await runGitCommand2(["diff", diffRange, "--", filePath], cwd, 1e4);
|
|
57111
|
-
}
|
|
57112
|
-
} catch {
|
|
57113
|
-
}
|
|
57114
|
-
const additions = (patch.match(/^\+[^+]/gm) || []).length;
|
|
57115
|
-
const deletions = (patch.match(/^-[^-]/gm) || []).length;
|
|
57116
|
-
files.push({ path: filePath, status, additions, deletions, patch });
|
|
57117
|
-
}
|
|
57118
|
-
const stats = {
|
|
57119
|
-
filesChanged: files.length,
|
|
57120
|
-
additions: files.reduce((sum, f) => sum + f.additions, 0),
|
|
57121
|
-
deletions: files.reduce((sum, f) => sum + f.deletions, 0)
|
|
57122
|
-
};
|
|
57123
|
-
res.json({ files, stats });
|
|
57124
|
-
} catch (err) {
|
|
57125
|
-
if (err instanceof ApiError) {
|
|
57126
|
-
throw err;
|
|
57127
|
-
}
|
|
57128
|
-
rethrowAsApiError5(err);
|
|
57129
|
-
}
|
|
57130
|
-
});
|
|
57131
56997
|
}
|
|
57132
56998
|
var init_register_task_workflow_routes = __esm({
|
|
57133
56999
|
"../dashboard/src/routes/register-task-workflow-routes.ts"() {
|
|
@@ -83032,6 +82898,9 @@ var init_provider_adapters = __esm({
|
|
|
83032
82898
|
provider: "cloudflare",
|
|
83033
82899
|
validateConfig(config) {
|
|
83034
82900
|
validateBaseConfig(config, "cloudflare");
|
|
82901
|
+
if (config.provider === "cloudflare" && config.quickTunnel === true) {
|
|
82902
|
+
return;
|
|
82903
|
+
}
|
|
83035
82904
|
if ("credentialsPath" in config && config.credentialsPath !== void 0) {
|
|
83036
82905
|
assertNonEmpty(config.credentialsPath, "credentialsPath");
|
|
83037
82906
|
if (isAbsoluteOrPathLike(config.credentialsPath)) {
|
|
@@ -83922,6 +83791,21 @@ var init_project_engine = __esm({
|
|
|
83922
83791
|
if (!cloudflare.enabled) {
|
|
83923
83792
|
return { provider, reason: "provider_not_enabled", message: "Cloudflare provider is disabled" };
|
|
83924
83793
|
}
|
|
83794
|
+
if (cloudflare.quickTunnel === true) {
|
|
83795
|
+
const executable2 = await this.checkExecutableAvailable("cloudflared");
|
|
83796
|
+
if (!executable2.available) {
|
|
83797
|
+
return { provider, reason: "runtime_prerequisite_missing", message: executable2.message };
|
|
83798
|
+
}
|
|
83799
|
+
return {
|
|
83800
|
+
provider,
|
|
83801
|
+
config: {
|
|
83802
|
+
provider: "cloudflare",
|
|
83803
|
+
quickTunnel: true,
|
|
83804
|
+
executablePath: "cloudflared",
|
|
83805
|
+
args: ["tunnel", "--url", "http://localhost:4040"]
|
|
83806
|
+
}
|
|
83807
|
+
};
|
|
83808
|
+
}
|
|
83925
83809
|
if (!cloudflare.tunnelName?.trim() || !cloudflare.ingressUrl?.trim()) {
|
|
83926
83810
|
return { provider, reason: "provider_not_configured", message: "Cloudflare tunnel name and ingress URL must be configured" };
|
|
83927
83811
|
}
|
|
@@ -85413,18 +85297,25 @@ var init_src2 = __esm({
|
|
|
85413
85297
|
function registerSettingsMemoryRoutes(ctx, deps) {
|
|
85414
85298
|
const { router, options, store, runtimeLogger, getProjectContext: getProjectContext3, rethrowAsApiError: rethrowAsApiError5 } = ctx;
|
|
85415
85299
|
const { githubToken, validateModelPresets: validateModelPresets2, sanitizeOverlapIgnorePaths: sanitizeOverlapIgnorePaths2, discoverDashboardPiExtensions: discoverDashboardPiExtensions2 } = deps;
|
|
85416
|
-
function resolveRemoteBaseUrl(remoteAccess) {
|
|
85300
|
+
function resolveRemoteBaseUrl(remoteAccess, tunnelUrl) {
|
|
85417
85301
|
if (!remoteAccess.activeProvider) {
|
|
85418
85302
|
throw new ApiError(409, "No active remote provider configured", { code: "REMOTE_PROVIDER_NOT_CONFIGURED" });
|
|
85419
85303
|
}
|
|
85420
85304
|
if (remoteAccess.activeProvider === "cloudflare") {
|
|
85421
|
-
const
|
|
85422
|
-
|
|
85305
|
+
const cloudflare = remoteAccess.providers.cloudflare;
|
|
85306
|
+
const ingressUrl = cloudflare.ingressUrl?.trim();
|
|
85307
|
+
const candidateUrl = cloudflare.quickTunnel === true && !ingressUrl ? tunnelUrl?.trim() ?? "" : ingressUrl;
|
|
85308
|
+
if (!candidateUrl) {
|
|
85309
|
+
if (cloudflare.quickTunnel === true) {
|
|
85310
|
+
throw new ApiError(409, "Cloudflare quick tunnel has not started yet", {
|
|
85311
|
+
code: "REMOTE_URL_NOT_READY"
|
|
85312
|
+
});
|
|
85313
|
+
}
|
|
85423
85314
|
throw new ApiError(409, "Cloudflare ingress URL is not configured", { code: "REMOTE_URL_NOT_CONFIGURED" });
|
|
85424
85315
|
}
|
|
85425
85316
|
let parsed;
|
|
85426
85317
|
try {
|
|
85427
|
-
parsed = new URL(
|
|
85318
|
+
parsed = new URL(candidateUrl);
|
|
85428
85319
|
} catch {
|
|
85429
85320
|
throw new ApiError(409, "Cloudflare ingress URL is invalid", { code: "REMOTE_URL_INVALID" });
|
|
85430
85321
|
}
|
|
@@ -85464,13 +85355,17 @@ function registerSettingsMemoryRoutes(ctx, deps) {
|
|
|
85464
85355
|
});
|
|
85465
85356
|
return token;
|
|
85466
85357
|
}
|
|
85467
|
-
|
|
85358
|
+
function getCurrentTunnelUrl(engine) {
|
|
85359
|
+
const manager = engine?.getRemoteTunnelManager?.();
|
|
85360
|
+
return manager?.getStatus?.().url ?? null;
|
|
85361
|
+
}
|
|
85362
|
+
async function buildRemoteLoginUrlForTokenType(scopedStore, mode, tunnelUrl) {
|
|
85468
85363
|
const settings = await scopedStore.getSettings();
|
|
85469
85364
|
const remoteAccess = settings.remoteAccess;
|
|
85470
85365
|
if (!remoteAccess || remoteAccess.activeProvider == null || !remoteAccess.providers[remoteAccess.activeProvider]?.enabled) {
|
|
85471
85366
|
throw new ApiError(409, "No remote provider is enabled", { code: "REMOTE_ACCESS_DISABLED" });
|
|
85472
85367
|
}
|
|
85473
|
-
const baseUrl = resolveRemoteBaseUrl(remoteAccess);
|
|
85368
|
+
const baseUrl = resolveRemoteBaseUrl(remoteAccess, tunnelUrl);
|
|
85474
85369
|
if (mode === "persistent") {
|
|
85475
85370
|
if (!remoteAccess.tokenStrategy.persistent.enabled) {
|
|
85476
85371
|
throw new ApiError(409, "Persistent remote token strategy is disabled", { code: "REMOTE_TOKEN_DISABLED" });
|
|
@@ -85584,6 +85479,7 @@ function registerSettingsMemoryRoutes(ctx, deps) {
|
|
|
85584
85479
|
remoteTailscaleTargetPort: Number(remoteAccess.providers.tailscale.targetPort ?? 4040),
|
|
85585
85480
|
remoteTailscaleAcceptRoutes: Boolean(remoteAccess.providers.tailscale.acceptRoutes),
|
|
85586
85481
|
remoteCloudflareEnabled: Boolean(remoteAccess.providers.cloudflare.enabled),
|
|
85482
|
+
remoteCloudflareQuickTunnel: Boolean(remoteAccess.providers.cloudflare.quickTunnel),
|
|
85587
85483
|
remoteCloudflareTunnelName: remoteAccess.providers.cloudflare.tunnelName,
|
|
85588
85484
|
remoteCloudflareTunnelToken: remoteAccess.providers.cloudflare.tunnelToken,
|
|
85589
85485
|
remoteCloudflareIngressUrl: remoteAccess.providers.cloudflare.ingressUrl,
|
|
@@ -85633,6 +85529,7 @@ function registerSettingsMemoryRoutes(ctx, deps) {
|
|
|
85633
85529
|
cloudflare: {
|
|
85634
85530
|
...remoteAccess.providers.cloudflare,
|
|
85635
85531
|
enabled: body.remoteCloudflareEnabled === void 0 ? remoteAccess.providers.cloudflare.enabled : Boolean(body.remoteCloudflareEnabled),
|
|
85532
|
+
quickTunnel: body.remoteCloudflareQuickTunnel === void 0 ? Boolean(remoteAccess.providers.cloudflare.quickTunnel) : Boolean(body.remoteCloudflareQuickTunnel),
|
|
85636
85533
|
tunnelName: body.remoteCloudflareTunnelName === void 0 ? remoteAccess.providers.cloudflare.tunnelName : String(body.remoteCloudflareTunnelName ?? ""),
|
|
85637
85534
|
tunnelToken: body.remoteCloudflareTunnelToken === void 0 ? remoteAccess.providers.cloudflare.tunnelToken : body.remoteCloudflareTunnelToken ? String(body.remoteCloudflareTunnelToken) : null,
|
|
85638
85535
|
ingressUrl: body.remoteCloudflareIngressUrl === void 0 ? remoteAccess.providers.cloudflare.ingressUrl : String(body.remoteCloudflareIngressUrl ?? "")
|
|
@@ -85828,8 +85725,8 @@ function registerSettingsMemoryRoutes(ctx, deps) {
|
|
|
85828
85725
|
if (mode !== "persistent" && mode !== "short-lived") {
|
|
85829
85726
|
throw new ApiError(400, "mode must be 'persistent' or 'short-lived'", { code: "INVALID_REMOTE_AUTH_MODE" });
|
|
85830
85727
|
}
|
|
85831
|
-
const { store: scopedStore } = await getProjectContext3(req);
|
|
85832
|
-
const payload = await buildRemoteLoginUrlForTokenType(scopedStore, mode);
|
|
85728
|
+
const { store: scopedStore, engine } = await getProjectContext3(req);
|
|
85729
|
+
const payload = await buildRemoteLoginUrlForTokenType(scopedStore, mode, getCurrentTunnelUrl(engine ?? options?.engine));
|
|
85833
85730
|
res.json({
|
|
85834
85731
|
loginUrl: payload.loginUrl,
|
|
85835
85732
|
tokenType: payload.tokenType,
|
|
@@ -85842,9 +85739,9 @@ function registerSettingsMemoryRoutes(ctx, deps) {
|
|
|
85842
85739
|
});
|
|
85843
85740
|
router.get("/remote/url", async (req, res) => {
|
|
85844
85741
|
try {
|
|
85845
|
-
const { store: scopedStore } = await getProjectContext3(req);
|
|
85742
|
+
const { store: scopedStore, engine } = await getProjectContext3(req);
|
|
85846
85743
|
const tokenType = req.query.tokenType === "short-lived" ? "short-lived" : "persistent";
|
|
85847
|
-
const payload = await buildRemoteLoginUrlForTokenType(scopedStore, tokenType);
|
|
85744
|
+
const payload = await buildRemoteLoginUrlForTokenType(scopedStore, tokenType, getCurrentTunnelUrl(engine ?? options?.engine));
|
|
85848
85745
|
res.json({ url: payload.loginUrl, tokenType: payload.tokenType, expiresAt: payload.expiresAt });
|
|
85849
85746
|
} catch (err) {
|
|
85850
85747
|
if (err instanceof ApiError) throw err;
|
|
@@ -85853,10 +85750,10 @@ function registerSettingsMemoryRoutes(ctx, deps) {
|
|
|
85853
85750
|
});
|
|
85854
85751
|
router.get("/remote/qr", async (req, res) => {
|
|
85855
85752
|
try {
|
|
85856
|
-
const { store: scopedStore } = await getProjectContext3(req);
|
|
85753
|
+
const { store: scopedStore, engine } = await getProjectContext3(req);
|
|
85857
85754
|
const tokenType = req.query.tokenType === "short-lived" ? "short-lived" : "persistent";
|
|
85858
85755
|
const format = req.query.format === "image/svg" ? "image/svg" : "text";
|
|
85859
|
-
const payload = await buildRemoteLoginUrlForTokenType(scopedStore, tokenType);
|
|
85756
|
+
const payload = await buildRemoteLoginUrlForTokenType(scopedStore, tokenType, getCurrentTunnelUrl(engine ?? options?.engine));
|
|
85860
85757
|
if (format === "image/svg") {
|
|
85861
85758
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="320" height="80"><rect width="100%" height="100%" fill="white"/><text x="10" y="42" font-size="12" fill="black">${payload.loginUrl.replace(/&/g, "&").replace(/</g, "<")}</text></svg>`;
|
|
85862
85759
|
res.json({ url: payload.loginUrl, tokenType: payload.tokenType, expiresAt: payload.expiresAt, format, data: svg });
|
|
@@ -88586,17 +88483,9 @@ var init_github_poll = __esm({
|
|
|
88586
88483
|
}
|
|
88587
88484
|
});
|
|
88588
88485
|
|
|
88589
|
-
// ../dashboard/src/routes/
|
|
88486
|
+
// ../dashboard/src/routes/resolve-diff-base.ts
|
|
88590
88487
|
import { execFile as execFile4 } from "node:child_process";
|
|
88591
|
-
import { isAbsolute as isAbsolute12 } from "node:path";
|
|
88592
88488
|
import { promisify as promisify11 } from "node:util";
|
|
88593
|
-
function getCommandErrorMessage2(error) {
|
|
88594
|
-
if (error instanceof Error) {
|
|
88595
|
-
const anyError = error;
|
|
88596
|
-
return [anyError.stderr, anyError.stdout, anyError.message].filter(Boolean).join("\n").trim() || anyError.message;
|
|
88597
|
-
}
|
|
88598
|
-
return String(error);
|
|
88599
|
-
}
|
|
88600
88489
|
async function runGitCommand(args, cwd, timeout2 = 1e4) {
|
|
88601
88490
|
const result = await execFileAsync2("git", args, {
|
|
88602
88491
|
cwd,
|
|
@@ -88615,6 +88504,55 @@ async function runGitCommand(args, cwd, timeout2 = 1e4) {
|
|
|
88615
88504
|
}
|
|
88616
88505
|
return "";
|
|
88617
88506
|
}
|
|
88507
|
+
async function resolveDiffBase(task, cwd, headRef = "HEAD", runGit = runGitCommand) {
|
|
88508
|
+
const baseBranch = task.baseBranch ?? "main";
|
|
88509
|
+
let mergeBase;
|
|
88510
|
+
try {
|
|
88511
|
+
try {
|
|
88512
|
+
mergeBase = (await runGit(["merge-base", headRef, baseBranch], cwd, 5e3)).trim() || void 0;
|
|
88513
|
+
} catch {
|
|
88514
|
+
mergeBase = (await runGit(["merge-base", headRef, `origin/${baseBranch}`], cwd, 5e3)).trim() || void 0;
|
|
88515
|
+
}
|
|
88516
|
+
} catch {
|
|
88517
|
+
}
|
|
88518
|
+
if (mergeBase) {
|
|
88519
|
+
try {
|
|
88520
|
+
const head = (await runGit(["rev-parse", headRef], cwd, 5e3)).trim();
|
|
88521
|
+
if (head && head !== mergeBase) return mergeBase;
|
|
88522
|
+
} catch {
|
|
88523
|
+
return mergeBase;
|
|
88524
|
+
}
|
|
88525
|
+
}
|
|
88526
|
+
if (task.baseCommitSha) {
|
|
88527
|
+
try {
|
|
88528
|
+
await runGit(["merge-base", "--is-ancestor", task.baseCommitSha, headRef], cwd, 5e3);
|
|
88529
|
+
return task.baseCommitSha;
|
|
88530
|
+
} catch {
|
|
88531
|
+
}
|
|
88532
|
+
}
|
|
88533
|
+
try {
|
|
88534
|
+
return (await runGit(["rev-parse", `${headRef}~1`], cwd, 5e3)).trim() || void 0;
|
|
88535
|
+
} catch {
|
|
88536
|
+
return void 0;
|
|
88537
|
+
}
|
|
88538
|
+
}
|
|
88539
|
+
var execFileAsync2;
|
|
88540
|
+
var init_resolve_diff_base = __esm({
|
|
88541
|
+
"../dashboard/src/routes/resolve-diff-base.ts"() {
|
|
88542
|
+
"use strict";
|
|
88543
|
+
execFileAsync2 = promisify11(execFile4);
|
|
88544
|
+
}
|
|
88545
|
+
});
|
|
88546
|
+
|
|
88547
|
+
// ../dashboard/src/routes/register-git-github.ts
|
|
88548
|
+
import { isAbsolute as isAbsolute12 } from "node:path";
|
|
88549
|
+
function getCommandErrorMessage2(error) {
|
|
88550
|
+
if (error instanceof Error) {
|
|
88551
|
+
const anyError = error;
|
|
88552
|
+
return [anyError.stderr, anyError.stdout, anyError.message].filter(Boolean).join("\n").trim() || anyError.message;
|
|
88553
|
+
}
|
|
88554
|
+
return String(error);
|
|
88555
|
+
}
|
|
88618
88556
|
function parseGitHubUrl(url) {
|
|
88619
88557
|
const httpsMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/i);
|
|
88620
88558
|
if (httpsMatch) {
|
|
@@ -90956,7 +90894,7 @@ ${body}`;
|
|
|
90956
90894
|
}
|
|
90957
90895
|
});
|
|
90958
90896
|
}
|
|
90959
|
-
var
|
|
90897
|
+
var batchImportWindowMs, batchImportInstances, batchImportCleanupInterval;
|
|
90960
90898
|
var init_register_git_github = __esm({
|
|
90961
90899
|
"../dashboard/src/routes/register-git-github.ts"() {
|
|
90962
90900
|
"use strict";
|
|
@@ -90965,7 +90903,7 @@ var init_register_git_github = __esm({
|
|
|
90965
90903
|
init_github();
|
|
90966
90904
|
init_github_poll();
|
|
90967
90905
|
init_github_webhooks();
|
|
90968
|
-
|
|
90906
|
+
init_resolve_diff_base();
|
|
90969
90907
|
batchImportWindowMs = 1e4;
|
|
90970
90908
|
batchImportInstances = [];
|
|
90971
90909
|
}
|
|
@@ -90973,13 +90911,13 @@ var init_register_git_github = __esm({
|
|
|
90973
90911
|
|
|
90974
90912
|
// ../dashboard/src/file-service.ts
|
|
90975
90913
|
import { join as join38, resolve as resolve17, relative as relative8, dirname as dirname11, basename as basename10 } from "node:path";
|
|
90976
|
-
import { readdir as readdir8, readFile as fsReadFile, writeFile as fsWriteFile, stat as stat7, copyFile as fsCopyFile, rename as fsRename, rm as fsRm, mkdir as mkdir12, access as
|
|
90914
|
+
import { readdir as readdir8, readFile as fsReadFile, writeFile as fsWriteFile, stat as stat7, copyFile as fsCopyFile, rename as fsRename, rm as fsRm, mkdir as mkdir12, access as access4 } from "node:fs/promises";
|
|
90977
90915
|
async function getTaskBasePath(store, taskId) {
|
|
90978
90916
|
try {
|
|
90979
90917
|
const task = await store.getTask(taskId);
|
|
90980
90918
|
if (task.worktree) {
|
|
90981
90919
|
try {
|
|
90982
|
-
await
|
|
90920
|
+
await access4(task.worktree);
|
|
90983
90921
|
return resolve17(task.worktree);
|
|
90984
90922
|
} catch {
|
|
90985
90923
|
}
|
|
@@ -117241,16 +117179,15 @@ var require_archiver = __commonJS({
|
|
|
117241
117179
|
});
|
|
117242
117180
|
|
|
117243
117181
|
// ../dashboard/src/routes/register-file-workspace-routes.ts
|
|
117244
|
-
import { access as
|
|
117182
|
+
import { access as access5 } from "node:fs/promises";
|
|
117245
117183
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
117246
117184
|
function extractFileParams(req) {
|
|
117247
117185
|
const filePath = Array.isArray(req.params.filepath) ? req.params.filepath[0] : req.params.filepath ?? "";
|
|
117248
117186
|
const workspace = typeof req.query.workspace === "string" && req.query.workspace.length > 0 ? req.query.workspace : "project";
|
|
117249
117187
|
return { filePath, workspace };
|
|
117250
117188
|
}
|
|
117251
|
-
function registerFileWorkspaceRoutes(ctx
|
|
117189
|
+
function registerFileWorkspaceRoutes(ctx) {
|
|
117252
117190
|
const { router, getProjectContext: getProjectContext3, rethrowAsApiError: rethrowAsApiError5 } = ctx;
|
|
117253
|
-
const { runGitCommand: runGitCommand2, resolveDiffBase: resolveDiffBase2 } = deps;
|
|
117254
117191
|
router.get("/tasks/:id/files", async (req, res) => {
|
|
117255
117192
|
try {
|
|
117256
117193
|
const { store: scopedStore } = await getProjectContext3(req);
|
|
@@ -117317,7 +117254,7 @@ function registerFileWorkspaceRoutes(ctx, deps) {
|
|
|
117317
117254
|
return null;
|
|
117318
117255
|
}
|
|
117319
117256
|
try {
|
|
117320
|
-
await
|
|
117257
|
+
await access5(task.worktree);
|
|
117321
117258
|
return {
|
|
117322
117259
|
id: task.id,
|
|
117323
117260
|
title: task.title,
|
|
@@ -117563,243 +117500,6 @@ function registerFileWorkspaceRoutes(ctx, deps) {
|
|
|
117563
117500
|
rethrowAsApiError5(err, "Internal server error");
|
|
117564
117501
|
}
|
|
117565
117502
|
});
|
|
117566
|
-
router.get("/tasks/:id/session-files", async (req, res) => {
|
|
117567
|
-
try {
|
|
117568
|
-
const { store: scopedStore } = await getProjectContext3(req);
|
|
117569
|
-
const task = await scopedStore.getTask(req.params.id);
|
|
117570
|
-
if (!task) {
|
|
117571
|
-
res.status(404).json({ error: "Task not found" });
|
|
117572
|
-
return;
|
|
117573
|
-
}
|
|
117574
|
-
if (!task.worktree) {
|
|
117575
|
-
res.json([]);
|
|
117576
|
-
return;
|
|
117577
|
-
}
|
|
117578
|
-
let worktreeExists = false;
|
|
117579
|
-
try {
|
|
117580
|
-
await access6(task.worktree);
|
|
117581
|
-
worktreeExists = true;
|
|
117582
|
-
} catch {
|
|
117583
|
-
worktreeExists = false;
|
|
117584
|
-
}
|
|
117585
|
-
if (!worktreeExists) {
|
|
117586
|
-
res.json([]);
|
|
117587
|
-
return;
|
|
117588
|
-
}
|
|
117589
|
-
const worktree = task.worktree;
|
|
117590
|
-
const cached = sessionFilesCache.get(task.id);
|
|
117591
|
-
if (cached && cached.expiresAt > Date.now()) {
|
|
117592
|
-
res.json(cached.files);
|
|
117593
|
-
return;
|
|
117594
|
-
}
|
|
117595
|
-
let files = [];
|
|
117596
|
-
try {
|
|
117597
|
-
const fileSet = /* @__PURE__ */ new Set();
|
|
117598
|
-
const baseRef = await resolveDiffBase2(task, worktree);
|
|
117599
|
-
if (baseRef) {
|
|
117600
|
-
const committedOutput = (await runGitCommand2(["diff", "--name-only", `${baseRef}..HEAD`], worktree, 5e3)).trim();
|
|
117601
|
-
for (const file of committedOutput.split("\n").filter(Boolean)) {
|
|
117602
|
-
fileSet.add(file);
|
|
117603
|
-
}
|
|
117604
|
-
}
|
|
117605
|
-
const stagedOutput = (await runGitCommand2(["diff", "--cached", "--name-only"], worktree, 5e3)).trim();
|
|
117606
|
-
for (const file of stagedOutput.split("\n").filter(Boolean)) {
|
|
117607
|
-
fileSet.add(file);
|
|
117608
|
-
}
|
|
117609
|
-
const workingTreeOutput = (await runGitCommand2(["diff", "--name-only"], worktree, 5e3)).trim();
|
|
117610
|
-
for (const file of workingTreeOutput.split("\n").filter(Boolean)) {
|
|
117611
|
-
fileSet.add(file);
|
|
117612
|
-
}
|
|
117613
|
-
const untrackedOutput = (await runGitCommand2(["ls-files", "--others", "--exclude-standard"], worktree, 5e3)).trim();
|
|
117614
|
-
for (const file of untrackedOutput.split("\n").filter(Boolean)) {
|
|
117615
|
-
fileSet.add(file);
|
|
117616
|
-
}
|
|
117617
|
-
files = Array.from(fileSet);
|
|
117618
|
-
} catch {
|
|
117619
|
-
files = [];
|
|
117620
|
-
}
|
|
117621
|
-
sessionFilesCache.set(task.id, {
|
|
117622
|
-
files,
|
|
117623
|
-
expiresAt: Date.now() + 1e4
|
|
117624
|
-
});
|
|
117625
|
-
res.json(files);
|
|
117626
|
-
} catch (err) {
|
|
117627
|
-
if (err instanceof ApiError) {
|
|
117628
|
-
throw err;
|
|
117629
|
-
}
|
|
117630
|
-
if (err.code === "ENOENT") {
|
|
117631
|
-
throw notFound(`Task ${req.params.id} not found`);
|
|
117632
|
-
}
|
|
117633
|
-
rethrowAsApiError5(err, "Internal server error");
|
|
117634
|
-
}
|
|
117635
|
-
});
|
|
117636
|
-
router.get("/tasks/:id/file-diffs", async (req, res) => {
|
|
117637
|
-
try {
|
|
117638
|
-
const { store: scopedStore } = await getProjectContext3(req);
|
|
117639
|
-
const task = await scopedStore.getTask(req.params.id);
|
|
117640
|
-
if (!task) {
|
|
117641
|
-
res.status(404).json({ error: "Task not found" });
|
|
117642
|
-
return;
|
|
117643
|
-
}
|
|
117644
|
-
if (task.column === "done" && task.mergeDetails?.commitSha) {
|
|
117645
|
-
const rootDir = scopedStore.getRootDir();
|
|
117646
|
-
const sha = task.mergeDetails.commitSha;
|
|
117647
|
-
let mergeBase;
|
|
117648
|
-
try {
|
|
117649
|
-
mergeBase = (await runGitCommand2(["rev-parse", `${sha}^`], rootDir, 5e3)).trim();
|
|
117650
|
-
} catch {
|
|
117651
|
-
res.json([]);
|
|
117652
|
-
return;
|
|
117653
|
-
}
|
|
117654
|
-
try {
|
|
117655
|
-
const nameStatus = (await runGitCommand2(["diff", "--name-status", `${mergeBase}..${sha}`], rootDir, 5e3)).trim();
|
|
117656
|
-
const doneFiles = [];
|
|
117657
|
-
for (const line of nameStatus.split("\n").filter(Boolean)) {
|
|
117658
|
-
const parts = line.split(" ");
|
|
117659
|
-
const statusCode = parts[0] ?? "M";
|
|
117660
|
-
const filePath = parts[1] ?? "";
|
|
117661
|
-
let status = "modified";
|
|
117662
|
-
if (statusCode.startsWith("A")) status = "added";
|
|
117663
|
-
else if (statusCode.startsWith("D")) status = "deleted";
|
|
117664
|
-
else if (statusCode.startsWith("R")) status = "renamed";
|
|
117665
|
-
let diff = "";
|
|
117666
|
-
try {
|
|
117667
|
-
diff = await runGitCommand2(["diff", `${mergeBase}..${sha}`, "--", filePath], rootDir, 5e3);
|
|
117668
|
-
} catch {
|
|
117669
|
-
}
|
|
117670
|
-
doneFiles.push({ path: filePath, status, diff });
|
|
117671
|
-
}
|
|
117672
|
-
res.json(doneFiles);
|
|
117673
|
-
} catch {
|
|
117674
|
-
res.json([]);
|
|
117675
|
-
}
|
|
117676
|
-
return;
|
|
117677
|
-
}
|
|
117678
|
-
if (task.column === "done") {
|
|
117679
|
-
res.json([]);
|
|
117680
|
-
return;
|
|
117681
|
-
}
|
|
117682
|
-
if (!task.worktree) {
|
|
117683
|
-
res.json([]);
|
|
117684
|
-
return;
|
|
117685
|
-
}
|
|
117686
|
-
let worktreeExists = false;
|
|
117687
|
-
try {
|
|
117688
|
-
await access6(task.worktree);
|
|
117689
|
-
worktreeExists = true;
|
|
117690
|
-
} catch {
|
|
117691
|
-
worktreeExists = false;
|
|
117692
|
-
}
|
|
117693
|
-
if (!worktreeExists) {
|
|
117694
|
-
res.json([]);
|
|
117695
|
-
return;
|
|
117696
|
-
}
|
|
117697
|
-
const worktree = task.worktree;
|
|
117698
|
-
const cached = fileDiffsCache.get(task.id);
|
|
117699
|
-
if (cached && cached.expiresAt > Date.now()) {
|
|
117700
|
-
res.json(cached.files);
|
|
117701
|
-
return;
|
|
117702
|
-
}
|
|
117703
|
-
const cwd = worktree;
|
|
117704
|
-
const diffBase = await resolveDiffBase2(task, cwd);
|
|
117705
|
-
const fileMap = /* @__PURE__ */ new Map();
|
|
117706
|
-
if (diffBase) {
|
|
117707
|
-
try {
|
|
117708
|
-
const committedOutput = (await runGitCommand2(["diff", "--name-status", `${diffBase}..HEAD`], cwd, 5e3)).trim();
|
|
117709
|
-
for (const line of committedOutput.split("\n").filter(Boolean)) {
|
|
117710
|
-
const parts = line.split(" ");
|
|
117711
|
-
const statusCode = parts[0] ?? "M";
|
|
117712
|
-
if (statusCode.startsWith("R")) {
|
|
117713
|
-
fileMap.set(parts[2] ?? parts[1] ?? "", { statusCode, oldPath: parts[1] });
|
|
117714
|
-
} else {
|
|
117715
|
-
fileMap.set(parts[1] ?? "", { statusCode });
|
|
117716
|
-
}
|
|
117717
|
-
}
|
|
117718
|
-
} catch {
|
|
117719
|
-
}
|
|
117720
|
-
}
|
|
117721
|
-
try {
|
|
117722
|
-
const stagedOutput = (await runGitCommand2(["diff", "--cached", "--name-status"], cwd, 5e3)).trim();
|
|
117723
|
-
for (const line of stagedOutput.split("\n").filter(Boolean)) {
|
|
117724
|
-
const parts = line.split(" ");
|
|
117725
|
-
const statusCode = parts[0] ?? "M";
|
|
117726
|
-
const filePath = parts[1] ?? "";
|
|
117727
|
-
if (filePath && !fileMap.has(filePath)) {
|
|
117728
|
-
if (statusCode.startsWith("R")) {
|
|
117729
|
-
fileMap.set(filePath, { statusCode, oldPath: parts[2] });
|
|
117730
|
-
} else {
|
|
117731
|
-
fileMap.set(filePath, { statusCode });
|
|
117732
|
-
}
|
|
117733
|
-
}
|
|
117734
|
-
}
|
|
117735
|
-
} catch {
|
|
117736
|
-
}
|
|
117737
|
-
try {
|
|
117738
|
-
const workingTreeOutput = (await runGitCommand2(["diff", "--name-status"], cwd, 5e3)).trim();
|
|
117739
|
-
for (const line of workingTreeOutput.split("\n").filter(Boolean)) {
|
|
117740
|
-
const parts = line.split(" ");
|
|
117741
|
-
const statusCode = parts[0] ?? "M";
|
|
117742
|
-
const filePath = parts[1] ?? "";
|
|
117743
|
-
if (filePath && !fileMap.has(filePath)) {
|
|
117744
|
-
if (statusCode.startsWith("R")) {
|
|
117745
|
-
fileMap.set(filePath, { statusCode, oldPath: parts[2] });
|
|
117746
|
-
} else {
|
|
117747
|
-
fileMap.set(filePath, { statusCode });
|
|
117748
|
-
}
|
|
117749
|
-
}
|
|
117750
|
-
}
|
|
117751
|
-
} catch {
|
|
117752
|
-
}
|
|
117753
|
-
try {
|
|
117754
|
-
const untrackedOutput = (await runGitCommand2(["ls-files", "--others", "--exclude-standard"], cwd, 5e3)).trim();
|
|
117755
|
-
for (const line of untrackedOutput.split("\n").filter(Boolean)) {
|
|
117756
|
-
if (line && !fileMap.has(line)) {
|
|
117757
|
-
fileMap.set(line, { statusCode: "U", isUntracked: true });
|
|
117758
|
-
}
|
|
117759
|
-
}
|
|
117760
|
-
} catch {
|
|
117761
|
-
}
|
|
117762
|
-
const diffRange = diffBase ? `${diffBase}..HEAD` : "HEAD";
|
|
117763
|
-
const files = [];
|
|
117764
|
-
for (const [filePath, { statusCode, oldPath, isUntracked }] of fileMap.entries()) {
|
|
117765
|
-
let status = "modified";
|
|
117766
|
-
if (statusCode.startsWith("A") || statusCode === "U") {
|
|
117767
|
-
status = "added";
|
|
117768
|
-
} else if (statusCode.startsWith("D")) {
|
|
117769
|
-
status = "deleted";
|
|
117770
|
-
} else if (statusCode.startsWith("R")) {
|
|
117771
|
-
status = "renamed";
|
|
117772
|
-
}
|
|
117773
|
-
let diff = "";
|
|
117774
|
-
try {
|
|
117775
|
-
if (isUntracked) {
|
|
117776
|
-
diff = await runGitCommand2(["diff", "--no-index", "/dev/null", filePath], cwd, 5e3).catch(() => "");
|
|
117777
|
-
} else {
|
|
117778
|
-
diff = await runGitCommand2(["diff", diffRange, "--", filePath], cwd, 5e3);
|
|
117779
|
-
}
|
|
117780
|
-
} catch {
|
|
117781
|
-
diff = "";
|
|
117782
|
-
}
|
|
117783
|
-
if (!diff && !isUntracked) {
|
|
117784
|
-
continue;
|
|
117785
|
-
}
|
|
117786
|
-
files.push(oldPath ? { path: filePath, status, diff, oldPath } : { path: filePath, status, diff });
|
|
117787
|
-
}
|
|
117788
|
-
fileDiffsCache.set(task.id, {
|
|
117789
|
-
files,
|
|
117790
|
-
expiresAt: Date.now() + 1e4
|
|
117791
|
-
});
|
|
117792
|
-
res.json(files);
|
|
117793
|
-
} catch (err) {
|
|
117794
|
-
if (err instanceof ApiError) {
|
|
117795
|
-
throw err;
|
|
117796
|
-
}
|
|
117797
|
-
if (err.code === "ENOENT") {
|
|
117798
|
-
throw notFound(`Task ${req.params.id} not found`);
|
|
117799
|
-
}
|
|
117800
|
-
rethrowAsApiError5(err, "Internal server error");
|
|
117801
|
-
}
|
|
117802
|
-
});
|
|
117803
117503
|
router.get("/project-files/md", async (req, res) => {
|
|
117804
117504
|
try {
|
|
117805
117505
|
const { store: scopedStore } = await getProjectContext3(req);
|
|
@@ -117815,14 +117515,11 @@ function registerFileWorkspaceRoutes(ctx, deps) {
|
|
|
117815
117515
|
}
|
|
117816
117516
|
});
|
|
117817
117517
|
}
|
|
117818
|
-
var sessionFilesCache, fileDiffsCache;
|
|
117819
117518
|
var init_register_file_workspace_routes = __esm({
|
|
117820
117519
|
"../dashboard/src/routes/register-file-workspace-routes.ts"() {
|
|
117821
117520
|
"use strict";
|
|
117822
117521
|
init_api_error();
|
|
117823
117522
|
init_file_service();
|
|
117824
|
-
sessionFilesCache = /* @__PURE__ */ new Map();
|
|
117825
|
-
fileDiffsCache = /* @__PURE__ */ new Map();
|
|
117826
117523
|
}
|
|
117827
117524
|
});
|
|
117828
117525
|
|
|
@@ -117840,7 +117537,7 @@ import { execFile as execFile5 } from "node:child_process";
|
|
|
117840
117537
|
import * as fsPromises from "node:fs/promises";
|
|
117841
117538
|
import { dirname as dirname12, isAbsolute as isAbsolute13, join as join39 } from "node:path";
|
|
117842
117539
|
import { promisify as promisify12 } from "node:util";
|
|
117843
|
-
var
|
|
117540
|
+
var access6, stat8, mkdir13, readdir9, rm2, execFileAsync3, registerProjectRoutes;
|
|
117844
117541
|
var init_register_project_routes = __esm({
|
|
117845
117542
|
"../dashboard/src/routes/register-project-routes.ts"() {
|
|
117846
117543
|
"use strict";
|
|
@@ -117848,7 +117545,7 @@ var init_register_project_routes = __esm({
|
|
|
117848
117545
|
init_api_error();
|
|
117849
117546
|
init_project_store_resolver();
|
|
117850
117547
|
({
|
|
117851
|
-
access:
|
|
117548
|
+
access: access6,
|
|
117852
117549
|
stat: stat8,
|
|
117853
117550
|
mkdir: mkdir13,
|
|
117854
117551
|
readdir: readdir9,
|
|
@@ -117975,14 +117672,14 @@ var init_register_project_routes = __esm({
|
|
|
117975
117672
|
let destinationCreatedForClone = false;
|
|
117976
117673
|
if (!isCloneMode) {
|
|
117977
117674
|
try {
|
|
117978
|
-
await
|
|
117675
|
+
await access6(normalizedPath);
|
|
117979
117676
|
} catch {
|
|
117980
117677
|
throw badRequest("Project path does not exist");
|
|
117981
117678
|
}
|
|
117982
117679
|
} else {
|
|
117983
117680
|
const destinationParent = dirname12(normalizedPath);
|
|
117984
117681
|
try {
|
|
117985
|
-
await
|
|
117682
|
+
await access6(destinationParent);
|
|
117986
117683
|
} catch {
|
|
117987
117684
|
throw badRequest("Clone destination parent directory does not exist");
|
|
117988
117685
|
}
|
|
@@ -118032,7 +117729,7 @@ var init_register_project_routes = __esm({
|
|
|
118032
117729
|
let hasFusionDir = false;
|
|
118033
117730
|
const fusionDirPath = join39(normalizedPath, ".fusion");
|
|
118034
117731
|
try {
|
|
118035
|
-
await
|
|
117732
|
+
await access6(fusionDirPath);
|
|
118036
117733
|
hasFusionDir = true;
|
|
118037
117734
|
} catch {
|
|
118038
117735
|
hasFusionDir = false;
|
|
@@ -118077,7 +117774,7 @@ var init_register_project_routes = __esm({
|
|
|
118077
117774
|
const { basePath } = req.body;
|
|
118078
117775
|
const searchPath = basePath || process.env.HOME || process.env.USERPROFILE || ".";
|
|
118079
117776
|
try {
|
|
118080
|
-
await
|
|
117777
|
+
await access6(searchPath);
|
|
118081
117778
|
} catch {
|
|
118082
117779
|
throw badRequest("Base path does not exist");
|
|
118083
117780
|
}
|
|
@@ -118096,14 +117793,14 @@ var init_register_project_routes = __esm({
|
|
|
118096
117793
|
let hasKbDb = false;
|
|
118097
117794
|
let hasFusionDir = false;
|
|
118098
117795
|
try {
|
|
118099
|
-
await
|
|
117796
|
+
await access6(join39(dirPath, ".fusion", "fusion.db"));
|
|
118100
117797
|
hasKbDb = true;
|
|
118101
117798
|
} catch {
|
|
118102
117799
|
hasKbDb = false;
|
|
118103
117800
|
}
|
|
118104
117801
|
if (!hasKbDb) {
|
|
118105
117802
|
try {
|
|
118106
|
-
await
|
|
117803
|
+
await access6(join39(dirPath, ".fusion"));
|
|
118107
117804
|
hasFusionDir = true;
|
|
118108
117805
|
} catch {
|
|
118109
117806
|
hasFusionDir = false;
|
|
@@ -121692,7 +121389,7 @@ ${body}`;
|
|
|
121692
121389
|
const skillDir = join40(skillsBaseDir, skillSlug);
|
|
121693
121390
|
const skillPath = join40(skillDir, "SKILL.md");
|
|
121694
121391
|
try {
|
|
121695
|
-
await
|
|
121392
|
+
await access7(skillPath);
|
|
121696
121393
|
result.skipped.push(name);
|
|
121697
121394
|
continue;
|
|
121698
121395
|
} catch {
|
|
@@ -122113,14 +121810,14 @@ function registerAgentGenerationRoutes(ctx) {
|
|
|
122113
121810
|
}
|
|
122114
121811
|
});
|
|
122115
121812
|
}
|
|
122116
|
-
var mkdtemp,
|
|
121813
|
+
var mkdtemp, access7, stat9, mkdir14, rm3, fsWriteFile2;
|
|
122117
121814
|
var init_register_agent_import_export_generation_routes = __esm({
|
|
122118
121815
|
"../dashboard/src/routes/register-agent-import-export-generation-routes.ts"() {
|
|
122119
121816
|
"use strict";
|
|
122120
121817
|
init_api_error();
|
|
122121
121818
|
init_ai_session_diagnostics();
|
|
122122
121819
|
init_agent_generation();
|
|
122123
|
-
({ mkdtemp, access:
|
|
121820
|
+
({ mkdtemp, access: access7, stat: stat9, mkdir: mkdir14, rm: rm3, writeFile: fsWriteFile2 } = fsPromises2);
|
|
122124
121821
|
}
|
|
122125
121822
|
});
|
|
122126
121823
|
|
|
@@ -127182,7 +126879,7 @@ Do NOT include any markdown formatting, code fences, or additional text. Only ou
|
|
|
127182
126879
|
// ../dashboard/src/roadmap-routes.ts
|
|
127183
126880
|
import { Router as Router4 } from "express";
|
|
127184
126881
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
127185
|
-
function
|
|
126882
|
+
function rethrowAsApiError3(error, fallbackMessage = "Internal server error") {
|
|
127186
126883
|
if (error instanceof ApiError) throw error;
|
|
127187
126884
|
if (error instanceof Error) throw new ApiError(500, error.message);
|
|
127188
126885
|
throw new ApiError(500, fallbackMessage);
|
|
@@ -127247,7 +126944,7 @@ function createRoadmapRouter(store) {
|
|
|
127247
126944
|
res.json(roadmaps);
|
|
127248
126945
|
} catch (err) {
|
|
127249
126946
|
if (err instanceof ApiError) throw err;
|
|
127250
|
-
|
|
126947
|
+
rethrowAsApiError3(err, "Failed to list roadmaps");
|
|
127251
126948
|
}
|
|
127252
126949
|
});
|
|
127253
126950
|
router.post("/", async (req, res) => {
|
|
@@ -127263,7 +126960,7 @@ function createRoadmapRouter(store) {
|
|
|
127263
126960
|
res.status(201).json(roadmap);
|
|
127264
126961
|
} catch (err) {
|
|
127265
126962
|
if (err instanceof ApiError) throw err;
|
|
127266
|
-
|
|
126963
|
+
rethrowAsApiError3(err, "Failed to create roadmap");
|
|
127267
126964
|
}
|
|
127268
126965
|
});
|
|
127269
126966
|
router.get("/:roadmapId", async (req, res) => {
|
|
@@ -127277,7 +126974,7 @@ function createRoadmapRouter(store) {
|
|
|
127277
126974
|
res.json(roadmap);
|
|
127278
126975
|
} catch (err) {
|
|
127279
126976
|
if (err instanceof ApiError) throw err;
|
|
127280
|
-
|
|
126977
|
+
rethrowAsApiError3(err, "Failed to get roadmap");
|
|
127281
126978
|
}
|
|
127282
126979
|
});
|
|
127283
126980
|
router.patch("/:roadmapId", async (req, res) => {
|
|
@@ -127292,7 +126989,7 @@ function createRoadmapRouter(store) {
|
|
|
127292
126989
|
res.json(roadmap);
|
|
127293
126990
|
} catch (err) {
|
|
127294
126991
|
if (err instanceof ApiError) throw err;
|
|
127295
|
-
|
|
126992
|
+
rethrowAsApiError3(err, "Failed to update roadmap");
|
|
127296
126993
|
}
|
|
127297
126994
|
});
|
|
127298
126995
|
router.delete("/:roadmapId", async (req, res) => {
|
|
@@ -127303,7 +127000,7 @@ function createRoadmapRouter(store) {
|
|
|
127303
127000
|
res.status(204).send();
|
|
127304
127001
|
} catch (err) {
|
|
127305
127002
|
if (err instanceof ApiError) throw err;
|
|
127306
|
-
|
|
127003
|
+
rethrowAsApiError3(err, "Failed to delete roadmap");
|
|
127307
127004
|
}
|
|
127308
127005
|
});
|
|
127309
127006
|
router.post("/:roadmapId/milestones", async (req, res) => {
|
|
@@ -127320,7 +127017,7 @@ function createRoadmapRouter(store) {
|
|
|
127320
127017
|
res.status(201).json(milestone);
|
|
127321
127018
|
} catch (err) {
|
|
127322
127019
|
if (err instanceof ApiError) throw err;
|
|
127323
|
-
|
|
127020
|
+
rethrowAsApiError3(err, "Failed to create milestone");
|
|
127324
127021
|
}
|
|
127325
127022
|
});
|
|
127326
127023
|
router.post("/:roadmapId/milestones/reorder", async (req, res) => {
|
|
@@ -127333,7 +127030,7 @@ function createRoadmapRouter(store) {
|
|
|
127333
127030
|
res.status(204).send();
|
|
127334
127031
|
} catch (err) {
|
|
127335
127032
|
if (err instanceof ApiError) throw err;
|
|
127336
|
-
|
|
127033
|
+
rethrowAsApiError3(err, "Failed to reorder milestones");
|
|
127337
127034
|
}
|
|
127338
127035
|
});
|
|
127339
127036
|
router.patch("/milestones/:milestoneId", async (req, res) => {
|
|
@@ -127348,7 +127045,7 @@ function createRoadmapRouter(store) {
|
|
|
127348
127045
|
res.json(milestone);
|
|
127349
127046
|
} catch (err) {
|
|
127350
127047
|
if (err instanceof ApiError) throw err;
|
|
127351
|
-
|
|
127048
|
+
rethrowAsApiError3(err, "Failed to update milestone");
|
|
127352
127049
|
}
|
|
127353
127050
|
});
|
|
127354
127051
|
router.delete("/milestones/:milestoneId", async (req, res) => {
|
|
@@ -127359,7 +127056,7 @@ function createRoadmapRouter(store) {
|
|
|
127359
127056
|
res.status(204).send();
|
|
127360
127057
|
} catch (err) {
|
|
127361
127058
|
if (err instanceof ApiError) throw err;
|
|
127362
|
-
|
|
127059
|
+
rethrowAsApiError3(err, "Failed to delete milestone");
|
|
127363
127060
|
}
|
|
127364
127061
|
});
|
|
127365
127062
|
router.post("/milestones/:milestoneId/features", async (req, res) => {
|
|
@@ -127376,7 +127073,7 @@ function createRoadmapRouter(store) {
|
|
|
127376
127073
|
res.status(201).json(feature);
|
|
127377
127074
|
} catch (err) {
|
|
127378
127075
|
if (err instanceof ApiError) throw err;
|
|
127379
|
-
|
|
127076
|
+
rethrowAsApiError3(err, "Failed to create feature");
|
|
127380
127077
|
}
|
|
127381
127078
|
});
|
|
127382
127079
|
router.post("/milestones/:milestoneId/features/reorder", async (req, res) => {
|
|
@@ -127397,7 +127094,7 @@ function createRoadmapRouter(store) {
|
|
|
127397
127094
|
res.status(204).send();
|
|
127398
127095
|
} catch (err) {
|
|
127399
127096
|
if (err instanceof ApiError) throw err;
|
|
127400
|
-
|
|
127097
|
+
rethrowAsApiError3(err, "Failed to reorder features");
|
|
127401
127098
|
}
|
|
127402
127099
|
});
|
|
127403
127100
|
router.patch("/features/:featureId", async (req, res) => {
|
|
@@ -127412,7 +127109,7 @@ function createRoadmapRouter(store) {
|
|
|
127412
127109
|
res.json(feature);
|
|
127413
127110
|
} catch (err) {
|
|
127414
127111
|
if (err instanceof ApiError) throw err;
|
|
127415
|
-
|
|
127112
|
+
rethrowAsApiError3(err, "Failed to update feature");
|
|
127416
127113
|
}
|
|
127417
127114
|
});
|
|
127418
127115
|
router.delete("/features/:featureId", async (req, res) => {
|
|
@@ -127423,7 +127120,7 @@ function createRoadmapRouter(store) {
|
|
|
127423
127120
|
res.status(204).send();
|
|
127424
127121
|
} catch (err) {
|
|
127425
127122
|
if (err instanceof ApiError) throw err;
|
|
127426
|
-
|
|
127123
|
+
rethrowAsApiError3(err, "Failed to delete feature");
|
|
127427
127124
|
}
|
|
127428
127125
|
});
|
|
127429
127126
|
router.post("/features/:featureId/move", async (req, res) => {
|
|
@@ -127459,7 +127156,7 @@ function createRoadmapRouter(store) {
|
|
|
127459
127156
|
res.status(204).send();
|
|
127460
127157
|
} catch (err) {
|
|
127461
127158
|
if (err instanceof ApiError) throw err;
|
|
127462
|
-
|
|
127159
|
+
rethrowAsApiError3(err, "Failed to move feature");
|
|
127463
127160
|
}
|
|
127464
127161
|
});
|
|
127465
127162
|
router.post("/:roadmapId/suggestions/milestones", async (req, res) => {
|
|
@@ -127510,7 +127207,7 @@ function createRoadmapRouter(store) {
|
|
|
127510
127207
|
}
|
|
127511
127208
|
} catch (err) {
|
|
127512
127209
|
if (err instanceof ApiError) throw err;
|
|
127513
|
-
|
|
127210
|
+
rethrowAsApiError3(err, "Failed to generate milestone suggestions");
|
|
127514
127211
|
} finally {
|
|
127515
127212
|
if (routeTimeoutId) clearTimeout(routeTimeoutId);
|
|
127516
127213
|
}
|
|
@@ -127577,7 +127274,7 @@ function createRoadmapRouter(store) {
|
|
|
127577
127274
|
}
|
|
127578
127275
|
} catch (err) {
|
|
127579
127276
|
if (err instanceof ApiError) throw err;
|
|
127580
|
-
|
|
127277
|
+
rethrowAsApiError3(err, "Failed to generate feature suggestions");
|
|
127581
127278
|
} finally {
|
|
127582
127279
|
if (routeTimeoutId) clearTimeout(routeTimeoutId);
|
|
127583
127280
|
}
|
|
@@ -127590,7 +127287,7 @@ function createRoadmapRouter(store) {
|
|
|
127590
127287
|
res.json(export_);
|
|
127591
127288
|
} catch (err) {
|
|
127592
127289
|
if (err instanceof ApiError) throw err;
|
|
127593
|
-
|
|
127290
|
+
rethrowAsApiError3(err, "Failed to export roadmap");
|
|
127594
127291
|
}
|
|
127595
127292
|
});
|
|
127596
127293
|
router.get("/:roadmapId/handoff", async (req, res) => {
|
|
@@ -127608,7 +127305,7 @@ function createRoadmapRouter(store) {
|
|
|
127608
127305
|
if (err instanceof Error && err.message.includes("not found")) {
|
|
127609
127306
|
throw notFound(err.message);
|
|
127610
127307
|
}
|
|
127611
|
-
|
|
127308
|
+
rethrowAsApiError3(err, "Failed to generate handoff");
|
|
127612
127309
|
}
|
|
127613
127310
|
});
|
|
127614
127311
|
router.get("/:roadmapId/handoff/mission", async (req, res) => {
|
|
@@ -127622,7 +127319,7 @@ function createRoadmapRouter(store) {
|
|
|
127622
127319
|
if (err instanceof Error && err.message.includes("not found")) {
|
|
127623
127320
|
throw notFound(err.message);
|
|
127624
127321
|
}
|
|
127625
|
-
|
|
127322
|
+
rethrowAsApiError3(err, "Failed to generate mission handoff");
|
|
127626
127323
|
}
|
|
127627
127324
|
});
|
|
127628
127325
|
router.get("/:roadmapId/milestones/:milestoneId/features/:featureId/handoff/task", async (req, res) => {
|
|
@@ -127633,7 +127330,7 @@ function createRoadmapRouter(store) {
|
|
|
127633
127330
|
res.json(handoff);
|
|
127634
127331
|
} catch (err) {
|
|
127635
127332
|
if (err instanceof ApiError) throw err;
|
|
127636
|
-
|
|
127333
|
+
rethrowAsApiError3(err, "Failed to generate task handoff");
|
|
127637
127334
|
}
|
|
127638
127335
|
});
|
|
127639
127336
|
return router;
|
|
@@ -127650,7 +127347,7 @@ var init_roadmap_routes = __esm({
|
|
|
127650
127347
|
// ../dashboard/src/insights-routes.ts
|
|
127651
127348
|
import { Router as Router5 } from "express";
|
|
127652
127349
|
import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
|
|
127653
|
-
function
|
|
127350
|
+
function rethrowAsApiError4(error, fallbackMessage = "Internal server error") {
|
|
127654
127351
|
if (error instanceof ApiError) throw error;
|
|
127655
127352
|
if (error instanceof Error) throw new ApiError(500, error.message);
|
|
127656
127353
|
throw new ApiError(500, fallbackMessage);
|
|
@@ -127686,7 +127383,7 @@ function createInsightsRouter(store) {
|
|
|
127686
127383
|
next();
|
|
127687
127384
|
});
|
|
127688
127385
|
}).catch((err) => {
|
|
127689
|
-
|
|
127386
|
+
rethrowAsApiError4(err, "Failed to get project store");
|
|
127690
127387
|
});
|
|
127691
127388
|
});
|
|
127692
127389
|
} else {
|
|
@@ -127741,7 +127438,7 @@ function createInsightsRouter(store) {
|
|
|
127741
127438
|
const count = store2.countInsights(options);
|
|
127742
127439
|
res.json({ insights, count });
|
|
127743
127440
|
} catch (error) {
|
|
127744
|
-
|
|
127441
|
+
rethrowAsApiError4(error, "Failed to list insights");
|
|
127745
127442
|
}
|
|
127746
127443
|
});
|
|
127747
127444
|
router.post("/run", async (req, res) => {
|
|
@@ -127856,7 +127553,7 @@ function createInsightsRouter(store) {
|
|
|
127856
127553
|
throw err;
|
|
127857
127554
|
}
|
|
127858
127555
|
} catch (error) {
|
|
127859
|
-
|
|
127556
|
+
rethrowAsApiError4(error, "Failed to create insight run");
|
|
127860
127557
|
}
|
|
127861
127558
|
});
|
|
127862
127559
|
router.get("/runs", (req, res) => {
|
|
@@ -127865,7 +127562,7 @@ function createInsightsRouter(store) {
|
|
|
127865
127562
|
const runs = store2.listRuns({});
|
|
127866
127563
|
res.json({ runs });
|
|
127867
127564
|
} catch (error) {
|
|
127868
|
-
|
|
127565
|
+
rethrowAsApiError4(error, "Failed to list runs");
|
|
127869
127566
|
}
|
|
127870
127567
|
});
|
|
127871
127568
|
router.get("/runs/:id", (req, res) => {
|
|
@@ -127878,7 +127575,7 @@ function createInsightsRouter(store) {
|
|
|
127878
127575
|
}
|
|
127879
127576
|
res.json(run);
|
|
127880
127577
|
} catch (error) {
|
|
127881
|
-
|
|
127578
|
+
rethrowAsApiError4(error, "Failed to get run");
|
|
127882
127579
|
}
|
|
127883
127580
|
});
|
|
127884
127581
|
router.get("/:id", (req, res) => {
|
|
@@ -127891,7 +127588,7 @@ function createInsightsRouter(store) {
|
|
|
127891
127588
|
}
|
|
127892
127589
|
res.json(insight);
|
|
127893
127590
|
} catch (error) {
|
|
127894
|
-
|
|
127591
|
+
rethrowAsApiError4(error, "Failed to get insight");
|
|
127895
127592
|
}
|
|
127896
127593
|
});
|
|
127897
127594
|
router.patch("/:id", (req, res) => {
|
|
@@ -127923,7 +127620,7 @@ function createInsightsRouter(store) {
|
|
|
127923
127620
|
}
|
|
127924
127621
|
res.json(insight);
|
|
127925
127622
|
} catch (error) {
|
|
127926
|
-
|
|
127623
|
+
rethrowAsApiError4(error, "Failed to update insight");
|
|
127927
127624
|
}
|
|
127928
127625
|
});
|
|
127929
127626
|
router.delete("/:id", (req, res) => {
|
|
@@ -127936,7 +127633,7 @@ function createInsightsRouter(store) {
|
|
|
127936
127633
|
}
|
|
127937
127634
|
res.status(204).send();
|
|
127938
127635
|
} catch (error) {
|
|
127939
|
-
|
|
127636
|
+
rethrowAsApiError4(error, "Failed to delete insight");
|
|
127940
127637
|
}
|
|
127941
127638
|
});
|
|
127942
127639
|
router.post("/:id/dismiss", (req, res) => {
|
|
@@ -127949,7 +127646,7 @@ function createInsightsRouter(store) {
|
|
|
127949
127646
|
}
|
|
127950
127647
|
res.json(insight);
|
|
127951
127648
|
} catch (error) {
|
|
127952
|
-
|
|
127649
|
+
rethrowAsApiError4(error, "Failed to dismiss insight");
|
|
127953
127650
|
}
|
|
127954
127651
|
});
|
|
127955
127652
|
router.post("/:id/create-task", (req, res) => {
|
|
@@ -127967,7 +127664,7 @@ function createInsightsRouter(store) {
|
|
|
127967
127664
|
suggestedDescription: insight.content ?? ""
|
|
127968
127665
|
});
|
|
127969
127666
|
} catch (error) {
|
|
127970
|
-
|
|
127667
|
+
rethrowAsApiError4(error, "Failed to create task from insight");
|
|
127971
127668
|
}
|
|
127972
127669
|
});
|
|
127973
127670
|
return router;
|
|
@@ -129166,6 +128863,606 @@ var init_register_integrated_routers = __esm({
|
|
|
129166
128863
|
}
|
|
129167
128864
|
});
|
|
129168
128865
|
|
|
128866
|
+
// ../dashboard/src/routes/register-terminal-routes.ts
|
|
128867
|
+
function registerTerminalRoutes(router, deps) {
|
|
128868
|
+
const { getProjectContext: getProjectContext3, terminalSessionManager: terminalSessionManager2, getTerminalService: getTerminalService2 } = deps;
|
|
128869
|
+
router.post("/terminal/exec", async (req, res) => {
|
|
128870
|
+
try {
|
|
128871
|
+
const { command } = req.body;
|
|
128872
|
+
if (!command || typeof command !== "string") {
|
|
128873
|
+
throw badRequest("command is required and must be a string");
|
|
128874
|
+
}
|
|
128875
|
+
if (command.length > 4096) {
|
|
128876
|
+
throw badRequest("command exceeds maximum length of 4096 characters");
|
|
128877
|
+
}
|
|
128878
|
+
const { store: scopedStore } = await getProjectContext3(req);
|
|
128879
|
+
const rootDir = scopedStore.getRootDir();
|
|
128880
|
+
const result = terminalSessionManager2.createSession(command, rootDir);
|
|
128881
|
+
if (result.error) {
|
|
128882
|
+
throw new ApiError(403, result.error);
|
|
128883
|
+
}
|
|
128884
|
+
res.status(201).json({ sessionId: result.sessionId });
|
|
128885
|
+
} catch (err) {
|
|
128886
|
+
if (err instanceof ApiError) {
|
|
128887
|
+
throw err;
|
|
128888
|
+
}
|
|
128889
|
+
rethrowAsApiError(err, "Failed to execute command");
|
|
128890
|
+
}
|
|
128891
|
+
});
|
|
128892
|
+
router.post("/terminal/sessions/:id/kill", (req, res) => {
|
|
128893
|
+
try {
|
|
128894
|
+
const { id } = req.params;
|
|
128895
|
+
const { signal } = req.body;
|
|
128896
|
+
const validSignals = ["SIGTERM", "SIGKILL", "SIGINT"];
|
|
128897
|
+
const killSignal = validSignals.includes(signal) ? signal : "SIGTERM";
|
|
128898
|
+
const killed = terminalSessionManager2.killSession(id, killSignal);
|
|
128899
|
+
if (!killed) {
|
|
128900
|
+
const session = terminalSessionManager2.getSession(id);
|
|
128901
|
+
if (!session) {
|
|
128902
|
+
throw notFound("Session not found");
|
|
128903
|
+
}
|
|
128904
|
+
throw badRequest("Session is not running");
|
|
128905
|
+
}
|
|
128906
|
+
res.json({ killed: true, sessionId: id });
|
|
128907
|
+
} catch (err) {
|
|
128908
|
+
if (err instanceof ApiError) {
|
|
128909
|
+
throw err;
|
|
128910
|
+
}
|
|
128911
|
+
rethrowAsApiError(err);
|
|
128912
|
+
}
|
|
128913
|
+
});
|
|
128914
|
+
router.get("/terminal/sessions/:id", (req, res) => {
|
|
128915
|
+
try {
|
|
128916
|
+
const session = terminalSessionManager2.getSession(req.params.id);
|
|
128917
|
+
if (!session) {
|
|
128918
|
+
throw notFound("Session not found");
|
|
128919
|
+
}
|
|
128920
|
+
res.json({
|
|
128921
|
+
id: session.id,
|
|
128922
|
+
command: session.command,
|
|
128923
|
+
running: session.exitCode === null && !session.killed,
|
|
128924
|
+
exitCode: session.exitCode,
|
|
128925
|
+
output: session.output.join(""),
|
|
128926
|
+
startTime: session.startTime.toISOString()
|
|
128927
|
+
});
|
|
128928
|
+
} catch (err) {
|
|
128929
|
+
if (err instanceof ApiError) {
|
|
128930
|
+
throw err;
|
|
128931
|
+
}
|
|
128932
|
+
rethrowAsApiError(err);
|
|
128933
|
+
}
|
|
128934
|
+
});
|
|
128935
|
+
router.get("/terminal/sessions/:id/stream", (req, res) => {
|
|
128936
|
+
try {
|
|
128937
|
+
const { id } = req.params;
|
|
128938
|
+
const session = terminalSessionManager2.getSession(id);
|
|
128939
|
+
if (!session) {
|
|
128940
|
+
throw notFound("Session not found");
|
|
128941
|
+
}
|
|
128942
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
128943
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
128944
|
+
res.setHeader("Connection", "keep-alive");
|
|
128945
|
+
res.setHeader("X-Accel-Buffering", "no");
|
|
128946
|
+
res.write(`event: connected
|
|
128947
|
+
data: ${JSON.stringify({ sessionId: id })}
|
|
128948
|
+
|
|
128949
|
+
`);
|
|
128950
|
+
const onOutput = (event) => {
|
|
128951
|
+
if (event.sessionId !== id) return;
|
|
128952
|
+
const eventName = event.type === "exit" ? "terminal:exit" : "terminal:output";
|
|
128953
|
+
const data = JSON.stringify({
|
|
128954
|
+
type: event.type,
|
|
128955
|
+
data: event.data,
|
|
128956
|
+
...event.exitCode !== void 0 && { exitCode: event.exitCode }
|
|
128957
|
+
});
|
|
128958
|
+
res.write(`event: ${eventName}
|
|
128959
|
+
data: ${data}
|
|
128960
|
+
|
|
128961
|
+
`);
|
|
128962
|
+
if (event.type === "exit") {
|
|
128963
|
+
setTimeout(() => {
|
|
128964
|
+
res.end();
|
|
128965
|
+
}, 100);
|
|
128966
|
+
}
|
|
128967
|
+
};
|
|
128968
|
+
terminalSessionManager2.on("output", onOutput);
|
|
128969
|
+
req.on("close", () => {
|
|
128970
|
+
terminalSessionManager2.off("output", onOutput);
|
|
128971
|
+
});
|
|
128972
|
+
req.on("error", () => {
|
|
128973
|
+
terminalSessionManager2.off("output", onOutput);
|
|
128974
|
+
});
|
|
128975
|
+
} catch (err) {
|
|
128976
|
+
if (err instanceof ApiError) {
|
|
128977
|
+
throw err;
|
|
128978
|
+
}
|
|
128979
|
+
rethrowAsApiError(err);
|
|
128980
|
+
}
|
|
128981
|
+
});
|
|
128982
|
+
router.post("/terminal/sessions", async (req, res) => {
|
|
128983
|
+
try {
|
|
128984
|
+
const { cwd, cols, rows } = req.body;
|
|
128985
|
+
const { store: scopedStore } = await getProjectContext3(req);
|
|
128986
|
+
const terminalService = getTerminalService2(scopedStore.getRootDir());
|
|
128987
|
+
const result = await terminalService.createSession({
|
|
128988
|
+
cwd,
|
|
128989
|
+
cols: typeof cols === "number" ? cols : void 0,
|
|
128990
|
+
rows: typeof rows === "number" ? rows : void 0
|
|
128991
|
+
});
|
|
128992
|
+
if (!result.success) {
|
|
128993
|
+
const statusByCode = {
|
|
128994
|
+
max_sessions: 503,
|
|
128995
|
+
invalid_shell: 400,
|
|
128996
|
+
pty_load_failed: 503,
|
|
128997
|
+
pty_spawn_failed: 500
|
|
128998
|
+
};
|
|
128999
|
+
throw new ApiError(statusByCode[result.code], result.error, { code: result.code });
|
|
129000
|
+
}
|
|
129001
|
+
res.status(201).json({
|
|
129002
|
+
sessionId: result.session.id,
|
|
129003
|
+
shell: result.session.shell,
|
|
129004
|
+
cwd: result.session.cwd
|
|
129005
|
+
});
|
|
129006
|
+
} catch (err) {
|
|
129007
|
+
if (err instanceof ApiError) {
|
|
129008
|
+
throw err;
|
|
129009
|
+
}
|
|
129010
|
+
rethrowAsApiError(err, "Failed to create terminal session");
|
|
129011
|
+
}
|
|
129012
|
+
});
|
|
129013
|
+
router.get("/terminal/sessions", async (req, res) => {
|
|
129014
|
+
try {
|
|
129015
|
+
const { store: scopedStore } = await getProjectContext3(req);
|
|
129016
|
+
const terminalService = getTerminalService2(scopedStore.getRootDir());
|
|
129017
|
+
const sessions6 = terminalService.getAllSessions();
|
|
129018
|
+
res.json(
|
|
129019
|
+
sessions6.map((session) => ({
|
|
129020
|
+
id: session.id,
|
|
129021
|
+
cwd: session.cwd,
|
|
129022
|
+
shell: session.shell,
|
|
129023
|
+
createdAt: session.createdAt.toISOString(),
|
|
129024
|
+
lastActivityAt: session.lastActivityAt.toISOString()
|
|
129025
|
+
}))
|
|
129026
|
+
);
|
|
129027
|
+
} catch (err) {
|
|
129028
|
+
if (err instanceof ApiError) {
|
|
129029
|
+
throw err;
|
|
129030
|
+
}
|
|
129031
|
+
rethrowAsApiError(err, "Failed to list sessions");
|
|
129032
|
+
}
|
|
129033
|
+
});
|
|
129034
|
+
router.delete("/terminal/sessions/:id", async (req, res) => {
|
|
129035
|
+
try {
|
|
129036
|
+
const { id } = req.params;
|
|
129037
|
+
const { store: scopedStore } = await getProjectContext3(req);
|
|
129038
|
+
const terminalService = getTerminalService2(scopedStore.getRootDir());
|
|
129039
|
+
const killed = terminalService.killSession(id);
|
|
129040
|
+
if (!killed) {
|
|
129041
|
+
const session = terminalService.getSession(id);
|
|
129042
|
+
if (!session) {
|
|
129043
|
+
throw notFound("Session not found");
|
|
129044
|
+
}
|
|
129045
|
+
throw badRequest("Failed to kill session");
|
|
129046
|
+
}
|
|
129047
|
+
res.json({ killed: true });
|
|
129048
|
+
} catch (err) {
|
|
129049
|
+
if (err instanceof ApiError) {
|
|
129050
|
+
throw err;
|
|
129051
|
+
}
|
|
129052
|
+
rethrowAsApiError(err);
|
|
129053
|
+
}
|
|
129054
|
+
});
|
|
129055
|
+
}
|
|
129056
|
+
var init_register_terminal_routes = __esm({
|
|
129057
|
+
"../dashboard/src/routes/register-terminal-routes.ts"() {
|
|
129058
|
+
"use strict";
|
|
129059
|
+
init_api_error();
|
|
129060
|
+
}
|
|
129061
|
+
});
|
|
129062
|
+
|
|
129063
|
+
// ../dashboard/src/routes/register-session-diff-routes.ts
|
|
129064
|
+
import { access as access8 } from "node:fs/promises";
|
|
129065
|
+
function registerSessionDiffRoutes(router, deps) {
|
|
129066
|
+
const { getProjectContext: getProjectContext3 } = deps;
|
|
129067
|
+
router.get("/tasks/:id/session-files", async (req, res) => {
|
|
129068
|
+
try {
|
|
129069
|
+
const { store: scopedStore } = await getProjectContext3(req);
|
|
129070
|
+
const task = await scopedStore.getTask(req.params.id);
|
|
129071
|
+
if (!task) {
|
|
129072
|
+
res.status(404).json({ error: "Task not found" });
|
|
129073
|
+
return;
|
|
129074
|
+
}
|
|
129075
|
+
if (!task.worktree) {
|
|
129076
|
+
res.json([]);
|
|
129077
|
+
return;
|
|
129078
|
+
}
|
|
129079
|
+
let worktreeExists = false;
|
|
129080
|
+
try {
|
|
129081
|
+
await access8(task.worktree);
|
|
129082
|
+
worktreeExists = true;
|
|
129083
|
+
} catch {
|
|
129084
|
+
worktreeExists = false;
|
|
129085
|
+
}
|
|
129086
|
+
if (!worktreeExists) {
|
|
129087
|
+
res.json([]);
|
|
129088
|
+
return;
|
|
129089
|
+
}
|
|
129090
|
+
const worktree = task.worktree;
|
|
129091
|
+
const cached = sessionFilesCache.get(task.id);
|
|
129092
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
129093
|
+
res.json(cached.files);
|
|
129094
|
+
return;
|
|
129095
|
+
}
|
|
129096
|
+
let files = [];
|
|
129097
|
+
try {
|
|
129098
|
+
const fileSet = /* @__PURE__ */ new Set();
|
|
129099
|
+
const baseRef = await resolveDiffBase(task, worktree);
|
|
129100
|
+
if (baseRef) {
|
|
129101
|
+
const committedOutput = (await runGitCommand(["diff", "--name-only", `${baseRef}..HEAD`], worktree, 5e3)).trim();
|
|
129102
|
+
for (const file of committedOutput.split("\n").filter(Boolean)) {
|
|
129103
|
+
fileSet.add(file);
|
|
129104
|
+
}
|
|
129105
|
+
}
|
|
129106
|
+
const stagedOutput = (await runGitCommand(["diff", "--cached", "--name-only"], worktree, 5e3)).trim();
|
|
129107
|
+
for (const file of stagedOutput.split("\n").filter(Boolean)) {
|
|
129108
|
+
fileSet.add(file);
|
|
129109
|
+
}
|
|
129110
|
+
const workingTreeOutput = (await runGitCommand(["diff", "--name-only"], worktree, 5e3)).trim();
|
|
129111
|
+
for (const file of workingTreeOutput.split("\n").filter(Boolean)) {
|
|
129112
|
+
fileSet.add(file);
|
|
129113
|
+
}
|
|
129114
|
+
const untrackedOutput = (await runGitCommand(["ls-files", "--others", "--exclude-standard"], worktree, 5e3)).trim();
|
|
129115
|
+
for (const file of untrackedOutput.split("\n").filter(Boolean)) {
|
|
129116
|
+
fileSet.add(file);
|
|
129117
|
+
}
|
|
129118
|
+
files = Array.from(fileSet);
|
|
129119
|
+
} catch {
|
|
129120
|
+
files = [];
|
|
129121
|
+
}
|
|
129122
|
+
sessionFilesCache.set(task.id, {
|
|
129123
|
+
files,
|
|
129124
|
+
expiresAt: Date.now() + 1e4
|
|
129125
|
+
});
|
|
129126
|
+
res.json(files);
|
|
129127
|
+
} catch (err) {
|
|
129128
|
+
if (err instanceof ApiError) {
|
|
129129
|
+
throw err;
|
|
129130
|
+
}
|
|
129131
|
+
if (err.code === "ENOENT") {
|
|
129132
|
+
throw notFound(`Task ${req.params.id} not found`);
|
|
129133
|
+
}
|
|
129134
|
+
rethrowAsApiError(err, "Internal server error");
|
|
129135
|
+
}
|
|
129136
|
+
});
|
|
129137
|
+
router.get("/tasks/:id/diff", async (req, res) => {
|
|
129138
|
+
try {
|
|
129139
|
+
const { store: scopedStore } = await getProjectContext3(req);
|
|
129140
|
+
const task = await scopedStore.getTask(req.params.id);
|
|
129141
|
+
if (!task) {
|
|
129142
|
+
res.status(404).json({ error: "Task not found" });
|
|
129143
|
+
return;
|
|
129144
|
+
}
|
|
129145
|
+
if (task.column === "done" && task.mergeDetails?.commitSha) {
|
|
129146
|
+
const rootDir = scopedStore.getRootDir();
|
|
129147
|
+
const sha = task.mergeDetails.commitSha;
|
|
129148
|
+
let mergeBase;
|
|
129149
|
+
try {
|
|
129150
|
+
mergeBase = (await runGitCommand(["rev-parse", `${sha}^`], rootDir, 5e3)).trim();
|
|
129151
|
+
} catch {
|
|
129152
|
+
res.json({ files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 } });
|
|
129153
|
+
return;
|
|
129154
|
+
}
|
|
129155
|
+
const nameStatus = (await runGitCommand(["diff", "--name-status", `${mergeBase}..${sha}`], rootDir, 1e4)).trim();
|
|
129156
|
+
const doneFiles = [];
|
|
129157
|
+
for (const line of nameStatus.split("\n").filter(Boolean)) {
|
|
129158
|
+
const parts = line.split(" ");
|
|
129159
|
+
const statusCode = parts[0] ?? "M";
|
|
129160
|
+
const filePath = parts[1] ?? "";
|
|
129161
|
+
if (!filePath) continue;
|
|
129162
|
+
let status = "modified";
|
|
129163
|
+
if (statusCode.startsWith("A")) status = "added";
|
|
129164
|
+
else if (statusCode.startsWith("D")) status = "deleted";
|
|
129165
|
+
let patch = "";
|
|
129166
|
+
try {
|
|
129167
|
+
patch = await runGitCommand(["diff", `${mergeBase}..${sha}`, "--", filePath], rootDir, 1e4);
|
|
129168
|
+
} catch {
|
|
129169
|
+
}
|
|
129170
|
+
const additions = (patch.match(/^\+[^+]/gm) || []).length;
|
|
129171
|
+
const deletions = (patch.match(/^-[^-]/gm) || []).length;
|
|
129172
|
+
doneFiles.push({ path: filePath, status, additions, deletions, patch });
|
|
129173
|
+
}
|
|
129174
|
+
const doneStats = {
|
|
129175
|
+
filesChanged: doneFiles.length,
|
|
129176
|
+
additions: doneFiles.reduce((s, f) => s + f.additions, 0),
|
|
129177
|
+
deletions: doneFiles.reduce((s, f) => s + f.deletions, 0)
|
|
129178
|
+
};
|
|
129179
|
+
res.json({ files: doneFiles, stats: doneStats });
|
|
129180
|
+
return;
|
|
129181
|
+
}
|
|
129182
|
+
if (task.column === "done") {
|
|
129183
|
+
const md = task.mergeDetails;
|
|
129184
|
+
res.json({
|
|
129185
|
+
files: [],
|
|
129186
|
+
stats: {
|
|
129187
|
+
filesChanged: md?.filesChanged ?? 0,
|
|
129188
|
+
additions: md?.insertions ?? 0,
|
|
129189
|
+
deletions: md?.deletions ?? 0
|
|
129190
|
+
}
|
|
129191
|
+
});
|
|
129192
|
+
return;
|
|
129193
|
+
}
|
|
129194
|
+
const worktree = typeof req.query.worktree === "string" ? req.query.worktree : void 0;
|
|
129195
|
+
const resolvedWorktree = worktree || task.worktree;
|
|
129196
|
+
if (!resolvedWorktree) {
|
|
129197
|
+
res.json({ files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 } });
|
|
129198
|
+
return;
|
|
129199
|
+
}
|
|
129200
|
+
let worktreeExists = false;
|
|
129201
|
+
try {
|
|
129202
|
+
await access8(resolvedWorktree);
|
|
129203
|
+
worktreeExists = true;
|
|
129204
|
+
} catch {
|
|
129205
|
+
worktreeExists = false;
|
|
129206
|
+
}
|
|
129207
|
+
if (!worktreeExists) {
|
|
129208
|
+
res.json({ files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 } });
|
|
129209
|
+
return;
|
|
129210
|
+
}
|
|
129211
|
+
const cwd = resolvedWorktree;
|
|
129212
|
+
const diffBase = await resolveDiffBase(task, cwd);
|
|
129213
|
+
const diffRange = diffBase ? `${diffBase}..HEAD` : "HEAD";
|
|
129214
|
+
const fileMap = /* @__PURE__ */ new Map();
|
|
129215
|
+
if (diffBase) {
|
|
129216
|
+
try {
|
|
129217
|
+
const committedOutput = (await runGitCommand(["diff", "--name-status", `${diffBase}..HEAD`], cwd, 1e4)).trim();
|
|
129218
|
+
for (const line of committedOutput.split("\n").filter(Boolean)) {
|
|
129219
|
+
const parts = line.split(" ");
|
|
129220
|
+
fileMap.set(parts[1] ?? "", parts[0] ?? "M");
|
|
129221
|
+
}
|
|
129222
|
+
} catch {
|
|
129223
|
+
}
|
|
129224
|
+
}
|
|
129225
|
+
try {
|
|
129226
|
+
const stagedOutput = (await runGitCommand(["diff", "--cached", "--name-status"], cwd, 1e4)).trim();
|
|
129227
|
+
for (const line of stagedOutput.split("\n").filter(Boolean)) {
|
|
129228
|
+
const parts = line.split(" ");
|
|
129229
|
+
const filePath = parts[1] ?? "";
|
|
129230
|
+
if (filePath && !fileMap.has(filePath)) {
|
|
129231
|
+
fileMap.set(filePath, parts[0] ?? "M");
|
|
129232
|
+
}
|
|
129233
|
+
}
|
|
129234
|
+
} catch {
|
|
129235
|
+
}
|
|
129236
|
+
try {
|
|
129237
|
+
const workingTreeOutput = (await runGitCommand(["diff", "--name-status"], cwd, 1e4)).trim();
|
|
129238
|
+
for (const line of workingTreeOutput.split("\n").filter(Boolean)) {
|
|
129239
|
+
const parts = line.split(" ");
|
|
129240
|
+
const filePath = parts[1] ?? "";
|
|
129241
|
+
if (filePath && !fileMap.has(filePath)) {
|
|
129242
|
+
fileMap.set(filePath, parts[0] ?? "M");
|
|
129243
|
+
}
|
|
129244
|
+
}
|
|
129245
|
+
} catch {
|
|
129246
|
+
}
|
|
129247
|
+
try {
|
|
129248
|
+
const untrackedOutput = (await runGitCommand(["ls-files", "--others", "--exclude-standard"], cwd, 1e4)).trim();
|
|
129249
|
+
for (const line of untrackedOutput.split("\n").filter(Boolean)) {
|
|
129250
|
+
fileMap.set(line, "U");
|
|
129251
|
+
}
|
|
129252
|
+
} catch {
|
|
129253
|
+
}
|
|
129254
|
+
const files = [];
|
|
129255
|
+
for (const [filePath, statusCode] of fileMap) {
|
|
129256
|
+
if (!filePath) continue;
|
|
129257
|
+
let status;
|
|
129258
|
+
if (statusCode.startsWith("A") || statusCode === "U") status = "added";
|
|
129259
|
+
else if (statusCode.startsWith("D")) status = "deleted";
|
|
129260
|
+
else status = "modified";
|
|
129261
|
+
let patch = "";
|
|
129262
|
+
try {
|
|
129263
|
+
if (statusCode === "U") {
|
|
129264
|
+
patch = await runGitCommand(["diff", "--no-index", "/dev/null", filePath], cwd, 1e4).catch(() => "");
|
|
129265
|
+
} else {
|
|
129266
|
+
patch = await runGitCommand(["diff", diffRange, "--", filePath], cwd, 1e4);
|
|
129267
|
+
}
|
|
129268
|
+
} catch {
|
|
129269
|
+
}
|
|
129270
|
+
const additions = (patch.match(/^\+[^+]/gm) || []).length;
|
|
129271
|
+
const deletions = (patch.match(/^-[^-]/gm) || []).length;
|
|
129272
|
+
files.push({ path: filePath, status, additions, deletions, patch });
|
|
129273
|
+
}
|
|
129274
|
+
const stats = {
|
|
129275
|
+
filesChanged: files.length,
|
|
129276
|
+
additions: files.reduce((sum, f) => sum + f.additions, 0),
|
|
129277
|
+
deletions: files.reduce((sum, f) => sum + f.deletions, 0)
|
|
129278
|
+
};
|
|
129279
|
+
res.json({ files, stats });
|
|
129280
|
+
} catch (err) {
|
|
129281
|
+
if (err instanceof ApiError) {
|
|
129282
|
+
throw err;
|
|
129283
|
+
}
|
|
129284
|
+
rethrowAsApiError(err);
|
|
129285
|
+
}
|
|
129286
|
+
});
|
|
129287
|
+
router.get("/tasks/:id/file-diffs", async (req, res) => {
|
|
129288
|
+
try {
|
|
129289
|
+
const { store: scopedStore } = await getProjectContext3(req);
|
|
129290
|
+
const task = await scopedStore.getTask(req.params.id);
|
|
129291
|
+
if (!task) {
|
|
129292
|
+
res.status(404).json({ error: "Task not found" });
|
|
129293
|
+
return;
|
|
129294
|
+
}
|
|
129295
|
+
if (task.column === "done" && task.mergeDetails?.commitSha) {
|
|
129296
|
+
const rootDir = scopedStore.getRootDir();
|
|
129297
|
+
const sha = task.mergeDetails.commitSha;
|
|
129298
|
+
let mergeBase;
|
|
129299
|
+
try {
|
|
129300
|
+
mergeBase = (await runGitCommand(["rev-parse", `${sha}^`], rootDir, 5e3)).trim();
|
|
129301
|
+
} catch {
|
|
129302
|
+
res.json([]);
|
|
129303
|
+
return;
|
|
129304
|
+
}
|
|
129305
|
+
try {
|
|
129306
|
+
const nameStatus = (await runGitCommand(["diff", "--name-status", `${mergeBase}..${sha}`], rootDir, 5e3)).trim();
|
|
129307
|
+
const doneFiles = [];
|
|
129308
|
+
for (const line of nameStatus.split("\n").filter(Boolean)) {
|
|
129309
|
+
const parts = line.split(" ");
|
|
129310
|
+
const statusCode = parts[0] ?? "M";
|
|
129311
|
+
const filePath = parts[1] ?? "";
|
|
129312
|
+
let status = "modified";
|
|
129313
|
+
if (statusCode.startsWith("A")) status = "added";
|
|
129314
|
+
else if (statusCode.startsWith("D")) status = "deleted";
|
|
129315
|
+
else if (statusCode.startsWith("R")) status = "renamed";
|
|
129316
|
+
let diff = "";
|
|
129317
|
+
try {
|
|
129318
|
+
diff = await runGitCommand(["diff", `${mergeBase}..${sha}`, "--", filePath], rootDir, 5e3);
|
|
129319
|
+
} catch {
|
|
129320
|
+
}
|
|
129321
|
+
doneFiles.push({ path: filePath, status, diff });
|
|
129322
|
+
}
|
|
129323
|
+
res.json(doneFiles);
|
|
129324
|
+
} catch {
|
|
129325
|
+
res.json([]);
|
|
129326
|
+
}
|
|
129327
|
+
return;
|
|
129328
|
+
}
|
|
129329
|
+
if (task.column === "done") {
|
|
129330
|
+
res.json([]);
|
|
129331
|
+
return;
|
|
129332
|
+
}
|
|
129333
|
+
if (!task.worktree) {
|
|
129334
|
+
res.json([]);
|
|
129335
|
+
return;
|
|
129336
|
+
}
|
|
129337
|
+
let worktreeExists = false;
|
|
129338
|
+
try {
|
|
129339
|
+
await access8(task.worktree);
|
|
129340
|
+
worktreeExists = true;
|
|
129341
|
+
} catch {
|
|
129342
|
+
worktreeExists = false;
|
|
129343
|
+
}
|
|
129344
|
+
if (!worktreeExists) {
|
|
129345
|
+
res.json([]);
|
|
129346
|
+
return;
|
|
129347
|
+
}
|
|
129348
|
+
const worktree = task.worktree;
|
|
129349
|
+
const cached = fileDiffsCache.get(task.id);
|
|
129350
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
129351
|
+
res.json(cached.files);
|
|
129352
|
+
return;
|
|
129353
|
+
}
|
|
129354
|
+
const cwd = worktree;
|
|
129355
|
+
const diffBase = await resolveDiffBase(task, cwd);
|
|
129356
|
+
const fileMap = /* @__PURE__ */ new Map();
|
|
129357
|
+
if (diffBase) {
|
|
129358
|
+
try {
|
|
129359
|
+
const committedOutput = (await runGitCommand(["diff", "--name-status", `${diffBase}..HEAD`], cwd, 5e3)).trim();
|
|
129360
|
+
for (const line of committedOutput.split("\n").filter(Boolean)) {
|
|
129361
|
+
const parts = line.split(" ");
|
|
129362
|
+
const statusCode = parts[0] ?? "M";
|
|
129363
|
+
if (statusCode.startsWith("R")) {
|
|
129364
|
+
fileMap.set(parts[2] ?? parts[1] ?? "", { statusCode, oldPath: parts[1] });
|
|
129365
|
+
} else {
|
|
129366
|
+
fileMap.set(parts[1] ?? "", { statusCode });
|
|
129367
|
+
}
|
|
129368
|
+
}
|
|
129369
|
+
} catch {
|
|
129370
|
+
}
|
|
129371
|
+
}
|
|
129372
|
+
try {
|
|
129373
|
+
const stagedOutput = (await runGitCommand(["diff", "--cached", "--name-status"], cwd, 5e3)).trim();
|
|
129374
|
+
for (const line of stagedOutput.split("\n").filter(Boolean)) {
|
|
129375
|
+
const parts = line.split(" ");
|
|
129376
|
+
const statusCode = parts[0] ?? "M";
|
|
129377
|
+
const filePath = parts[1] ?? "";
|
|
129378
|
+
if (filePath && !fileMap.has(filePath)) {
|
|
129379
|
+
if (statusCode.startsWith("R")) {
|
|
129380
|
+
fileMap.set(filePath, { statusCode, oldPath: parts[2] });
|
|
129381
|
+
} else {
|
|
129382
|
+
fileMap.set(filePath, { statusCode });
|
|
129383
|
+
}
|
|
129384
|
+
}
|
|
129385
|
+
}
|
|
129386
|
+
} catch {
|
|
129387
|
+
}
|
|
129388
|
+
try {
|
|
129389
|
+
const workingTreeOutput = (await runGitCommand(["diff", "--name-status"], cwd, 5e3)).trim();
|
|
129390
|
+
for (const line of workingTreeOutput.split("\n").filter(Boolean)) {
|
|
129391
|
+
const parts = line.split(" ");
|
|
129392
|
+
const statusCode = parts[0] ?? "M";
|
|
129393
|
+
const filePath = parts[1] ?? "";
|
|
129394
|
+
if (filePath && !fileMap.has(filePath)) {
|
|
129395
|
+
if (statusCode.startsWith("R")) {
|
|
129396
|
+
fileMap.set(filePath, { statusCode, oldPath: parts[2] });
|
|
129397
|
+
} else {
|
|
129398
|
+
fileMap.set(filePath, { statusCode });
|
|
129399
|
+
}
|
|
129400
|
+
}
|
|
129401
|
+
}
|
|
129402
|
+
} catch {
|
|
129403
|
+
}
|
|
129404
|
+
try {
|
|
129405
|
+
const untrackedOutput = (await runGitCommand(["ls-files", "--others", "--exclude-standard"], cwd, 5e3)).trim();
|
|
129406
|
+
for (const line of untrackedOutput.split("\n").filter(Boolean)) {
|
|
129407
|
+
if (line && !fileMap.has(line)) {
|
|
129408
|
+
fileMap.set(line, { statusCode: "U", isUntracked: true });
|
|
129409
|
+
}
|
|
129410
|
+
}
|
|
129411
|
+
} catch {
|
|
129412
|
+
}
|
|
129413
|
+
const diffRange = diffBase ? `${diffBase}..HEAD` : "HEAD";
|
|
129414
|
+
const files = [];
|
|
129415
|
+
for (const [filePath, { statusCode, oldPath, isUntracked }] of fileMap.entries()) {
|
|
129416
|
+
let status = "modified";
|
|
129417
|
+
if (statusCode.startsWith("A") || statusCode === "U") {
|
|
129418
|
+
status = "added";
|
|
129419
|
+
} else if (statusCode.startsWith("D")) {
|
|
129420
|
+
status = "deleted";
|
|
129421
|
+
} else if (statusCode.startsWith("R")) {
|
|
129422
|
+
status = "renamed";
|
|
129423
|
+
}
|
|
129424
|
+
let diff = "";
|
|
129425
|
+
try {
|
|
129426
|
+
if (isUntracked) {
|
|
129427
|
+
diff = await runGitCommand(["diff", "--no-index", "/dev/null", filePath], cwd, 5e3).catch(() => "");
|
|
129428
|
+
} else {
|
|
129429
|
+
diff = await runGitCommand(["diff", diffRange, "--", filePath], cwd, 5e3);
|
|
129430
|
+
}
|
|
129431
|
+
} catch {
|
|
129432
|
+
diff = "";
|
|
129433
|
+
}
|
|
129434
|
+
if (!diff && !isUntracked) {
|
|
129435
|
+
continue;
|
|
129436
|
+
}
|
|
129437
|
+
files.push(oldPath ? { path: filePath, status, diff, oldPath } : { path: filePath, status, diff });
|
|
129438
|
+
}
|
|
129439
|
+
fileDiffsCache.set(task.id, {
|
|
129440
|
+
files,
|
|
129441
|
+
expiresAt: Date.now() + 1e4
|
|
129442
|
+
});
|
|
129443
|
+
res.json(files);
|
|
129444
|
+
} catch (err) {
|
|
129445
|
+
if (err instanceof ApiError) {
|
|
129446
|
+
throw err;
|
|
129447
|
+
}
|
|
129448
|
+
if (err.code === "ENOENT") {
|
|
129449
|
+
throw notFound(`Task ${req.params.id} not found`);
|
|
129450
|
+
}
|
|
129451
|
+
rethrowAsApiError(err, "Internal server error");
|
|
129452
|
+
}
|
|
129453
|
+
});
|
|
129454
|
+
}
|
|
129455
|
+
var sessionFilesCache, fileDiffsCache;
|
|
129456
|
+
var init_register_session_diff_routes = __esm({
|
|
129457
|
+
"../dashboard/src/routes/register-session-diff-routes.ts"() {
|
|
129458
|
+
"use strict";
|
|
129459
|
+
init_api_error();
|
|
129460
|
+
init_resolve_diff_base();
|
|
129461
|
+
sessionFilesCache = /* @__PURE__ */ new Map();
|
|
129462
|
+
fileDiffsCache = /* @__PURE__ */ new Map();
|
|
129463
|
+
}
|
|
129464
|
+
});
|
|
129465
|
+
|
|
129169
129466
|
// ../dashboard/src/ai-refine.ts
|
|
129170
129467
|
var ai_refine_exports = {};
|
|
129171
129468
|
__export(ai_refine_exports, {
|
|
@@ -129526,47 +129823,6 @@ function assertConsistentOptionalPair(provider, modelId, pairName) {
|
|
|
129526
129823
|
modelId: normalizedModelId
|
|
129527
129824
|
};
|
|
129528
129825
|
}
|
|
129529
|
-
function rethrowAsApiError4(error, fallbackMessage = "Internal server error") {
|
|
129530
|
-
if (error instanceof ApiError) {
|
|
129531
|
-
throw error;
|
|
129532
|
-
}
|
|
129533
|
-
if (error instanceof Error && error.message) {
|
|
129534
|
-
throw internalError(error.message);
|
|
129535
|
-
}
|
|
129536
|
-
throw internalError(fallbackMessage);
|
|
129537
|
-
}
|
|
129538
|
-
async function resolveDiffBase(task, cwd, headRef = "HEAD", runGit = runGitCommand) {
|
|
129539
|
-
const baseBranch = task.baseBranch ?? "main";
|
|
129540
|
-
let mergeBase;
|
|
129541
|
-
try {
|
|
129542
|
-
try {
|
|
129543
|
-
mergeBase = (await runGit(["merge-base", headRef, baseBranch], cwd, 5e3)).trim() || void 0;
|
|
129544
|
-
} catch {
|
|
129545
|
-
mergeBase = (await runGit(["merge-base", headRef, `origin/${baseBranch}`], cwd, 5e3)).trim() || void 0;
|
|
129546
|
-
}
|
|
129547
|
-
} catch {
|
|
129548
|
-
}
|
|
129549
|
-
if (mergeBase) {
|
|
129550
|
-
try {
|
|
129551
|
-
const head = (await runGit(["rev-parse", headRef], cwd, 5e3)).trim();
|
|
129552
|
-
if (head && head !== mergeBase) return mergeBase;
|
|
129553
|
-
} catch {
|
|
129554
|
-
return mergeBase;
|
|
129555
|
-
}
|
|
129556
|
-
}
|
|
129557
|
-
if (task.baseCommitSha) {
|
|
129558
|
-
try {
|
|
129559
|
-
await runGit(["merge-base", "--is-ancestor", task.baseCommitSha, headRef], cwd, 5e3);
|
|
129560
|
-
return task.baseCommitSha;
|
|
129561
|
-
} catch {
|
|
129562
|
-
}
|
|
129563
|
-
}
|
|
129564
|
-
try {
|
|
129565
|
-
return (await runGit(["rev-parse", `${headRef}~1`], cwd, 5e3)).trim() || void 0;
|
|
129566
|
-
} catch {
|
|
129567
|
-
return void 0;
|
|
129568
|
-
}
|
|
129569
|
-
}
|
|
129570
129826
|
function slugifyPresetName(name) {
|
|
129571
129827
|
const slug = name.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/-+/g, "-").replace(/^[-_]+|[-_]+$/g, "").slice(0, 32);
|
|
129572
129828
|
return slug || "preset";
|
|
@@ -129875,7 +130131,7 @@ function createApiRoutes(store, options) {
|
|
|
129875
130131
|
resolveAutomationStore,
|
|
129876
130132
|
resolveRoutineStore,
|
|
129877
130133
|
resolveRoutineRunner,
|
|
129878
|
-
rethrowAsApiError
|
|
130134
|
+
rethrowAsApiError
|
|
129879
130135
|
};
|
|
129880
130136
|
const githubToken = options?.githubToken ?? process.env.GITHUB_TOKEN;
|
|
129881
130137
|
const aiSessionStore = options?.aiSessionStore;
|
|
@@ -129892,7 +130148,6 @@ function createApiRoutes(store, options) {
|
|
|
129892
130148
|
validateOptionalModelField,
|
|
129893
130149
|
normalizeModelSelectionPair,
|
|
129894
130150
|
runGitCommand,
|
|
129895
|
-
resolveDiffBase,
|
|
129896
130151
|
trimTaskDetailActivityLog,
|
|
129897
130152
|
triggerCommentWakeForAssignedAgent: (...args) => triggerCommentWakeForAssignedAgent(...args)
|
|
129898
130153
|
});
|
|
@@ -129909,10 +130164,8 @@ function createApiRoutes(store, options) {
|
|
|
129909
130164
|
});
|
|
129910
130165
|
registerMessagingScriptRoutes(routeContext);
|
|
129911
130166
|
registerGitGitHubRoutes(routeContext);
|
|
129912
|
-
|
|
129913
|
-
|
|
129914
|
-
resolveDiffBase
|
|
129915
|
-
});
|
|
130167
|
+
registerSessionDiffRoutes(router, { getProjectContext: getProjectContext3 });
|
|
130168
|
+
registerFileWorkspaceRoutes(routeContext);
|
|
129916
130169
|
registerAgentsProjectsNodesRoutes(routeContext);
|
|
129917
130170
|
registerPluginsAutomationRoutes(routeContext);
|
|
129918
130171
|
registerProxyRoutes(routeContext);
|
|
@@ -129998,7 +130251,7 @@ function createApiRoutes(store, options) {
|
|
|
129998
130251
|
if (err instanceof ApiError) {
|
|
129999
130252
|
throw err;
|
|
130000
130253
|
}
|
|
130001
|
-
|
|
130254
|
+
rethrowAsApiError(err);
|
|
130002
130255
|
}
|
|
130003
130256
|
});
|
|
130004
130257
|
router.put("/pi-settings", async (req, res) => {
|
|
@@ -130046,7 +130299,7 @@ function createApiRoutes(store, options) {
|
|
|
130046
130299
|
if (err instanceof ApiError) {
|
|
130047
130300
|
throw err;
|
|
130048
130301
|
}
|
|
130049
|
-
|
|
130302
|
+
rethrowAsApiError(err);
|
|
130050
130303
|
}
|
|
130051
130304
|
});
|
|
130052
130305
|
router.post("/pi-settings/packages", async (req, res) => {
|
|
@@ -130072,7 +130325,7 @@ function createApiRoutes(store, options) {
|
|
|
130072
130325
|
if (err instanceof ApiError) {
|
|
130073
130326
|
throw err;
|
|
130074
130327
|
}
|
|
130075
|
-
|
|
130328
|
+
rethrowAsApiError(err);
|
|
130076
130329
|
}
|
|
130077
130330
|
});
|
|
130078
130331
|
router.post("/pi-settings/reinstall-fusion", async (_req, res) => {
|
|
@@ -130093,7 +130346,7 @@ function createApiRoutes(store, options) {
|
|
|
130093
130346
|
if (err instanceof ApiError) {
|
|
130094
130347
|
throw err;
|
|
130095
130348
|
}
|
|
130096
|
-
|
|
130349
|
+
rethrowAsApiError(err);
|
|
130097
130350
|
}
|
|
130098
130351
|
});
|
|
130099
130352
|
router.get("/executor/stats", async (req, res) => {
|
|
@@ -130118,7 +130371,7 @@ function createApiRoutes(store, options) {
|
|
|
130118
130371
|
if (err instanceof ApiError) {
|
|
130119
130372
|
throw err;
|
|
130120
130373
|
}
|
|
130121
|
-
|
|
130374
|
+
rethrowAsApiError(err);
|
|
130122
130375
|
}
|
|
130123
130376
|
});
|
|
130124
130377
|
router.get("/backups", async (req, res) => {
|
|
@@ -130138,7 +130391,7 @@ function createApiRoutes(store, options) {
|
|
|
130138
130391
|
if (err instanceof ApiError) {
|
|
130139
130392
|
throw err;
|
|
130140
130393
|
}
|
|
130141
|
-
|
|
130394
|
+
rethrowAsApiError(err, "Failed to list backups");
|
|
130142
130395
|
}
|
|
130143
130396
|
});
|
|
130144
130397
|
router.post("/backups", async (req, res) => {
|
|
@@ -130161,196 +130414,15 @@ function createApiRoutes(store, options) {
|
|
|
130161
130414
|
if (err instanceof ApiError) {
|
|
130162
130415
|
throw err;
|
|
130163
130416
|
}
|
|
130164
|
-
|
|
130417
|
+
rethrowAsApiError(err, "Failed to create backup");
|
|
130165
130418
|
}
|
|
130166
130419
|
});
|
|
130167
130420
|
registerModelRoutes(routeContext);
|
|
130168
130421
|
registerAuthRoutes(routeContext);
|
|
130169
|
-
router
|
|
130170
|
-
|
|
130171
|
-
|
|
130172
|
-
|
|
130173
|
-
throw badRequest("command is required and must be a string");
|
|
130174
|
-
}
|
|
130175
|
-
if (command.length > 4096) {
|
|
130176
|
-
throw badRequest("command exceeds maximum length of 4096 characters");
|
|
130177
|
-
}
|
|
130178
|
-
const { store: scopedStore } = await getProjectContext3(req);
|
|
130179
|
-
const rootDir = scopedStore.getRootDir();
|
|
130180
|
-
const result = terminalSessionManager.createSession(command, rootDir);
|
|
130181
|
-
if (result.error) {
|
|
130182
|
-
throw new ApiError(403, result.error);
|
|
130183
|
-
}
|
|
130184
|
-
res.status(201).json({ sessionId: result.sessionId });
|
|
130185
|
-
} catch (err) {
|
|
130186
|
-
if (err instanceof ApiError) {
|
|
130187
|
-
throw err;
|
|
130188
|
-
}
|
|
130189
|
-
rethrowAsApiError4(err, "Failed to execute command");
|
|
130190
|
-
}
|
|
130191
|
-
});
|
|
130192
|
-
router.post("/terminal/sessions/:id/kill", (req, res) => {
|
|
130193
|
-
try {
|
|
130194
|
-
const { id } = req.params;
|
|
130195
|
-
const { signal } = req.body;
|
|
130196
|
-
const validSignals = ["SIGTERM", "SIGKILL", "SIGINT"];
|
|
130197
|
-
const killSignal = validSignals.includes(signal) ? signal : "SIGTERM";
|
|
130198
|
-
const killed = terminalSessionManager.killSession(id, killSignal);
|
|
130199
|
-
if (!killed) {
|
|
130200
|
-
const session = terminalSessionManager.getSession(id);
|
|
130201
|
-
if (!session) {
|
|
130202
|
-
throw notFound("Session not found");
|
|
130203
|
-
}
|
|
130204
|
-
throw badRequest("Session is not running");
|
|
130205
|
-
}
|
|
130206
|
-
res.json({ killed: true, sessionId: id });
|
|
130207
|
-
} catch (err) {
|
|
130208
|
-
if (err instanceof ApiError) {
|
|
130209
|
-
throw err;
|
|
130210
|
-
}
|
|
130211
|
-
rethrowAsApiError4(err);
|
|
130212
|
-
}
|
|
130213
|
-
});
|
|
130214
|
-
router.get("/terminal/sessions/:id", (req, res) => {
|
|
130215
|
-
try {
|
|
130216
|
-
const session = terminalSessionManager.getSession(req.params.id);
|
|
130217
|
-
if (!session) {
|
|
130218
|
-
throw notFound("Session not found");
|
|
130219
|
-
}
|
|
130220
|
-
res.json({
|
|
130221
|
-
id: session.id,
|
|
130222
|
-
command: session.command,
|
|
130223
|
-
running: session.exitCode === null && !session.killed,
|
|
130224
|
-
exitCode: session.exitCode,
|
|
130225
|
-
output: session.output.join(""),
|
|
130226
|
-
startTime: session.startTime.toISOString()
|
|
130227
|
-
});
|
|
130228
|
-
} catch (err) {
|
|
130229
|
-
if (err instanceof ApiError) {
|
|
130230
|
-
throw err;
|
|
130231
|
-
}
|
|
130232
|
-
rethrowAsApiError4(err);
|
|
130233
|
-
}
|
|
130234
|
-
});
|
|
130235
|
-
router.get("/terminal/sessions/:id/stream", (req, res) => {
|
|
130236
|
-
try {
|
|
130237
|
-
const { id } = req.params;
|
|
130238
|
-
const session = terminalSessionManager.getSession(id);
|
|
130239
|
-
if (!session) {
|
|
130240
|
-
throw notFound("Session not found");
|
|
130241
|
-
}
|
|
130242
|
-
res.setHeader("Content-Type", "text/event-stream");
|
|
130243
|
-
res.setHeader("Cache-Control", "no-cache");
|
|
130244
|
-
res.setHeader("Connection", "keep-alive");
|
|
130245
|
-
res.setHeader("X-Accel-Buffering", "no");
|
|
130246
|
-
res.write(`event: connected
|
|
130247
|
-
data: ${JSON.stringify({ sessionId: id })}
|
|
130248
|
-
|
|
130249
|
-
`);
|
|
130250
|
-
const onOutput = (event) => {
|
|
130251
|
-
if (event.sessionId !== id) return;
|
|
130252
|
-
const eventName = event.type === "exit" ? "terminal:exit" : "terminal:output";
|
|
130253
|
-
const data = JSON.stringify({
|
|
130254
|
-
type: event.type,
|
|
130255
|
-
data: event.data,
|
|
130256
|
-
...event.exitCode !== void 0 && { exitCode: event.exitCode }
|
|
130257
|
-
});
|
|
130258
|
-
res.write(`event: ${eventName}
|
|
130259
|
-
data: ${data}
|
|
130260
|
-
|
|
130261
|
-
`);
|
|
130262
|
-
if (event.type === "exit") {
|
|
130263
|
-
setTimeout(() => {
|
|
130264
|
-
res.end();
|
|
130265
|
-
}, 100);
|
|
130266
|
-
}
|
|
130267
|
-
};
|
|
130268
|
-
terminalSessionManager.on("output", onOutput);
|
|
130269
|
-
req.on("close", () => {
|
|
130270
|
-
terminalSessionManager.off("output", onOutput);
|
|
130271
|
-
});
|
|
130272
|
-
req.on("error", () => {
|
|
130273
|
-
terminalSessionManager.off("output", onOutput);
|
|
130274
|
-
});
|
|
130275
|
-
} catch (err) {
|
|
130276
|
-
if (err instanceof ApiError) {
|
|
130277
|
-
throw err;
|
|
130278
|
-
}
|
|
130279
|
-
rethrowAsApiError4(err);
|
|
130280
|
-
}
|
|
130281
|
-
});
|
|
130282
|
-
router.post("/terminal/sessions", async (req, res) => {
|
|
130283
|
-
try {
|
|
130284
|
-
const { cwd, cols, rows } = req.body;
|
|
130285
|
-
const { store: scopedStore } = await getProjectContext3(req);
|
|
130286
|
-
const terminalService = getTerminalService(scopedStore.getRootDir());
|
|
130287
|
-
const result = await terminalService.createSession({
|
|
130288
|
-
cwd,
|
|
130289
|
-
cols: typeof cols === "number" ? cols : void 0,
|
|
130290
|
-
rows: typeof rows === "number" ? rows : void 0
|
|
130291
|
-
});
|
|
130292
|
-
if (!result.success) {
|
|
130293
|
-
const statusByCode = {
|
|
130294
|
-
max_sessions: 503,
|
|
130295
|
-
invalid_shell: 400,
|
|
130296
|
-
pty_load_failed: 503,
|
|
130297
|
-
pty_spawn_failed: 500
|
|
130298
|
-
};
|
|
130299
|
-
throw new ApiError(statusByCode[result.code], result.error, { code: result.code });
|
|
130300
|
-
}
|
|
130301
|
-
res.status(201).json({
|
|
130302
|
-
sessionId: result.session.id,
|
|
130303
|
-
shell: result.session.shell,
|
|
130304
|
-
cwd: result.session.cwd
|
|
130305
|
-
});
|
|
130306
|
-
} catch (err) {
|
|
130307
|
-
if (err instanceof ApiError) {
|
|
130308
|
-
throw err;
|
|
130309
|
-
}
|
|
130310
|
-
rethrowAsApiError4(err, "Failed to create terminal session");
|
|
130311
|
-
}
|
|
130312
|
-
});
|
|
130313
|
-
router.get("/terminal/sessions", async (req, res) => {
|
|
130314
|
-
try {
|
|
130315
|
-
const { store: scopedStore } = await getProjectContext3(req);
|
|
130316
|
-
const terminalService = getTerminalService(scopedStore.getRootDir());
|
|
130317
|
-
const sessions6 = terminalService.getAllSessions();
|
|
130318
|
-
res.json(
|
|
130319
|
-
sessions6.map((s) => ({
|
|
130320
|
-
id: s.id,
|
|
130321
|
-
cwd: s.cwd,
|
|
130322
|
-
shell: s.shell,
|
|
130323
|
-
createdAt: s.createdAt.toISOString(),
|
|
130324
|
-
lastActivityAt: s.lastActivityAt.toISOString()
|
|
130325
|
-
}))
|
|
130326
|
-
);
|
|
130327
|
-
} catch (err) {
|
|
130328
|
-
if (err instanceof ApiError) {
|
|
130329
|
-
throw err;
|
|
130330
|
-
}
|
|
130331
|
-
rethrowAsApiError4(err, "Failed to list sessions");
|
|
130332
|
-
}
|
|
130333
|
-
});
|
|
130334
|
-
router.delete("/terminal/sessions/:id", async (req, res) => {
|
|
130335
|
-
try {
|
|
130336
|
-
const { id } = req.params;
|
|
130337
|
-
const { store: scopedStore } = await getProjectContext3(req);
|
|
130338
|
-
const terminalService = getTerminalService(scopedStore.getRootDir());
|
|
130339
|
-
const killed = terminalService.killSession(id);
|
|
130340
|
-
if (!killed) {
|
|
130341
|
-
const session = terminalService.getSession(id);
|
|
130342
|
-
if (!session) {
|
|
130343
|
-
throw notFound("Session not found");
|
|
130344
|
-
}
|
|
130345
|
-
throw badRequest("Failed to kill session");
|
|
130346
|
-
}
|
|
130347
|
-
res.json({ killed: true });
|
|
130348
|
-
} catch (err) {
|
|
130349
|
-
if (err instanceof ApiError) {
|
|
130350
|
-
throw err;
|
|
130351
|
-
}
|
|
130352
|
-
rethrowAsApiError4(err);
|
|
130353
|
-
}
|
|
130422
|
+
registerTerminalRoutes(router, {
|
|
130423
|
+
getProjectContext: getProjectContext3,
|
|
130424
|
+
terminalSessionManager,
|
|
130425
|
+
getTerminalService
|
|
130354
130426
|
});
|
|
130355
130427
|
router.post("/ai/refine-text", async (req, res) => {
|
|
130356
130428
|
try {
|
|
@@ -130399,9 +130471,9 @@ data: ${data}
|
|
|
130399
130471
|
if (err instanceof Error && err.name === "RateLimitError") {
|
|
130400
130472
|
throw rateLimited(err.message);
|
|
130401
130473
|
} else if (err instanceof Error && err.name === "AiServiceError") {
|
|
130402
|
-
|
|
130474
|
+
rethrowAsApiError(err, "AI service error");
|
|
130403
130475
|
} else {
|
|
130404
|
-
|
|
130476
|
+
rethrowAsApiError(err, "Failed to refine text");
|
|
130405
130477
|
}
|
|
130406
130478
|
}
|
|
130407
130479
|
});
|
|
@@ -130473,7 +130545,7 @@ data: ${data}
|
|
|
130473
130545
|
summarizeDiagnostics.errorFromException("Unexpected summarize title error", err, {
|
|
130474
130546
|
operation: "summarize-title"
|
|
130475
130547
|
});
|
|
130476
|
-
|
|
130548
|
+
rethrowAsApiError(err, "Failed to generate title");
|
|
130477
130549
|
}
|
|
130478
130550
|
}
|
|
130479
130551
|
});
|
|
@@ -130496,7 +130568,7 @@ data: ${data}
|
|
|
130496
130568
|
if (err instanceof ApiError) {
|
|
130497
130569
|
throw err;
|
|
130498
130570
|
}
|
|
130499
|
-
|
|
130571
|
+
rethrowAsApiError(err);
|
|
130500
130572
|
}
|
|
130501
130573
|
});
|
|
130502
130574
|
router.post("/automations", async (req, res) => {
|
|
@@ -130546,7 +130618,7 @@ data: ${data}
|
|
|
130546
130618
|
if (err instanceof ApiError) {
|
|
130547
130619
|
throw err;
|
|
130548
130620
|
}
|
|
130549
|
-
|
|
130621
|
+
rethrowAsApiError(err);
|
|
130550
130622
|
}
|
|
130551
130623
|
});
|
|
130552
130624
|
router.get("/automations/:id", async (req, res) => {
|
|
@@ -130566,7 +130638,7 @@ data: ${data}
|
|
|
130566
130638
|
if (err.code === "ENOENT") {
|
|
130567
130639
|
throw notFound("Schedule not found");
|
|
130568
130640
|
}
|
|
130569
|
-
|
|
130641
|
+
rethrowAsApiError(err);
|
|
130570
130642
|
}
|
|
130571
130643
|
});
|
|
130572
130644
|
router.patch("/automations/:id", async (req, res) => {
|
|
@@ -130613,7 +130685,7 @@ data: ${data}
|
|
|
130613
130685
|
if ((err instanceof Error ? err.message : String(err)).includes("cannot be empty") || (err instanceof Error ? err.message : String(err)).includes("Invalid cron")) {
|
|
130614
130686
|
throw badRequest(err instanceof Error ? err.message : String(err));
|
|
130615
130687
|
}
|
|
130616
|
-
|
|
130688
|
+
rethrowAsApiError(err);
|
|
130617
130689
|
}
|
|
130618
130690
|
});
|
|
130619
130691
|
router.delete("/automations/:id", async (req, res) => {
|
|
@@ -130636,7 +130708,7 @@ data: ${data}
|
|
|
130636
130708
|
if (err.code === "ENOENT") {
|
|
130637
130709
|
throw notFound("Schedule not found");
|
|
130638
130710
|
}
|
|
130639
|
-
|
|
130711
|
+
rethrowAsApiError(err);
|
|
130640
130712
|
}
|
|
130641
130713
|
});
|
|
130642
130714
|
router.post("/automations/:id/run", async (req, res) => {
|
|
@@ -130664,7 +130736,7 @@ data: ${data}
|
|
|
130664
130736
|
if (err.code === "ENOENT") {
|
|
130665
130737
|
throw notFound("Schedule not found");
|
|
130666
130738
|
}
|
|
130667
|
-
|
|
130739
|
+
rethrowAsApiError(err);
|
|
130668
130740
|
}
|
|
130669
130741
|
});
|
|
130670
130742
|
router.post("/automations/:id/toggle", async (req, res) => {
|
|
@@ -130687,7 +130759,7 @@ data: ${data}
|
|
|
130687
130759
|
if (err.code === "ENOENT") {
|
|
130688
130760
|
throw notFound("Schedule not found");
|
|
130689
130761
|
}
|
|
130690
|
-
|
|
130762
|
+
rethrowAsApiError(err);
|
|
130691
130763
|
}
|
|
130692
130764
|
});
|
|
130693
130765
|
router.post("/automations/:id/steps/reorder", async (req, res) => {
|
|
@@ -130717,7 +130789,7 @@ data: ${data}
|
|
|
130717
130789
|
if ((err instanceof Error ? err.message : String(err)).includes("mismatch") || (err instanceof Error ? err.message : String(err)).includes("Unknown step") || (err instanceof Error ? err.message : String(err)).includes("no steps")) {
|
|
130718
130790
|
throw badRequest(err instanceof Error ? err.message : String(err));
|
|
130719
130791
|
}
|
|
130720
|
-
|
|
130792
|
+
rethrowAsApiError(err);
|
|
130721
130793
|
}
|
|
130722
130794
|
});
|
|
130723
130795
|
router.get("/routines", async (req, res) => {
|
|
@@ -130738,7 +130810,7 @@ data: ${data}
|
|
|
130738
130810
|
if (err instanceof ApiError) {
|
|
130739
130811
|
throw err;
|
|
130740
130812
|
}
|
|
130741
|
-
|
|
130813
|
+
rethrowAsApiError(err);
|
|
130742
130814
|
}
|
|
130743
130815
|
});
|
|
130744
130816
|
router.post("/routines", async (req, res) => {
|
|
@@ -130813,7 +130885,7 @@ data: ${data}
|
|
|
130813
130885
|
if (err instanceof ApiError) {
|
|
130814
130886
|
throw err;
|
|
130815
130887
|
}
|
|
130816
|
-
|
|
130888
|
+
rethrowAsApiError(err);
|
|
130817
130889
|
}
|
|
130818
130890
|
});
|
|
130819
130891
|
router.get("/routines/:id", async (req, res) => {
|
|
@@ -130833,7 +130905,7 @@ data: ${data}
|
|
|
130833
130905
|
if (err.code === "ENOENT") {
|
|
130834
130906
|
throw notFound("Routine not found");
|
|
130835
130907
|
}
|
|
130836
|
-
|
|
130908
|
+
rethrowAsApiError(err);
|
|
130837
130909
|
}
|
|
130838
130910
|
});
|
|
130839
130911
|
router.patch("/routines/:id", async (req, res) => {
|
|
@@ -130899,7 +130971,7 @@ data: ${data}
|
|
|
130899
130971
|
if ((err instanceof Error ? err.message : String(err)).includes("cannot be empty") || (err instanceof Error ? err.message : String(err)).includes("Invalid cron")) {
|
|
130900
130972
|
throw badRequest(err instanceof Error ? err.message : String(err));
|
|
130901
130973
|
}
|
|
130902
|
-
|
|
130974
|
+
rethrowAsApiError(err);
|
|
130903
130975
|
}
|
|
130904
130976
|
});
|
|
130905
130977
|
router.delete("/routines/:id", async (req, res) => {
|
|
@@ -130922,7 +130994,7 @@ data: ${data}
|
|
|
130922
130994
|
if (err.code === "ENOENT") {
|
|
130923
130995
|
throw notFound("Routine not found");
|
|
130924
130996
|
}
|
|
130925
|
-
|
|
130997
|
+
rethrowAsApiError(err);
|
|
130926
130998
|
}
|
|
130927
130999
|
});
|
|
130928
131000
|
router.post("/routines/:id/run", async (req, res) => {
|
|
@@ -130948,7 +131020,7 @@ data: ${data}
|
|
|
130948
131020
|
if (err.code === "ENOENT") {
|
|
130949
131021
|
throw notFound("Routine not found");
|
|
130950
131022
|
}
|
|
130951
|
-
|
|
131023
|
+
rethrowAsApiError(err);
|
|
130952
131024
|
}
|
|
130953
131025
|
});
|
|
130954
131026
|
router.post("/routines/:id/trigger", async (req, res) => {
|
|
@@ -130974,7 +131046,7 @@ data: ${data}
|
|
|
130974
131046
|
if (err.code === "ENOENT") {
|
|
130975
131047
|
throw notFound("Routine not found");
|
|
130976
131048
|
}
|
|
130977
|
-
|
|
131049
|
+
rethrowAsApiError(err);
|
|
130978
131050
|
}
|
|
130979
131051
|
});
|
|
130980
131052
|
router.get("/routines/:id/runs", async (req, res) => {
|
|
@@ -130994,7 +131066,7 @@ data: ${data}
|
|
|
130994
131066
|
if (err.code === "ENOENT") {
|
|
130995
131067
|
throw notFound("Routine not found");
|
|
130996
131068
|
}
|
|
130997
|
-
|
|
131069
|
+
rethrowAsApiError(err);
|
|
130998
131070
|
}
|
|
130999
131071
|
});
|
|
131000
131072
|
router.post("/routines/:id/webhook", async (req, res) => {
|
|
@@ -131038,7 +131110,7 @@ data: ${data}
|
|
|
131038
131110
|
if (err.code === "ENOENT") {
|
|
131039
131111
|
throw notFound("Routine not found");
|
|
131040
131112
|
}
|
|
131041
|
-
|
|
131113
|
+
rethrowAsApiError(err);
|
|
131042
131114
|
}
|
|
131043
131115
|
});
|
|
131044
131116
|
router.get("/activity", async (req, res) => {
|
|
@@ -131070,7 +131142,7 @@ data: ${data}
|
|
|
131070
131142
|
if (err instanceof ApiError) {
|
|
131071
131143
|
throw err;
|
|
131072
131144
|
}
|
|
131073
|
-
|
|
131145
|
+
rethrowAsApiError(err);
|
|
131074
131146
|
}
|
|
131075
131147
|
});
|
|
131076
131148
|
router.delete("/activity", async (req, res) => {
|
|
@@ -131082,7 +131154,7 @@ data: ${data}
|
|
|
131082
131154
|
if (err instanceof ApiError) {
|
|
131083
131155
|
throw err;
|
|
131084
131156
|
}
|
|
131085
|
-
|
|
131157
|
+
rethrowAsApiError(err);
|
|
131086
131158
|
}
|
|
131087
131159
|
});
|
|
131088
131160
|
router.get("/workflow-steps", async (req, res) => {
|
|
@@ -131094,7 +131166,7 @@ data: ${data}
|
|
|
131094
131166
|
if (err instanceof ApiError) {
|
|
131095
131167
|
throw err;
|
|
131096
131168
|
}
|
|
131097
|
-
|
|
131169
|
+
rethrowAsApiError(err);
|
|
131098
131170
|
}
|
|
131099
131171
|
});
|
|
131100
131172
|
router.post("/workflow-steps", async (req, res) => {
|
|
@@ -131269,7 +131341,7 @@ data: ${data}
|
|
|
131269
131341
|
if ((err instanceof Error ? err.message : String(err)).includes("not found")) {
|
|
131270
131342
|
throw notFound(err instanceof Error ? err.message : String(err));
|
|
131271
131343
|
} else {
|
|
131272
|
-
|
|
131344
|
+
rethrowAsApiError(err);
|
|
131273
131345
|
}
|
|
131274
131346
|
}
|
|
131275
131347
|
});
|
|
@@ -131339,7 +131411,7 @@ Description: ${step.description}`
|
|
|
131339
131411
|
if (err instanceof ApiError) {
|
|
131340
131412
|
throw err;
|
|
131341
131413
|
}
|
|
131342
|
-
|
|
131414
|
+
rethrowAsApiError(err);
|
|
131343
131415
|
}
|
|
131344
131416
|
});
|
|
131345
131417
|
router.get("/workflow-step-templates", async (_req, res) => {
|
|
@@ -131350,7 +131422,7 @@ Description: ${step.description}`
|
|
|
131350
131422
|
if (err instanceof ApiError) {
|
|
131351
131423
|
throw err;
|
|
131352
131424
|
}
|
|
131353
|
-
|
|
131425
|
+
rethrowAsApiError(err);
|
|
131354
131426
|
}
|
|
131355
131427
|
});
|
|
131356
131428
|
router.post("/workflow-step-templates/:id/create", async (req, res) => {
|
|
@@ -131378,7 +131450,7 @@ Description: ${step.description}`
|
|
|
131378
131450
|
if (err instanceof ApiError) {
|
|
131379
131451
|
throw err;
|
|
131380
131452
|
}
|
|
131381
|
-
|
|
131453
|
+
rethrowAsApiError(err);
|
|
131382
131454
|
}
|
|
131383
131455
|
});
|
|
131384
131456
|
const TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set(["done", "archived"]);
|
|
@@ -131943,7 +132015,7 @@ Description: ${step.description}`
|
|
|
131943
132015
|
if (err instanceof ApiError) {
|
|
131944
132016
|
throw err;
|
|
131945
132017
|
}
|
|
131946
|
-
|
|
132018
|
+
rethrowAsApiError(err);
|
|
131947
132019
|
}
|
|
131948
132020
|
});
|
|
131949
132021
|
registerProjectRoutes(routeContext);
|
|
@@ -131968,7 +132040,7 @@ Description: ${step.description}`
|
|
|
131968
132040
|
if (err instanceof ApiError) {
|
|
131969
132041
|
throw err;
|
|
131970
132042
|
}
|
|
131971
|
-
|
|
132043
|
+
rethrowAsApiError(err);
|
|
131972
132044
|
}
|
|
131973
132045
|
});
|
|
131974
132046
|
router.get("/global-concurrency", async (_req, res) => {
|
|
@@ -131983,7 +132055,7 @@ Description: ${step.description}`
|
|
|
131983
132055
|
if (err instanceof ApiError) {
|
|
131984
132056
|
throw err;
|
|
131985
132057
|
}
|
|
131986
|
-
|
|
132058
|
+
rethrowAsApiError(err);
|
|
131987
132059
|
}
|
|
131988
132060
|
});
|
|
131989
132061
|
router.put("/global-concurrency", async (req, res) => {
|
|
@@ -132002,7 +132074,7 @@ Description: ${step.description}`
|
|
|
132002
132074
|
if (err instanceof ApiError) {
|
|
132003
132075
|
throw err;
|
|
132004
132076
|
}
|
|
132005
|
-
|
|
132077
|
+
rethrowAsApiError(err);
|
|
132006
132078
|
}
|
|
132007
132079
|
});
|
|
132008
132080
|
router.get("/first-run-status", async (_req, res) => {
|
|
@@ -132019,7 +132091,7 @@ Description: ${step.description}`
|
|
|
132019
132091
|
if (err instanceof ApiError) {
|
|
132020
132092
|
throw err;
|
|
132021
132093
|
}
|
|
132022
|
-
|
|
132094
|
+
rethrowAsApiError(err);
|
|
132023
132095
|
}
|
|
132024
132096
|
});
|
|
132025
132097
|
router.get("/setup-state", async (_req, res) => {
|
|
@@ -132047,7 +132119,7 @@ Description: ${step.description}`
|
|
|
132047
132119
|
if (err instanceof ApiError) {
|
|
132048
132120
|
throw err;
|
|
132049
132121
|
}
|
|
132050
|
-
|
|
132122
|
+
rethrowAsApiError(err);
|
|
132051
132123
|
}
|
|
132052
132124
|
});
|
|
132053
132125
|
router.post("/complete-setup", async (req, res) => {
|
|
@@ -132075,7 +132147,7 @@ Description: ${step.description}`
|
|
|
132075
132147
|
if (err instanceof ApiError) {
|
|
132076
132148
|
throw err;
|
|
132077
132149
|
}
|
|
132078
|
-
|
|
132150
|
+
rethrowAsApiError(err);
|
|
132079
132151
|
}
|
|
132080
132152
|
});
|
|
132081
132153
|
registerIntegratedDevServerRouter({ router, store });
|
|
@@ -132298,7 +132370,11 @@ var init_routes = __esm({
|
|
|
132298
132370
|
init_register_usage_routes();
|
|
132299
132371
|
init_register_auth_routes();
|
|
132300
132372
|
init_register_integrated_routers();
|
|
132373
|
+
init_register_terminal_routes();
|
|
132374
|
+
init_register_session_diff_routes();
|
|
132375
|
+
init_resolve_diff_base();
|
|
132301
132376
|
init_register_git_github();
|
|
132377
|
+
init_resolve_diff_base();
|
|
132302
132378
|
TASK_DETAIL_ACTIVITY_LOG_LIMIT = 500;
|
|
132303
132379
|
upload = multer({
|
|
132304
132380
|
storage: multer.memoryStorage(),
|