@runfusion/fusion 0.2.0 → 0.2.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/dist/bin.js +2188 -323
- package/dist/client/assets/{AgentDetailView-CDZED6Dy.css → AgentDetailView-BMrHuWGs.css} +1 -1
- package/dist/client/assets/{AgentDetailView-zycSdnO8.js → AgentDetailView-CkuuGA1O.js} +1 -1
- package/dist/client/assets/AgentsView-CWFLMIDP.js +522 -0
- package/dist/client/assets/AgentsView-DETxUmHS.css +1 -0
- package/dist/client/assets/{ChatView-BOd-sxbT.js → ChatView-C_T91ebd.js} +1 -1
- package/dist/client/assets/{DevServerView-09GQf34f.js → DevServerView-ChWTzTvy.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-CcdN1Zs7.js → DirectoryPicker-BMJIT7HD.js} +1 -1
- package/dist/client/assets/{DocumentsView-CS8aiwtz.js → DocumentsView-CjfVl8mZ.js} +1 -1
- package/dist/client/assets/{InsightsView-Bu9Cv8Ol.js → InsightsView-Rb735C9_.js} +1 -1
- package/dist/client/assets/{MemoryView-CtqgDtV9.js → MemoryView-LLc_uNtG.js} +1 -1
- package/dist/client/assets/NodesView-BYVG2yY-.css +1 -0
- package/dist/client/assets/{NodesView-BInPcedy.js → NodesView-BviqBWRA.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-COxkYM2m.js → PiExtensionsManager-CriZBkQe.js} +1 -1
- package/dist/client/assets/{PluginManager-CXUWZBOc.js → PluginManager-BywTPbLB.js} +1 -1
- package/dist/client/assets/{RoadmapsView-BbCexaoi.js → RoadmapsView-Dhl--4vY.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-Cakxqkad.js → SetupWizardModal-CVtmwoJC.js} +1 -1
- package/dist/client/assets/{SkillsView-D3iqYCVf.js → SkillsView-CG9y4fsE.js} +1 -1
- package/dist/client/assets/{folder-open-kO5Hsk66.js → folder-open-BVDq27HP.js} +1 -1
- package/dist/client/assets/index-CikysL-d.js +644 -0
- package/dist/client/assets/index-Da1qmtc7.css +1 -0
- package/dist/client/assets/{upload-DHBQat92.js → upload-BDvpReDO.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/extension.js +12 -10
- package/package.json +4 -4
- package/dist/client/assets/AgentsView-DoQkkDLf.css +0 -1
- package/dist/client/assets/AgentsView-pO7WiBS5.js +0 -522
- package/dist/client/assets/NodesView-DlQZHGXA.css +0 -1
- package/dist/client/assets/index-BiSuUXCa.css +0 -1
- package/dist/client/assets/index-y194HxzU.js +0 -644
package/dist/bin.js
CHANGED
|
@@ -14150,7 +14150,7 @@ var require_multicast_dns = __commonJS({
|
|
|
14150
14150
|
var dgram = __require("dgram");
|
|
14151
14151
|
var thunky = require_thunky();
|
|
14152
14152
|
var events = __require("events");
|
|
14153
|
-
var
|
|
14153
|
+
var os4 = __require("os");
|
|
14154
14154
|
var noop = function() {
|
|
14155
14155
|
};
|
|
14156
14156
|
module.exports = function(opts) {
|
|
@@ -14280,14 +14280,14 @@ var require_multicast_dns = __commonJS({
|
|
|
14280
14280
|
return that;
|
|
14281
14281
|
};
|
|
14282
14282
|
function defaultInterface() {
|
|
14283
|
-
var networks =
|
|
14283
|
+
var networks = os4.networkInterfaces();
|
|
14284
14284
|
var names = Object.keys(networks);
|
|
14285
14285
|
for (var i = 0; i < names.length; i++) {
|
|
14286
14286
|
var net = networks[names[i]];
|
|
14287
14287
|
for (var j = 0; j < net.length; j++) {
|
|
14288
14288
|
var iface = net[j];
|
|
14289
14289
|
if (isIPv4(iface.family) && !iface.internal) {
|
|
14290
|
-
if (
|
|
14290
|
+
if (os4.platform() === "darwin" && names[i] === "en0") return iface.address;
|
|
14291
14291
|
return "0.0.0.0";
|
|
14292
14292
|
}
|
|
14293
14293
|
}
|
|
@@ -14295,7 +14295,7 @@ var require_multicast_dns = __commonJS({
|
|
|
14295
14295
|
return "127.0.0.1";
|
|
14296
14296
|
}
|
|
14297
14297
|
function allInterfaces() {
|
|
14298
|
-
var networks =
|
|
14298
|
+
var networks = os4.networkInterfaces();
|
|
14299
14299
|
var names = Object.keys(networks);
|
|
14300
14300
|
var res = [];
|
|
14301
14301
|
for (var i = 0; i < names.length; i++) {
|
|
@@ -16717,9 +16717,9 @@ var init_central_core = __esm({
|
|
|
16717
16717
|
async generateProjectName(projectPath) {
|
|
16718
16718
|
try {
|
|
16719
16719
|
const { execFile: execFile5 } = await import("node:child_process");
|
|
16720
|
-
const { promisify:
|
|
16721
|
-
const
|
|
16722
|
-
const { stdout } = await
|
|
16720
|
+
const { promisify: promisify15 } = await import("node:util");
|
|
16721
|
+
const execFileAsync4 = promisify15(execFile5);
|
|
16722
|
+
const { stdout } = await execFileAsync4(
|
|
16723
16723
|
"git",
|
|
16724
16724
|
["remote", "get-url", "origin"],
|
|
16725
16725
|
{ cwd: projectPath, timeout: 5e3 }
|
|
@@ -17204,8 +17204,8 @@ function hasProjectDbFile(dir2, folderName, dbName) {
|
|
|
17204
17204
|
if (!existsSync8(projectDir)) return false;
|
|
17205
17205
|
if (!existsSync8(dbPath)) return false;
|
|
17206
17206
|
try {
|
|
17207
|
-
const
|
|
17208
|
-
return
|
|
17207
|
+
const stat11 = statSync2(dbPath);
|
|
17208
|
+
return stat11.isFile() && stat11.size > 0;
|
|
17209
17209
|
} catch {
|
|
17210
17210
|
return false;
|
|
17211
17211
|
}
|
|
@@ -17333,9 +17333,9 @@ var init_migration = __esm({
|
|
|
17333
17333
|
}
|
|
17334
17334
|
try {
|
|
17335
17335
|
const { execFile: execFile5 } = await import("node:child_process");
|
|
17336
|
-
const { promisify:
|
|
17337
|
-
const
|
|
17338
|
-
const { stdout } = await
|
|
17336
|
+
const { promisify: promisify15 } = await import("node:util");
|
|
17337
|
+
const execFileAsync4 = promisify15(execFile5);
|
|
17338
|
+
const { stdout } = await execFileAsync4(
|
|
17339
17339
|
"git",
|
|
17340
17340
|
["remote", "get-url", "origin"],
|
|
17341
17341
|
{ cwd: projectPath, timeout: 1e3 }
|
|
@@ -28036,12 +28036,12 @@ async function searchWithQmd(rootDir, options) {
|
|
|
28036
28036
|
const limit = Math.max(1, Math.min(options.limit ?? 5, 20));
|
|
28037
28037
|
try {
|
|
28038
28038
|
const { execFile: execFile5 } = await import("node:child_process");
|
|
28039
|
-
const { promisify:
|
|
28040
|
-
const
|
|
28041
|
-
await ensureQmdProjectMemoryCollection(rootDir,
|
|
28039
|
+
const { promisify: promisify15 } = await import("node:util");
|
|
28040
|
+
const execFileAsync4 = promisify15(execFile5);
|
|
28041
|
+
await ensureQmdProjectMemoryCollection(rootDir, execFileAsync4);
|
|
28042
28042
|
scheduleQmdProjectMemoryRefresh(rootDir);
|
|
28043
28043
|
const args = buildQmdSearchArgs(rootDir, options);
|
|
28044
|
-
const { stdout } = await
|
|
28044
|
+
const { stdout } = await execFileAsync4(command, args, {
|
|
28045
28045
|
cwd: rootDir,
|
|
28046
28046
|
timeout: 4e3,
|
|
28047
28047
|
maxBuffer: 1024 * 1024
|
|
@@ -28066,12 +28066,12 @@ async function searchWithQmd(rootDir, options) {
|
|
|
28066
28066
|
return [];
|
|
28067
28067
|
}
|
|
28068
28068
|
}
|
|
28069
|
-
async function ensureQmdProjectMemoryCollection(rootDir,
|
|
28069
|
+
async function ensureQmdProjectMemoryCollection(rootDir, execFileAsync4) {
|
|
28070
28070
|
const collectionName = qmdMemoryCollectionName(rootDir);
|
|
28071
28071
|
const memoryDir = memoryWorkspacePath(rootDir);
|
|
28072
28072
|
await mkdir6(memoryDir, { recursive: true });
|
|
28073
28073
|
try {
|
|
28074
|
-
await
|
|
28074
|
+
await execFileAsync4("qmd", buildQmdCollectionAddArgs(rootDir), {
|
|
28075
28075
|
cwd: rootDir,
|
|
28076
28076
|
timeout: 4e3,
|
|
28077
28077
|
maxBuffer: 512 * 1024
|
|
@@ -28088,8 +28088,8 @@ ${stderr}`)) {
|
|
|
28088
28088
|
}
|
|
28089
28089
|
async function getDefaultExecFileAsync() {
|
|
28090
28090
|
const { execFile: execFile5 } = await import("node:child_process");
|
|
28091
|
-
const { promisify:
|
|
28092
|
-
return
|
|
28091
|
+
const { promisify: promisify15 } = await import("node:util");
|
|
28092
|
+
return promisify15(execFile5);
|
|
28093
28093
|
}
|
|
28094
28094
|
async function refreshQmdProjectMemoryIndex(rootDir, options) {
|
|
28095
28095
|
const key = resolve5(rootDir);
|
|
@@ -28104,14 +28104,14 @@ async function refreshQmdProjectMemoryIndex(rootDir, options) {
|
|
|
28104
28104
|
}
|
|
28105
28105
|
}
|
|
28106
28106
|
const promise = (async () => {
|
|
28107
|
-
const
|
|
28108
|
-
await ensureQmdProjectMemoryCollection(rootDir,
|
|
28109
|
-
await
|
|
28107
|
+
const execFileAsync4 = options?.execFileAsync ?? await getDefaultExecFileAsync();
|
|
28108
|
+
await ensureQmdProjectMemoryCollection(rootDir, execFileAsync4);
|
|
28109
|
+
await execFileAsync4("qmd", ["update"], {
|
|
28110
28110
|
cwd: rootDir,
|
|
28111
28111
|
timeout: 3e4,
|
|
28112
28112
|
maxBuffer: 1024 * 1024
|
|
28113
28113
|
});
|
|
28114
|
-
await
|
|
28114
|
+
await execFileAsync4("qmd", ["embed"], {
|
|
28115
28115
|
cwd: rootDir,
|
|
28116
28116
|
timeout: 12e4,
|
|
28117
28117
|
maxBuffer: 1024 * 1024
|
|
@@ -28136,8 +28136,8 @@ function scheduleQmdProjectMemoryRefresh(rootDir) {
|
|
|
28136
28136
|
}
|
|
28137
28137
|
async function isQmdAvailable() {
|
|
28138
28138
|
try {
|
|
28139
|
-
const
|
|
28140
|
-
await
|
|
28139
|
+
const execFileAsync4 = await getDefaultExecFileAsync();
|
|
28140
|
+
await execFileAsync4("qmd", ["--help"], {
|
|
28141
28141
|
timeout: 3e3,
|
|
28142
28142
|
maxBuffer: 128 * 1024
|
|
28143
28143
|
});
|
|
@@ -28147,12 +28147,12 @@ async function isQmdAvailable() {
|
|
|
28147
28147
|
}
|
|
28148
28148
|
}
|
|
28149
28149
|
async function installQmd(options) {
|
|
28150
|
-
const
|
|
28150
|
+
const execFileAsync4 = options?.execFileAsync ?? await getDefaultExecFileAsync();
|
|
28151
28151
|
const [command, ...args] = QMD_INSTALL_COMMAND.split(" ");
|
|
28152
28152
|
if (!command || args.length === 0) {
|
|
28153
28153
|
throw new MemoryBackendError("BACKEND_UNAVAILABLE", "qmd install command is not configured", "qmd");
|
|
28154
28154
|
}
|
|
28155
|
-
await
|
|
28155
|
+
await execFileAsync4(command, args, {
|
|
28156
28156
|
timeout: 12e4,
|
|
28157
28157
|
maxBuffer: 1024 * 1024
|
|
28158
28158
|
});
|
|
@@ -37215,7 +37215,7 @@ var require_has_flag = __commonJS({
|
|
|
37215
37215
|
var require_supports_color = __commonJS({
|
|
37216
37216
|
"../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
|
|
37217
37217
|
"use strict";
|
|
37218
|
-
var
|
|
37218
|
+
var os4 = __require("os");
|
|
37219
37219
|
var tty = __require("tty");
|
|
37220
37220
|
var hasFlag = require_has_flag();
|
|
37221
37221
|
var { env } = process;
|
|
@@ -37263,7 +37263,7 @@ var require_supports_color = __commonJS({
|
|
|
37263
37263
|
return min;
|
|
37264
37264
|
}
|
|
37265
37265
|
if (process.platform === "win32") {
|
|
37266
|
-
const osRelease =
|
|
37266
|
+
const osRelease = os4.release().split(".");
|
|
37267
37267
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
37268
37268
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
37269
37269
|
}
|
|
@@ -39096,11 +39096,11 @@ var require_extract_zip = __commonJS({
|
|
|
39096
39096
|
var { createWriteStream: createWriteStream2, promises: fs2 } = __require("fs");
|
|
39097
39097
|
var getStream = require_get_stream();
|
|
39098
39098
|
var path4 = __require("path");
|
|
39099
|
-
var { promisify:
|
|
39099
|
+
var { promisify: promisify15 } = __require("util");
|
|
39100
39100
|
var stream = __require("stream");
|
|
39101
39101
|
var yauzl = require_yauzl();
|
|
39102
|
-
var openZip =
|
|
39103
|
-
var pipeline =
|
|
39102
|
+
var openZip = promisify15(yauzl.open);
|
|
39103
|
+
var pipeline = promisify15(stream.pipeline);
|
|
39104
39104
|
var Extractor = class {
|
|
39105
39105
|
constructor(zipPath, opts) {
|
|
39106
39106
|
this.zipPath = zipPath;
|
|
@@ -39182,7 +39182,7 @@ var require_extract_zip = __commonJS({
|
|
|
39182
39182
|
await fs2.mkdir(destDir, mkdirOptions);
|
|
39183
39183
|
if (isDir) return;
|
|
39184
39184
|
debug("opening read stream", dest);
|
|
39185
|
-
const readStream = await
|
|
39185
|
+
const readStream = await promisify15(this.zipfile.openReadStream.bind(this.zipfile))(entry);
|
|
39186
39186
|
if (symlink) {
|
|
39187
39187
|
const link = await getStream(readStream);
|
|
39188
39188
|
debug("creating symlink", link, dest);
|
|
@@ -46843,12 +46843,12 @@ function resolveExtractionRoot(tempDir) {
|
|
|
46843
46843
|
return tempDir;
|
|
46844
46844
|
}
|
|
46845
46845
|
async function extractTarArchive(archivePath, outputDir) {
|
|
46846
|
-
const [{ execFile: execFile5 }, { promisify:
|
|
46846
|
+
const [{ execFile: execFile5 }, { promisify: promisify15 }] = await Promise.all([
|
|
46847
46847
|
import("node:child_process"),
|
|
46848
46848
|
import("node:util")
|
|
46849
46849
|
]);
|
|
46850
|
-
const
|
|
46851
|
-
await
|
|
46850
|
+
const execFileAsync4 = promisify15(execFile5);
|
|
46851
|
+
await execFileAsync4("tar", ["xzf", archivePath, "-C", outputDir]);
|
|
46852
46852
|
}
|
|
46853
46853
|
async function parseCompanyArchive(archivePath) {
|
|
46854
46854
|
const resolvedArchivePath = resolve8(archivePath);
|
|
@@ -50654,7 +50654,7 @@ var require_windowsPtyAgent = __commonJS({
|
|
|
50654
50654
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50655
50655
|
exports.argsToCommandLine = exports.WindowsPtyAgent = void 0;
|
|
50656
50656
|
var fs2 = __require("fs");
|
|
50657
|
-
var
|
|
50657
|
+
var os4 = __require("os");
|
|
50658
50658
|
var path4 = __require("path");
|
|
50659
50659
|
var child_process_1 = __require("child_process");
|
|
50660
50660
|
var net_1 = __require("net");
|
|
@@ -50836,7 +50836,7 @@ var require_windowsPtyAgent = __commonJS({
|
|
|
50836
50836
|
configurable: true
|
|
50837
50837
|
});
|
|
50838
50838
|
WindowsPtyAgent2.prototype._getWindowsBuildNumber = function() {
|
|
50839
|
-
var osVersion = /(\d+)\.(\d+)\.(\d+)/g.exec(
|
|
50839
|
+
var osVersion = /(\d+)\.(\d+)\.(\d+)/g.exec(os4.release());
|
|
50840
50840
|
var buildNumber = 0;
|
|
50841
50841
|
if (osVersion && osVersion.length === 4) {
|
|
50842
50842
|
buildNumber = parseInt(osVersion[3]);
|
|
@@ -51735,8 +51735,8 @@ var init_terminal_service = __esm({
|
|
|
51735
51735
|
return this.projectRoot;
|
|
51736
51736
|
}
|
|
51737
51737
|
try {
|
|
51738
|
-
const
|
|
51739
|
-
if (
|
|
51738
|
+
const stat11 = await import("node:fs/promises").then((fs2) => fs2.stat(cwd));
|
|
51739
|
+
if (stat11.isDirectory()) {
|
|
51740
51740
|
return cwd;
|
|
51741
51741
|
}
|
|
51742
51742
|
} catch {
|
|
@@ -60177,10 +60177,10 @@ async function refreshAgentMemoryQmdIndex(rootDir, agentMemory) {
|
|
|
60177
60177
|
}
|
|
60178
60178
|
const promise = (async () => {
|
|
60179
60179
|
const { execFile: execFile5 } = await import("node:child_process");
|
|
60180
|
-
const { promisify:
|
|
60181
|
-
const
|
|
60180
|
+
const { promisify: promisify15 } = await import("node:util");
|
|
60181
|
+
const execFileAsync4 = promisify15(execFile5);
|
|
60182
60182
|
try {
|
|
60183
|
-
await
|
|
60183
|
+
await execFileAsync4("qmd", buildQmdAgentMemoryCollectionAddArgs(rootDir, agentMemory.agentId), {
|
|
60184
60184
|
cwd: rootDir,
|
|
60185
60185
|
timeout: 4e3,
|
|
60186
60186
|
maxBuffer: 512 * 1024
|
|
@@ -60193,8 +60193,8 @@ ${stderr}`)) {
|
|
|
60193
60193
|
throw error;
|
|
60194
60194
|
}
|
|
60195
60195
|
}
|
|
60196
|
-
await
|
|
60197
|
-
await
|
|
60196
|
+
await execFileAsync4("qmd", ["update"], { cwd: rootDir, timeout: 3e4, maxBuffer: 1024 * 1024 });
|
|
60197
|
+
await execFileAsync4("qmd", ["embed"], { cwd: rootDir, timeout: 12e4, maxBuffer: 1024 * 1024 });
|
|
60198
60198
|
})();
|
|
60199
60199
|
agentQmdRefreshState.set(key, { lastStartedAt: now, inFlight: promise });
|
|
60200
60200
|
try {
|
|
@@ -60216,9 +60216,9 @@ async function searchAgentMemoryWithQmd(rootDir, agentMemory, query, limit) {
|
|
|
60216
60216
|
try {
|
|
60217
60217
|
await refreshAgentMemoryQmdIndex(rootDir, agentMemory);
|
|
60218
60218
|
const { execFile: execFile5 } = await import("node:child_process");
|
|
60219
|
-
const { promisify:
|
|
60220
|
-
const
|
|
60221
|
-
const { stdout } = await
|
|
60219
|
+
const { promisify: promisify15 } = await import("node:util");
|
|
60220
|
+
const execFileAsync4 = promisify15(execFile5);
|
|
60221
|
+
const { stdout } = await execFileAsync4("qmd", buildQmdAgentMemorySearchArgs(rootDir, agentMemory.agentId, query, limit), {
|
|
60222
60222
|
cwd: rootDir,
|
|
60223
60223
|
timeout: 4e3,
|
|
60224
60224
|
maxBuffer: 1024 * 1024
|
|
@@ -79190,7 +79190,7 @@ var init_self_healing = __esm({
|
|
|
79190
79190
|
const recoverFn = this.options.recoverCompletedTask;
|
|
79191
79191
|
if (!recoverFn) return 0;
|
|
79192
79192
|
try {
|
|
79193
|
-
const tasks = await this.store.listTasks({ column: "in-progress" });
|
|
79193
|
+
const tasks = await this.store.listTasks({ column: "in-progress", slim: true });
|
|
79194
79194
|
const executingIds = this.options.getExecutingTaskIds?.() ?? /* @__PURE__ */ new Set();
|
|
79195
79195
|
const stuckCompleted = tasks.filter(
|
|
79196
79196
|
(t) => t.column === "in-progress" && !t.paused && !executingIds.has(t.id) && t.steps.length > 0 && t.steps.every((s) => s.status === "done" || s.status === "skipped")
|
|
@@ -79224,7 +79224,7 @@ var init_self_healing = __esm({
|
|
|
79224
79224
|
*/
|
|
79225
79225
|
async recoverMergeableReviewTasks() {
|
|
79226
79226
|
try {
|
|
79227
|
-
const tasks = await this.store.listTasks({ column: "in-review" });
|
|
79227
|
+
const tasks = await this.store.listTasks({ column: "in-review", slim: true });
|
|
79228
79228
|
const mergeable = tasks.filter(
|
|
79229
79229
|
(t) => t.column === "in-review" && Boolean(t.worktree) && t.mergeDetails?.mergeConfirmed !== true && getTaskMergeBlocker(t) === void 0
|
|
79230
79230
|
);
|
|
@@ -79281,7 +79281,7 @@ var init_self_healing = __esm({
|
|
|
79281
79281
|
const settings = await this.store.getSettings();
|
|
79282
79282
|
const maxFixes = settings.maxPostReviewFixes ?? 1;
|
|
79283
79283
|
if (!Number.isFinite(maxFixes) || maxFixes <= 0) return 0;
|
|
79284
|
-
const tasks = await this.store.listTasks({ column: "in-review" });
|
|
79284
|
+
const tasks = await this.store.listTasks({ column: "in-review", slim: true });
|
|
79285
79285
|
const executingIds = this.options.getExecutingTaskIds?.() ?? /* @__PURE__ */ new Set();
|
|
79286
79286
|
const candidates = tasks.filter((task) => {
|
|
79287
79287
|
if (task.column !== "in-review") return false;
|
|
@@ -79346,7 +79346,7 @@ var init_self_healing = __esm({
|
|
|
79346
79346
|
const timeoutMs = settings.taskStuckTimeoutMs;
|
|
79347
79347
|
if (!timeoutMs || timeoutMs <= 0) return 0;
|
|
79348
79348
|
const now = Date.now();
|
|
79349
|
-
const tasks = await this.store.listTasks({ column: "in-review" });
|
|
79349
|
+
const tasks = await this.store.listTasks({ column: "in-review", slim: true });
|
|
79350
79350
|
const staleIncomplete = tasks.filter(
|
|
79351
79351
|
(task) => task.column === "in-review" && !task.paused && !task.status && task.steps.length > 0 && task.steps.some((step) => NON_TERMINAL_STEP_STATUSES2.has(step.status)) && now - new Date(task.updatedAt).getTime() >= timeoutMs
|
|
79352
79352
|
);
|
|
@@ -79393,7 +79393,7 @@ var init_self_healing = __esm({
|
|
|
79393
79393
|
const settings = await this.store.getSettings();
|
|
79394
79394
|
const timeoutMs = settings.taskStuckTimeoutMs;
|
|
79395
79395
|
if (!timeoutMs || timeoutMs <= 0) return 0;
|
|
79396
|
-
const tasks = await this.store.listTasks({ column: "in-review" });
|
|
79396
|
+
const tasks = await this.store.listTasks({ column: "in-review", slim: true });
|
|
79397
79397
|
const candidates = tasks.filter(
|
|
79398
79398
|
(task) => task.column === "in-review" && Boolean(task.status && ACTIVE_MERGE_STATUSES.has(task.status)) && this.isPastInterruptedMergeGrace(task, timeoutMs)
|
|
79399
79399
|
);
|
|
@@ -79464,7 +79464,7 @@ var init_self_healing = __esm({
|
|
|
79464
79464
|
*/
|
|
79465
79465
|
async recoverMergedReviewTasks() {
|
|
79466
79466
|
try {
|
|
79467
|
-
const tasks = await this.store.listTasks({ column: "in-review" });
|
|
79467
|
+
const tasks = await this.store.listTasks({ column: "in-review", slim: true });
|
|
79468
79468
|
const mergedButNotDone = tasks.filter(
|
|
79469
79469
|
(t) => t.column === "in-review" && t.mergeDetails?.mergeConfirmed === true
|
|
79470
79470
|
);
|
|
@@ -79512,7 +79512,7 @@ var init_self_healing = __esm({
|
|
|
79512
79512
|
*/
|
|
79513
79513
|
async recoverMisclassifiedFailures() {
|
|
79514
79514
|
try {
|
|
79515
|
-
const tasks = await this.store.listTasks({ column: "in-review" });
|
|
79515
|
+
const tasks = await this.store.listTasks({ column: "in-review", slim: true });
|
|
79516
79516
|
const misclassified = tasks.filter(
|
|
79517
79517
|
(t) => t.column === "in-review" && t.status === "failed" && t.error?.includes("without calling task_done") && t.steps.length > 0 && t.steps.every((s) => s.status === "done" || s.status === "skipped")
|
|
79518
79518
|
);
|
|
@@ -79553,7 +79553,7 @@ var init_self_healing = __esm({
|
|
|
79553
79553
|
*/
|
|
79554
79554
|
async recoverOrphanedExecutions() {
|
|
79555
79555
|
try {
|
|
79556
|
-
const tasks = await this.store.listTasks({ column: "in-progress" });
|
|
79556
|
+
const tasks = await this.store.listTasks({ column: "in-progress", slim: true });
|
|
79557
79557
|
const executingIds = this.options.getExecutingTaskIds?.() ?? /* @__PURE__ */ new Set();
|
|
79558
79558
|
const now = Date.now();
|
|
79559
79559
|
const orphaned = tasks.filter((t) => {
|
|
@@ -79610,7 +79610,7 @@ var init_self_healing = __esm({
|
|
|
79610
79610
|
*/
|
|
79611
79611
|
async recoverNoProgressNoTaskDoneFailures() {
|
|
79612
79612
|
try {
|
|
79613
|
-
const tasks = await this.store.listTasks({ column: "in-progress" });
|
|
79613
|
+
const tasks = await this.store.listTasks({ column: "in-progress", slim: true });
|
|
79614
79614
|
const executingIds = this.options.getExecutingTaskIds?.() ?? /* @__PURE__ */ new Set();
|
|
79615
79615
|
const candidates = tasks.filter(
|
|
79616
79616
|
(task) => task.column === "in-progress" && task.status === "failed" && isNoTaskDoneFailure(task) && !task.paused && !executingIds.has(task.id) && !isTaskWorkComplete(task) && !hasStepProgress(task)
|
|
@@ -79672,7 +79672,7 @@ var init_self_healing = __esm({
|
|
|
79672
79672
|
*/
|
|
79673
79673
|
async recoverPartialProgressNoTaskDoneFailures() {
|
|
79674
79674
|
try {
|
|
79675
|
-
const tasks = await this.store.listTasks({ column: "in-review" });
|
|
79675
|
+
const tasks = await this.store.listTasks({ column: "in-review", slim: true });
|
|
79676
79676
|
const candidates = tasks.filter(
|
|
79677
79677
|
(task) => task.column === "in-review" && task.status === "failed" && isNoTaskDoneFailure(task) && !task.paused && !isTaskWorkComplete(task) && hasStepProgress(task) && (task.taskDoneRetryCount ?? 0) < MAX_TASK_DONE_RETRIES
|
|
79678
79678
|
);
|
|
@@ -89559,7 +89559,7 @@ var require_readdir_glob = __commonJS({
|
|
|
89559
89559
|
var { EventEmitter: EventEmitter33 } = __require("events");
|
|
89560
89560
|
var { Minimatch } = require_minimatch();
|
|
89561
89561
|
var { resolve: resolve31 } = __require("path");
|
|
89562
|
-
function
|
|
89562
|
+
function readdir12(dir2, strict) {
|
|
89563
89563
|
return new Promise((resolve32, reject2) => {
|
|
89564
89564
|
fs2.readdir(dir2, { withFileTypes: true }, (err, files) => {
|
|
89565
89565
|
if (err) {
|
|
@@ -89592,7 +89592,7 @@ var require_readdir_glob = __commonJS({
|
|
|
89592
89592
|
});
|
|
89593
89593
|
});
|
|
89594
89594
|
}
|
|
89595
|
-
function
|
|
89595
|
+
function stat11(file, followSymlinks) {
|
|
89596
89596
|
return new Promise((resolve32, reject2) => {
|
|
89597
89597
|
const statFunc = followSymlinks ? fs2.stat : fs2.lstat;
|
|
89598
89598
|
statFunc(file, (err, stats) => {
|
|
@@ -89600,7 +89600,7 @@ var require_readdir_glob = __commonJS({
|
|
|
89600
89600
|
switch (err.code) {
|
|
89601
89601
|
case "ENOENT":
|
|
89602
89602
|
if (followSymlinks) {
|
|
89603
|
-
resolve32(
|
|
89603
|
+
resolve32(stat11(file, false));
|
|
89604
89604
|
} else {
|
|
89605
89605
|
resolve32(null);
|
|
89606
89606
|
}
|
|
@@ -89616,7 +89616,7 @@ var require_readdir_glob = __commonJS({
|
|
|
89616
89616
|
});
|
|
89617
89617
|
}
|
|
89618
89618
|
async function* exploreWalkAsync(dir2, path4, followSymlinks, useStat, shouldSkip, strict) {
|
|
89619
|
-
let files = await
|
|
89619
|
+
let files = await readdir12(path4 + dir2, strict);
|
|
89620
89620
|
for (const file of files) {
|
|
89621
89621
|
let name = file.name;
|
|
89622
89622
|
if (name === void 0) {
|
|
@@ -89628,7 +89628,7 @@ var require_readdir_glob = __commonJS({
|
|
|
89628
89628
|
const absolute = path4 + "/" + relative12;
|
|
89629
89629
|
let stats = null;
|
|
89630
89630
|
if (useStat || followSymlinks) {
|
|
89631
|
-
stats = await
|
|
89631
|
+
stats = await stat11(absolute, followSymlinks);
|
|
89632
89632
|
}
|
|
89633
89633
|
if (!stats && file.name !== void 0) {
|
|
89634
89634
|
stats = file;
|
|
@@ -92197,9 +92197,9 @@ var require_graceful_fs = __commonJS({
|
|
|
92197
92197
|
}
|
|
92198
92198
|
}
|
|
92199
92199
|
var fs$readdir = fs3.readdir;
|
|
92200
|
-
fs3.readdir =
|
|
92200
|
+
fs3.readdir = readdir12;
|
|
92201
92201
|
var noReaddirOptionVersions = /^v[0-5]\./;
|
|
92202
|
-
function
|
|
92202
|
+
function readdir12(path4, options, cb) {
|
|
92203
92203
|
if (typeof options === "function")
|
|
92204
92204
|
cb = options, options = null;
|
|
92205
92205
|
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path5, options2, cb2, startTime) {
|
|
@@ -115707,9 +115707,9 @@ async function getRemoteCommits(remoteRef, limit = 10, cwd) {
|
|
|
115707
115707
|
async function getCommitDiff(hash, cwd) {
|
|
115708
115708
|
try {
|
|
115709
115709
|
await runGitCommand(["cat-file", "-t", hash], cwd, 5e3);
|
|
115710
|
-
const
|
|
115710
|
+
const stat11 = (await runGitCommand(["show", "--stat", "--format=", hash], cwd, 1e4)).trim();
|
|
115711
115711
|
const patch = await runGitCommand(["show", "--format=", hash], cwd, 1e4);
|
|
115712
|
-
return { stat:
|
|
115712
|
+
return { stat: stat11, patch };
|
|
115713
115713
|
} catch {
|
|
115714
115714
|
return null;
|
|
115715
115715
|
}
|
|
@@ -116111,17 +116111,56 @@ async function getGitFileChanges(cwd) {
|
|
|
116111
116111
|
}
|
|
116112
116112
|
async function getGitWorkingDiff(cwd) {
|
|
116113
116113
|
try {
|
|
116114
|
-
const
|
|
116114
|
+
const stat11 = (await runGitCommand(["diff", "--stat"], cwd, 1e4)).trim();
|
|
116115
116115
|
const patch = await runGitCommand(["diff"], cwd, 1e4);
|
|
116116
|
-
return { stat:
|
|
116116
|
+
return { stat: stat11, patch };
|
|
116117
116117
|
} catch {
|
|
116118
116118
|
return { stat: "", patch: "" };
|
|
116119
116119
|
}
|
|
116120
116120
|
}
|
|
116121
|
+
function isValidGitFilePath(filePath) {
|
|
116122
|
+
if (!filePath || !filePath.trim()) return false;
|
|
116123
|
+
if (filePath.startsWith("-")) return false;
|
|
116124
|
+
if (isAbsolute12(filePath)) return false;
|
|
116125
|
+
if (filePath.includes("\0")) return false;
|
|
116126
|
+
if (filePath.includes("..")) return false;
|
|
116127
|
+
if (/[;&|`$(){}[\]\r\n]/.test(filePath)) return false;
|
|
116128
|
+
return true;
|
|
116129
|
+
}
|
|
116130
|
+
async function runNoIndexDiff(args, cwd) {
|
|
116131
|
+
try {
|
|
116132
|
+
return await runGitCommand(args, cwd, 1e4);
|
|
116133
|
+
} catch (error) {
|
|
116134
|
+
const commandError = error;
|
|
116135
|
+
if (typeof commandError.stdout === "string") {
|
|
116136
|
+
return commandError.stdout;
|
|
116137
|
+
}
|
|
116138
|
+
throw error;
|
|
116139
|
+
}
|
|
116140
|
+
}
|
|
116141
|
+
async function getGitFileDiff(filePath, staged, cwd) {
|
|
116142
|
+
if (!isValidGitFilePath(filePath)) {
|
|
116143
|
+
throw new Error(`Invalid file path: ${filePath}`);
|
|
116144
|
+
}
|
|
116145
|
+
if (staged) {
|
|
116146
|
+
const stat12 = (await runGitCommand(["diff", "--cached", "--stat", "--", filePath], cwd, 1e4)).trim();
|
|
116147
|
+
const patch2 = await runGitCommand(["diff", "--cached", "--", filePath], cwd, 1e4);
|
|
116148
|
+
return { stat: stat12, patch: patch2 };
|
|
116149
|
+
}
|
|
116150
|
+
const untracked = (await runGitCommand(["ls-files", "--others", "--exclude-standard", "--", filePath], cwd, 5e3)).trim();
|
|
116151
|
+
if (untracked === filePath) {
|
|
116152
|
+
const stat12 = (await runNoIndexDiff(["diff", "--no-index", "--stat", "/dev/null", filePath], cwd)).trim();
|
|
116153
|
+
const patch2 = await runNoIndexDiff(["diff", "--no-index", "/dev/null", filePath], cwd);
|
|
116154
|
+
return { stat: stat12, patch: patch2 };
|
|
116155
|
+
}
|
|
116156
|
+
const stat11 = (await runGitCommand(["diff", "--stat", "--", filePath], cwd, 1e4)).trim();
|
|
116157
|
+
const patch = await runGitCommand(["diff", "--", filePath], cwd, 1e4);
|
|
116158
|
+
return { stat: stat11, patch };
|
|
116159
|
+
}
|
|
116121
116160
|
async function stageGitFiles(files, cwd) {
|
|
116122
116161
|
if (!files.length) throw new Error("No files specified");
|
|
116123
116162
|
for (const f of files) {
|
|
116124
|
-
if (
|
|
116163
|
+
if (!isValidGitFilePath(f)) {
|
|
116125
116164
|
throw new Error(`Invalid file path: ${f}`);
|
|
116126
116165
|
}
|
|
116127
116166
|
}
|
|
@@ -116131,7 +116170,7 @@ async function stageGitFiles(files, cwd) {
|
|
|
116131
116170
|
async function unstageGitFiles(files, cwd) {
|
|
116132
116171
|
if (!files.length) throw new Error("No files specified");
|
|
116133
116172
|
for (const f of files) {
|
|
116134
|
-
if (
|
|
116173
|
+
if (!isValidGitFilePath(f)) {
|
|
116135
116174
|
throw new Error(`Invalid file path: ${f}`);
|
|
116136
116175
|
}
|
|
116137
116176
|
}
|
|
@@ -116149,7 +116188,7 @@ async function createGitCommit(message, cwd) {
|
|
|
116149
116188
|
async function discardGitChanges(files, cwd) {
|
|
116150
116189
|
if (!files.length) throw new Error("No files specified");
|
|
116151
116190
|
for (const f of files) {
|
|
116152
|
-
if (
|
|
116191
|
+
if (!isValidGitFilePath(f)) {
|
|
116153
116192
|
throw new Error(`Invalid file path: ${f}`);
|
|
116154
116193
|
}
|
|
116155
116194
|
}
|
|
@@ -119470,6 +119509,33 @@ function createApiRoutes(store, options) {
|
|
|
119470
119509
|
rethrowAsApiError3(err);
|
|
119471
119510
|
}
|
|
119472
119511
|
});
|
|
119512
|
+
router.get("/git/diff/file", async (req, res) => {
|
|
119513
|
+
try {
|
|
119514
|
+
const { store: scopedStore } = await getProjectContext2(req);
|
|
119515
|
+
const rootDir = scopedStore.getRootDir();
|
|
119516
|
+
if (!await isGitRepo(rootDir)) {
|
|
119517
|
+
throw badRequest("Not a git repository");
|
|
119518
|
+
}
|
|
119519
|
+
const rawPath = req.query.path;
|
|
119520
|
+
const rawStaged = req.query.staged;
|
|
119521
|
+
if (typeof rawPath !== "string" || !rawPath.trim()) {
|
|
119522
|
+
throw badRequest("path query parameter is required");
|
|
119523
|
+
}
|
|
119524
|
+
if (rawStaged !== "true" && rawStaged !== "false") {
|
|
119525
|
+
throw badRequest("staged query parameter must be 'true' or 'false'");
|
|
119526
|
+
}
|
|
119527
|
+
if (!isValidGitFilePath(rawPath)) {
|
|
119528
|
+
throw badRequest(`Invalid file path: ${rawPath}`);
|
|
119529
|
+
}
|
|
119530
|
+
const diff = await getGitFileDiff(rawPath, rawStaged === "true", rootDir);
|
|
119531
|
+
res.json(diff);
|
|
119532
|
+
} catch (err) {
|
|
119533
|
+
if (err instanceof ApiError) {
|
|
119534
|
+
throw err;
|
|
119535
|
+
}
|
|
119536
|
+
rethrowAsApiError3(err);
|
|
119537
|
+
}
|
|
119538
|
+
});
|
|
119473
119539
|
router.get("/git/changes", async (req, res) => {
|
|
119474
119540
|
try {
|
|
119475
119541
|
const { store: scopedStore } = await getProjectContext2(req);
|
|
@@ -125858,7 +125924,7 @@ ${body}`;
|
|
|
125858
125924
|
}
|
|
125859
125925
|
}
|
|
125860
125926
|
const { resolve: resolve31, dirname: dirname25, join: join60 } = await import("node:path");
|
|
125861
|
-
const { readdir:
|
|
125927
|
+
const { readdir: readdir12, stat: stat11 } = await import("node:fs/promises");
|
|
125862
125928
|
const rawPath = req.query.path || process.env.HOME || process.env.USERPROFILE || "/";
|
|
125863
125929
|
const showHidden = req.query.showHidden === "true";
|
|
125864
125930
|
const resolvedPath = resolve31(rawPath);
|
|
@@ -125870,14 +125936,14 @@ ${body}`;
|
|
|
125870
125936
|
}
|
|
125871
125937
|
let pathStat;
|
|
125872
125938
|
try {
|
|
125873
|
-
pathStat = await
|
|
125939
|
+
pathStat = await stat11(resolvedPath);
|
|
125874
125940
|
} catch {
|
|
125875
125941
|
throw notFound("Directory not found");
|
|
125876
125942
|
}
|
|
125877
125943
|
if (!pathStat.isDirectory()) {
|
|
125878
125944
|
throw badRequest("Path is not a directory");
|
|
125879
125945
|
}
|
|
125880
|
-
const dirEntries = await
|
|
125946
|
+
const dirEntries = await readdir12(resolvedPath, { withFileTypes: true });
|
|
125881
125947
|
const entries = [];
|
|
125882
125948
|
for (const entry of dirEntries) {
|
|
125883
125949
|
if (!entry.isDirectory()) continue;
|
|
@@ -125885,7 +125951,7 @@ ${body}`;
|
|
|
125885
125951
|
const entryPath = join60(resolvedPath, entry.name);
|
|
125886
125952
|
let hasChildren = false;
|
|
125887
125953
|
try {
|
|
125888
|
-
const subEntries = await
|
|
125954
|
+
const subEntries = await readdir12(entryPath, { withFileTypes: true });
|
|
125889
125955
|
hasChildren = subEntries.some((e) => e.isDirectory());
|
|
125890
125956
|
} catch {
|
|
125891
125957
|
}
|
|
@@ -128405,8 +128471,8 @@ function validateAutomationSteps(steps) {
|
|
|
128405
128471
|
}
|
|
128406
128472
|
async function executeSingleCommand(command, timeoutMs, startedAt) {
|
|
128407
128473
|
const { exec: exec12 } = await import("node:child_process");
|
|
128408
|
-
const { promisify:
|
|
128409
|
-
const execAsyncFn =
|
|
128474
|
+
const { promisify: promisify15 } = await import("node:util");
|
|
128475
|
+
const execAsyncFn = promisify15(exec12);
|
|
128410
128476
|
const DEFAULT_TIMEOUT_MS3 = 5 * 60 * 1e3;
|
|
128411
128477
|
const MAX_BUFFER3 = 1024 * 1024;
|
|
128412
128478
|
const MAX_OUTPUT = 10240;
|
|
@@ -129060,11 +129126,14 @@ function markSSEClientAlive(clientId, projectId) {
|
|
|
129060
129126
|
}
|
|
129061
129127
|
function safeWrite(res, data) {
|
|
129062
129128
|
try {
|
|
129063
|
-
if (res.writableEnded || res.destroyed) return
|
|
129129
|
+
if (res.writableEnded || res.destroyed) return "dead";
|
|
129130
|
+
if (typeof res.writableLength === "number" && res.writableLength > SSE_MAX_BUFFERED_BYTES) {
|
|
129131
|
+
return "backpressure";
|
|
129132
|
+
}
|
|
129064
129133
|
res.write(data);
|
|
129065
|
-
return
|
|
129134
|
+
return "ok";
|
|
129066
129135
|
} catch {
|
|
129067
|
-
return
|
|
129136
|
+
return "dead";
|
|
129068
129137
|
}
|
|
129069
129138
|
}
|
|
129070
129139
|
function stripTaskListHeavyFields(task) {
|
|
@@ -129143,7 +129212,16 @@ function createSSE(store, missionStore, aiSessionStore, pluginStore, options, ag
|
|
|
129143
129212
|
console.log(`[sse] + connection (active=${activeConnections}, hwm=${highWaterMark})`);
|
|
129144
129213
|
res.write(": connected\n\n");
|
|
129145
129214
|
const send = (data) => {
|
|
129146
|
-
|
|
129215
|
+
const result = safeWrite(res, data);
|
|
129216
|
+
if (result === "ok") return;
|
|
129217
|
+
if (result === "backpressure") {
|
|
129218
|
+
console.warn(
|
|
129219
|
+
`[sse] connection ${connectionId} backpressure exceeded (buffered=${res.writableLength}B, threshold=${SSE_MAX_BUFFERED_BYTES}B); closing`
|
|
129220
|
+
);
|
|
129221
|
+
closeConnection("backpressure");
|
|
129222
|
+
return;
|
|
129223
|
+
}
|
|
129224
|
+
cleanup("send-failed");
|
|
129147
129225
|
};
|
|
129148
129226
|
const onCreated = (task) => {
|
|
129149
129227
|
send(`event: task:created
|
|
@@ -129636,7 +129714,7 @@ data: ${JSON.stringify({ id: messageId })}
|
|
|
129636
129714
|
}
|
|
129637
129715
|
};
|
|
129638
129716
|
}
|
|
129639
|
-
var activeConnections, highWaterMark, nextConnectionId, SSE_CLIENT_ID_MAX_LENGTH, SSE_CLIENT_STALE_MS, managedConnections;
|
|
129717
|
+
var activeConnections, highWaterMark, nextConnectionId, SSE_CLIENT_ID_MAX_LENGTH, SSE_CLIENT_STALE_MS, SSE_MAX_BUFFERED_BYTES, managedConnections;
|
|
129640
129718
|
var init_sse = __esm({
|
|
129641
129719
|
"../dashboard/src/sse.ts"() {
|
|
129642
129720
|
"use strict";
|
|
@@ -129645,6 +129723,7 @@ var init_sse = __esm({
|
|
|
129645
129723
|
nextConnectionId = 1;
|
|
129646
129724
|
SSE_CLIENT_ID_MAX_LENGTH = 128;
|
|
129647
129725
|
SSE_CLIENT_STALE_MS = 5e3;
|
|
129726
|
+
SSE_MAX_BUFFERED_BYTES = 4 * 1024 * 1024;
|
|
129648
129727
|
managedConnections = /* @__PURE__ */ new Map();
|
|
129649
129728
|
}
|
|
129650
129729
|
});
|
|
@@ -136000,8 +136079,8 @@ function installFusionSkillIntoProject(projectPath, options = {}) {
|
|
|
136000
136079
|
mkdirSync7(dirname19(target), { recursive: true });
|
|
136001
136080
|
let replaced = false;
|
|
136002
136081
|
if (existsSync35(target) || isBrokenSymlink(target)) {
|
|
136003
|
-
const
|
|
136004
|
-
if (
|
|
136082
|
+
const stat11 = lstatSync2(target);
|
|
136083
|
+
if (stat11.isSymbolicLink()) {
|
|
136005
136084
|
const current = safeReadlink(target);
|
|
136006
136085
|
if (current && resolve21(dirname19(target), current) === resolve21(source)) {
|
|
136007
136086
|
return { outcome: "already-installed", target, source };
|
|
@@ -136067,8 +136146,8 @@ function ensureFusionSkillForProjects(projects, options = { enabled: false }) {
|
|
|
136067
136146
|
}
|
|
136068
136147
|
function isBrokenSymlink(path4) {
|
|
136069
136148
|
try {
|
|
136070
|
-
const
|
|
136071
|
-
if (!
|
|
136149
|
+
const stat11 = lstatSync2(path4);
|
|
136150
|
+
if (!stat11.isSymbolicLink()) return false;
|
|
136072
136151
|
return !existsSync35(path4);
|
|
136073
136152
|
} catch {
|
|
136074
136153
|
return false;
|
|
@@ -136306,7 +136385,7 @@ var init_state = __esm({
|
|
|
136306
136385
|
});
|
|
136307
136386
|
|
|
136308
136387
|
// src/commands/dashboard-tui/logo.ts
|
|
136309
|
-
var FUSION_LOGO_LINES, FUSION_TAGLINE;
|
|
136388
|
+
var FUSION_LOGO_LINES, FUSION_LOGO_LARGE_LINES, FUSION_TAGLINE;
|
|
136310
136389
|
var init_logo = __esm({
|
|
136311
136390
|
"src/commands/dashboard-tui/logo.ts"() {
|
|
136312
136391
|
"use strict";
|
|
@@ -136318,6 +136397,20 @@ var init_logo = __esm({
|
|
|
136318
136397
|
"\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551",
|
|
136319
136398
|
"\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D"
|
|
136320
136399
|
];
|
|
136400
|
+
FUSION_LOGO_LARGE_LINES = [
|
|
136401
|
+
"\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557",
|
|
136402
|
+
"\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557",
|
|
136403
|
+
"\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551",
|
|
136404
|
+
"\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551",
|
|
136405
|
+
"\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551",
|
|
136406
|
+
"\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551",
|
|
136407
|
+
"\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551",
|
|
136408
|
+
"\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551",
|
|
136409
|
+
"\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551",
|
|
136410
|
+
"\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551",
|
|
136411
|
+
"\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D",
|
|
136412
|
+
"\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D"
|
|
136413
|
+
];
|
|
136321
136414
|
FUSION_TAGLINE = "AI coding agent dashboard";
|
|
136322
136415
|
}
|
|
136323
136416
|
});
|
|
@@ -136431,43 +136524,48 @@ function formatRelativeTime(iso) {
|
|
|
136431
136524
|
const h = Math.floor(m / 60);
|
|
136432
136525
|
return `${h}h ago`;
|
|
136433
136526
|
}
|
|
136434
|
-
function logoColor(index2) {
|
|
136435
|
-
|
|
136527
|
+
function logoColor(index2, total) {
|
|
136528
|
+
const slot = Math.min(
|
|
136529
|
+
LOGO_COLORS.length - 1,
|
|
136530
|
+
Math.floor(index2 / Math.max(1, total - 1) * (LOGO_COLORS.length - 1))
|
|
136531
|
+
);
|
|
136532
|
+
return LOGO_COLORS[slot];
|
|
136436
136533
|
}
|
|
136437
|
-
function AnimatedFusionLogo() {
|
|
136438
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", alignItems: "center", children:
|
|
136534
|
+
function AnimatedFusionLogo({ lines }) {
|
|
136535
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", alignItems: "center", children: lines.map((line, i) => /* @__PURE__ */ jsx(Text, { color: logoColor(i, lines.length), bold: true, children: line }, i)) });
|
|
136439
136536
|
}
|
|
136440
136537
|
function SplashScreen({ loadingStatus }) {
|
|
136441
136538
|
const { stdout } = useStdout();
|
|
136442
136539
|
const cols = stdout?.columns ?? 80;
|
|
136443
136540
|
const rows = stdout?.rows ?? 24;
|
|
136444
136541
|
const compact = cols < SPLASH_MIN_COLS || rows < SPLASH_MIN_ROWS;
|
|
136542
|
+
const large = cols >= LARGE_LOGO_MIN_COLS && rows >= LARGE_LOGO_MIN_ROWS;
|
|
136445
136543
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
|
|
136446
|
-
compact ? /* @__PURE__ */ jsx(Text, { bold: true, color: "cyanBright", children: "FUSION" }) : /* @__PURE__ */ jsx(AnimatedFusionLogo, {}),
|
|
136447
|
-
/* @__PURE__ */ jsx(Text, { color: "
|
|
136544
|
+
compact ? /* @__PURE__ */ jsx(Text, { bold: true, color: "cyanBright", children: "FUSION" }) : /* @__PURE__ */ jsx(AnimatedFusionLogo, { lines: large ? FUSION_LOGO_LARGE_LINES : FUSION_LOGO_LINES }),
|
|
136545
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", dimColor: true, children: FUSION_TAGLINE }),
|
|
136448
136546
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
136449
136547
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
136450
136548
|
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
136451
|
-
/* @__PURE__ */ jsx(Text, { color: "
|
|
136549
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", dimColor: true, children: loadingStatus })
|
|
136452
136550
|
] })
|
|
136453
136551
|
] });
|
|
136454
136552
|
}
|
|
136455
136553
|
function MiniLogo() {
|
|
136456
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 0, children: /* @__PURE__ */ jsx(Text, { color: "
|
|
136554
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 0, children: /* @__PURE__ */ jsx(Text, { color: "cyanBright", bold: true, children: "FUSION" }) });
|
|
136457
136555
|
}
|
|
136458
136556
|
function Panel({ title, isFocused, children, flexGrow, flexShrink, width }) {
|
|
136459
136557
|
return /* @__PURE__ */ jsxs(
|
|
136460
136558
|
Box,
|
|
136461
136559
|
{
|
|
136462
136560
|
borderStyle: "round",
|
|
136463
|
-
borderColor: isFocused ? "
|
|
136561
|
+
borderColor: isFocused ? "cyanBright" : "gray",
|
|
136464
136562
|
flexDirection: "column",
|
|
136465
136563
|
flexGrow,
|
|
136466
136564
|
flexShrink,
|
|
136467
136565
|
width,
|
|
136468
136566
|
overflow: "hidden",
|
|
136469
136567
|
children: [
|
|
136470
|
-
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: isFocused, color: isFocused ? "
|
|
136568
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: isFocused, color: isFocused ? "cyanBright" : void 0, dimColor: !isFocused, children: title }) }),
|
|
136471
136569
|
/* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children })
|
|
136472
136570
|
]
|
|
136473
136571
|
}
|
|
@@ -136486,7 +136584,7 @@ function SystemPanel({ state, isFocused }) {
|
|
|
136486
136584
|
] }),
|
|
136487
136585
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
136488
136586
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "URL:" }),
|
|
136489
|
-
/* @__PURE__ */ jsx(Text, { color: "
|
|
136587
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: info.baseUrl })
|
|
136490
136588
|
] }),
|
|
136491
136589
|
info.authEnabled ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
136492
136590
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
@@ -136499,24 +136597,12 @@ function SystemPanel({ state, isFocused }) {
|
|
|
136499
136597
|
] }),
|
|
136500
136598
|
info.tokenizedUrl && /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
136501
136599
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Open:" }),
|
|
136502
|
-
/* @__PURE__ */ jsx(Text, { wrap: "truncate", color: "
|
|
136503
|
-
] }),
|
|
136504
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
136505
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press" }),
|
|
136506
|
-
/* @__PURE__ */ jsx(Text, { color: "cyanBright", bold: true, children: "[Enter]" }),
|
|
136507
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "to open in browser" })
|
|
136508
|
-
] })
|
|
136509
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
136510
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
136511
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Auth:" }),
|
|
136512
|
-
/* @__PURE__ */ jsx(Text, { color: "yellow", children: "no auth" })
|
|
136513
|
-
] }),
|
|
136514
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
136515
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press" }),
|
|
136516
|
-
/* @__PURE__ */ jsx(Text, { color: "cyanBright", bold: true, children: "[Enter]" }),
|
|
136517
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "to open in browser" })
|
|
136600
|
+
/* @__PURE__ */ jsx(Text, { wrap: "truncate", color: "white", children: info.tokenizedUrl })
|
|
136518
136601
|
] })
|
|
136519
|
-
] }),
|
|
136602
|
+
] }) : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
136603
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Auth:" }),
|
|
136604
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: "no auth" })
|
|
136605
|
+
] }) }),
|
|
136520
136606
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
136521
136607
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Engine:" }),
|
|
136522
136608
|
info.engineMode === "dev" && /* @__PURE__ */ jsx(Text, { color: "yellow", children: "dev" }),
|
|
@@ -136533,40 +136619,113 @@ function SystemPanel({ state, isFocused }) {
|
|
|
136533
136619
|
] })
|
|
136534
136620
|
] }) });
|
|
136535
136621
|
}
|
|
136622
|
+
function formatBytes2(bytes) {
|
|
136623
|
+
if (!Number.isFinite(bytes) || bytes < 0) return "\u2014";
|
|
136624
|
+
const mb = bytes / (1024 * 1024);
|
|
136625
|
+
if (mb < 1024) return `${mb.toFixed(0)} MB`;
|
|
136626
|
+
return `${(mb / 1024).toFixed(2)} GB`;
|
|
136627
|
+
}
|
|
136628
|
+
function heapColor(used, limit) {
|
|
136629
|
+
if (limit <= 0) return "green";
|
|
136630
|
+
const pct = used / limit;
|
|
136631
|
+
if (pct >= 0.85) return "red";
|
|
136632
|
+
if (pct >= 0.65) return "yellow";
|
|
136633
|
+
return "green";
|
|
136634
|
+
}
|
|
136635
|
+
function rssColor(rss, totalSystemMem) {
|
|
136636
|
+
if (totalSystemMem <= 0) return void 0;
|
|
136637
|
+
const pct = rss / totalSystemMem;
|
|
136638
|
+
if (pct >= 0.5) return "red";
|
|
136639
|
+
if (pct >= 0.25) return "yellow";
|
|
136640
|
+
return void 0;
|
|
136641
|
+
}
|
|
136642
|
+
function sysMemColor(used, total) {
|
|
136643
|
+
if (total <= 0) return void 0;
|
|
136644
|
+
const pct = used / total;
|
|
136645
|
+
if (pct >= 0.9) return "red";
|
|
136646
|
+
if (pct >= 0.75) return "yellow";
|
|
136647
|
+
return void 0;
|
|
136648
|
+
}
|
|
136649
|
+
function cpuColor(percent, cores) {
|
|
136650
|
+
const norm = cores > 0 ? percent / cores : percent;
|
|
136651
|
+
if (norm >= 80) return "red";
|
|
136652
|
+
if (norm >= 50) return "yellow";
|
|
136653
|
+
return void 0;
|
|
136654
|
+
}
|
|
136655
|
+
function StatRow({ label, children }) {
|
|
136656
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
136657
|
+
/* @__PURE__ */ jsx(Box, { width: 10, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: label }) }),
|
|
136658
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children })
|
|
136659
|
+
] });
|
|
136660
|
+
}
|
|
136661
|
+
function SectionHeader({ title }) {
|
|
136662
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyanBright", children: title }) });
|
|
136663
|
+
}
|
|
136536
136664
|
function StatsPanel({ state, isFocused }) {
|
|
136537
136665
|
const stats = state.taskStats;
|
|
136538
|
-
|
|
136539
|
-
|
|
136540
|
-
|
|
136541
|
-
/* @__PURE__ */ jsx(
|
|
136542
|
-
|
|
136543
|
-
|
|
136544
|
-
|
|
136545
|
-
|
|
136546
|
-
|
|
136547
|
-
|
|
136548
|
-
|
|
136549
|
-
|
|
136666
|
+
const sys = state.systemStats;
|
|
136667
|
+
return /* @__PURE__ */ jsx(Panel, { title: "Stats", isFocused, flexGrow: 1, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
136668
|
+
sys && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
136669
|
+
/* @__PURE__ */ jsx(SectionHeader, { title: "Process" }),
|
|
136670
|
+
/* @__PURE__ */ jsxs(StatRow, { label: "RSS", children: [
|
|
136671
|
+
/* @__PURE__ */ jsx(Text, { color: rssColor(sys.rss, sys.systemTotalMem), children: formatBytes2(sys.rss) }),
|
|
136672
|
+
sys.systemTotalMem > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
136673
|
+
(sys.rss / sys.systemTotalMem * 100).toFixed(1),
|
|
136674
|
+
"%"
|
|
136675
|
+
] })
|
|
136676
|
+
] }),
|
|
136677
|
+
/* @__PURE__ */ jsxs(StatRow, { label: "Heap", children: [
|
|
136678
|
+
/* @__PURE__ */ jsx(Text, { color: heapColor(sys.heapUsed, sys.heapLimit), children: formatBytes2(sys.heapUsed) }),
|
|
136679
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "/" }),
|
|
136680
|
+
/* @__PURE__ */ jsx(Text, { children: formatBytes2(sys.heapTotal) })
|
|
136681
|
+
] }),
|
|
136682
|
+
/* @__PURE__ */ jsxs(StatRow, { label: "", children: [
|
|
136683
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "limit" }),
|
|
136684
|
+
/* @__PURE__ */ jsx(Text, { children: formatBytes2(sys.heapLimit) })
|
|
136685
|
+
] }),
|
|
136686
|
+
/* @__PURE__ */ jsxs(StatRow, { label: "External", children: [
|
|
136687
|
+
/* @__PURE__ */ jsx(Text, { children: formatBytes2(sys.external) }),
|
|
136688
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "buffers" }),
|
|
136689
|
+
/* @__PURE__ */ jsx(Text, { children: formatBytes2(sys.arrayBuffers) })
|
|
136690
|
+
] }),
|
|
136691
|
+
/* @__PURE__ */ jsxs(StatRow, { label: "CPU", children: [
|
|
136692
|
+
/* @__PURE__ */ jsxs(Text, { color: cpuColor(sys.cpuPercent, sys.cpuCount), children: [
|
|
136693
|
+
sys.cpuPercent.toFixed(1),
|
|
136694
|
+
"%"
|
|
136550
136695
|
] }),
|
|
136551
|
-
/* @__PURE__ */ jsx(Text, {
|
|
136552
|
-
|
|
136553
|
-
}),
|
|
136554
|
-
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
136555
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Agents:" }),
|
|
136556
|
-
/* @__PURE__ */ jsxs(Box, { marginLeft: 1, flexDirection: "column", children: [
|
|
136557
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
136558
|
-
"idle: ",
|
|
136559
|
-
/* @__PURE__ */ jsx(Text, { color: "white", children: stats.agents.idle })
|
|
136696
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "load" }),
|
|
136697
|
+
/* @__PURE__ */ jsx(Text, { children: sys.loadAvg.map((n) => n.toFixed(2)).join(" ") })
|
|
136560
136698
|
] }),
|
|
136561
|
-
/* @__PURE__ */
|
|
136562
|
-
|
|
136563
|
-
/* @__PURE__ */ jsx(Text, { color:
|
|
136699
|
+
/* @__PURE__ */ jsx(SectionHeader, { title: "System" }),
|
|
136700
|
+
/* @__PURE__ */ jsxs(StatRow, { label: "Memory", children: [
|
|
136701
|
+
/* @__PURE__ */ jsx(Text, { color: sysMemColor(sys.systemTotalMem - sys.systemFreeMem, sys.systemTotalMem), children: formatBytes2(sys.systemTotalMem - sys.systemFreeMem) }),
|
|
136702
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "used" }),
|
|
136703
|
+
/* @__PURE__ */ jsx(Text, { children: formatBytes2(sys.systemFreeMem) }),
|
|
136704
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "free" })
|
|
136564
136705
|
] }),
|
|
136565
|
-
/* @__PURE__ */ jsxs(
|
|
136566
|
-
|
|
136567
|
-
|
|
136706
|
+
/* @__PURE__ */ jsxs(StatRow, { label: "Cores", children: [
|
|
136707
|
+
/* @__PURE__ */ jsx(Text, { children: sys.cpuCount }),
|
|
136708
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: sys.platform })
|
|
136709
|
+
] }),
|
|
136710
|
+
/* @__PURE__ */ jsxs(StatRow, { label: "Node", children: [
|
|
136711
|
+
/* @__PURE__ */ jsx(Text, { children: sys.nodeVersion }),
|
|
136712
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "pid" }),
|
|
136713
|
+
/* @__PURE__ */ jsx(Text, { children: sys.pid })
|
|
136568
136714
|
] })
|
|
136569
|
-
] })
|
|
136715
|
+
] }),
|
|
136716
|
+
stats && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
136717
|
+
/* @__PURE__ */ jsx(SectionHeader, { title: "Tasks" }),
|
|
136718
|
+
Object.entries(stats.byColumn).map(([col, count]) => {
|
|
136719
|
+
const name = col.replace(/-/g, " ");
|
|
136720
|
+
const isActive = (col === "in-progress" || col === "in-review") && count > 0;
|
|
136721
|
+
return /* @__PURE__ */ jsx(StatRow, { label: name, children: /* @__PURE__ */ jsx(Text, { color: isActive ? "green" : void 0, children: count }) }, col);
|
|
136722
|
+
}),
|
|
136723
|
+
/* @__PURE__ */ jsx(SectionHeader, { title: "Agents" }),
|
|
136724
|
+
/* @__PURE__ */ jsx(StatRow, { label: "idle", children: /* @__PURE__ */ jsx(Text, { children: stats.agents.idle }) }),
|
|
136725
|
+
/* @__PURE__ */ jsx(StatRow, { label: "active", children: /* @__PURE__ */ jsx(Text, { color: "green", children: stats.agents.active }) }),
|
|
136726
|
+
/* @__PURE__ */ jsx(StatRow, { label: "error", children: /* @__PURE__ */ jsx(Text, { color: stats.agents.error > 0 ? "red" : void 0, children: stats.agents.error }) })
|
|
136727
|
+
] }),
|
|
136728
|
+
!sys && !stats && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Stats not available." })
|
|
136570
136729
|
] }) });
|
|
136571
136730
|
}
|
|
136572
136731
|
function SettingsPanel({ state, isFocused }) {
|
|
@@ -136646,7 +136805,7 @@ function LogsPanel({
|
|
|
136646
136805
|
visibleEntries.map((entry, displayIdx) => {
|
|
136647
136806
|
const absoluteIndex = visibleStart + displayIdx;
|
|
136648
136807
|
const isSelected = absoluteIndex === cursor;
|
|
136649
|
-
const bg = isSelected ? "
|
|
136808
|
+
const bg = isSelected ? "cyan" : void 0;
|
|
136650
136809
|
const fg = isSelected ? "whiteBright" : void 0;
|
|
136651
136810
|
const ts = formatTimestamp3(entry.timestamp);
|
|
136652
136811
|
const lvl = entry.level === "error" ? "\u2717" : entry.level === "warn" ? "\u26A0" : "\u2713";
|
|
@@ -136659,7 +136818,7 @@ function LogsPanel({
|
|
|
136659
136818
|
backgroundColor: bg,
|
|
136660
136819
|
wrap: logsWrapEnabled ? "wrap" : "truncate-end",
|
|
136661
136820
|
children: [
|
|
136662
|
-
/* @__PURE__ */ jsx(Text, { color: isSelected ? "
|
|
136821
|
+
/* @__PURE__ */ jsx(Text, { color: isSelected ? "white" : "gray", bold: isSelected, children: marker }),
|
|
136663
136822
|
/* @__PURE__ */ jsxs(Text, { color: fg, dimColor: !isSelected, children: [
|
|
136664
136823
|
ts,
|
|
136665
136824
|
" "
|
|
@@ -136675,7 +136834,7 @@ function LogsPanel({
|
|
|
136675
136834
|
] }) });
|
|
136676
136835
|
}
|
|
136677
136836
|
function ExpandedLog({ entry, index: index2, total }) {
|
|
136678
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
136837
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, width: "100%", children: [
|
|
136679
136838
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
136680
136839
|
"Entry ",
|
|
136681
136840
|
index2 + 1,
|
|
@@ -136722,6 +136881,7 @@ function HelpOverlay() {
|
|
|
136722
136881
|
["[b]", "Board view (interactive mode)"],
|
|
136723
136882
|
["[a]", "Agents view"],
|
|
136724
136883
|
["[g]", "Settings view"],
|
|
136884
|
+
["[t]", "Git view"],
|
|
136725
136885
|
["[s]", "Status mode"],
|
|
136726
136886
|
["[1] / [2] / [3]", "Board / Agents / Settings (interactive)"],
|
|
136727
136887
|
["[Tab]", "Cycle focused panel forward"],
|
|
@@ -136750,8 +136910,8 @@ function HelpOverlay() {
|
|
|
136750
136910
|
const rowDescWidth = Math.max(...shortcuts.map(([, d]) => d.length));
|
|
136751
136911
|
const innerWidth = rowKeyWidth + 2 + rowDescWidth + 2;
|
|
136752
136912
|
const titleRow = " KEYBOARD SHORTCUTS".padEnd(innerWidth);
|
|
136753
|
-
return /* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: "
|
|
136754
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: "black", bold: true, color: "
|
|
136913
|
+
return /* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: "cyanBright", flexDirection: "column", backgroundColor: "black", children: [
|
|
136914
|
+
/* @__PURE__ */ jsx(Text, { backgroundColor: "black", bold: true, color: "white", children: titleRow }),
|
|
136755
136915
|
/* @__PURE__ */ jsx(Text, { backgroundColor: "black", children: " " }),
|
|
136756
136916
|
shortcuts.map(([key, desc]) => {
|
|
136757
136917
|
const keyCell = ` ${key.padEnd(rowKeyWidth - 1)} `;
|
|
@@ -136772,24 +136932,13 @@ function StatusModeGrid({
|
|
|
136772
136932
|
const bodyRows = Math.max(8, rows - 7);
|
|
136773
136933
|
const logsAvailableRows = Math.max(4, bodyRows - 4);
|
|
136774
136934
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
|
|
136775
|
-
/* @__PURE__ */
|
|
136776
|
-
/* @__PURE__ */ jsx(MiniLogo, {}),
|
|
136777
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
136778
|
-
SECTION_ORDER.map((section, i) => {
|
|
136779
|
-
const isActive = section === focused;
|
|
136780
|
-
const label = section.charAt(0).toUpperCase() + section.slice(1);
|
|
136781
|
-
return /* @__PURE__ */ jsx(Box, { marginRight: 1, children: isActive ? /* @__PURE__ */ jsx(Text, { backgroundColor: "cyan", color: "black", bold: true, children: ` [${i + 1}] ${label} ` }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: `[${i + 1}] ${label}` }) }, section);
|
|
136782
|
-
}),
|
|
136783
|
-
/* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
|
|
136784
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[b] board [a] agents [g] settings [?] help [q] quit" })
|
|
136785
|
-
] }),
|
|
136935
|
+
/* @__PURE__ */ jsx(MainHeader, { state }),
|
|
136786
136936
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexGrow: 1, overflow: "hidden", children: [
|
|
136787
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow:
|
|
136937
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 5, overflow: "hidden", children: [
|
|
136788
136938
|
/* @__PURE__ */ jsx(SystemPanel, { state, isFocused: focused === "system" }),
|
|
136789
|
-
/* @__PURE__ */ jsx(StatsPanel, { state, isFocused: focused === "stats" })
|
|
136790
|
-
/* @__PURE__ */ jsx(SettingsPanel, { state, isFocused: focused === "settings" })
|
|
136939
|
+
/* @__PURE__ */ jsx(StatsPanel, { state, isFocused: focused === "stats" })
|
|
136791
136940
|
] }),
|
|
136792
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow:
|
|
136941
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 6, overflow: "hidden", children: [
|
|
136793
136942
|
/* @__PURE__ */ jsx(
|
|
136794
136943
|
LogsPanel,
|
|
136795
136944
|
{
|
|
@@ -136798,7 +136947,10 @@ function StatusModeGrid({
|
|
|
136798
136947
|
availableRows: logsAvailableRows
|
|
136799
136948
|
}
|
|
136800
136949
|
),
|
|
136801
|
-
/* @__PURE__ */
|
|
136950
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", overflow: "hidden", children: [
|
|
136951
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx(UtilitiesPanel, { isFocused: focused === "utilities" }) }),
|
|
136952
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx(SettingsPanel, { state, isFocused: focused === "settings" }) })
|
|
136953
|
+
] })
|
|
136802
136954
|
] })
|
|
136803
136955
|
] }),
|
|
136804
136956
|
/* @__PURE__ */ jsx(StatusBar, { state, controller })
|
|
@@ -136824,15 +136976,7 @@ function StatusModeSingle({
|
|
|
136824
136976
|
}
|
|
136825
136977
|
};
|
|
136826
136978
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
|
|
136827
|
-
/* @__PURE__ */
|
|
136828
|
-
/* @__PURE__ */ jsx(MiniLogo, {}),
|
|
136829
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
136830
|
-
SECTION_ORDER.map((section, i) => {
|
|
136831
|
-
const isActive = section === focused;
|
|
136832
|
-
const label = section.charAt(0).toUpperCase() + section.slice(1);
|
|
136833
|
-
return /* @__PURE__ */ jsx(Box, { marginRight: 1, children: isActive ? /* @__PURE__ */ jsx(Text, { backgroundColor: "cyan", color: "black", bold: true, children: ` [${i + 1}] ${label} ` }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: `[${i + 1}] ${label}` }) }, section);
|
|
136834
|
-
})
|
|
136835
|
-
] }),
|
|
136979
|
+
/* @__PURE__ */ jsx(MainHeader, { state }),
|
|
136836
136980
|
/* @__PURE__ */ jsx(Box, { flexGrow: 1, flexDirection: "column", overflow: "hidden", children: activePanel() }),
|
|
136837
136981
|
/* @__PURE__ */ jsx(StatusBar, { state, controller })
|
|
136838
136982
|
] });
|
|
@@ -136857,21 +137001,53 @@ function StatusBar({ state, controller: _controller }) {
|
|
|
136857
137001
|
statusParts.length > 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: statusParts.join(" | ") })
|
|
136858
137002
|
] });
|
|
136859
137003
|
}
|
|
136860
|
-
function
|
|
136861
|
-
const
|
|
137004
|
+
function MainHeader({ state }) {
|
|
137005
|
+
const inInteractive = state.mode === "interactive";
|
|
137006
|
+
const focused = state.activeSection;
|
|
137007
|
+
const interactiveView = state.interactiveView;
|
|
137008
|
+
const { stdout } = useStdout();
|
|
137009
|
+
const cols = stdout?.columns ?? 80;
|
|
137010
|
+
const rows = stdout?.rows ?? 24;
|
|
137011
|
+
const interactiveTabs = [
|
|
136862
137012
|
{ key: "b", label: "Board", view: "board" },
|
|
136863
137013
|
{ key: "a", label: "Agents", view: "agents" },
|
|
136864
|
-
{ key: "g", label: "Settings", view: "settings" }
|
|
137014
|
+
{ key: "g", label: "Settings", view: "settings" },
|
|
137015
|
+
{ key: "t", label: "Git", view: "git" },
|
|
137016
|
+
{ key: "e", label: "Explorer", view: "files" }
|
|
136865
137017
|
];
|
|
136866
|
-
|
|
137018
|
+
if (rows < 10) return null;
|
|
137019
|
+
const showHelpHint = cols >= 110;
|
|
137020
|
+
const compactInteractive = cols < 100;
|
|
137021
|
+
const compactSections = cols < 90;
|
|
137022
|
+
const minimal = cols < 70;
|
|
137023
|
+
const tiny = cols < 50;
|
|
137024
|
+
if (tiny) {
|
|
137025
|
+
const activeSectionIdx = inInteractive ? -1 : SECTION_ORDER.indexOf(focused);
|
|
137026
|
+
const activeSectionLabel = activeSectionIdx >= 0 ? SECTION_ORDER[activeSectionIdx].charAt(0).toUpperCase() + SECTION_ORDER[activeSectionIdx].slice(1) : null;
|
|
137027
|
+
const activeInteractive = inInteractive ? interactiveTabs.find((t) => t.view === interactiveView) ?? null : null;
|
|
137028
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, paddingX: 1, children: [
|
|
137029
|
+
/* @__PURE__ */ jsx(MiniLogo, {}),
|
|
137030
|
+
activeSectionLabel && /* @__PURE__ */ jsx(Text, { backgroundColor: "cyan", color: "black", bold: true, children: ` ${activeSectionIdx + 1} ${activeSectionLabel} ` }),
|
|
137031
|
+
activeInteractive && /* @__PURE__ */ jsx(Text, { backgroundColor: "cyan", color: "black", bold: true, children: ` ${activeInteractive.key} ${activeInteractive.label} ` })
|
|
137032
|
+
] });
|
|
137033
|
+
}
|
|
137034
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, paddingX: 1, paddingY: 0, children: [
|
|
136867
137035
|
/* @__PURE__ */ jsx(MiniLogo, {}),
|
|
136868
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
136869
|
-
|
|
136870
|
-
const isActive =
|
|
136871
|
-
|
|
137036
|
+
!minimal && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
137037
|
+
SECTION_ORDER.map((section, i) => {
|
|
137038
|
+
const isActive = !inInteractive && section === focused;
|
|
137039
|
+
const label = section.charAt(0).toUpperCase() + section.slice(1);
|
|
137040
|
+
if (minimal && !isActive) return null;
|
|
137041
|
+
return /* @__PURE__ */ jsx(Box, { marginRight: 1, children: isActive ? /* @__PURE__ */ jsx(Text, { backgroundColor: "cyan", color: "black", bold: true, children: compactSections ? ` ${i + 1} ${label} ` : ` [${i + 1}] ${label} ` }) : compactSections ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: `[${i + 1}]` }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: `[${i + 1}] ${label}` }) }, section);
|
|
137042
|
+
}),
|
|
137043
|
+
!minimal && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
137044
|
+
interactiveTabs.map(({ key, label, view }) => {
|
|
137045
|
+
const isActive = inInteractive && view === interactiveView;
|
|
137046
|
+
if (minimal && !isActive) return null;
|
|
137047
|
+
return /* @__PURE__ */ jsx(Box, { marginRight: 1, children: isActive ? /* @__PURE__ */ jsx(Text, { backgroundColor: "cyan", color: "black", bold: true, children: compactInteractive ? ` ${key} ${label} ` : ` [${key}] ${label} ` }) : compactInteractive ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: `[${key}]` }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: `[${key}] ${label}` }) }, view);
|
|
136872
137048
|
}),
|
|
136873
137049
|
/* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
|
|
136874
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[
|
|
137050
|
+
showHelpHint && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[?] help [q] quit" })
|
|
136875
137051
|
] });
|
|
136876
137052
|
}
|
|
136877
137053
|
function columnLabel(col) {
|
|
@@ -136886,6 +137062,7 @@ function TaskCard({
|
|
|
136886
137062
|
const borderColor = selected ? "cyanBright" : "gray";
|
|
136887
137063
|
const titleColor = selected ? "whiteBright" : void 0;
|
|
136888
137064
|
const shortId = task.id.length > 10 ? task.id.slice(0, 8) : task.id;
|
|
137065
|
+
const title = task.title ?? task.description ?? "(untitled)";
|
|
136889
137066
|
return /* @__PURE__ */ jsxs(
|
|
136890
137067
|
Box,
|
|
136891
137068
|
{
|
|
@@ -136903,7 +137080,7 @@ function TaskCard({
|
|
|
136903
137080
|
task.agentState
|
|
136904
137081
|
] })
|
|
136905
137082
|
] }),
|
|
136906
|
-
/* @__PURE__ */ jsx(Text, { bold: selected, color: titleColor, wrap: "
|
|
137083
|
+
/* @__PURE__ */ jsx(Text, { bold: selected, color: titleColor, wrap: "wrap", children: title })
|
|
136907
137084
|
]
|
|
136908
137085
|
}
|
|
136909
137086
|
);
|
|
@@ -136913,27 +137090,60 @@ function KanbanColumnView({
|
|
|
136913
137090
|
tasks,
|
|
136914
137091
|
isFocused,
|
|
136915
137092
|
selectedIndex,
|
|
136916
|
-
width
|
|
137093
|
+
width,
|
|
137094
|
+
availableRows
|
|
136917
137095
|
}) {
|
|
136918
137096
|
const accent = COLUMN_COLORS[column];
|
|
136919
137097
|
const headerColor = isFocused ? "whiteBright" : accent;
|
|
136920
|
-
const cardWidth = Math.max(
|
|
136921
|
-
|
|
136922
|
-
|
|
136923
|
-
|
|
136924
|
-
|
|
136925
|
-
|
|
136926
|
-
|
|
136927
|
-
|
|
136928
|
-
|
|
136929
|
-
|
|
136930
|
-
|
|
136931
|
-
|
|
136932
|
-
|
|
136933
|
-
|
|
136934
|
-
|
|
136935
|
-
|
|
136936
|
-
|
|
137098
|
+
const cardWidth = Math.max(16, width - 2);
|
|
137099
|
+
const innerHeaderWidth = Math.max(8, width - 2);
|
|
137100
|
+
const label = `${columnLabel(column).toUpperCase()} (${tasks.length})`;
|
|
137101
|
+
const headerText = ` ${label} `.length > innerHeaderWidth ? ` ${label} `.slice(0, innerHeaderWidth) : ` ${label} `.padEnd(innerHeaderWidth, " ");
|
|
137102
|
+
const cardRowsBudget = Math.max(0, availableRows - 4);
|
|
137103
|
+
const visibleCount = Math.max(1, Math.floor(cardRowsBudget / 4));
|
|
137104
|
+
const halfWindow = Math.floor(visibleCount / 2);
|
|
137105
|
+
const maxStart = Math.max(0, tasks.length - visibleCount);
|
|
137106
|
+
const windowStart = Math.max(0, Math.min(selectedIndex - halfWindow, maxStart));
|
|
137107
|
+
const windowEnd = Math.min(tasks.length, windowStart + visibleCount);
|
|
137108
|
+
const visibleTasks = tasks.slice(windowStart, windowEnd);
|
|
137109
|
+
const hiddenAbove = windowStart;
|
|
137110
|
+
const hiddenBelow = tasks.length - windowEnd;
|
|
137111
|
+
return /* @__PURE__ */ jsxs(
|
|
137112
|
+
Box,
|
|
137113
|
+
{
|
|
137114
|
+
flexDirection: "column",
|
|
137115
|
+
width,
|
|
137116
|
+
flexShrink: 1,
|
|
137117
|
+
flexGrow: 1,
|
|
137118
|
+
paddingX: 1,
|
|
137119
|
+
overflow: "hidden",
|
|
137120
|
+
children: [
|
|
137121
|
+
/* @__PURE__ */ jsx(Box, { width: innerHeaderWidth, flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { bold: true, color: headerColor, backgroundColor: isFocused ? accent : void 0, children: headerText }) }),
|
|
137122
|
+
/* @__PURE__ */ jsx(Box, { height: 1, flexShrink: 0 }),
|
|
137123
|
+
tasks.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2014" }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 0, flexShrink: 1, overflow: "hidden", children: [
|
|
137124
|
+
hiddenAbove > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
137125
|
+
"\u2191 ",
|
|
137126
|
+
hiddenAbove,
|
|
137127
|
+
" more"
|
|
137128
|
+
] }),
|
|
137129
|
+
visibleTasks.map((task, i) => /* @__PURE__ */ jsx(
|
|
137130
|
+
TaskCard,
|
|
137131
|
+
{
|
|
137132
|
+
task,
|
|
137133
|
+
selected: isFocused && windowStart + i === selectedIndex,
|
|
137134
|
+
width: cardWidth
|
|
137135
|
+
},
|
|
137136
|
+
task.id
|
|
137137
|
+
)),
|
|
137138
|
+
hiddenBelow > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
137139
|
+
"\u2193 ",
|
|
137140
|
+
hiddenBelow,
|
|
137141
|
+
" more"
|
|
137142
|
+
] })
|
|
137143
|
+
] })
|
|
137144
|
+
]
|
|
137145
|
+
}
|
|
137146
|
+
);
|
|
136937
137147
|
}
|
|
136938
137148
|
function ProjectSelector({
|
|
136939
137149
|
open,
|
|
@@ -136945,7 +137155,7 @@ function ProjectSelector({
|
|
|
136945
137155
|
if (!open) {
|
|
136946
137156
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
136947
137157
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Project:" }),
|
|
136948
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "
|
|
137158
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: current?.name ?? "(none)" }),
|
|
136949
137159
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[p] change" })
|
|
136950
137160
|
] });
|
|
136951
137161
|
}
|
|
@@ -136953,17 +137163,17 @@ function ProjectSelector({
|
|
|
136953
137163
|
Box,
|
|
136954
137164
|
{
|
|
136955
137165
|
borderStyle: "round",
|
|
136956
|
-
borderColor: "
|
|
137166
|
+
borderColor: "cyanBright",
|
|
136957
137167
|
flexDirection: "column",
|
|
136958
137168
|
paddingX: 1,
|
|
136959
137169
|
backgroundColor: "black",
|
|
136960
137170
|
width: Math.max(30, ...projects.map((p) => p.name.length + 4)),
|
|
136961
137171
|
children: [
|
|
136962
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "
|
|
137172
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyanBright", backgroundColor: "black", children: "Pick a project" }),
|
|
136963
137173
|
projects.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, backgroundColor: "black", children: "(no projects registered)" }) : projects.map((p, i) => {
|
|
136964
137174
|
const isSel = i === selectedIndex;
|
|
136965
137175
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, backgroundColor: "black", children: [
|
|
136966
|
-
/* @__PURE__ */ jsx(Text, { color: isSel ? "
|
|
137176
|
+
/* @__PURE__ */ jsx(Text, { color: isSel ? "white" : "gray", backgroundColor: "black", children: isSel ? "\u25B6" : " " }),
|
|
136967
137177
|
/* @__PURE__ */ jsx(Text, { bold: isSel, color: isSel ? "whiteBright" : void 0, backgroundColor: "black", children: p.name })
|
|
136968
137178
|
] }, p.id);
|
|
136969
137179
|
}),
|
|
@@ -136973,40 +137183,226 @@ function ProjectSelector({
|
|
|
136973
137183
|
}
|
|
136974
137184
|
);
|
|
136975
137185
|
}
|
|
136976
|
-
function
|
|
137186
|
+
function formatDurationMs(ms) {
|
|
137187
|
+
const s = Math.floor(ms / 1e3);
|
|
137188
|
+
const m = Math.floor(s / 60);
|
|
137189
|
+
if (m > 0) return `${m}m ${s % 60}s`;
|
|
137190
|
+
return `${s}s`;
|
|
137191
|
+
}
|
|
137192
|
+
function formatLogTime(iso) {
|
|
137193
|
+
try {
|
|
137194
|
+
const d = new Date(iso);
|
|
137195
|
+
return `${d.getHours().toString().padStart(2, "0")}:${d.getMinutes().toString().padStart(2, "0")}:${d.getSeconds().toString().padStart(2, "0")}`;
|
|
137196
|
+
} catch {
|
|
137197
|
+
return "??:??:??";
|
|
137198
|
+
}
|
|
137199
|
+
}
|
|
137200
|
+
function TaskDetailScreen({
|
|
137201
|
+
task,
|
|
137202
|
+
projectPath,
|
|
137203
|
+
interactiveData
|
|
137204
|
+
}) {
|
|
137205
|
+
const { stdout } = useStdout();
|
|
137206
|
+
const rows = stdout?.rows ?? 24;
|
|
137207
|
+
const [detail, setDetail] = useState2(null);
|
|
137208
|
+
const [logScrollOffset, setLogScrollOffset] = useState2(0);
|
|
137209
|
+
const [autoFollow, setAutoFollow] = useState2(true);
|
|
137210
|
+
const FIXED_ROWS = 22;
|
|
137211
|
+
const logPaneRows = Math.max(4, rows - FIXED_ROWS);
|
|
137212
|
+
useEffect2(() => {
|
|
137213
|
+
if (!projectPath || !interactiveData) {
|
|
137214
|
+
setDetail("unavailable");
|
|
137215
|
+
return;
|
|
137216
|
+
}
|
|
137217
|
+
let cancelled = false;
|
|
137218
|
+
void interactiveData.tasks.getTaskDetail(projectPath, task.id).then((d) => {
|
|
137219
|
+
if (cancelled) return;
|
|
137220
|
+
if (d === null) {
|
|
137221
|
+
setDetail("unavailable");
|
|
137222
|
+
} else {
|
|
137223
|
+
const trimmed = { ...d, recentLogs: d.recentLogs.slice(-INITIAL_LOG_LIMIT) };
|
|
137224
|
+
setDetail(trimmed);
|
|
137225
|
+
}
|
|
137226
|
+
});
|
|
137227
|
+
const unsub = interactiveData.tasks.subscribeTaskEvents(
|
|
137228
|
+
projectPath,
|
|
137229
|
+
task.id,
|
|
137230
|
+
(event) => {
|
|
137231
|
+
if (cancelled) return;
|
|
137232
|
+
setDetail((prev) => {
|
|
137233
|
+
if (!prev || prev === "unavailable") return prev;
|
|
137234
|
+
if (event.kind === "step:updated") {
|
|
137235
|
+
const steps = prev.steps.map(
|
|
137236
|
+
(s) => s.index === event.step.index ? event.step : s
|
|
137237
|
+
);
|
|
137238
|
+
return { ...prev, steps };
|
|
137239
|
+
}
|
|
137240
|
+
if (event.kind === "log:appended") {
|
|
137241
|
+
const logs = [...prev.recentLogs, event.entry];
|
|
137242
|
+
const trimmed = logs.length > MAX_LOG_ENTRIES2 ? logs.slice(logs.length - MAX_LOG_ENTRIES2) : logs;
|
|
137243
|
+
return { ...prev, recentLogs: trimmed };
|
|
137244
|
+
}
|
|
137245
|
+
if (event.kind === "task:updated") {
|
|
137246
|
+
const merged = [...prev.recentLogs, ...event.task.recentLogs];
|
|
137247
|
+
const deduped = Array.from(
|
|
137248
|
+
new Map(merged.map((e) => [e.timestamp + e.text, e])).values()
|
|
137249
|
+
);
|
|
137250
|
+
const trimmed = deduped.length > MAX_LOG_ENTRIES2 ? deduped.slice(deduped.length - MAX_LOG_ENTRIES2) : deduped;
|
|
137251
|
+
return { ...event.task, recentLogs: trimmed };
|
|
137252
|
+
}
|
|
137253
|
+
return prev;
|
|
137254
|
+
});
|
|
137255
|
+
}
|
|
137256
|
+
);
|
|
137257
|
+
return () => {
|
|
137258
|
+
cancelled = true;
|
|
137259
|
+
unsub();
|
|
137260
|
+
};
|
|
137261
|
+
}, [projectPath, task.id]);
|
|
137262
|
+
const logCount = detail && detail !== "unavailable" ? detail.recentLogs.length : 0;
|
|
137263
|
+
useEffect2(() => {
|
|
137264
|
+
if (autoFollow) setLogScrollOffset(0);
|
|
137265
|
+
}, [autoFollow, logCount]);
|
|
137266
|
+
useInput((input, key) => {
|
|
137267
|
+
if (detail && detail !== "unavailable" && detail.recentLogs.length > 0) {
|
|
137268
|
+
const maxOffset = Math.max(0, detail.recentLogs.length - logPaneRows);
|
|
137269
|
+
if (key.upArrow || input === "k") {
|
|
137270
|
+
setAutoFollow(false);
|
|
137271
|
+
setLogScrollOffset((o) => Math.min(maxOffset, o + 1));
|
|
137272
|
+
return;
|
|
137273
|
+
}
|
|
137274
|
+
if (key.downArrow || input === "j") {
|
|
137275
|
+
setLogScrollOffset((o) => {
|
|
137276
|
+
const next = Math.max(0, o - 1);
|
|
137277
|
+
if (next === 0) setAutoFollow(true);
|
|
137278
|
+
return next;
|
|
137279
|
+
});
|
|
137280
|
+
return;
|
|
137281
|
+
}
|
|
137282
|
+
if (key.pageUp) {
|
|
137283
|
+
setAutoFollow(false);
|
|
137284
|
+
setLogScrollOffset((o) => Math.min(maxOffset, o + Math.floor(logPaneRows / 2)));
|
|
137285
|
+
return;
|
|
137286
|
+
}
|
|
137287
|
+
if (key.pageDown) {
|
|
137288
|
+
setLogScrollOffset((o) => {
|
|
137289
|
+
const next = Math.max(0, o - Math.floor(logPaneRows / 2));
|
|
137290
|
+
if (next === 0) setAutoFollow(true);
|
|
137291
|
+
return next;
|
|
137292
|
+
});
|
|
137293
|
+
return;
|
|
137294
|
+
}
|
|
137295
|
+
if (input === "G") {
|
|
137296
|
+
setLogScrollOffset(0);
|
|
137297
|
+
setAutoFollow(true);
|
|
137298
|
+
return;
|
|
137299
|
+
}
|
|
137300
|
+
if (input === "g") {
|
|
137301
|
+
setAutoFollow(false);
|
|
137302
|
+
setLogScrollOffset(maxOffset);
|
|
137303
|
+
return;
|
|
137304
|
+
}
|
|
137305
|
+
}
|
|
137306
|
+
});
|
|
136977
137307
|
const accent = COLUMN_COLORS[task.column] ?? "white";
|
|
136978
137308
|
return /* @__PURE__ */ jsxs(
|
|
136979
137309
|
Box,
|
|
136980
137310
|
{
|
|
136981
137311
|
borderStyle: "round",
|
|
136982
|
-
borderColor: "
|
|
137312
|
+
borderColor: "cyanBright",
|
|
136983
137313
|
flexDirection: "column",
|
|
136984
137314
|
paddingX: 2,
|
|
136985
137315
|
paddingY: 1,
|
|
136986
137316
|
flexGrow: 1,
|
|
136987
137317
|
children: [
|
|
136988
|
-
/* @__PURE__ */
|
|
136989
|
-
|
|
136990
|
-
|
|
136991
|
-
|
|
136992
|
-
|
|
136993
|
-
|
|
136994
|
-
|
|
136995
|
-
|
|
137318
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", justifyContent: "space-between", flexShrink: 0, children: [
|
|
137319
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
|
|
137320
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: task.id }),
|
|
137321
|
+
/* @__PURE__ */ jsxs(Text, { color: accent, bold: true, children: [
|
|
137322
|
+
"[",
|
|
137323
|
+
columnLabel(task.column),
|
|
137324
|
+
"]"
|
|
137325
|
+
] }),
|
|
137326
|
+
task.agentState && /* @__PURE__ */ jsxs(Text, { color: accent, children: [
|
|
137327
|
+
"\u25B6 ",
|
|
137328
|
+
task.agentState
|
|
137329
|
+
] })
|
|
136996
137330
|
] }),
|
|
136997
|
-
|
|
136998
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Agent " }),
|
|
136999
|
-
/* @__PURE__ */ jsx(Text, { color: accent, bold: true, children: task.agentState })
|
|
137000
|
-
] })
|
|
137331
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[Esc] back" })
|
|
137001
137332
|
] }),
|
|
137002
|
-
|
|
137003
|
-
|
|
137004
|
-
|
|
137005
|
-
|
|
137006
|
-
/* @__PURE__ */ jsx(Text, {
|
|
137333
|
+
/* @__PURE__ */ jsx(Box, { height: 1, flexShrink: 0 }),
|
|
137334
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "whiteBright", wrap: "wrap", children: task.title ?? task.id }),
|
|
137335
|
+
/* @__PURE__ */ jsx(Box, { height: 1, flexShrink: 0 }),
|
|
137336
|
+
detail === null && /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, flexShrink: 0, children: [
|
|
137337
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
137338
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading task details\u2026" })
|
|
137339
|
+
] }),
|
|
137340
|
+
detail === "unavailable" && /* @__PURE__ */ jsx(Text, { color: "yellow", children: "Task no longer available \u2014 Esc to go back" }),
|
|
137341
|
+
detail && detail !== "unavailable" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
137342
|
+
(detail.branch || detail.worktree) && /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, flexShrink: 0, children: [
|
|
137343
|
+
detail.branch && /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
137344
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Branch" }),
|
|
137345
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: detail.branch })
|
|
137346
|
+
] }),
|
|
137347
|
+
detail.worktree && /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
137348
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Worktree" }),
|
|
137349
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", wrap: "truncate", children: detail.worktree })
|
|
137350
|
+
] })
|
|
137351
|
+
] }),
|
|
137352
|
+
/* @__PURE__ */ jsx(Box, { height: 1, flexShrink: 0 }),
|
|
137353
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500 Steps \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
137354
|
+
detail.steps.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(no steps yet)" }) : detail.steps.map((step) => {
|
|
137355
|
+
const icon = STEP_ICON[step.status] ?? "\xB7";
|
|
137356
|
+
const color = STEP_COLOR[step.status] ?? "white";
|
|
137357
|
+
const isRunning = step.status === "running";
|
|
137358
|
+
const isDone = step.status === "done" || step.status === "failed" || step.status === "skipped";
|
|
137359
|
+
let durationText = "";
|
|
137360
|
+
if (isRunning && step.startedAt) {
|
|
137361
|
+
const elapsed = Date.now() - new Date(step.startedAt).getTime();
|
|
137362
|
+
durationText = ` (running \u2014 ${formatDurationMs(elapsed)})`;
|
|
137363
|
+
} else if (isDone && step.startedAt && step.endedAt) {
|
|
137364
|
+
const elapsed = new Date(step.endedAt).getTime() - new Date(step.startedAt).getTime();
|
|
137365
|
+
durationText = ` (${step.status} \u2014 ${formatDurationMs(elapsed)})`;
|
|
137366
|
+
}
|
|
137367
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, flexShrink: 0, children: [
|
|
137368
|
+
/* @__PURE__ */ jsx(Text, { color, children: icon }),
|
|
137369
|
+
/* @__PURE__ */ jsxs(Text, { bold: isRunning, color: isRunning ? "whiteBright" : void 0, dimColor: step.status === "pending", children: [
|
|
137370
|
+
step.index + 1,
|
|
137371
|
+
". ",
|
|
137372
|
+
step.name
|
|
137373
|
+
] }),
|
|
137374
|
+
durationText !== "" && /* @__PURE__ */ jsx(Text, { dimColor: true, children: durationText })
|
|
137375
|
+
] }, step.index);
|
|
137376
|
+
}),
|
|
137377
|
+
/* @__PURE__ */ jsx(Box, { height: 1, flexShrink: 0 }),
|
|
137378
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", justifyContent: "space-between", flexShrink: 0, children: [
|
|
137379
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500 Logs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
137380
|
+
/* @__PURE__ */ jsx(Text, { color: autoFollow ? "cyanBright" : void 0, dimColor: !autoFollow, children: autoFollow ? "[live]" : "[paused]" })
|
|
137381
|
+
] }),
|
|
137382
|
+
detail.recentLogs.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(no log entries yet)" }) : /* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: (() => {
|
|
137383
|
+
const logs = detail.recentLogs;
|
|
137384
|
+
const total = logs.length;
|
|
137385
|
+
const endIdx = total - logScrollOffset;
|
|
137386
|
+
const startIdx = Math.max(0, endIdx - logPaneRows);
|
|
137387
|
+
const visible = logs.slice(startIdx, endIdx);
|
|
137388
|
+
return visible.map((entry, i) => {
|
|
137389
|
+
const levelColor = entry.level === "warn" ? "yellow" : entry.level === "error" ? "red" : entry.level === "debug" ? "gray" : "white";
|
|
137390
|
+
const levelLabel = entry.level.toUpperCase().padEnd(5);
|
|
137391
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, flexShrink: 0, children: [
|
|
137392
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: formatLogTime(entry.timestamp) }),
|
|
137393
|
+
/* @__PURE__ */ jsx(Text, { color: levelColor, children: levelLabel }),
|
|
137394
|
+
entry.source && /* @__PURE__ */ jsxs(Text, { color: "cyan", dimColor: true, children: [
|
|
137395
|
+
"[",
|
|
137396
|
+
entry.source,
|
|
137397
|
+
"]"
|
|
137398
|
+
] }),
|
|
137399
|
+
/* @__PURE__ */ jsx(Text, { wrap: "wrap", children: entry.text })
|
|
137400
|
+
] }, startIdx + i);
|
|
137401
|
+
});
|
|
137402
|
+
})() })
|
|
137007
137403
|
] }),
|
|
137008
137404
|
/* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
|
|
137009
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "
|
|
137405
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193/j/k scroll \xB7 PgUp/PgDn half-page \xB7 g top \xB7 G bottom \xB7 Esc back" })
|
|
137010
137406
|
]
|
|
137011
137407
|
}
|
|
137012
137408
|
);
|
|
@@ -137027,10 +137423,13 @@ function groupTasksByColumn(tasks) {
|
|
|
137027
137423
|
}
|
|
137028
137424
|
return out;
|
|
137029
137425
|
}
|
|
137030
|
-
function BoardView({ state }) {
|
|
137426
|
+
function BoardView({ state, controller }) {
|
|
137031
137427
|
const { stdout } = useStdout();
|
|
137032
137428
|
const cols = stdout?.columns ?? 80;
|
|
137033
|
-
const
|
|
137429
|
+
const rows = stdout?.rows ?? 24;
|
|
137430
|
+
const isNarrow = cols < NARROW_THRESHOLD;
|
|
137431
|
+
const columnWidth = isNarrow ? Math.max(20, cols - 2) : Math.max(20, Math.floor((cols - 2) / KANBAN_COLUMNS.length));
|
|
137432
|
+
const availableCardRows = Math.max(8, rows - 8);
|
|
137034
137433
|
const [subView, setSubView] = useState2("board");
|
|
137035
137434
|
const [projectIndex, setProjectIndex] = useState2(0);
|
|
137036
137435
|
const [colIndex, setColIndex] = useState2(0);
|
|
@@ -137048,6 +137447,12 @@ function BoardView({ state }) {
|
|
|
137048
137447
|
const selectedProject = projectsState.projects[projectIndex] ?? null;
|
|
137049
137448
|
const tasksState = useTasks(state.interactiveData, selectedProject);
|
|
137050
137449
|
const grouped = groupTasksByColumn(tasksState.tasks);
|
|
137450
|
+
useEffect2(() => {
|
|
137451
|
+
controller.setBoardScopedProjectPath(selectedProject?.path ?? null);
|
|
137452
|
+
return () => {
|
|
137453
|
+
controller.setBoardScopedProjectPath(null);
|
|
137454
|
+
};
|
|
137455
|
+
}, [controller, selectedProject?.path]);
|
|
137051
137456
|
const focusedColumn = KANBAN_COLUMNS[colIndex];
|
|
137052
137457
|
const focusedTasks = grouped[focusedColumn];
|
|
137053
137458
|
const focusedRow = clamp2(rowByColumn[focusedColumn] ?? 0, 0, Math.max(0, focusedTasks.length - 1));
|
|
@@ -137087,6 +137492,18 @@ function BoardView({ state }) {
|
|
|
137087
137492
|
}
|
|
137088
137493
|
return;
|
|
137089
137494
|
}
|
|
137495
|
+
if (input === "g") {
|
|
137496
|
+
controller.setInteractiveView("settings");
|
|
137497
|
+
return;
|
|
137498
|
+
}
|
|
137499
|
+
if (input === "a" || input === "A") {
|
|
137500
|
+
controller.setInteractiveView("agents");
|
|
137501
|
+
return;
|
|
137502
|
+
}
|
|
137503
|
+
if (input === "t" || input === "T") {
|
|
137504
|
+
controller.setInteractiveView("git");
|
|
137505
|
+
return;
|
|
137506
|
+
}
|
|
137090
137507
|
if (input === "p" || input === "P") {
|
|
137091
137508
|
setPickerOriginal(projectIndex);
|
|
137092
137509
|
setSubView("picker");
|
|
@@ -137126,7 +137543,8 @@ function BoardView({ state }) {
|
|
|
137126
137543
|
return;
|
|
137127
137544
|
}
|
|
137128
137545
|
});
|
|
137129
|
-
const
|
|
137546
|
+
const narrowColumnIndicator = isNarrow ? ` \xB7 ${colIndex + 1}/${KANBAN_COLUMNS.length} ${columnLabel(focusedColumn).toUpperCase()} (${focusedTasks.length})` : "";
|
|
137547
|
+
const hintText = subView === "picker" ? "\u2191\u2193 pick \xB7 Enter confirm \xB7 Esc cancel" : subView === "detail" ? "Esc back \xB7 q quit" : subView === "create" ? "type a task title \xB7 Enter create \xB7 Esc cancel" : `\u2190\u2192 column \xB7 \u2191\u2193 task \xB7 Enter open \xB7 n new \xB7 p project${narrowColumnIndicator}`;
|
|
137130
137548
|
const submitNewTask = async () => {
|
|
137131
137549
|
const title = newTaskTitle.trim();
|
|
137132
137550
|
if (!title) {
|
|
@@ -137151,7 +137569,7 @@ function BoardView({ state }) {
|
|
|
137151
137569
|
}
|
|
137152
137570
|
};
|
|
137153
137571
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
|
|
137154
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, paddingX: 1, children: [
|
|
137572
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, paddingX: 1, flexShrink: 0, children: [
|
|
137155
137573
|
/* @__PURE__ */ jsx(
|
|
137156
137574
|
ProjectSelector,
|
|
137157
137575
|
{
|
|
@@ -137164,18 +137582,18 @@ function BoardView({ state }) {
|
|
|
137164
137582
|
/* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
|
|
137165
137583
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: hintText })
|
|
137166
137584
|
] }),
|
|
137167
|
-
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
137585
|
+
/* @__PURE__ */ jsx(Box, { height: 1, flexShrink: 0 }),
|
|
137168
137586
|
subView === "create" ? /* @__PURE__ */ jsx(Box, { justifyContent: "center", alignItems: "center", flexGrow: 1, children: /* @__PURE__ */ jsxs(
|
|
137169
137587
|
Box,
|
|
137170
137588
|
{
|
|
137171
137589
|
borderStyle: "round",
|
|
137172
|
-
borderColor: "
|
|
137590
|
+
borderColor: "cyanBright",
|
|
137173
137591
|
flexDirection: "column",
|
|
137174
137592
|
paddingX: 2,
|
|
137175
137593
|
paddingY: 1,
|
|
137176
137594
|
width: Math.min(80, Math.max(40, cols - 8)),
|
|
137177
137595
|
children: [
|
|
137178
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "
|
|
137596
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: "New Task" }),
|
|
137179
137597
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
137180
137598
|
"Project: ",
|
|
137181
137599
|
selectedProject?.name ?? "(none)"
|
|
@@ -137183,7 +137601,7 @@ function BoardView({ state }) {
|
|
|
137183
137601
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
137184
137602
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Title" }),
|
|
137185
137603
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
137186
|
-
/* @__PURE__ */ jsx(Text, { color: "
|
|
137604
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: "\u25B8 " }),
|
|
137187
137605
|
/* @__PURE__ */ jsx(
|
|
137188
137606
|
TextInput,
|
|
137189
137607
|
{
|
|
@@ -137197,25 +137615,44 @@ function BoardView({ state }) {
|
|
|
137197
137615
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
137198
137616
|
createError && /* @__PURE__ */ jsx(Text, { color: "red", children: createError }),
|
|
137199
137617
|
creating ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
137200
|
-
/* @__PURE__ */ jsx(Text, { color: "
|
|
137618
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
137201
137619
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Creating\u2026" })
|
|
137202
137620
|
] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Enter to create \xB7 Esc to cancel" })
|
|
137203
137621
|
]
|
|
137204
137622
|
}
|
|
137205
|
-
) }) : subView === "detail" && selectedTask ? /* @__PURE__ */ jsx(Box, { flexGrow: 1, paddingX: 1, children: /* @__PURE__ */ jsx(
|
|
137206
|
-
|
|
137623
|
+
) }) : subView === "detail" && selectedTask ? /* @__PURE__ */ jsx(Box, { flexGrow: 1, paddingX: 1, children: /* @__PURE__ */ jsx(
|
|
137624
|
+
TaskDetailScreen,
|
|
137625
|
+
{
|
|
137626
|
+
task: selectedTask,
|
|
137627
|
+
projectPath: selectedProject?.path ?? null,
|
|
137628
|
+
interactiveData: state.interactiveData
|
|
137629
|
+
}
|
|
137630
|
+
) }) : tasksState.loading ? /* @__PURE__ */ jsxs(Box, { justifyContent: "center", alignItems: "center", flexGrow: 1, gap: 1, children: [
|
|
137631
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
137207
137632
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading tasks\u2026" })
|
|
137208
137633
|
] }) : tasksState.tasks.length === 0 ? /* @__PURE__ */ jsxs(Box, { justifyContent: "center", alignItems: "center", flexGrow: 1, flexDirection: "column", children: [
|
|
137209
137634
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "No tasks in this project." }),
|
|
137210
137635
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press [p] to switch projects." })
|
|
137211
|
-
] }) : /* @__PURE__ */ jsx(Box, { flexDirection: "row", flexGrow: 1, overflow: "hidden", children:
|
|
137636
|
+
] }) : /* @__PURE__ */ jsx(Box, { flexDirection: "row", flexGrow: 1, overflow: "hidden", children: isNarrow ? /* @__PURE__ */ jsx(
|
|
137637
|
+
KanbanColumnView,
|
|
137638
|
+
{
|
|
137639
|
+
column: focusedColumn,
|
|
137640
|
+
tasks: focusedTasks,
|
|
137641
|
+
isFocused: true,
|
|
137642
|
+
selectedIndex: focusedRow,
|
|
137643
|
+
width: columnWidth,
|
|
137644
|
+
availableRows: availableCardRows
|
|
137645
|
+
},
|
|
137646
|
+
focusedColumn
|
|
137647
|
+
) : KANBAN_COLUMNS.map((col, i) => /* @__PURE__ */ jsx(
|
|
137212
137648
|
KanbanColumnView,
|
|
137213
137649
|
{
|
|
137214
137650
|
column: col,
|
|
137215
137651
|
tasks: grouped[col],
|
|
137216
137652
|
isFocused: i === colIndex,
|
|
137217
137653
|
selectedIndex: rowByColumn[col] ?? 0,
|
|
137218
|
-
width: columnWidth
|
|
137654
|
+
width: columnWidth,
|
|
137655
|
+
availableRows: availableCardRows
|
|
137219
137656
|
},
|
|
137220
137657
|
col
|
|
137221
137658
|
)) })
|
|
@@ -137224,7 +137661,7 @@ function BoardView({ state }) {
|
|
|
137224
137661
|
function agentStateColor(state) {
|
|
137225
137662
|
switch (state) {
|
|
137226
137663
|
case "active":
|
|
137227
|
-
return "
|
|
137664
|
+
return "cyanBright";
|
|
137228
137665
|
case "running":
|
|
137229
137666
|
return "green";
|
|
137230
137667
|
case "error":
|
|
@@ -137241,7 +137678,7 @@ function heartbeatFreshness(lastHeartbeatAt) {
|
|
|
137241
137678
|
function AgentsView({ state }) {
|
|
137242
137679
|
const { stdout } = useStdout();
|
|
137243
137680
|
const cols = stdout?.columns ?? 80;
|
|
137244
|
-
const isNarrow = cols <
|
|
137681
|
+
const isNarrow = cols < NARROW_THRESHOLD;
|
|
137245
137682
|
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
137246
137683
|
const [agents, setAgents] = useState2([]);
|
|
137247
137684
|
const [detail, setDetail] = useState2(null);
|
|
@@ -137306,6 +137743,14 @@ function AgentsView({ state }) {
|
|
|
137306
137743
|
setDetailFocused((f) => !f);
|
|
137307
137744
|
return;
|
|
137308
137745
|
}
|
|
137746
|
+
if (key.leftArrow) {
|
|
137747
|
+
setDetailFocused(false);
|
|
137748
|
+
return;
|
|
137749
|
+
}
|
|
137750
|
+
if (key.rightArrow) {
|
|
137751
|
+
setDetailFocused(true);
|
|
137752
|
+
return;
|
|
137753
|
+
}
|
|
137309
137754
|
if (!detailFocused) {
|
|
137310
137755
|
if (key.upArrow || input === "k") {
|
|
137311
137756
|
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
@@ -137359,19 +137804,19 @@ function AgentsView({ state }) {
|
|
|
137359
137804
|
}
|
|
137360
137805
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
|
|
137361
137806
|
statusMsg && /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: statusMsg }) }),
|
|
137362
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection:
|
|
137363
|
-
/* @__PURE__ */ jsxs(
|
|
137807
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexGrow: 1, overflow: "hidden", children: [
|
|
137808
|
+
(!isNarrow || !detailFocused) && /* @__PURE__ */ jsxs(
|
|
137364
137809
|
Box,
|
|
137365
137810
|
{
|
|
137366
137811
|
borderStyle: "round",
|
|
137367
|
-
borderColor: detailFocused ? "gray" : "
|
|
137812
|
+
borderColor: detailFocused ? "gray" : "cyanBright",
|
|
137368
137813
|
flexDirection: "column",
|
|
137369
137814
|
width: isNarrow ? void 0 : "30%",
|
|
137370
137815
|
flexGrow: isNarrow ? 1 : 0,
|
|
137371
137816
|
flexShrink: 0,
|
|
137372
137817
|
overflow: "hidden",
|
|
137373
137818
|
children: [
|
|
137374
|
-
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsxs(Text, { bold: !detailFocused, color: !detailFocused ? "
|
|
137819
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsxs(Text, { bold: !detailFocused, color: !detailFocused ? "cyanBright" : void 0, dimColor: detailFocused, children: [
|
|
137375
137820
|
"Agents (",
|
|
137376
137821
|
agents.length,
|
|
137377
137822
|
")"
|
|
@@ -137380,7 +137825,7 @@ function AgentsView({ state }) {
|
|
|
137380
137825
|
const isSel = i === selectedIndex;
|
|
137381
137826
|
const { fresh, label } = heartbeatFreshness(agent.lastHeartbeatAt);
|
|
137382
137827
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
137383
|
-
/* @__PURE__ */ jsx(Text, { color: isSel ? "
|
|
137828
|
+
/* @__PURE__ */ jsx(Text, { color: isSel ? "white" : "gray", children: isSel ? "\u25B6" : " " }),
|
|
137384
137829
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
|
|
137385
137830
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
137386
137831
|
/* @__PURE__ */ jsx(Text, { bold: isSel, color: isSel ? "whiteBright" : void 0, wrap: "truncate", children: agent.name }),
|
|
@@ -137396,18 +137841,18 @@ function AgentsView({ state }) {
|
|
|
137396
137841
|
]
|
|
137397
137842
|
}
|
|
137398
137843
|
),
|
|
137399
|
-
/* @__PURE__ */ jsxs(
|
|
137844
|
+
(!isNarrow || detailFocused) && /* @__PURE__ */ jsxs(
|
|
137400
137845
|
Box,
|
|
137401
137846
|
{
|
|
137402
137847
|
borderStyle: "round",
|
|
137403
|
-
borderColor: detailFocused ? "
|
|
137848
|
+
borderColor: detailFocused ? "cyanBright" : "gray",
|
|
137404
137849
|
flexDirection: "column",
|
|
137405
137850
|
flexGrow: 1,
|
|
137406
137851
|
overflow: "hidden",
|
|
137407
137852
|
children: [
|
|
137408
|
-
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: detailFocused, color: detailFocused ? "
|
|
137853
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: detailFocused, color: detailFocused ? "cyanBright" : void 0, dimColor: !detailFocused, children: "Agent Detail" }) }),
|
|
137409
137854
|
/* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: !selectedAgent ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Select an agent from the list." }) : loadingDetail ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
137410
|
-
/* @__PURE__ */ jsx(Text, { color: "
|
|
137855
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
137411
137856
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading\u2026" })
|
|
137412
137857
|
] }) : !detail ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Could not load agent detail." }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
137413
137858
|
/* @__PURE__ */ jsx(Text, { bold: true, color: "whiteBright", children: detail.name }),
|
|
@@ -137427,7 +137872,7 @@ function AgentsView({ state }) {
|
|
|
137427
137872
|
] }),
|
|
137428
137873
|
detail.taskId && /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
137429
137874
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Task:" }),
|
|
137430
|
-
/* @__PURE__ */ jsx(Text, { color: "
|
|
137875
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: detail.taskId })
|
|
137431
137876
|
] }),
|
|
137432
137877
|
detail.capabilities.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
137433
137878
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Caps:" }),
|
|
@@ -137447,7 +137892,13 @@ function AgentsView({ state }) {
|
|
|
137447
137892
|
}
|
|
137448
137893
|
)
|
|
137449
137894
|
] }),
|
|
137450
|
-
/* @__PURE__ */
|
|
137895
|
+
/* @__PURE__ */ jsxs(Box, { paddingX: 1, flexDirection: "row", gap: 1, children: [
|
|
137896
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[s] start [x] stop [D] delete [r] refresh [Tab] focus \u2191\u2193 select" }),
|
|
137897
|
+
isNarrow && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
137898
|
+
"[narrow] ",
|
|
137899
|
+
detailFocused ? "detail" : "list"
|
|
137900
|
+
] })
|
|
137901
|
+
] })
|
|
137451
137902
|
] });
|
|
137452
137903
|
}
|
|
137453
137904
|
function SettingsInteractiveView({ state }) {
|
|
@@ -137546,7 +137997,7 @@ function SettingsInteractiveView({ state }) {
|
|
|
137546
137997
|
return /* @__PURE__ */ jsx(Text, { color: v ? "green" : "yellow", children: v ? "enabled" : "disabled" });
|
|
137547
137998
|
}
|
|
137548
137999
|
if (def.type === "enum") {
|
|
137549
|
-
return /* @__PURE__ */ jsx(Text, { color: "
|
|
138000
|
+
return /* @__PURE__ */ jsx(Text, { color: "cyanBright", children: String(v) });
|
|
137550
138001
|
}
|
|
137551
138002
|
return /* @__PURE__ */ jsx(Text, { children: String(v) });
|
|
137552
138003
|
}
|
|
@@ -137557,16 +138008,16 @@ function SettingsInteractiveView({ state }) {
|
|
|
137557
138008
|
Box,
|
|
137558
138009
|
{
|
|
137559
138010
|
borderStyle: "round",
|
|
137560
|
-
borderColor: detailFocused ? "gray" : "
|
|
138011
|
+
borderColor: detailFocused ? "gray" : "cyanBright",
|
|
137561
138012
|
flexDirection: "column",
|
|
137562
138013
|
width: "35%",
|
|
137563
138014
|
overflow: "hidden",
|
|
137564
138015
|
children: [
|
|
137565
|
-
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: !detailFocused, color: !detailFocused ? "
|
|
138016
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: !detailFocused, color: !detailFocused ? "cyanBright" : void 0, dimColor: detailFocused, children: "Settings" }) }),
|
|
137566
138017
|
/* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: !localSettings ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading\u2026" }) : SETTING_DEFS.map((def, i) => {
|
|
137567
138018
|
const isSel = i === selectedIndex;
|
|
137568
138019
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
137569
|
-
/* @__PURE__ */ jsx(Text, { color: isSel ? "
|
|
138020
|
+
/* @__PURE__ */ jsx(Text, { color: isSel ? "white" : "gray", children: isSel ? "\u25B6" : " " }),
|
|
137570
138021
|
/* @__PURE__ */ jsx(Text, { bold: isSel, color: isSel ? "whiteBright" : void 0, wrap: "truncate", children: def.label }),
|
|
137571
138022
|
/* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
|
|
137572
138023
|
renderValue(def, localSettings)
|
|
@@ -137579,12 +138030,12 @@ function SettingsInteractiveView({ state }) {
|
|
|
137579
138030
|
Box,
|
|
137580
138031
|
{
|
|
137581
138032
|
borderStyle: "round",
|
|
137582
|
-
borderColor: detailFocused ? "
|
|
138033
|
+
borderColor: detailFocused ? "cyanBright" : "gray",
|
|
137583
138034
|
flexDirection: "column",
|
|
137584
138035
|
flexGrow: 1,
|
|
137585
138036
|
overflow: "hidden",
|
|
137586
138037
|
children: [
|
|
137587
|
-
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: detailFocused, color: detailFocused ? "
|
|
138038
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: detailFocused, color: detailFocused ? "cyanBright" : void 0, dimColor: !detailFocused, children: "Edit / Models" }) }),
|
|
137588
138039
|
/* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: !localSettings ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading settings\u2026" }) : !selectedDef ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
137589
138040
|
/* @__PURE__ */ jsx(Text, { bold: true, color: "whiteBright", children: selectedDef.label }),
|
|
137590
138041
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
@@ -137598,7 +138049,7 @@ function SettingsInteractiveView({ state }) {
|
|
|
137598
138049
|
selectedDef.type === "enum" && selectedDef.options && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
137599
138050
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[\u2190/\u2192] cycle options:" }),
|
|
137600
138051
|
selectedDef.options.map((opt) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginLeft: 1, children: [
|
|
137601
|
-
/* @__PURE__ */ jsx(Text, { color: localSettings[selectedDef.key] === opt ? "
|
|
138052
|
+
/* @__PURE__ */ jsx(Text, { color: localSettings[selectedDef.key] === opt ? "white" : "gray", children: localSettings[selectedDef.key] === opt ? "\u25B6" : " " }),
|
|
137602
138053
|
/* @__PURE__ */ jsx(Text, { children: opt })
|
|
137603
138054
|
] }, opt))
|
|
137604
138055
|
] }),
|
|
@@ -137629,20 +138080,989 @@ function SettingsInteractiveView({ state }) {
|
|
|
137629
138080
|
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[Tab] switch panel \u2191\u2193 select setting [Space] toggle bool [+/-] adjust num [\u2190/\u2192] cycle enum" }) })
|
|
137630
138081
|
] });
|
|
137631
138082
|
}
|
|
137632
|
-
function
|
|
138083
|
+
function relMs(ms) {
|
|
138084
|
+
if (ms === null) return "never";
|
|
138085
|
+
const diff = Date.now() - ms;
|
|
138086
|
+
const s = Math.floor(diff / 1e3);
|
|
138087
|
+
if (s < 60) return `${s}s ago`;
|
|
138088
|
+
const m = Math.floor(s / 60);
|
|
138089
|
+
if (m < 60) return `${m}m ago`;
|
|
138090
|
+
const h = Math.floor(m / 60);
|
|
138091
|
+
if (h < 24) return `${h}h ago`;
|
|
138092
|
+
return `${Math.floor(h / 24)}d ago`;
|
|
138093
|
+
}
|
|
138094
|
+
function statusColor(s) {
|
|
138095
|
+
if (s === "A") return "green";
|
|
138096
|
+
if (s === "D") return "red";
|
|
138097
|
+
if (s === "R" || s === "C") return "cyan";
|
|
138098
|
+
if (s === "M" || s === "m") return "yellow";
|
|
138099
|
+
return "gray";
|
|
138100
|
+
}
|
|
138101
|
+
function truncatePath(p, maxLen) {
|
|
138102
|
+
if (p.length <= maxLen) return p;
|
|
138103
|
+
return "\u2026" + p.slice(-(maxLen - 1));
|
|
138104
|
+
}
|
|
138105
|
+
function authorInitials(name) {
|
|
138106
|
+
const parts = name.trim().split(/\s+/);
|
|
138107
|
+
if (parts.length === 1) return (parts[0] ?? "?").slice(0, 2).toUpperCase();
|
|
138108
|
+
return ((parts[0]?.[0] ?? "") + (parts[parts.length - 1]?.[0] ?? "")).toUpperCase();
|
|
138109
|
+
}
|
|
138110
|
+
function PushModal({
|
|
138111
|
+
status,
|
|
138112
|
+
commits,
|
|
138113
|
+
onConfirm,
|
|
138114
|
+
onCancel
|
|
138115
|
+
}) {
|
|
138116
|
+
useInput((_input, key) => {
|
|
138117
|
+
if (key.return) {
|
|
138118
|
+
onConfirm();
|
|
138119
|
+
return;
|
|
138120
|
+
}
|
|
138121
|
+
if (key.escape) {
|
|
138122
|
+
onCancel();
|
|
138123
|
+
return;
|
|
138124
|
+
}
|
|
138125
|
+
});
|
|
138126
|
+
const toPush = commits.slice(0, status.ahead);
|
|
138127
|
+
return /* @__PURE__ */ jsxs(
|
|
138128
|
+
Box,
|
|
138129
|
+
{
|
|
138130
|
+
position: "absolute",
|
|
138131
|
+
flexDirection: "column",
|
|
138132
|
+
borderStyle: "round",
|
|
138133
|
+
borderColor: "cyanBright",
|
|
138134
|
+
paddingX: 2,
|
|
138135
|
+
paddingY: 1,
|
|
138136
|
+
backgroundColor: "black",
|
|
138137
|
+
children: [
|
|
138138
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: "Push to remote" }),
|
|
138139
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
138140
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138141
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Branch:" }),
|
|
138142
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: status.branch }),
|
|
138143
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "ahead" }),
|
|
138144
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: status.ahead })
|
|
138145
|
+
] }),
|
|
138146
|
+
toPush.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138147
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
138148
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Commits to push (oldest\u2192newest):" }),
|
|
138149
|
+
[...toPush].reverse().map((c) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginLeft: 1, children: [
|
|
138150
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: c.shortSha }),
|
|
138151
|
+
/* @__PURE__ */ jsx(Text, { wrap: "truncate", children: c.subject })
|
|
138152
|
+
] }, c.sha))
|
|
138153
|
+
] }),
|
|
138154
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
138155
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[Enter] push [Esc] cancel" })
|
|
138156
|
+
]
|
|
138157
|
+
}
|
|
138158
|
+
);
|
|
138159
|
+
}
|
|
138160
|
+
function GitView({ state }) {
|
|
138161
|
+
const { stdout } = useStdout();
|
|
138162
|
+
const cols = stdout?.columns ?? 80;
|
|
138163
|
+
const data = state.interactiveData;
|
|
138164
|
+
const [projectIndex, setProjectIndex] = useState2(0);
|
|
138165
|
+
const [pickerOpen, setPickerOpen] = useState2(false);
|
|
138166
|
+
const [pickerOriginal, setPickerOriginal] = useState2(0);
|
|
138167
|
+
const projectsState = useProjects(data);
|
|
138168
|
+
const selectedProject = projectsState.projects[projectIndex] ?? null;
|
|
138169
|
+
const projectPath = selectedProject?.path ?? null;
|
|
138170
|
+
const [gitStatus, setGitStatus] = useState2(null);
|
|
138171
|
+
const [commits, setCommits] = useState2([]);
|
|
138172
|
+
const [branches, setBranches] = useState2([]);
|
|
138173
|
+
const [worktrees, setWorktrees] = useState2([]);
|
|
138174
|
+
const [loading, setLoading] = useState2(false);
|
|
138175
|
+
const [statusMsg, setStatusMsg] = useState2(null);
|
|
138176
|
+
const [commitIndex, setCommitIndex] = useState2(0);
|
|
138177
|
+
const [commitDetail, setCommitDetail] = useState2(null);
|
|
138178
|
+
const [loadingDetail, setLoadingDetail] = useState2(false);
|
|
138179
|
+
const [branchIndex, setBranchIndex] = useState2(0);
|
|
138180
|
+
const [worktreeIndex, setWorktreeIndex] = useState2(0);
|
|
138181
|
+
const [activePane, setActivePane] = useState2("status");
|
|
138182
|
+
const [pushModal, setPushModal] = useState2(null);
|
|
138183
|
+
const refresh = useCallback2(async () => {
|
|
138184
|
+
if (!data || !projectPath) return;
|
|
138185
|
+
setLoading(true);
|
|
138186
|
+
try {
|
|
138187
|
+
const [s, c, b, w] = await Promise.all([
|
|
138188
|
+
data.git.getStatus(projectPath),
|
|
138189
|
+
data.git.listCommits(projectPath, 15),
|
|
138190
|
+
data.git.listBranches(projectPath),
|
|
138191
|
+
data.git.listWorktrees(projectPath)
|
|
138192
|
+
]);
|
|
138193
|
+
setGitStatus(s);
|
|
138194
|
+
setCommits(c);
|
|
138195
|
+
setBranches(b);
|
|
138196
|
+
setWorktrees(w);
|
|
138197
|
+
} catch (err) {
|
|
138198
|
+
setStatusMsg(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
138199
|
+
} finally {
|
|
138200
|
+
setLoading(false);
|
|
138201
|
+
}
|
|
138202
|
+
}, [data, projectPath]);
|
|
138203
|
+
useEffect2(() => {
|
|
138204
|
+
void refresh();
|
|
138205
|
+
}, [refresh]);
|
|
138206
|
+
useEffect2(() => {
|
|
138207
|
+
const id = setInterval(() => {
|
|
138208
|
+
void refresh();
|
|
138209
|
+
}, 5e3);
|
|
138210
|
+
return () => clearInterval(id);
|
|
138211
|
+
}, [refresh]);
|
|
138212
|
+
const selectedCommit = commits[commitIndex] ?? null;
|
|
138213
|
+
useEffect2(() => {
|
|
138214
|
+
if (!data || !projectPath || !selectedCommit) {
|
|
138215
|
+
setCommitDetail(null);
|
|
138216
|
+
return;
|
|
138217
|
+
}
|
|
138218
|
+
setLoadingDetail(true);
|
|
138219
|
+
data.git.showCommit(projectPath, selectedCommit.sha).then((d) => {
|
|
138220
|
+
setCommitDetail(d);
|
|
138221
|
+
setLoadingDetail(false);
|
|
138222
|
+
}).catch(() => {
|
|
138223
|
+
setCommitDetail(null);
|
|
138224
|
+
setLoadingDetail(false);
|
|
138225
|
+
});
|
|
138226
|
+
}, [data, projectPath, selectedCommit?.sha]);
|
|
138227
|
+
useInput((input, key) => {
|
|
138228
|
+
if (pushModal) {
|
|
138229
|
+
if (pushModal.phase === "confirm") {
|
|
138230
|
+
if (key.return) {
|
|
138231
|
+
setPushModal({ phase: "pushing" });
|
|
138232
|
+
if (data && projectPath) {
|
|
138233
|
+
data.git.push(projectPath).then((result) => {
|
|
138234
|
+
setPushModal({ phase: "done", message: result.output || (result.success ? "Push successful" : "Push failed"), isError: !result.success });
|
|
138235
|
+
if (result.success) {
|
|
138236
|
+
setTimeout(() => {
|
|
138237
|
+
setPushModal(null);
|
|
138238
|
+
void refresh();
|
|
138239
|
+
}, 2e3);
|
|
138240
|
+
}
|
|
138241
|
+
}).catch((err) => {
|
|
138242
|
+
setPushModal({ phase: "done", message: err instanceof Error ? err.message : String(err), isError: true });
|
|
138243
|
+
});
|
|
138244
|
+
}
|
|
138245
|
+
return;
|
|
138246
|
+
}
|
|
138247
|
+
if (key.escape) {
|
|
138248
|
+
setPushModal(null);
|
|
138249
|
+
return;
|
|
138250
|
+
}
|
|
138251
|
+
}
|
|
138252
|
+
if (pushModal.phase === "done" && (pushModal.isError || key.escape)) {
|
|
138253
|
+
setPushModal(null);
|
|
138254
|
+
return;
|
|
138255
|
+
}
|
|
138256
|
+
return;
|
|
138257
|
+
}
|
|
138258
|
+
if (pickerOpen) {
|
|
138259
|
+
if (key.upArrow || input === "k") {
|
|
138260
|
+
setProjectIndex((p) => Math.max(0, p - 1));
|
|
138261
|
+
return;
|
|
138262
|
+
}
|
|
138263
|
+
if (key.downArrow || input === "j") {
|
|
138264
|
+
setProjectIndex((p) => Math.min(projectsState.projects.length - 1, p + 1));
|
|
138265
|
+
return;
|
|
138266
|
+
}
|
|
138267
|
+
if (key.return) {
|
|
138268
|
+
setPickerOpen(false);
|
|
138269
|
+
return;
|
|
138270
|
+
}
|
|
138271
|
+
if (key.escape) {
|
|
138272
|
+
setProjectIndex(pickerOriginal);
|
|
138273
|
+
setPickerOpen(false);
|
|
138274
|
+
return;
|
|
138275
|
+
}
|
|
138276
|
+
return;
|
|
138277
|
+
}
|
|
138278
|
+
if (input === "p") {
|
|
138279
|
+
setPickerOriginal(projectIndex);
|
|
138280
|
+
setPickerOpen(true);
|
|
138281
|
+
return;
|
|
138282
|
+
}
|
|
138283
|
+
if (input === "r") {
|
|
138284
|
+
void refresh();
|
|
138285
|
+
return;
|
|
138286
|
+
}
|
|
138287
|
+
if (input === "P" && gitStatus && gitStatus.ahead > 0) {
|
|
138288
|
+
setPushModal({ phase: "confirm", commits });
|
|
138289
|
+
return;
|
|
138290
|
+
}
|
|
138291
|
+
if (input === "F" && data && projectPath) {
|
|
138292
|
+
setStatusMsg("Fetching\u2026");
|
|
138293
|
+
data.git.fetch(projectPath).then((result) => {
|
|
138294
|
+
setStatusMsg(result.success ? "Fetched" : `Fetch failed: ${result.output}`);
|
|
138295
|
+
void refresh();
|
|
138296
|
+
}).catch((err) => {
|
|
138297
|
+
setStatusMsg(`Fetch error: ${err instanceof Error ? err.message : String(err)}`);
|
|
138298
|
+
});
|
|
138299
|
+
return;
|
|
138300
|
+
}
|
|
138301
|
+
if (key.leftArrow || input === "h") {
|
|
138302
|
+
setActivePane((p) => {
|
|
138303
|
+
const order = worktrees.length > 1 ? ["status", "branches", "worktrees", "commits", "changes"] : ["status", "branches", "commits", "changes"];
|
|
138304
|
+
const i = order.indexOf(p);
|
|
138305
|
+
return order[Math.max(0, i - 1)] ?? p;
|
|
138306
|
+
});
|
|
138307
|
+
return;
|
|
138308
|
+
}
|
|
138309
|
+
if (key.rightArrow || input === "l") {
|
|
138310
|
+
setActivePane((p) => {
|
|
138311
|
+
const order = worktrees.length > 1 ? ["status", "branches", "worktrees", "commits", "changes"] : ["status", "branches", "commits", "changes"];
|
|
138312
|
+
const i = order.indexOf(p);
|
|
138313
|
+
return order[Math.min(order.length - 1, i + 1)] ?? p;
|
|
138314
|
+
});
|
|
138315
|
+
return;
|
|
138316
|
+
}
|
|
138317
|
+
if (activePane === "commits") {
|
|
138318
|
+
if (key.upArrow || input === "k") {
|
|
138319
|
+
setCommitIndex((i) => Math.max(0, i - 1));
|
|
138320
|
+
return;
|
|
138321
|
+
}
|
|
138322
|
+
if (key.downArrow || input === "j") {
|
|
138323
|
+
setCommitIndex((i) => Math.min(commits.length - 1, i + 1));
|
|
138324
|
+
return;
|
|
138325
|
+
}
|
|
138326
|
+
}
|
|
138327
|
+
if (activePane === "branches") {
|
|
138328
|
+
if (key.upArrow || input === "k") {
|
|
138329
|
+
setBranchIndex((i) => Math.max(0, i - 1));
|
|
138330
|
+
return;
|
|
138331
|
+
}
|
|
138332
|
+
if (key.downArrow || input === "j") {
|
|
138333
|
+
setBranchIndex((i) => Math.min(branches.length - 1, i + 1));
|
|
138334
|
+
return;
|
|
138335
|
+
}
|
|
138336
|
+
}
|
|
138337
|
+
if (activePane === "worktrees") {
|
|
138338
|
+
if (key.upArrow || input === "k") {
|
|
138339
|
+
setWorktreeIndex((i) => Math.max(0, i - 1));
|
|
138340
|
+
return;
|
|
138341
|
+
}
|
|
138342
|
+
if (key.downArrow || input === "j") {
|
|
138343
|
+
setWorktreeIndex((i) => Math.min(worktrees.length - 1, i + 1));
|
|
138344
|
+
return;
|
|
138345
|
+
}
|
|
138346
|
+
}
|
|
138347
|
+
});
|
|
138348
|
+
const isNarrow = cols < NARROW_THRESHOLD;
|
|
138349
|
+
const leftWidth = Math.max(24, Math.floor(cols * 0.35));
|
|
138350
|
+
const rightWidth = cols - leftWidth - 1;
|
|
138351
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: [
|
|
138352
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, paddingX: 1, children: [
|
|
138353
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138354
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Project:" }),
|
|
138355
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: selectedProject?.name ?? "(none)" }),
|
|
138356
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[p] change" })
|
|
138357
|
+
] }),
|
|
138358
|
+
loading && /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138359
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
138360
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "refreshing" })
|
|
138361
|
+
] }),
|
|
138362
|
+
statusMsg && /* @__PURE__ */ jsx(Text, { color: "yellow", children: statusMsg }),
|
|
138363
|
+
/* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
|
|
138364
|
+
gitStatus && /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 1, children: gitStatus.detached ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: "detached HEAD" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138365
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: gitStatus.branch }),
|
|
138366
|
+
gitStatus.ahead > 0 && /* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
138367
|
+
"\u2191",
|
|
138368
|
+
gitStatus.ahead
|
|
138369
|
+
] }),
|
|
138370
|
+
gitStatus.behind > 0 && /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
138371
|
+
"\u2193",
|
|
138372
|
+
gitStatus.behind
|
|
138373
|
+
] })
|
|
138374
|
+
] }) })
|
|
138375
|
+
] }),
|
|
138376
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexGrow: 1, overflow: "hidden", children: [
|
|
138377
|
+
(!isNarrow || activePane === "status" || activePane === "branches" || activePane === "worktrees") && /* @__PURE__ */ jsxs(
|
|
138378
|
+
Box,
|
|
138379
|
+
{
|
|
138380
|
+
flexDirection: "column",
|
|
138381
|
+
width: isNarrow ? void 0 : leftWidth,
|
|
138382
|
+
flexGrow: isNarrow ? 1 : 0,
|
|
138383
|
+
flexShrink: 0,
|
|
138384
|
+
overflow: "hidden",
|
|
138385
|
+
children: [
|
|
138386
|
+
(!isNarrow || activePane === "status") && /* @__PURE__ */ jsxs(
|
|
138387
|
+
Box,
|
|
138388
|
+
{
|
|
138389
|
+
borderStyle: "round",
|
|
138390
|
+
borderColor: activePane === "status" ? "cyanBright" : "gray",
|
|
138391
|
+
flexDirection: "column",
|
|
138392
|
+
flexShrink: 0,
|
|
138393
|
+
overflow: "hidden",
|
|
138394
|
+
children: [
|
|
138395
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: activePane === "status", color: activePane === "status" ? "blue" : void 0, dimColor: activePane !== "status", children: "Status" }) }),
|
|
138396
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, overflow: "hidden", children: !gitStatus ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: projectPath ? "Loading\u2026" : "No project" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138397
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138398
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Remote:" }),
|
|
138399
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", wrap: "truncate", children: gitStatus.remoteUrl || "(none)" })
|
|
138400
|
+
] }),
|
|
138401
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138402
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Fetched:" }),
|
|
138403
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: relMs(gitStatus.lastFetchAt) })
|
|
138404
|
+
] }),
|
|
138405
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138406
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Staged:" }),
|
|
138407
|
+
/* @__PURE__ */ jsx(Text, { color: gitStatus.staged.length > 0 ? "green" : "gray", children: gitStatus.staged.length }),
|
|
138408
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Modified:" }),
|
|
138409
|
+
/* @__PURE__ */ jsx(Text, { color: gitStatus.unstaged.length > 0 ? "yellow" : "gray", children: gitStatus.unstaged.length }),
|
|
138410
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "New:" }),
|
|
138411
|
+
/* @__PURE__ */ jsx(Text, { color: gitStatus.untracked.length > 0 ? "cyan" : "gray", children: gitStatus.untracked.length })
|
|
138412
|
+
] })
|
|
138413
|
+
] }) })
|
|
138414
|
+
]
|
|
138415
|
+
}
|
|
138416
|
+
),
|
|
138417
|
+
(!isNarrow || activePane === "branches") && /* @__PURE__ */ jsxs(
|
|
138418
|
+
Box,
|
|
138419
|
+
{
|
|
138420
|
+
borderStyle: "round",
|
|
138421
|
+
borderColor: activePane === "branches" ? "cyanBright" : "gray",
|
|
138422
|
+
flexDirection: "column",
|
|
138423
|
+
flexGrow: isNarrow ? 1 : 1,
|
|
138424
|
+
overflow: "hidden",
|
|
138425
|
+
children: [
|
|
138426
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: activePane === "branches", color: activePane === "branches" ? "blue" : void 0, dimColor: activePane !== "branches", children: "Branches" }) }),
|
|
138427
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: [
|
|
138428
|
+
branches.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2014" }) : branches.slice(0, 8).map((b, bi) => {
|
|
138429
|
+
const isSel = activePane === "branches" && bi === branchIndex;
|
|
138430
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138431
|
+
/* @__PURE__ */ jsx(Text, { color: isSel ? "white" : b.isCurrent ? "cyanBright" : "gray", children: isSel ? "\u25B6" : b.isCurrent ? "\u25B6" : " " }),
|
|
138432
|
+
/* @__PURE__ */ jsx(Text, { color: isSel ? "whiteBright" : b.isCurrent ? "white" : "gray", bold: isSel || b.isCurrent, wrap: "truncate", children: b.name }),
|
|
138433
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: b.shortSha })
|
|
138434
|
+
] }, b.name);
|
|
138435
|
+
}),
|
|
138436
|
+
branches.length > 8 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
138437
|
+
"\u2026+",
|
|
138438
|
+
branches.length - 8,
|
|
138439
|
+
" more"
|
|
138440
|
+
] })
|
|
138441
|
+
] })
|
|
138442
|
+
]
|
|
138443
|
+
}
|
|
138444
|
+
),
|
|
138445
|
+
worktrees.length > 1 && (!isNarrow || activePane === "worktrees") && /* @__PURE__ */ jsxs(
|
|
138446
|
+
Box,
|
|
138447
|
+
{
|
|
138448
|
+
borderStyle: "round",
|
|
138449
|
+
borderColor: activePane === "worktrees" ? "cyanBright" : "gray",
|
|
138450
|
+
flexDirection: "column",
|
|
138451
|
+
flexShrink: 0,
|
|
138452
|
+
overflow: "hidden",
|
|
138453
|
+
children: [
|
|
138454
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsxs(Text, { bold: activePane === "worktrees", color: activePane === "worktrees" ? "blue" : void 0, dimColor: activePane !== "worktrees", children: [
|
|
138455
|
+
"Worktrees (",
|
|
138456
|
+
worktrees.length,
|
|
138457
|
+
")"
|
|
138458
|
+
] }) }),
|
|
138459
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, overflow: "hidden", children: worktrees.map((wt, wi) => {
|
|
138460
|
+
const isSel = activePane === "worktrees" && wi === worktreeIndex;
|
|
138461
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138462
|
+
/* @__PURE__ */ jsx(Text, { color: isSel ? "white" : wt.isCurrent ? "cyanBright" : "gray", children: isSel ? "\u25B6" : wt.isCurrent ? "\u25B6" : " " }),
|
|
138463
|
+
/* @__PURE__ */ jsx(Text, { color: isSel ? "whiteBright" : wt.isCurrent ? "white" : "gray", bold: isSel, wrap: "truncate", children: wt.branch }),
|
|
138464
|
+
wt.isLocked && /* @__PURE__ */ jsx(Text, { color: "yellow", children: "\u{1F512}" })
|
|
138465
|
+
] }, wt.path);
|
|
138466
|
+
}) })
|
|
138467
|
+
]
|
|
138468
|
+
}
|
|
138469
|
+
)
|
|
138470
|
+
]
|
|
138471
|
+
}
|
|
138472
|
+
),
|
|
138473
|
+
(!isNarrow || activePane === "commits" || activePane === "changes") && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: [
|
|
138474
|
+
(!isNarrow || activePane === "commits") && /* @__PURE__ */ jsxs(
|
|
138475
|
+
Box,
|
|
138476
|
+
{
|
|
138477
|
+
borderStyle: "round",
|
|
138478
|
+
borderColor: activePane === "commits" ? "cyanBright" : "gray",
|
|
138479
|
+
flexDirection: "column",
|
|
138480
|
+
flexGrow: 1,
|
|
138481
|
+
overflow: "hidden",
|
|
138482
|
+
children: [
|
|
138483
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: activePane === "commits", color: activePane === "commits" ? "blue" : void 0, dimColor: activePane !== "commits", children: "Commits" }) }),
|
|
138484
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: commits.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: loading ? "Loading\u2026" : "No commits" }) : commits.map((c, i) => {
|
|
138485
|
+
const isSel = i === commitIndex;
|
|
138486
|
+
const initials = authorInitials(c.authorName);
|
|
138487
|
+
const subjectWidth = Math.max(10, isNarrow ? cols - 30 : rightWidth - 30);
|
|
138488
|
+
const subject = c.subject.length > subjectWidth ? c.subject.slice(0, subjectWidth - 1) + "\u2026" : c.subject;
|
|
138489
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138490
|
+
/* @__PURE__ */ jsx(Text, { color: isSel ? "white" : "gray", children: isSel ? "\u25B6" : " " }),
|
|
138491
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: c.shortSha }),
|
|
138492
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: c.relativeTime.slice(0, 8).padEnd(8) }),
|
|
138493
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: initials.padEnd(2) }),
|
|
138494
|
+
/* @__PURE__ */ jsx(Text, { bold: isSel, color: isSel ? "whiteBright" : void 0, wrap: "truncate", children: subject })
|
|
138495
|
+
] }, c.sha);
|
|
138496
|
+
}) }),
|
|
138497
|
+
selectedCommit && /* @__PURE__ */ jsx(
|
|
138498
|
+
Box,
|
|
138499
|
+
{
|
|
138500
|
+
borderStyle: "round",
|
|
138501
|
+
borderColor: "gray",
|
|
138502
|
+
flexDirection: "column",
|
|
138503
|
+
paddingX: 1,
|
|
138504
|
+
flexShrink: 0,
|
|
138505
|
+
overflow: "hidden",
|
|
138506
|
+
children: loadingDetail ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138507
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
138508
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading\u2026" })
|
|
138509
|
+
] }) : commitDetail ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138510
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138511
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: commitDetail.shortSha }),
|
|
138512
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: commitDetail.isoTime.slice(0, 16) }),
|
|
138513
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "by" }),
|
|
138514
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: commitDetail.authorName })
|
|
138515
|
+
] }),
|
|
138516
|
+
commitDetail.body && /* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "wrap", children: commitDetail.body.slice(0, 200) }),
|
|
138517
|
+
commitDetail.stat && /* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate", children: commitDetail.stat.split("\n").slice(-1)[0] })
|
|
138518
|
+
] }) : null
|
|
138519
|
+
}
|
|
138520
|
+
)
|
|
138521
|
+
]
|
|
138522
|
+
}
|
|
138523
|
+
),
|
|
138524
|
+
(!isNarrow || activePane === "changes") && /* @__PURE__ */ jsxs(
|
|
138525
|
+
Box,
|
|
138526
|
+
{
|
|
138527
|
+
borderStyle: "round",
|
|
138528
|
+
borderColor: activePane === "changes" ? "cyanBright" : "gray",
|
|
138529
|
+
flexDirection: "column",
|
|
138530
|
+
flexShrink: 0,
|
|
138531
|
+
overflow: "hidden",
|
|
138532
|
+
children: [
|
|
138533
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: activePane === "changes", color: activePane === "changes" ? "blue" : void 0, dimColor: activePane !== "changes", children: "Changes" }) }),
|
|
138534
|
+
gitStatus && (gitStatus.staged.length > 0 || gitStatus.unstaged.length > 0 || gitStatus.untracked.length > 0) ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", paddingX: 1, overflow: "hidden", children: [
|
|
138535
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: "50%", overflow: "hidden", children: [
|
|
138536
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
138537
|
+
"Staged (",
|
|
138538
|
+
gitStatus.staged.length,
|
|
138539
|
+
")"
|
|
138540
|
+
] }),
|
|
138541
|
+
gitStatus.staged.slice(0, 6).map((f) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138542
|
+
/* @__PURE__ */ jsx(Text, { color: statusColor(f.status), children: f.status }),
|
|
138543
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", wrap: "truncate", children: truncatePath(f.path, Math.floor(leftWidth / 2) - 4) })
|
|
138544
|
+
] }, `s-${f.path}`)),
|
|
138545
|
+
gitStatus.staged.length > 6 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
138546
|
+
"\u2026+",
|
|
138547
|
+
gitStatus.staged.length - 6
|
|
138548
|
+
] })
|
|
138549
|
+
] }),
|
|
138550
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: [
|
|
138551
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
138552
|
+
"Unstaged (",
|
|
138553
|
+
gitStatus.unstaged.length + gitStatus.untracked.length,
|
|
138554
|
+
")"
|
|
138555
|
+
] }),
|
|
138556
|
+
gitStatus.unstaged.slice(0, 4).map((f) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138557
|
+
/* @__PURE__ */ jsx(Text, { color: statusColor(f.status), children: f.status }),
|
|
138558
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", wrap: "truncate", children: truncatePath(f.path, Math.floor((isNarrow ? cols : rightWidth) / 2) - 4) })
|
|
138559
|
+
] }, `u-${f.path}`)),
|
|
138560
|
+
gitStatus.untracked.slice(0, 2).map((f) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138561
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "?" }),
|
|
138562
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", wrap: "truncate", children: truncatePath(f.path, Math.floor((isNarrow ? cols : rightWidth) / 2) - 4) })
|
|
138563
|
+
] }, `n-${f.path}`)),
|
|
138564
|
+
gitStatus.unstaged.length + gitStatus.untracked.length > 6 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
138565
|
+
"\u2026+",
|
|
138566
|
+
gitStatus.unstaged.length + gitStatus.untracked.length - 6
|
|
138567
|
+
] })
|
|
138568
|
+
] })
|
|
138569
|
+
] }) : /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Working tree clean" }) })
|
|
138570
|
+
]
|
|
138571
|
+
}
|
|
138572
|
+
)
|
|
138573
|
+
] })
|
|
138574
|
+
] }),
|
|
138575
|
+
/* @__PURE__ */ jsxs(Box, { paddingX: 1, flexDirection: "row", gap: 1, children: [
|
|
138576
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
138577
|
+
"[r] refresh ",
|
|
138578
|
+
gitStatus && gitStatus.ahead > 0 ? "[P] push " : "",
|
|
138579
|
+
"[F] fetch [\u2191\u2193] rows [\u2190\u2192] status\u25B8branches",
|
|
138580
|
+
worktrees.length > 1 ? "\u25B8worktrees" : "",
|
|
138581
|
+
"\u25B8commits\u25B8changes [p] project [Esc/s] back"
|
|
138582
|
+
] }),
|
|
138583
|
+
isNarrow && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
138584
|
+
"[narrow] ",
|
|
138585
|
+
activePane
|
|
138586
|
+
] })
|
|
138587
|
+
] }),
|
|
138588
|
+
pickerOpen && /* @__PURE__ */ jsx(Box, { position: "absolute", marginTop: 1, marginLeft: 1, children: /* @__PURE__ */ jsx(
|
|
138589
|
+
ProjectSelector,
|
|
138590
|
+
{
|
|
138591
|
+
open: true,
|
|
138592
|
+
projects: projectsState.projects,
|
|
138593
|
+
selectedIndex: projectIndex,
|
|
138594
|
+
onSelect: setProjectIndex
|
|
138595
|
+
}
|
|
138596
|
+
) }),
|
|
138597
|
+
pushModal && /* @__PURE__ */ jsxs(Box, { position: "absolute", marginTop: 2, marginLeft: 4, children: [
|
|
138598
|
+
pushModal.phase === "confirm" && gitStatus && /* @__PURE__ */ jsx(
|
|
138599
|
+
PushModal,
|
|
138600
|
+
{
|
|
138601
|
+
status: gitStatus,
|
|
138602
|
+
commits,
|
|
138603
|
+
onConfirm: () => {
|
|
138604
|
+
setPushModal({ phase: "pushing" });
|
|
138605
|
+
if (data && projectPath) {
|
|
138606
|
+
data.git.push(projectPath).then((result) => {
|
|
138607
|
+
setPushModal({ phase: "done", message: result.output || (result.success ? "Push successful" : "Push failed"), isError: !result.success });
|
|
138608
|
+
if (result.success) {
|
|
138609
|
+
setTimeout(() => {
|
|
138610
|
+
setPushModal(null);
|
|
138611
|
+
void refresh();
|
|
138612
|
+
}, 2e3);
|
|
138613
|
+
}
|
|
138614
|
+
}).catch((err) => {
|
|
138615
|
+
setPushModal({ phase: "done", message: err instanceof Error ? err.message : String(err), isError: true });
|
|
138616
|
+
});
|
|
138617
|
+
}
|
|
138618
|
+
},
|
|
138619
|
+
onCancel: () => setPushModal(null)
|
|
138620
|
+
}
|
|
138621
|
+
),
|
|
138622
|
+
pushModal.phase === "pushing" && /* @__PURE__ */ jsxs(
|
|
138623
|
+
Box,
|
|
138624
|
+
{
|
|
138625
|
+
borderStyle: "round",
|
|
138626
|
+
borderColor: "cyanBright",
|
|
138627
|
+
flexDirection: "row",
|
|
138628
|
+
paddingX: 2,
|
|
138629
|
+
paddingY: 1,
|
|
138630
|
+
gap: 1,
|
|
138631
|
+
backgroundColor: "black",
|
|
138632
|
+
children: [
|
|
138633
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
138634
|
+
/* @__PURE__ */ jsxs(Text, { color: "white", children: [
|
|
138635
|
+
"Pushing to origin/",
|
|
138636
|
+
gitStatus?.branch ?? "\u2026"
|
|
138637
|
+
] })
|
|
138638
|
+
]
|
|
138639
|
+
}
|
|
138640
|
+
),
|
|
138641
|
+
pushModal.phase === "done" && /* @__PURE__ */ jsxs(
|
|
138642
|
+
Box,
|
|
138643
|
+
{
|
|
138644
|
+
borderStyle: "round",
|
|
138645
|
+
borderColor: pushModal.isError ? "red" : "blue",
|
|
138646
|
+
flexDirection: "column",
|
|
138647
|
+
paddingX: 2,
|
|
138648
|
+
paddingY: 1,
|
|
138649
|
+
backgroundColor: "black",
|
|
138650
|
+
children: [
|
|
138651
|
+
/* @__PURE__ */ jsx(Text, { color: pushModal.isError ? "red" : "green", children: pushModal.message }),
|
|
138652
|
+
pushModal.isError && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[Esc] dismiss" })
|
|
138653
|
+
]
|
|
138654
|
+
}
|
|
138655
|
+
)
|
|
138656
|
+
] })
|
|
138657
|
+
] });
|
|
138658
|
+
}
|
|
138659
|
+
function truncateMiddle(s, max) {
|
|
138660
|
+
if (s.length <= max) return s;
|
|
138661
|
+
const half = Math.floor((max - 1) / 2);
|
|
138662
|
+
return s.slice(0, half) + "\u2026" + s.slice(s.length - (max - half - 1));
|
|
138663
|
+
}
|
|
138664
|
+
function formatFileSize(bytes) {
|
|
138665
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
138666
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
138667
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
138668
|
+
}
|
|
138669
|
+
function flattenTree(nodes, showHidden) {
|
|
138670
|
+
const result = [];
|
|
138671
|
+
function walk(list) {
|
|
138672
|
+
for (const node of list) {
|
|
138673
|
+
if (!showHidden && node.entry.name.startsWith(".")) continue;
|
|
138674
|
+
result.push(node);
|
|
138675
|
+
if (node.expanded && node.children) {
|
|
138676
|
+
walk(node.children);
|
|
138677
|
+
}
|
|
138678
|
+
}
|
|
138679
|
+
}
|
|
138680
|
+
walk(nodes);
|
|
138681
|
+
return result;
|
|
138682
|
+
}
|
|
138683
|
+
function entriesToNodes(entries, depth) {
|
|
138684
|
+
const filtered = entries.filter((e) => !FILES_DENYLIST.has(e.name));
|
|
138685
|
+
const dirs = filtered.filter((e) => e.isDirectory).sort((a, b) => a.name.localeCompare(b.name));
|
|
138686
|
+
const files = filtered.filter((e) => !e.isDirectory).sort((a, b) => a.name.localeCompare(b.name));
|
|
138687
|
+
return [...dirs, ...files].map((e) => ({ entry: e, depth, expanded: false, children: void 0 }));
|
|
138688
|
+
}
|
|
138689
|
+
function FilesView({ state }) {
|
|
138690
|
+
const { stdout } = useStdout();
|
|
138691
|
+
const cols = stdout?.columns ?? 80;
|
|
138692
|
+
const data = state.interactiveData;
|
|
138693
|
+
const [projectIndex, setProjectIndex] = useState2(0);
|
|
138694
|
+
const [pickerOpen, setPickerOpen] = useState2(false);
|
|
138695
|
+
const [pickerOriginal, setPickerOriginal] = useState2(0);
|
|
138696
|
+
const projectsState = useProjects(data);
|
|
138697
|
+
const selectedProject = projectsState.projects[projectIndex] ?? null;
|
|
138698
|
+
const projectPath = selectedProject?.path ?? null;
|
|
138699
|
+
const [rootNodes, setRootNodes] = useState2([]);
|
|
138700
|
+
const [treeLoading, setTreeLoading] = useState2(false);
|
|
138701
|
+
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
138702
|
+
const [showHidden, setShowHidden] = useState2(false);
|
|
138703
|
+
const [previewResult, setPreviewResult] = useState2(null);
|
|
138704
|
+
const [previewPath, setPreviewPath] = useState2(null);
|
|
138705
|
+
const [previewLoading, setPreviewLoading] = useState2(false);
|
|
138706
|
+
const [previewScroll, setPreviewScroll] = useState2(0);
|
|
138707
|
+
const [wrapEnabled, setWrapEnabled] = useState2(false);
|
|
138708
|
+
const [focusedPane, setFocusedPane] = useState2("tree");
|
|
138709
|
+
const flatNodes = flattenTree(rootNodes, showHidden);
|
|
138710
|
+
const selectedNode = flatNodes[selectedIndex] ?? null;
|
|
138711
|
+
const hiddenCount = rootNodes.filter((n) => n.entry.name.startsWith(".")).length;
|
|
138712
|
+
useEffect2(() => {
|
|
138713
|
+
if (!data || !projectPath) return;
|
|
138714
|
+
setTreeLoading(true);
|
|
138715
|
+
setRootNodes([]);
|
|
138716
|
+
setSelectedIndex(0);
|
|
138717
|
+
setPreviewResult(null);
|
|
138718
|
+
setPreviewPath(null);
|
|
138719
|
+
data.files.listDirectory(projectPath, "").then((entries) => {
|
|
138720
|
+
setRootNodes(entriesToNodes(entries, 0));
|
|
138721
|
+
}).catch(() => {
|
|
138722
|
+
setRootNodes([]);
|
|
138723
|
+
}).finally(() => {
|
|
138724
|
+
setTreeLoading(false);
|
|
138725
|
+
});
|
|
138726
|
+
}, [data, projectPath]);
|
|
138727
|
+
useEffect2(() => {
|
|
138728
|
+
if (!data || !projectPath || !selectedNode) return;
|
|
138729
|
+
if (selectedNode.entry.isDirectory) return;
|
|
138730
|
+
const rel = selectedNode.entry.path;
|
|
138731
|
+
if (rel === previewPath) return;
|
|
138732
|
+
setPreviewLoading(true);
|
|
138733
|
+
setPreviewScroll(0);
|
|
138734
|
+
data.files.readFile(projectPath, rel).then((result) => {
|
|
138735
|
+
setPreviewResult(result);
|
|
138736
|
+
setPreviewPath(rel);
|
|
138737
|
+
}).catch(() => {
|
|
138738
|
+
setPreviewResult(null);
|
|
138739
|
+
setPreviewPath(rel);
|
|
138740
|
+
}).finally(() => {
|
|
138741
|
+
setPreviewLoading(false);
|
|
138742
|
+
});
|
|
138743
|
+
}, [data, projectPath, selectedNode?.entry.path]);
|
|
138744
|
+
const expandNode = useCallback2(async (node) => {
|
|
138745
|
+
if (!data || !projectPath) return;
|
|
138746
|
+
if (!node.entry.isDirectory) return;
|
|
138747
|
+
if (node.children !== void 0) {
|
|
138748
|
+
node.expanded = !node.expanded;
|
|
138749
|
+
setRootNodes((prev) => [...prev]);
|
|
138750
|
+
return;
|
|
138751
|
+
}
|
|
138752
|
+
try {
|
|
138753
|
+
const entries = await data.files.listDirectory(projectPath, node.entry.path);
|
|
138754
|
+
node.children = entriesToNodes(entries, node.depth + 1);
|
|
138755
|
+
node.expanded = true;
|
|
138756
|
+
setRootNodes((prev) => [...prev]);
|
|
138757
|
+
} catch {
|
|
138758
|
+
node.children = [];
|
|
138759
|
+
node.expanded = true;
|
|
138760
|
+
setRootNodes((prev) => [...prev]);
|
|
138761
|
+
}
|
|
138762
|
+
}, [data, projectPath]);
|
|
138763
|
+
const collapseNode = useCallback2((node) => {
|
|
138764
|
+
node.expanded = false;
|
|
138765
|
+
setRootNodes((prev) => [...prev]);
|
|
138766
|
+
}, []);
|
|
138767
|
+
function findParentOf(nodes, target, depth) {
|
|
138768
|
+
for (const n of nodes) {
|
|
138769
|
+
if (n.depth === depth - 1 && n.expanded && n.children) {
|
|
138770
|
+
if (n.children.includes(target)) return n;
|
|
138771
|
+
const found = findParentOf(n.children, target, depth);
|
|
138772
|
+
if (found) return found;
|
|
138773
|
+
}
|
|
138774
|
+
}
|
|
138775
|
+
return null;
|
|
138776
|
+
}
|
|
138777
|
+
const previewHeight = Math.max(4, (stdout?.rows ?? 24) - 7);
|
|
138778
|
+
const halfPage = Math.max(1, Math.floor(previewHeight / 2));
|
|
138779
|
+
useInput((input, key) => {
|
|
138780
|
+
if (!data) return;
|
|
138781
|
+
if (pickerOpen) {
|
|
138782
|
+
if (key.upArrow || input === "k") {
|
|
138783
|
+
setProjectIndex((p) => Math.max(0, p - 1));
|
|
138784
|
+
return;
|
|
138785
|
+
}
|
|
138786
|
+
if (key.downArrow || input === "j") {
|
|
138787
|
+
setProjectIndex((p) => Math.min(projectsState.projects.length - 1, p + 1));
|
|
138788
|
+
return;
|
|
138789
|
+
}
|
|
138790
|
+
if (key.return) {
|
|
138791
|
+
setPickerOpen(false);
|
|
138792
|
+
return;
|
|
138793
|
+
}
|
|
138794
|
+
if (key.escape) {
|
|
138795
|
+
setProjectIndex(pickerOriginal);
|
|
138796
|
+
setPickerOpen(false);
|
|
138797
|
+
return;
|
|
138798
|
+
}
|
|
138799
|
+
return;
|
|
138800
|
+
}
|
|
138801
|
+
if (input === "p") {
|
|
138802
|
+
setPickerOriginal(projectIndex);
|
|
138803
|
+
setPickerOpen(true);
|
|
138804
|
+
return;
|
|
138805
|
+
}
|
|
138806
|
+
if (key.tab) {
|
|
138807
|
+
setFocusedPane((p) => p === "tree" ? "preview" : "tree");
|
|
138808
|
+
return;
|
|
138809
|
+
}
|
|
138810
|
+
if (input === ".") {
|
|
138811
|
+
setShowHidden((v) => !v);
|
|
138812
|
+
return;
|
|
138813
|
+
}
|
|
138814
|
+
if (input === "w" || input === "W") {
|
|
138815
|
+
setWrapEnabled((v) => !v);
|
|
138816
|
+
return;
|
|
138817
|
+
}
|
|
138818
|
+
if (input === "r" || input === "R") {
|
|
138819
|
+
if (data && projectPath && selectedNode && !selectedNode.entry.isDirectory) {
|
|
138820
|
+
setPreviewLoading(true);
|
|
138821
|
+
setPreviewScroll(0);
|
|
138822
|
+
setPreviewPath(null);
|
|
138823
|
+
}
|
|
138824
|
+
return;
|
|
138825
|
+
}
|
|
138826
|
+
if (focusedPane === "tree") {
|
|
138827
|
+
if (key.upArrow || input === "k") {
|
|
138828
|
+
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
138829
|
+
return;
|
|
138830
|
+
}
|
|
138831
|
+
if (key.downArrow || input === "j") {
|
|
138832
|
+
setSelectedIndex((i) => Math.min(flatNodes.length - 1, i + 1));
|
|
138833
|
+
return;
|
|
138834
|
+
}
|
|
138835
|
+
if (key.rightArrow) {
|
|
138836
|
+
if (selectedNode?.entry.isDirectory) {
|
|
138837
|
+
if (selectedNode.expanded) {
|
|
138838
|
+
const ci = flatNodes.indexOf(selectedNode) + 1;
|
|
138839
|
+
if (ci < flatNodes.length) setSelectedIndex(ci);
|
|
138840
|
+
} else {
|
|
138841
|
+
void expandNode(selectedNode);
|
|
138842
|
+
}
|
|
138843
|
+
}
|
|
138844
|
+
return;
|
|
138845
|
+
}
|
|
138846
|
+
if (key.leftArrow) {
|
|
138847
|
+
if (selectedNode?.entry.isDirectory && selectedNode.expanded) {
|
|
138848
|
+
collapseNode(selectedNode);
|
|
138849
|
+
} else if (selectedNode && selectedNode.depth > 0) {
|
|
138850
|
+
const parent2 = findParentOf(rootNodes, selectedNode, selectedNode.depth);
|
|
138851
|
+
if (parent2) {
|
|
138852
|
+
const pi = flatNodes.indexOf(parent2);
|
|
138853
|
+
if (pi >= 0) setSelectedIndex(pi);
|
|
138854
|
+
}
|
|
138855
|
+
}
|
|
138856
|
+
return;
|
|
138857
|
+
}
|
|
138858
|
+
if (key.return) {
|
|
138859
|
+
if (selectedNode?.entry.isDirectory) {
|
|
138860
|
+
void expandNode(selectedNode);
|
|
138861
|
+
} else if (selectedNode) {
|
|
138862
|
+
setFocusedPane("preview");
|
|
138863
|
+
setPreviewScroll(0);
|
|
138864
|
+
}
|
|
138865
|
+
return;
|
|
138866
|
+
}
|
|
138867
|
+
}
|
|
138868
|
+
if (focusedPane === "preview") {
|
|
138869
|
+
const lineCount = previewResult?.lineCount ?? 0;
|
|
138870
|
+
const maxScroll = Math.max(0, lineCount - previewHeight);
|
|
138871
|
+
if (key.upArrow || input === "k") {
|
|
138872
|
+
setPreviewScroll((s) => Math.max(0, s - 1));
|
|
138873
|
+
return;
|
|
138874
|
+
}
|
|
138875
|
+
if (key.downArrow || input === "j") {
|
|
138876
|
+
setPreviewScroll((s) => Math.min(maxScroll, s + 1));
|
|
138877
|
+
return;
|
|
138878
|
+
}
|
|
138879
|
+
if (key.pageUp) {
|
|
138880
|
+
setPreviewScroll((s) => Math.max(0, s - halfPage));
|
|
138881
|
+
return;
|
|
138882
|
+
}
|
|
138883
|
+
if (key.pageDown) {
|
|
138884
|
+
setPreviewScroll((s) => Math.min(maxScroll, s + halfPage));
|
|
138885
|
+
return;
|
|
138886
|
+
}
|
|
138887
|
+
if (input === "g") {
|
|
138888
|
+
setPreviewScroll(0);
|
|
138889
|
+
return;
|
|
138890
|
+
}
|
|
138891
|
+
if (input === "G") {
|
|
138892
|
+
setPreviewScroll(maxScroll);
|
|
138893
|
+
return;
|
|
138894
|
+
}
|
|
138895
|
+
}
|
|
138896
|
+
}, { isActive: state.interactiveView === "files" });
|
|
138897
|
+
const isNarrow = cols < NARROW_THRESHOLD;
|
|
138898
|
+
const treeWidth = isNarrow ? Math.max(20, cols - 2) : Math.max(20, Math.floor(cols * 0.38));
|
|
138899
|
+
const previewEntry = selectedNode && !selectedNode.entry.isDirectory ? selectedNode.entry : null;
|
|
138900
|
+
const previewLines = previewResult?.content ? previewResult.content.split("\n").slice(previewScroll, previewScroll + previewHeight) : null;
|
|
138901
|
+
const totalLines = previewResult?.lineCount ?? 0;
|
|
138902
|
+
const lineNumWidth = Math.max(3, String(previewScroll + previewHeight).length);
|
|
138903
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: [
|
|
138904
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", paddingX: 1, gap: 1, children: [
|
|
138905
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", bold: true, children: selectedProject?.name ?? "\u2014" }),
|
|
138906
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
138907
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, color: focusedPane === "tree" ? "cyanBright" : "gray", children: focusedPane === "tree" ? "tree" : "preview" }),
|
|
138908
|
+
previewEntry && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138909
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
138910
|
+
/* @__PURE__ */ jsx(Text, { color: "white", wrap: "truncate", children: truncateMiddle(previewEntry.path, Math.max(10, cols - 40)) }),
|
|
138911
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
138912
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: formatFileSize(previewEntry.size) }),
|
|
138913
|
+
previewResult && !previewResult.isBinary && !previewResult.tooLarge && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138914
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
138915
|
+
previewResult.lineCount,
|
|
138916
|
+
"L"
|
|
138917
|
+
] }),
|
|
138918
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: formatRelativeTime(previewEntry.modifiedAt) })
|
|
138919
|
+
] })
|
|
138920
|
+
] })
|
|
138921
|
+
] }),
|
|
138922
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexGrow: 1, overflow: "hidden", children: [
|
|
138923
|
+
(!isNarrow || focusedPane === "tree") && /* @__PURE__ */ jsxs(
|
|
138924
|
+
Box,
|
|
138925
|
+
{
|
|
138926
|
+
flexDirection: "column",
|
|
138927
|
+
width: isNarrow ? void 0 : treeWidth,
|
|
138928
|
+
flexGrow: isNarrow ? 1 : 0,
|
|
138929
|
+
flexShrink: 0,
|
|
138930
|
+
borderStyle: "round",
|
|
138931
|
+
borderColor: focusedPane === "tree" ? "cyanBright" : "gray",
|
|
138932
|
+
overflow: "hidden",
|
|
138933
|
+
children: [
|
|
138934
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: focusedPane === "tree", color: focusedPane === "tree" ? "cyanBright" : void 0, dimColor: focusedPane !== "tree", children: "Files" }) }),
|
|
138935
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: treeLoading ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138936
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
138937
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading\u2026" })
|
|
138938
|
+
] }) : flatNodes.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(empty)" }) : flatNodes.map((node, i) => {
|
|
138939
|
+
const isSelected = focusedPane === "tree" && i === selectedIndex;
|
|
138940
|
+
const indent = " ".repeat(node.depth);
|
|
138941
|
+
let prefix;
|
|
138942
|
+
if (node.entry.isDirectory) {
|
|
138943
|
+
prefix = node.expanded ? "\u25BE " : "\u25B8 ";
|
|
138944
|
+
} else {
|
|
138945
|
+
prefix = "\xB7 ";
|
|
138946
|
+
}
|
|
138947
|
+
const name = node.entry.name;
|
|
138948
|
+
const maxNameWidth = treeWidth - node.depth * 2 - 4;
|
|
138949
|
+
const displayName = name.length > maxNameWidth ? name.slice(0, maxNameWidth - 1) + "\u2026" : name;
|
|
138950
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
138951
|
+
isSelected && /* @__PURE__ */ jsx(Text, { color: "cyanBright", children: "\u25B6" }),
|
|
138952
|
+
!isSelected && /* @__PURE__ */ jsx(Text, { children: " " }),
|
|
138953
|
+
/* @__PURE__ */ jsxs(
|
|
138954
|
+
Text,
|
|
138955
|
+
{
|
|
138956
|
+
color: isSelected ? "whiteBright" : node.entry.isDirectory ? "cyan" : void 0,
|
|
138957
|
+
dimColor: !isSelected && !node.entry.isDirectory,
|
|
138958
|
+
wrap: "truncate",
|
|
138959
|
+
children: [
|
|
138960
|
+
indent,
|
|
138961
|
+
prefix,
|
|
138962
|
+
displayName
|
|
138963
|
+
]
|
|
138964
|
+
}
|
|
138965
|
+
)
|
|
138966
|
+
] }, node.entry.path);
|
|
138967
|
+
}) }),
|
|
138968
|
+
/* @__PURE__ */ jsxs(Box, { paddingX: 1, children: [
|
|
138969
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate", children: selectedNode ? truncateMiddle(
|
|
138970
|
+
projectPath ? `${projectPath}/${selectedNode.entry.path}` : selectedNode.entry.path,
|
|
138971
|
+
treeWidth - 4
|
|
138972
|
+
) : " " }),
|
|
138973
|
+
!showHidden && hiddenCount > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
138974
|
+
" [",
|
|
138975
|
+
hiddenCount,
|
|
138976
|
+
" hidden]"
|
|
138977
|
+
] })
|
|
138978
|
+
] })
|
|
138979
|
+
]
|
|
138980
|
+
}
|
|
138981
|
+
),
|
|
138982
|
+
(!isNarrow || focusedPane === "preview") && /* @__PURE__ */ jsxs(
|
|
138983
|
+
Box,
|
|
138984
|
+
{
|
|
138985
|
+
flexDirection: "column",
|
|
138986
|
+
flexGrow: 1,
|
|
138987
|
+
borderStyle: "round",
|
|
138988
|
+
borderColor: focusedPane === "preview" ? "cyanBright" : "gray",
|
|
138989
|
+
overflow: "hidden",
|
|
138990
|
+
children: [
|
|
138991
|
+
/* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { bold: focusedPane === "preview", color: focusedPane === "preview" ? "cyanBright" : void 0, dimColor: focusedPane !== "preview", children: "Preview" }) }),
|
|
138992
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: previewLoading ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
138993
|
+
/* @__PURE__ */ jsx(Text, { color: "cyanBright", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
138994
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading\u2026" })
|
|
138995
|
+
] }) : !previewEntry ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Select a file to preview" }) : previewResult === null ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Unable to read file" }) : previewResult.isBinary ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
138996
|
+
"[binary file, ",
|
|
138997
|
+
formatFileSize(previewResult.size),
|
|
138998
|
+
"]"
|
|
138999
|
+
] }) : previewResult.tooLarge ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
139000
|
+
formatFileSize(previewResult.size),
|
|
139001
|
+
" \u2014 [too large to preview]"
|
|
139002
|
+
] }) : previewResult.content === "" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(empty file)" }) : previewLines ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", overflow: "hidden", children: [
|
|
139003
|
+
previewLines.map((line, i) => {
|
|
139004
|
+
const lineNo = previewScroll + i + 1;
|
|
139005
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
139006
|
+
/* @__PURE__ */ jsx(Box, { width: lineNumWidth + 1, flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: String(lineNo).padStart(lineNumWidth) }) }),
|
|
139007
|
+
/* @__PURE__ */ jsx(Text, { wrap: wrapEnabled ? "wrap" : "truncate-end", children: line })
|
|
139008
|
+
] }, lineNo);
|
|
139009
|
+
}),
|
|
139010
|
+
totalLines > previewScroll + previewHeight && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
139011
|
+
"\u2026 ",
|
|
139012
|
+
totalLines - previewScroll - previewHeight,
|
|
139013
|
+
" more lines"
|
|
139014
|
+
] })
|
|
139015
|
+
] }) : null })
|
|
139016
|
+
]
|
|
139017
|
+
}
|
|
139018
|
+
)
|
|
139019
|
+
] }),
|
|
139020
|
+
/* @__PURE__ */ jsxs(Box, { paddingX: 1, flexDirection: "row", gap: 1, children: [
|
|
139021
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[Tab] switch pane [\u2191\u2193/jk] move [Enter] open [\u2190/\u2192] collapse/expand [.] hidden [w] wrap [p] project [r] reload" }),
|
|
139022
|
+
isNarrow && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
139023
|
+
"[narrow] ",
|
|
139024
|
+
focusedPane
|
|
139025
|
+
] })
|
|
139026
|
+
] }),
|
|
139027
|
+
pickerOpen && /* @__PURE__ */ jsx(Box, { position: "absolute", marginTop: 2, marginLeft: 2, children: /* @__PURE__ */ jsxs(
|
|
139028
|
+
Box,
|
|
139029
|
+
{
|
|
139030
|
+
borderStyle: "round",
|
|
139031
|
+
borderColor: "cyanBright",
|
|
139032
|
+
flexDirection: "column",
|
|
139033
|
+
paddingX: 2,
|
|
139034
|
+
paddingY: 1,
|
|
139035
|
+
backgroundColor: "black",
|
|
139036
|
+
children: [
|
|
139037
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: "Select Project" }),
|
|
139038
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
139039
|
+
projectsState.projects.map((proj, i) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
139040
|
+
/* @__PURE__ */ jsx(Text, { color: i === projectIndex ? "cyanBright" : "gray", children: i === projectIndex ? "\u25B6" : " " }),
|
|
139041
|
+
/* @__PURE__ */ jsx(Text, { color: i === projectIndex ? "whiteBright" : void 0, children: proj.name })
|
|
139042
|
+
] }, proj.id)),
|
|
139043
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
139044
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[\u2191\u2193] move [Enter] select [Esc] cancel" })
|
|
139045
|
+
]
|
|
139046
|
+
}
|
|
139047
|
+
) })
|
|
139048
|
+
] });
|
|
139049
|
+
}
|
|
139050
|
+
function InteractiveMode({ state, controller }) {
|
|
137633
139051
|
if (state.interactiveData === null) {
|
|
137634
139052
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
|
|
137635
|
-
/* @__PURE__ */ jsx(
|
|
139053
|
+
/* @__PURE__ */ jsx(MainHeader, { state }),
|
|
137636
139054
|
/* @__PURE__ */ jsx(Box, { justifyContent: "center", alignItems: "center", flexGrow: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Interactive mode unavailable \u2014 no data source" }) })
|
|
137637
139055
|
] });
|
|
137638
139056
|
}
|
|
137639
139057
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
|
|
137640
|
-
/* @__PURE__ */ jsx(
|
|
137641
|
-
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
139058
|
+
/* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsx(MainHeader, { state }) }),
|
|
139059
|
+
/* @__PURE__ */ jsx(Box, { height: 1, flexShrink: 0 }),
|
|
137642
139060
|
/* @__PURE__ */ jsxs(Box, { flexGrow: 1, overflow: "hidden", children: [
|
|
137643
|
-
state.interactiveView === "board" && /* @__PURE__ */ jsx(BoardView, { state }),
|
|
139061
|
+
state.interactiveView === "board" && /* @__PURE__ */ jsx(BoardView, { state, controller }),
|
|
137644
139062
|
state.interactiveView === "agents" && /* @__PURE__ */ jsx(AgentsView, { state }),
|
|
137645
|
-
state.interactiveView === "settings" && /* @__PURE__ */ jsx(SettingsInteractiveView, { state })
|
|
139063
|
+
state.interactiveView === "settings" && /* @__PURE__ */ jsx(SettingsInteractiveView, { state }),
|
|
139064
|
+
state.interactiveView === "git" && /* @__PURE__ */ jsx(GitView, { state }),
|
|
139065
|
+
state.interactiveView === "files" && /* @__PURE__ */ jsx(FilesView, { state })
|
|
137646
139066
|
] })
|
|
137647
139067
|
] });
|
|
137648
139068
|
}
|
|
@@ -137671,30 +139091,47 @@ function DashboardApp({ controller }) {
|
|
|
137671
139091
|
controller.setInteractiveView("agents");
|
|
137672
139092
|
return;
|
|
137673
139093
|
}
|
|
137674
|
-
if (input === "g"
|
|
139094
|
+
if (input === "g") {
|
|
137675
139095
|
controller.setMode("interactive");
|
|
137676
139096
|
controller.setInteractiveView("settings");
|
|
137677
139097
|
return;
|
|
137678
139098
|
}
|
|
139099
|
+
if (input === "f" || input === "F") {
|
|
139100
|
+
if (state.mode === "status") {
|
|
139101
|
+
controller.cycleSeverityFilter();
|
|
139102
|
+
return;
|
|
139103
|
+
}
|
|
139104
|
+
}
|
|
139105
|
+
if (input === "t" || input === "T") {
|
|
139106
|
+
controller.setMode("interactive");
|
|
139107
|
+
controller.setInteractiveView("git");
|
|
139108
|
+
return;
|
|
139109
|
+
}
|
|
139110
|
+
if (input === "e" || input === "E") {
|
|
139111
|
+
controller.setMode("interactive");
|
|
139112
|
+
controller.setInteractiveView("files");
|
|
139113
|
+
return;
|
|
139114
|
+
}
|
|
137679
139115
|
if (input === "s" || input === "S") {
|
|
137680
139116
|
if (state.mode === "interactive") {
|
|
137681
139117
|
controller.setMode("status");
|
|
137682
139118
|
return;
|
|
137683
139119
|
}
|
|
137684
139120
|
}
|
|
139121
|
+
const sectionForNumber = {
|
|
139122
|
+
"1": "system",
|
|
139123
|
+
"2": "logs",
|
|
139124
|
+
"3": "utilities",
|
|
139125
|
+
"4": "stats",
|
|
139126
|
+
"5": "settings"
|
|
139127
|
+
};
|
|
139128
|
+
const targetSection = sectionForNumber[input];
|
|
139129
|
+
if (targetSection) {
|
|
139130
|
+
if (state.mode === "interactive") controller.setMode("status");
|
|
139131
|
+
controller.setActiveSection(targetSection);
|
|
139132
|
+
return;
|
|
139133
|
+
}
|
|
137685
139134
|
if (state.mode === "interactive") {
|
|
137686
|
-
if (input === "1") {
|
|
137687
|
-
controller.setInteractiveView("board");
|
|
137688
|
-
return;
|
|
137689
|
-
}
|
|
137690
|
-
if (input === "2") {
|
|
137691
|
-
controller.setInteractiveView("agents");
|
|
137692
|
-
return;
|
|
137693
|
-
}
|
|
137694
|
-
if (input === "3") {
|
|
137695
|
-
controller.setInteractiveView("settings");
|
|
137696
|
-
return;
|
|
137697
|
-
}
|
|
137698
139135
|
return;
|
|
137699
139136
|
}
|
|
137700
139137
|
if (input === "?" || input === "h" || input === "H") {
|
|
@@ -137760,10 +139197,6 @@ function DashboardApp({ controller }) {
|
|
|
137760
139197
|
controller.setLogsWrapEnabled(!state.logsWrapEnabled);
|
|
137761
139198
|
return;
|
|
137762
139199
|
}
|
|
137763
|
-
if (input === "f" || input === "F") {
|
|
137764
|
-
controller.cycleSeverityFilter();
|
|
137765
|
-
return;
|
|
137766
|
-
}
|
|
137767
139200
|
if (key.upArrow || input === "k" || input === "K") {
|
|
137768
139201
|
if (state.selectedLogIndex > 0) {
|
|
137769
139202
|
controller.setSelectedLogIndex(state.selectedLogIndex - 1);
|
|
@@ -137780,7 +139213,7 @@ function DashboardApp({ controller }) {
|
|
|
137780
139213
|
controller.setSelectedLogIndex(0);
|
|
137781
139214
|
return;
|
|
137782
139215
|
}
|
|
137783
|
-
if (key.end) {
|
|
139216
|
+
if (key.end || input === "G") {
|
|
137784
139217
|
controller.setSelectedLogIndex(Math.max(0, filteredEntries.length - 1));
|
|
137785
139218
|
return;
|
|
137786
139219
|
}
|
|
@@ -137791,29 +139224,48 @@ function DashboardApp({ controller }) {
|
|
|
137791
139224
|
}
|
|
137792
139225
|
const isNarrow = cols < 80 || rows < 20;
|
|
137793
139226
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: rows, children: [
|
|
137794
|
-
state.mode === "interactive" ? /* @__PURE__ */ jsx(InteractiveMode, { state }) : isNarrow ? /* @__PURE__ */ jsx(StatusModeSingle, { state, controller }) : /* @__PURE__ */ jsx(StatusModeGrid, { state, rows, controller }),
|
|
139227
|
+
state.mode === "interactive" ? /* @__PURE__ */ jsx(InteractiveMode, { state, controller }) : isNarrow ? /* @__PURE__ */ jsx(StatusModeSingle, { state, controller }) : /* @__PURE__ */ jsx(StatusModeGrid, { state, rows, controller }),
|
|
137795
139228
|
state.showHelp && /* @__PURE__ */ jsx(Box, { position: "absolute", marginTop: 3, marginLeft: 4, children: /* @__PURE__ */ jsx(HelpOverlay, {}) })
|
|
137796
139229
|
] });
|
|
137797
139230
|
}
|
|
137798
|
-
var LOGO_COLORS, SPLASH_MIN_COLS, SPLASH_MIN_ROWS, PREFIX_WIDTH, PANEL_ORDER, KANBAN_COLUMNS, COLUMN_COLORS, SETTING_DEFS;
|
|
139231
|
+
var LOGO_COLORS, NARROW_THRESHOLD, SPLASH_MIN_COLS, SPLASH_MIN_ROWS, LARGE_LOGO_MIN_COLS, LARGE_LOGO_MIN_ROWS, PREFIX_WIDTH, PANEL_ORDER, KANBAN_COLUMNS, COLUMN_COLORS, STEP_ICON, STEP_COLOR, MAX_LOG_ENTRIES2, INITIAL_LOG_LIMIT, SETTING_DEFS, FILES_DENYLIST;
|
|
137799
139232
|
var init_app = __esm({
|
|
137800
139233
|
"src/commands/dashboard-tui/app.tsx"() {
|
|
137801
139234
|
"use strict";
|
|
137802
139235
|
init_state();
|
|
137803
139236
|
init_logo();
|
|
137804
139237
|
init_use_projects();
|
|
137805
|
-
LOGO_COLORS = ["whiteBright", "cyanBright", "
|
|
139238
|
+
LOGO_COLORS = ["whiteBright", "white", "white", "cyanBright", "cyanBright", "cyan", "cyan", "blue"];
|
|
139239
|
+
NARROW_THRESHOLD = 80;
|
|
137806
139240
|
SPLASH_MIN_COLS = 56;
|
|
137807
|
-
SPLASH_MIN_ROWS =
|
|
139241
|
+
SPLASH_MIN_ROWS = 12;
|
|
139242
|
+
LARGE_LOGO_MIN_COLS = 70;
|
|
139243
|
+
LARGE_LOGO_MIN_ROWS = 16;
|
|
137808
139244
|
PREFIX_WIDTH = 14;
|
|
137809
139245
|
PANEL_ORDER = ["system", "logs", "utilities", "stats", "settings"];
|
|
137810
139246
|
KANBAN_COLUMNS = ["todo", "in-progress", "in-review", "done"];
|
|
137811
139247
|
COLUMN_COLORS = {
|
|
137812
139248
|
todo: "yellow",
|
|
137813
|
-
"in-progress": "
|
|
137814
|
-
"in-review": "
|
|
139249
|
+
"in-progress": "cyanBright",
|
|
139250
|
+
"in-review": "cyan",
|
|
137815
139251
|
done: "green"
|
|
137816
139252
|
};
|
|
139253
|
+
STEP_ICON = {
|
|
139254
|
+
done: "\u2713",
|
|
139255
|
+
running: "\u25B6",
|
|
139256
|
+
pending: "\xB7",
|
|
139257
|
+
failed: "\u2717",
|
|
139258
|
+
skipped: "\u23ED"
|
|
139259
|
+
};
|
|
139260
|
+
STEP_COLOR = {
|
|
139261
|
+
done: "green",
|
|
139262
|
+
running: "blue",
|
|
139263
|
+
pending: "gray",
|
|
139264
|
+
failed: "red",
|
|
139265
|
+
skipped: "gray"
|
|
139266
|
+
};
|
|
139267
|
+
MAX_LOG_ENTRIES2 = 1e3;
|
|
139268
|
+
INITIAL_LOG_LIMIT = 200;
|
|
137817
139269
|
SETTING_DEFS = [
|
|
137818
139270
|
{ key: "maxConcurrent", label: "Max Concurrent", type: "number" },
|
|
137819
139271
|
{ key: "maxWorktrees", label: "Max Worktrees", type: "number" },
|
|
@@ -137823,10 +139275,13 @@ var init_app = __esm({
|
|
|
137823
139275
|
{ key: "enginePaused", label: "Engine Paused", type: "boolean" },
|
|
137824
139276
|
{ key: "globalPause", label: "Global Pause", type: "boolean" }
|
|
137825
139277
|
];
|
|
139278
|
+
FILES_DENYLIST = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".next", "target", "build"]);
|
|
137826
139279
|
}
|
|
137827
139280
|
});
|
|
137828
139281
|
|
|
137829
139282
|
// src/commands/dashboard-tui/controller.ts
|
|
139283
|
+
import os3 from "node:os";
|
|
139284
|
+
import v8 from "node:v8";
|
|
137830
139285
|
var DashboardTUI;
|
|
137831
139286
|
var init_controller = __esm({
|
|
137832
139287
|
"src/commands/dashboard-tui/controller.ts"() {
|
|
@@ -137841,6 +139296,11 @@ var init_controller = __esm({
|
|
|
137841
139296
|
logBuffer;
|
|
137842
139297
|
systemInfo = null;
|
|
137843
139298
|
taskStats = null;
|
|
139299
|
+
systemStats = null;
|
|
139300
|
+
// When set, dashboard.ts refreshes task stats from this project path
|
|
139301
|
+
// instead of the launch cwd. Mirrors BoardView's selected project.
|
|
139302
|
+
boardScopedProjectPath = null;
|
|
139303
|
+
boardScopeListener = null;
|
|
137844
139304
|
settings = null;
|
|
137845
139305
|
callbacks = null;
|
|
137846
139306
|
isRunning = false;
|
|
@@ -137864,6 +139324,10 @@ var init_controller = __esm({
|
|
|
137864
139324
|
inkInstance = null;
|
|
137865
139325
|
// Uptime ticker to keep footer time live.
|
|
137866
139326
|
uptimeTimer = null;
|
|
139327
|
+
// System stats sampler — process memory + CPU%.
|
|
139328
|
+
systemStatsTimer = null;
|
|
139329
|
+
lastCpuUsage = null;
|
|
139330
|
+
lastCpuSampleAt = 0;
|
|
137867
139331
|
constructor() {
|
|
137868
139332
|
this.logBuffer = new LogRingBuffer();
|
|
137869
139333
|
}
|
|
@@ -137879,6 +139343,7 @@ var init_controller = __esm({
|
|
|
137879
139343
|
logEntries: this.logBuffer.getAll(),
|
|
137880
139344
|
systemInfo: this.systemInfo,
|
|
137881
139345
|
taskStats: this.taskStats,
|
|
139346
|
+
systemStats: this.systemStats,
|
|
137882
139347
|
settings: this.settings,
|
|
137883
139348
|
callbacks: this.callbacks,
|
|
137884
139349
|
showHelp: this.showHelp,
|
|
@@ -137914,6 +139379,56 @@ var init_controller = __esm({
|
|
|
137914
139379
|
this.taskStats = stats;
|
|
137915
139380
|
this.notify();
|
|
137916
139381
|
}
|
|
139382
|
+
setSystemStats(stats) {
|
|
139383
|
+
this.systemStats = stats;
|
|
139384
|
+
this.notify();
|
|
139385
|
+
}
|
|
139386
|
+
setBoardScopedProjectPath(path4) {
|
|
139387
|
+
if (this.boardScopedProjectPath === path4) return;
|
|
139388
|
+
this.boardScopedProjectPath = path4;
|
|
139389
|
+
this.boardScopeListener?.(path4);
|
|
139390
|
+
this.notify();
|
|
139391
|
+
}
|
|
139392
|
+
onBoardScopeChange(listener) {
|
|
139393
|
+
this.boardScopeListener = listener;
|
|
139394
|
+
return () => {
|
|
139395
|
+
if (this.boardScopeListener === listener) this.boardScopeListener = null;
|
|
139396
|
+
};
|
|
139397
|
+
}
|
|
139398
|
+
/** Sample process memory + CPU% in-place. Called from the sampler timer. */
|
|
139399
|
+
sampleSystemStats() {
|
|
139400
|
+
const mem = process.memoryUsage();
|
|
139401
|
+
const heapStats = v8.getHeapStatistics();
|
|
139402
|
+
const now = Date.now();
|
|
139403
|
+
const cpu = process.cpuUsage();
|
|
139404
|
+
let cpuPercent = 0;
|
|
139405
|
+
if (this.lastCpuUsage && this.lastCpuSampleAt > 0) {
|
|
139406
|
+
const elapsedMicros = (now - this.lastCpuSampleAt) * 1e3;
|
|
139407
|
+
if (elapsedMicros > 0) {
|
|
139408
|
+
const usedMicros = cpu.user - this.lastCpuUsage.user + (cpu.system - this.lastCpuUsage.system);
|
|
139409
|
+
cpuPercent = usedMicros / elapsedMicros * 100;
|
|
139410
|
+
}
|
|
139411
|
+
}
|
|
139412
|
+
this.lastCpuUsage = cpu;
|
|
139413
|
+
this.lastCpuSampleAt = now;
|
|
139414
|
+
const load = os3.loadavg();
|
|
139415
|
+
this.setSystemStats({
|
|
139416
|
+
rss: mem.rss,
|
|
139417
|
+
heapUsed: mem.heapUsed,
|
|
139418
|
+
heapTotal: mem.heapTotal,
|
|
139419
|
+
heapLimit: heapStats.heap_size_limit,
|
|
139420
|
+
external: mem.external,
|
|
139421
|
+
arrayBuffers: mem.arrayBuffers,
|
|
139422
|
+
cpuPercent,
|
|
139423
|
+
loadAvg: [load[0] ?? 0, load[1] ?? 0, load[2] ?? 0],
|
|
139424
|
+
cpuCount: os3.cpus().length,
|
|
139425
|
+
systemTotalMem: os3.totalmem(),
|
|
139426
|
+
systemFreeMem: os3.freemem(),
|
|
139427
|
+
pid: process.pid,
|
|
139428
|
+
nodeVersion: process.version,
|
|
139429
|
+
platform: `${process.platform}/${process.arch}`
|
|
139430
|
+
});
|
|
139431
|
+
}
|
|
137917
139432
|
setSettings(settings) {
|
|
137918
139433
|
this.settings = settings;
|
|
137919
139434
|
this.notify();
|
|
@@ -138041,6 +139556,12 @@ var init_controller = __esm({
|
|
|
138041
139556
|
this.uptimeTimer = setInterval(() => {
|
|
138042
139557
|
if (this.isRunning) this.notify();
|
|
138043
139558
|
}, 5e3);
|
|
139559
|
+
this.lastCpuUsage = process.cpuUsage();
|
|
139560
|
+
this.lastCpuSampleAt = Date.now();
|
|
139561
|
+
this.sampleSystemStats();
|
|
139562
|
+
this.systemStatsTimer = setInterval(() => {
|
|
139563
|
+
if (this.isRunning) this.sampleSystemStats();
|
|
139564
|
+
}, 2e3);
|
|
138044
139565
|
}
|
|
138045
139566
|
async stop() {
|
|
138046
139567
|
if (!this.isRunning) return;
|
|
@@ -138049,6 +139570,10 @@ var init_controller = __esm({
|
|
|
138049
139570
|
clearInterval(this.uptimeTimer);
|
|
138050
139571
|
this.uptimeTimer = null;
|
|
138051
139572
|
}
|
|
139573
|
+
if (this.systemStatsTimer) {
|
|
139574
|
+
clearInterval(this.systemStatsTimer);
|
|
139575
|
+
this.systemStatsTimer = null;
|
|
139576
|
+
}
|
|
138052
139577
|
if (this.inkInstance) {
|
|
138053
139578
|
this.inkInstance.unmount();
|
|
138054
139579
|
this.inkInstance = null;
|
|
@@ -138217,7 +139742,10 @@ __export(dashboard_exports, {
|
|
|
138217
139742
|
promptForPort: () => promptForPort,
|
|
138218
139743
|
runDashboard: () => runDashboard
|
|
138219
139744
|
});
|
|
138220
|
-
import { join as join48 } from "node:path";
|
|
139745
|
+
import { join as join48, resolve as pathResolve } from "node:path";
|
|
139746
|
+
import { execFile as execFileCb } from "node:child_process";
|
|
139747
|
+
import { promisify as promisify12 } from "node:util";
|
|
139748
|
+
import { stat as stat10, readdir as readdir11, readFile as fsReadFile3 } from "node:fs/promises";
|
|
138221
139749
|
import { AuthStorage as AuthStorage2, DefaultPackageManager as DefaultPackageManager2, ModelRegistry as ModelRegistry3, discoverAndLoadExtensions as discoverAndLoadExtensions2, createExtensionRuntime as createExtensionRuntime2 } from "@mariozechner/pi-coding-agent";
|
|
138222
139750
|
function formatRuntimeContext(context) {
|
|
138223
139751
|
if (context === void 0) {
|
|
@@ -138246,7 +139774,7 @@ function createDashboardRuntimeLogger(logSink, scope) {
|
|
|
138246
139774
|
}
|
|
138247
139775
|
};
|
|
138248
139776
|
}
|
|
138249
|
-
function
|
|
139777
|
+
function formatBytes3(bytes) {
|
|
138250
139778
|
if (bytes < 1024) return `${bytes}B`;
|
|
138251
139779
|
if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)}KB`;
|
|
138252
139780
|
if (bytes < 1024 * 1024 * 1024) return `${Math.round(bytes / (1024 * 1024))}MB`;
|
|
@@ -138289,7 +139817,7 @@ function logDiagnostics(logger2, prefix, startTime, dbHealthCheck) {
|
|
|
138289
139817
|
} catch {
|
|
138290
139818
|
}
|
|
138291
139819
|
}
|
|
138292
|
-
const logLine = `[${prefix}] diagnostics: uptime=${formatUptime2(uptime)} rss=${
|
|
139820
|
+
const logLine = `[${prefix}] diagnostics: uptime=${formatUptime2(uptime)} rss=${formatBytes3(mem.rss)} heap=${formatBytes3(mem.heapUsed)}/${formatBytes3(mem.heapTotal)} external=${formatBytes3(mem.external)} arrayBuffers=${formatBytes3(mem.arrayBuffers)} handles=${handleCount} requests=${requestCount} db=${dbHealth}${listenerInfo}`;
|
|
138293
139821
|
logger2.info(logLine);
|
|
138294
139822
|
}
|
|
138295
139823
|
function ensureProcessDiagnostics(logger2) {
|
|
@@ -138338,6 +139866,229 @@ function setDiagnosticDbHealthCheck(check) {
|
|
|
138338
139866
|
function setDiagnosticStoreListenerCheck(check) {
|
|
138339
139867
|
diagnosticStoreListenerCheck = check;
|
|
138340
139868
|
}
|
|
139869
|
+
async function gitExec(cwd, args) {
|
|
139870
|
+
const { stdout } = await execFileAsync3("git", args, { cwd, maxBuffer: 4 * 1024 * 1024 });
|
|
139871
|
+
return stdout;
|
|
139872
|
+
}
|
|
139873
|
+
async function buildGitStatus(projectPath) {
|
|
139874
|
+
const [sbOut, remoteOut] = await Promise.allSettled([
|
|
139875
|
+
gitExec(projectPath, ["status", "-sb", "--porcelain=v1"]),
|
|
139876
|
+
gitExec(projectPath, ["remote", "get-url", "origin"])
|
|
139877
|
+
]);
|
|
139878
|
+
const sbRaw = sbOut.status === "fulfilled" ? sbOut.value : "";
|
|
139879
|
+
const remoteUrl = remoteOut.status === "fulfilled" ? remoteOut.value.trim() : "";
|
|
139880
|
+
const lines = sbRaw.split("\n");
|
|
139881
|
+
const header = lines[0] ?? "";
|
|
139882
|
+
let branch = "HEAD";
|
|
139883
|
+
let detached = false;
|
|
139884
|
+
let ahead = 0;
|
|
139885
|
+
let behind = 0;
|
|
139886
|
+
const noCommitMatch = header.match(/^## No commits yet on (.+)$/);
|
|
139887
|
+
if (noCommitMatch) {
|
|
139888
|
+
branch = noCommitMatch[1] ?? "HEAD";
|
|
139889
|
+
} else {
|
|
139890
|
+
const branchMatch = header.match(/^## ([^.]+?)(?:\.\.\.(\S+?)(?:\s+\[ahead (\d+)(?:, behind (\d+))?\]|\s+\[behind (\d+)\])?)?$/);
|
|
139891
|
+
if (branchMatch) {
|
|
139892
|
+
branch = branchMatch[1] ?? "HEAD";
|
|
139893
|
+
ahead = parseInt(branchMatch[3] ?? "0", 10);
|
|
139894
|
+
behind = parseInt(branchMatch[4] ?? branchMatch[5] ?? "0", 10);
|
|
139895
|
+
} else if (header.startsWith("## HEAD (no branch)")) {
|
|
139896
|
+
detached = true;
|
|
139897
|
+
branch = "HEAD";
|
|
139898
|
+
}
|
|
139899
|
+
}
|
|
139900
|
+
const staged = [];
|
|
139901
|
+
const unstaged = [];
|
|
139902
|
+
const untracked = [];
|
|
139903
|
+
for (const line of lines.slice(1)) {
|
|
139904
|
+
if (line.length < 3) continue;
|
|
139905
|
+
const x = line[0] ?? " ";
|
|
139906
|
+
const y = line[1] ?? " ";
|
|
139907
|
+
const path4 = line.slice(3);
|
|
139908
|
+
if (x === "?" && y === "?") {
|
|
139909
|
+
untracked.push({ path: path4 });
|
|
139910
|
+
} else {
|
|
139911
|
+
if (x !== " " && x !== "?") staged.push({ status: x, path: path4 });
|
|
139912
|
+
if (y !== " " && y !== "?") unstaged.push({ status: y, path: path4 });
|
|
139913
|
+
}
|
|
139914
|
+
}
|
|
139915
|
+
let lastFetchAt = null;
|
|
139916
|
+
try {
|
|
139917
|
+
const fetchHead = await stat10(`${projectPath}/.git/FETCH_HEAD`);
|
|
139918
|
+
lastFetchAt = fetchHead.mtimeMs;
|
|
139919
|
+
} catch {
|
|
139920
|
+
}
|
|
139921
|
+
return { branch, detached, ahead, behind, staged, unstaged, untracked, remoteUrl, lastFetchAt };
|
|
139922
|
+
}
|
|
139923
|
+
async function buildGitCommits(projectPath, limit = 15) {
|
|
139924
|
+
const sep7 = "";
|
|
139925
|
+
const recSep = "";
|
|
139926
|
+
const fmt = [`%H`, `%h`, `%s`, `%an`, `%ar`, `%aI`].join(sep7);
|
|
139927
|
+
let out = "";
|
|
139928
|
+
try {
|
|
139929
|
+
out = await gitExec(projectPath, ["log", `--max-count=${limit}`, `--format=${fmt}${recSep}`]);
|
|
139930
|
+
} catch {
|
|
139931
|
+
return [];
|
|
139932
|
+
}
|
|
139933
|
+
return out.split(recSep).flatMap((rec) => {
|
|
139934
|
+
const parts = rec.trim().split(sep7);
|
|
139935
|
+
if (parts.length < 6 || !parts[0]) return [];
|
|
139936
|
+
return [{
|
|
139937
|
+
sha: parts[0] ?? "",
|
|
139938
|
+
shortSha: parts[1] ?? "",
|
|
139939
|
+
subject: parts[2] ?? "",
|
|
139940
|
+
authorName: parts[3] ?? "",
|
|
139941
|
+
relativeTime: parts[4] ?? "",
|
|
139942
|
+
isoTime: parts[5] ?? ""
|
|
139943
|
+
}];
|
|
139944
|
+
});
|
|
139945
|
+
}
|
|
139946
|
+
async function buildGitCommitDetail(projectPath, sha) {
|
|
139947
|
+
const sep7 = "";
|
|
139948
|
+
const fmt = [`%H`, `%h`, `%s`, `%an`, `%ar`, `%aI`, `%b`].join(sep7);
|
|
139949
|
+
const [showOut, statOut] = await Promise.allSettled([
|
|
139950
|
+
gitExec(projectPath, ["show", `--format=${fmt}`, "--no-patch", sha]),
|
|
139951
|
+
gitExec(projectPath, ["show", "--stat", "--format=", sha])
|
|
139952
|
+
]);
|
|
139953
|
+
const raw = showOut.status === "fulfilled" ? showOut.value.trim() : "";
|
|
139954
|
+
const parts = raw.split(sep7);
|
|
139955
|
+
return {
|
|
139956
|
+
sha: parts[0] ?? sha,
|
|
139957
|
+
shortSha: parts[1] ?? sha.slice(0, 7),
|
|
139958
|
+
subject: parts[2] ?? "",
|
|
139959
|
+
authorName: parts[3] ?? "",
|
|
139960
|
+
relativeTime: parts[4] ?? "",
|
|
139961
|
+
isoTime: parts[5] ?? "",
|
|
139962
|
+
body: (parts[6] ?? "").trim(),
|
|
139963
|
+
stat: statOut.status === "fulfilled" ? statOut.value.trim() : ""
|
|
139964
|
+
};
|
|
139965
|
+
}
|
|
139966
|
+
async function buildGitBranches(projectPath) {
|
|
139967
|
+
let out = "";
|
|
139968
|
+
try {
|
|
139969
|
+
out = await gitExec(projectPath, [
|
|
139970
|
+
"for-each-ref",
|
|
139971
|
+
"--sort=-committerdate",
|
|
139972
|
+
"refs/heads",
|
|
139973
|
+
"--format=%(refname:short)|%(objectname:short)|%(committerdate:relative)|%(upstream:track)|%(HEAD)"
|
|
139974
|
+
]);
|
|
139975
|
+
} catch {
|
|
139976
|
+
return [];
|
|
139977
|
+
}
|
|
139978
|
+
return out.trim().split("\n").flatMap((line) => {
|
|
139979
|
+
if (!line) return [];
|
|
139980
|
+
const parts = line.split("|");
|
|
139981
|
+
return [{
|
|
139982
|
+
name: parts[0] ?? "",
|
|
139983
|
+
shortSha: parts[1] ?? "",
|
|
139984
|
+
relativeTime: parts[2] ?? "",
|
|
139985
|
+
upstreamTrack: parts[3] ?? "",
|
|
139986
|
+
isCurrent: (parts[4] ?? "") === "*"
|
|
139987
|
+
}];
|
|
139988
|
+
});
|
|
139989
|
+
}
|
|
139990
|
+
async function buildGitWorktrees(projectPath) {
|
|
139991
|
+
let out = "";
|
|
139992
|
+
try {
|
|
139993
|
+
out = await gitExec(projectPath, ["worktree", "list", "--porcelain"]);
|
|
139994
|
+
} catch {
|
|
139995
|
+
return [];
|
|
139996
|
+
}
|
|
139997
|
+
const worktrees = [];
|
|
139998
|
+
let current = {};
|
|
139999
|
+
let isFirst = true;
|
|
140000
|
+
for (const line of out.split("\n")) {
|
|
140001
|
+
if (line.startsWith("worktree ")) {
|
|
140002
|
+
if (current.rawPath) {
|
|
140003
|
+
worktrees.push({
|
|
140004
|
+
path: current.rawPath,
|
|
140005
|
+
branch: current.branch ?? "HEAD",
|
|
140006
|
+
sha: current.sha ?? "",
|
|
140007
|
+
isCurrent: current.isCurrent ?? false,
|
|
140008
|
+
isLocked: current.isLocked ?? false
|
|
140009
|
+
});
|
|
140010
|
+
}
|
|
140011
|
+
current = { rawPath: line.slice(9), isCurrent: isFirst };
|
|
140012
|
+
isFirst = false;
|
|
140013
|
+
} else if (line.startsWith("HEAD ")) {
|
|
140014
|
+
current.sha = line.slice(5);
|
|
140015
|
+
} else if (line.startsWith("branch ")) {
|
|
140016
|
+
current.branch = line.slice(7).replace("refs/heads/", "");
|
|
140017
|
+
} else if (line === "locked") {
|
|
140018
|
+
current.isLocked = true;
|
|
140019
|
+
} else if (line.startsWith("locked ")) {
|
|
140020
|
+
current.isLocked = true;
|
|
140021
|
+
}
|
|
140022
|
+
}
|
|
140023
|
+
if (current.rawPath) {
|
|
140024
|
+
worktrees.push({
|
|
140025
|
+
path: current.rawPath,
|
|
140026
|
+
branch: current.branch ?? "HEAD",
|
|
140027
|
+
sha: current.sha ?? "",
|
|
140028
|
+
isCurrent: current.isCurrent ?? false,
|
|
140029
|
+
isLocked: current.isLocked ?? false
|
|
140030
|
+
});
|
|
140031
|
+
}
|
|
140032
|
+
return worktrees;
|
|
140033
|
+
}
|
|
140034
|
+
function guardRelativePath(projectPath, relativePath) {
|
|
140035
|
+
const resolved = pathResolve(projectPath, relativePath);
|
|
140036
|
+
const base = projectPath.endsWith("/") ? projectPath : projectPath + "/";
|
|
140037
|
+
if (resolved !== projectPath && !resolved.startsWith(base)) {
|
|
140038
|
+
throw new Error(`Path traversal denied: ${relativePath}`);
|
|
140039
|
+
}
|
|
140040
|
+
return resolved;
|
|
140041
|
+
}
|
|
140042
|
+
async function buildFileListDirectory(projectPath, relativePath) {
|
|
140043
|
+
const absDir = guardRelativePath(projectPath, relativePath);
|
|
140044
|
+
const dirents = await readdir11(absDir, { withFileTypes: true });
|
|
140045
|
+
const entries = [];
|
|
140046
|
+
for (const d of dirents) {
|
|
140047
|
+
if (FILES_DENYLIST2.has(d.name)) continue;
|
|
140048
|
+
const entryRelPath = relativePath ? `${relativePath}/${d.name}` : d.name;
|
|
140049
|
+
let size = 0;
|
|
140050
|
+
let modifiedAt = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
140051
|
+
try {
|
|
140052
|
+
const s = await stat10(join48(absDir, d.name));
|
|
140053
|
+
size = d.isDirectory() ? 0 : s.size;
|
|
140054
|
+
modifiedAt = s.mtime.toISOString();
|
|
140055
|
+
} catch {
|
|
140056
|
+
}
|
|
140057
|
+
entries.push({
|
|
140058
|
+
name: d.name,
|
|
140059
|
+
path: entryRelPath,
|
|
140060
|
+
isDirectory: d.isDirectory(),
|
|
140061
|
+
size,
|
|
140062
|
+
modifiedAt
|
|
140063
|
+
});
|
|
140064
|
+
}
|
|
140065
|
+
entries.sort((a, b) => {
|
|
140066
|
+
if (a.isDirectory !== b.isDirectory) return a.isDirectory ? -1 : 1;
|
|
140067
|
+
return a.name.localeCompare(b.name);
|
|
140068
|
+
});
|
|
140069
|
+
return entries;
|
|
140070
|
+
}
|
|
140071
|
+
async function buildFileReadFile(projectPath, relativePath) {
|
|
140072
|
+
const absFile = guardRelativePath(projectPath, relativePath);
|
|
140073
|
+
const s = await stat10(absFile);
|
|
140074
|
+
const modifiedAt = s.mtime.toISOString();
|
|
140075
|
+
const size = s.size;
|
|
140076
|
+
if (size > FILE_SIZE_LIMIT) {
|
|
140077
|
+
return { content: null, isBinary: false, tooLarge: true, size, modifiedAt, lineCount: 0 };
|
|
140078
|
+
}
|
|
140079
|
+
const buf = await fsReadFile3(absFile);
|
|
140080
|
+
const checkLen = Math.min(buf.length, BINARY_CHECK_BYTES);
|
|
140081
|
+
for (let i = 0; i < checkLen; i++) {
|
|
140082
|
+
if (buf[i] === 0) {
|
|
140083
|
+
return { content: null, isBinary: true, tooLarge: false, size, modifiedAt, lineCount: 0 };
|
|
140084
|
+
}
|
|
140085
|
+
}
|
|
140086
|
+
const text = buf.toString("utf8");
|
|
140087
|
+
const lines = text.split("\n");
|
|
140088
|
+
const lineCount = lines.length;
|
|
140089
|
+
const content = lineCount > MAX_PREVIEW_LINES ? lines.slice(0, MAX_PREVIEW_LINES).join("\n") : text;
|
|
140090
|
+
return { content, isBinary: false, tooLarge: false, size, modifiedAt, lineCount };
|
|
140091
|
+
}
|
|
138341
140092
|
async function resolveRuntimeProjectPath() {
|
|
138342
140093
|
try {
|
|
138343
140094
|
return (await resolveProject(void 0)).projectPath;
|
|
@@ -138465,13 +140216,30 @@ async function runDashboard(port, opts = {}) {
|
|
|
138465
140216
|
}));
|
|
138466
140217
|
let tuiRefreshPending = false;
|
|
138467
140218
|
let tuiRefreshDebounceTimer = null;
|
|
140219
|
+
const projectStores = /* @__PURE__ */ new Map();
|
|
140220
|
+
async function getProjectStore(projectPath) {
|
|
140221
|
+
const cached = projectStores.get(projectPath);
|
|
140222
|
+
if (cached) return cached;
|
|
140223
|
+
let projectStore;
|
|
140224
|
+
if (projectPath === cwd) {
|
|
140225
|
+
if (!store) throw new Error("cwd TaskStore not yet initialized");
|
|
140226
|
+
projectStore = store;
|
|
140227
|
+
} else {
|
|
140228
|
+
projectStore = new TaskStore(projectPath);
|
|
140229
|
+
await projectStore.init();
|
|
140230
|
+
}
|
|
140231
|
+
projectStores.set(projectPath, projectStore);
|
|
140232
|
+
return projectStore;
|
|
140233
|
+
}
|
|
138468
140234
|
async function refreshTUIStats() {
|
|
138469
140235
|
if (!tui || !isTTY) return;
|
|
138470
140236
|
if (!store || !agentStore) return;
|
|
138471
140237
|
if (tuiRefreshPending) return;
|
|
138472
140238
|
tuiRefreshPending = true;
|
|
138473
140239
|
try {
|
|
138474
|
-
const
|
|
140240
|
+
const scopedPath = tui.boardScopedProjectPath;
|
|
140241
|
+
const taskStore = scopedPath ? await getProjectStore(scopedPath) : store;
|
|
140242
|
+
const tasks = await taskStore.listTasks({ slim: true, includeArchived: false });
|
|
138475
140243
|
const counts = /* @__PURE__ */ new Map();
|
|
138476
140244
|
for (const task of tasks) {
|
|
138477
140245
|
counts.set(task.column, (counts.get(task.column) ?? 0) + 1);
|
|
@@ -138522,6 +140290,11 @@ async function runDashboard(port, opts = {}) {
|
|
|
138522
140290
|
void refreshTUIStats();
|
|
138523
140291
|
}, 500);
|
|
138524
140292
|
}
|
|
140293
|
+
if (tui) {
|
|
140294
|
+
tui.onBoardScopeChange(() => {
|
|
140295
|
+
void refreshTUIStats();
|
|
140296
|
+
});
|
|
140297
|
+
}
|
|
138525
140298
|
const handlers = [];
|
|
138526
140299
|
const disposeCallbacks = [];
|
|
138527
140300
|
let disposed = false;
|
|
@@ -139181,19 +140954,13 @@ async function runDashboard(port, opts = {}) {
|
|
|
139181
140954
|
});
|
|
139182
140955
|
if (centralCoreForMesh) {
|
|
139183
140956
|
const centralCore = centralCoreForMesh;
|
|
139184
|
-
const projectStores = /* @__PURE__ */ new Map();
|
|
139185
140957
|
tui.setInteractiveData({
|
|
139186
140958
|
listProjects: async () => {
|
|
139187
140959
|
const projects = await centralCore.listProjects();
|
|
139188
140960
|
return projects.map((p) => ({ id: p.id, name: p.name, path: p.path }));
|
|
139189
140961
|
},
|
|
139190
140962
|
listTasks: async (projectPath) => {
|
|
139191
|
-
|
|
139192
|
-
if (!projectStore) {
|
|
139193
|
-
projectStore = projectPath === cwd ? store : new TaskStore(projectPath);
|
|
139194
|
-
if (projectPath !== cwd) await projectStore.init();
|
|
139195
|
-
projectStores.set(projectPath, projectStore);
|
|
139196
|
-
}
|
|
140963
|
+
const projectStore = await getProjectStore(projectPath);
|
|
139197
140964
|
const tasks2 = await projectStore.listTasks({ slim: true, includeArchived: false });
|
|
139198
140965
|
return tasks2.map((t) => ({
|
|
139199
140966
|
id: t.id,
|
|
@@ -139204,12 +140971,7 @@ async function runDashboard(port, opts = {}) {
|
|
|
139204
140971
|
}));
|
|
139205
140972
|
},
|
|
139206
140973
|
createTask: async (projectPath, input) => {
|
|
139207
|
-
|
|
139208
|
-
if (!projectStore) {
|
|
139209
|
-
projectStore = projectPath === cwd ? store : new TaskStore(projectPath);
|
|
139210
|
-
if (projectPath !== cwd) await projectStore.init();
|
|
139211
|
-
projectStores.set(projectPath, projectStore);
|
|
139212
|
-
}
|
|
140974
|
+
const projectStore = await getProjectStore(projectPath);
|
|
139213
140975
|
const created = await projectStore.createTask({
|
|
139214
140976
|
title: input.title,
|
|
139215
140977
|
description: input.description ?? input.title
|
|
@@ -139290,6 +141052,104 @@ async function runDashboard(port, opts = {}) {
|
|
|
139290
141052
|
provider: m.provider ?? "unknown",
|
|
139291
141053
|
contextWindow: m.contextWindow ?? 0
|
|
139292
141054
|
}));
|
|
141055
|
+
},
|
|
141056
|
+
git: {
|
|
141057
|
+
getStatus: (projectPath) => buildGitStatus(projectPath),
|
|
141058
|
+
listCommits: (projectPath, limit) => buildGitCommits(projectPath, limit),
|
|
141059
|
+
showCommit: (projectPath, sha) => buildGitCommitDetail(projectPath, sha),
|
|
141060
|
+
listBranches: (projectPath) => buildGitBranches(projectPath),
|
|
141061
|
+
listWorktrees: (projectPath) => buildGitWorktrees(projectPath),
|
|
141062
|
+
push: async (projectPath) => {
|
|
141063
|
+
try {
|
|
141064
|
+
const { stdout, stderr } = await execFileAsync3("git", ["push"], { cwd: projectPath, maxBuffer: 4 * 1024 * 1024 });
|
|
141065
|
+
return { success: true, output: (stdout + stderr).trim() };
|
|
141066
|
+
} catch (err) {
|
|
141067
|
+
const msg = err instanceof Error ? err.stderr ?? err.message : String(err);
|
|
141068
|
+
return { success: false, output: msg.trim() };
|
|
141069
|
+
}
|
|
141070
|
+
},
|
|
141071
|
+
fetch: async (projectPath) => {
|
|
141072
|
+
try {
|
|
141073
|
+
const { stdout, stderr } = await execFileAsync3("git", ["fetch"], { cwd: projectPath, maxBuffer: 4 * 1024 * 1024 });
|
|
141074
|
+
return { success: true, output: (stdout + stderr).trim() };
|
|
141075
|
+
} catch (err) {
|
|
141076
|
+
const msg = err instanceof Error ? err.stderr ?? err.message : String(err);
|
|
141077
|
+
return { success: false, output: msg.trim() };
|
|
141078
|
+
}
|
|
141079
|
+
}
|
|
141080
|
+
},
|
|
141081
|
+
files: {
|
|
141082
|
+
listDirectory: (projectPath, relativePath) => buildFileListDirectory(projectPath, relativePath),
|
|
141083
|
+
readFile: (projectPath, relativePath) => buildFileReadFile(projectPath, relativePath)
|
|
141084
|
+
},
|
|
141085
|
+
tasks: {
|
|
141086
|
+
getTaskDetail: async (projectPath, taskId) => {
|
|
141087
|
+
try {
|
|
141088
|
+
const projectStore = await getProjectStore(projectPath);
|
|
141089
|
+
const t = await projectStore.getTask(taskId);
|
|
141090
|
+
const steps = t.steps.map((s, idx) => ({
|
|
141091
|
+
index: idx,
|
|
141092
|
+
name: s.name,
|
|
141093
|
+
status: s.status === "in-progress" ? "running" : s.status
|
|
141094
|
+
}));
|
|
141095
|
+
const recentLogs = t.log.slice(-200).map((entry) => ({
|
|
141096
|
+
timestamp: entry.timestamp,
|
|
141097
|
+
level: "info",
|
|
141098
|
+
text: entry.outcome ? `${entry.action} \u2192 ${entry.outcome}` : entry.action,
|
|
141099
|
+
source: entry.runContext?.agentId ? "agent" : "executor"
|
|
141100
|
+
}));
|
|
141101
|
+
return {
|
|
141102
|
+
id: t.id,
|
|
141103
|
+
title: t.title,
|
|
141104
|
+
description: t.description ?? "",
|
|
141105
|
+
column: t.column,
|
|
141106
|
+
agentState: t.agentState,
|
|
141107
|
+
branch: t.branch,
|
|
141108
|
+
worktree: t.worktree,
|
|
141109
|
+
currentStepIndex: t.currentStep,
|
|
141110
|
+
steps,
|
|
141111
|
+
recentLogs
|
|
141112
|
+
};
|
|
141113
|
+
} catch {
|
|
141114
|
+
return null;
|
|
141115
|
+
}
|
|
141116
|
+
},
|
|
141117
|
+
subscribeTaskEvents: (projectPath, taskId, handler) => {
|
|
141118
|
+
let projectStorePromise = null;
|
|
141119
|
+
let lastLogLength = 0;
|
|
141120
|
+
const listener = (task) => {
|
|
141121
|
+
if (task.id !== taskId) return;
|
|
141122
|
+
task.steps.forEach((s, idx) => {
|
|
141123
|
+
const status = s.status === "in-progress" ? "running" : s.status;
|
|
141124
|
+
handler({
|
|
141125
|
+
kind: "step:updated",
|
|
141126
|
+
step: { index: idx, name: s.name, status }
|
|
141127
|
+
});
|
|
141128
|
+
});
|
|
141129
|
+
const newEntries = task.log.slice(lastLogLength);
|
|
141130
|
+
lastLogLength = task.log.length;
|
|
141131
|
+
for (const entry of newEntries) {
|
|
141132
|
+
handler({
|
|
141133
|
+
kind: "log:appended",
|
|
141134
|
+
entry: {
|
|
141135
|
+
timestamp: entry.timestamp,
|
|
141136
|
+
level: "info",
|
|
141137
|
+
text: entry.outcome ? `${entry.action} \u2192 ${entry.outcome}` : entry.action,
|
|
141138
|
+
source: entry.runContext?.agentId ? "agent" : "executor"
|
|
141139
|
+
}
|
|
141140
|
+
});
|
|
141141
|
+
}
|
|
141142
|
+
};
|
|
141143
|
+
projectStorePromise = getProjectStore(projectPath).then((ps) => {
|
|
141144
|
+
ps.on("task:updated", listener);
|
|
141145
|
+
return ps;
|
|
141146
|
+
}).catch(() => null);
|
|
141147
|
+
return () => {
|
|
141148
|
+
void projectStorePromise?.then((ps) => {
|
|
141149
|
+
if (ps) ps.off("task:updated", listener);
|
|
141150
|
+
});
|
|
141151
|
+
};
|
|
141152
|
+
}
|
|
139293
141153
|
}
|
|
139294
141154
|
});
|
|
139295
141155
|
}
|
|
@@ -139333,7 +141193,7 @@ async function runDashboard(port, opts = {}) {
|
|
|
139333
141193
|
});
|
|
139334
141194
|
return { dispose };
|
|
139335
141195
|
}
|
|
139336
|
-
var processDiagnosticsRegistered, diagnosticIntervalHandle, DIAGNOSTIC_INTERVAL_MS, diagnosticStartTime, diagnosticDbHealthCheck, diagnosticStoreListenerCheck, STREAM_LOG_FLUSH_IDLE_MS, StreamedLogBuffer;
|
|
141196
|
+
var processDiagnosticsRegistered, diagnosticIntervalHandle, DIAGNOSTIC_INTERVAL_MS, diagnosticStartTime, diagnosticDbHealthCheck, diagnosticStoreListenerCheck, STREAM_LOG_FLUSH_IDLE_MS, StreamedLogBuffer, execFileAsync3, FILES_DENYLIST2, FILE_SIZE_LIMIT, BINARY_CHECK_BYTES, MAX_PREVIEW_LINES;
|
|
139337
141197
|
var init_dashboard = __esm({
|
|
139338
141198
|
"src/commands/dashboard.ts"() {
|
|
139339
141199
|
"use strict";
|
|
@@ -139409,6 +141269,11 @@ var init_dashboard = __esm({
|
|
|
139409
141269
|
}
|
|
139410
141270
|
}
|
|
139411
141271
|
};
|
|
141272
|
+
execFileAsync3 = promisify12(execFileCb);
|
|
141273
|
+
FILES_DENYLIST2 = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".next", "target", "build"]);
|
|
141274
|
+
FILE_SIZE_LIMIT = 1024 * 1024;
|
|
141275
|
+
BINARY_CHECK_BYTES = 8 * 1024;
|
|
141276
|
+
MAX_PREVIEW_LINES = 2e3;
|
|
139412
141277
|
}
|
|
139413
141278
|
});
|
|
139414
141279
|
|
|
@@ -139416,7 +141281,7 @@ var init_dashboard = __esm({
|
|
|
139416
141281
|
var node_exports = {};
|
|
139417
141282
|
__export(node_exports, {
|
|
139418
141283
|
findNodeByNameOrId: () => findNodeByNameOrId,
|
|
139419
|
-
formatBytes: () =>
|
|
141284
|
+
formatBytes: () => formatBytes4,
|
|
139420
141285
|
formatLastActivity: () => formatLastActivity,
|
|
139421
141286
|
formatStatusBar: () => formatStatusBar,
|
|
139422
141287
|
formatUptime: () => formatUptime3,
|
|
@@ -139438,7 +141303,7 @@ function maskApiKey(key) {
|
|
|
139438
141303
|
if (key.length < 4) return "****";
|
|
139439
141304
|
return `****${key.slice(-4)}`;
|
|
139440
141305
|
}
|
|
139441
|
-
function
|
|
141306
|
+
function formatBytes4(bytes) {
|
|
139442
141307
|
if (bytes === 0) return "0 B";
|
|
139443
141308
|
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
139444
141309
|
const k = 1024;
|
|
@@ -139695,8 +141560,8 @@ async function runNodeShow(name, options = {}) {
|
|
|
139695
141560
|
console.log();
|
|
139696
141561
|
console.log(" System Metrics:");
|
|
139697
141562
|
console.log(` CPU Usage: ${formatStatusBar(metrics.cpuUsage)}`);
|
|
139698
|
-
console.log(` Memory: ${
|
|
139699
|
-
console.log(` Storage: ${
|
|
141563
|
+
console.log(` Memory: ${formatBytes4(metrics.memoryUsed)} / ${formatBytes4(metrics.memoryTotal)}`);
|
|
141564
|
+
console.log(` Storage: ${formatBytes4(metrics.storageUsed)} / ${formatBytes4(metrics.storageTotal)}`);
|
|
139700
141565
|
console.log(` Uptime: ${formatUptime3(metrics.uptime)}`);
|
|
139701
141566
|
console.log(` Reported: ${formatLastActivity(metrics.reportedAt)}`);
|
|
139702
141567
|
} else {
|
|
@@ -139847,7 +141712,7 @@ async function resolveRuntimeProjectPath2() {
|
|
|
139847
141712
|
return process.cwd();
|
|
139848
141713
|
}
|
|
139849
141714
|
}
|
|
139850
|
-
function
|
|
141715
|
+
function formatBytes5(bytes) {
|
|
139851
141716
|
if (bytes < 1024) return `${bytes}B`;
|
|
139852
141717
|
if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)}KB`;
|
|
139853
141718
|
if (bytes < 1024 * 1024 * 1024) return `${Math.round(bytes / (1024 * 1024))}MB`;
|
|
@@ -139888,7 +141753,7 @@ function logDiagnostics2(prefix, dbHealthCheck) {
|
|
|
139888
141753
|
} catch {
|
|
139889
141754
|
}
|
|
139890
141755
|
}
|
|
139891
|
-
const logLine = `[${prefix}] diagnostics: uptime=${formatUptime4(uptime)} rss=${
|
|
141756
|
+
const logLine = `[${prefix}] diagnostics: uptime=${formatUptime4(uptime)} rss=${formatBytes5(mem.rss)} heap=${formatBytes5(mem.heapUsed)}/${formatBytes5(mem.heapTotal)} external=${formatBytes5(mem.external)} arrayBuffers=${formatBytes5(mem.arrayBuffers)} handles=${handleCount} requests=${requestCount} db=${dbHealth}${listenerInfo}`;
|
|
139892
141757
|
console.log(logLine);
|
|
139893
141758
|
}
|
|
139894
141759
|
function stopDiagnosticInterval2() {
|
|
@@ -140415,7 +142280,7 @@ async function resolveRuntimeProjectPath3() {
|
|
|
140415
142280
|
return process.cwd();
|
|
140416
142281
|
}
|
|
140417
142282
|
}
|
|
140418
|
-
function
|
|
142283
|
+
function formatBytes6(bytes) {
|
|
140419
142284
|
if (bytes < 1024) return `${bytes}B`;
|
|
140420
142285
|
if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)}KB`;
|
|
140421
142286
|
if (bytes < 1024 * 1024 * 1024) return `${Math.round(bytes / (1024 * 1024))}MB`;
|
|
@@ -140449,7 +142314,7 @@ function logDiagnostics3(dbHealthCheck) {
|
|
|
140449
142314
|
dbHealth = "error";
|
|
140450
142315
|
}
|
|
140451
142316
|
}
|
|
140452
|
-
const logLine = `[daemon] diagnostics: uptime=${formatUptime5(uptime)} rss=${
|
|
142317
|
+
const logLine = `[daemon] diagnostics: uptime=${formatUptime5(uptime)} rss=${formatBytes6(mem.rss)} heap=${formatBytes6(mem.heapUsed)}/${formatBytes6(mem.heapTotal)} external=${formatBytes6(mem.external)} arrayBuffers=${formatBytes6(mem.arrayBuffers)} handles=${handleCount} requests=${requestCount} db=${dbHealth}`;
|
|
140453
142318
|
console.log(logLine);
|
|
140454
142319
|
}
|
|
140455
142320
|
function maskToken(token) {
|
|
@@ -142610,7 +144475,7 @@ __export(git_exports, {
|
|
|
142610
144475
|
runGitStatus: () => runGitStatus
|
|
142611
144476
|
});
|
|
142612
144477
|
import { exec as exec10 } from "node:child_process";
|
|
142613
|
-
import { promisify as
|
|
144478
|
+
import { promisify as promisify13 } from "node:util";
|
|
142614
144479
|
import { createInterface as createInterface4 } from "node:readline/promises";
|
|
142615
144480
|
async function resolveGitCwd(projectName) {
|
|
142616
144481
|
if (projectName) {
|
|
@@ -142884,7 +144749,7 @@ var init_git = __esm({
|
|
|
142884
144749
|
"src/commands/git.ts"() {
|
|
142885
144750
|
"use strict";
|
|
142886
144751
|
init_project_context();
|
|
142887
|
-
execAsync10 =
|
|
144752
|
+
execAsync10 = promisify13(exec10);
|
|
142888
144753
|
}
|
|
142889
144754
|
});
|
|
142890
144755
|
|
|
@@ -142935,12 +144800,12 @@ async function runBackupList(projectName) {
|
|
|
142935
144800
|
console.log(`Found ${backups.length} backup(s):
|
|
142936
144801
|
`);
|
|
142937
144802
|
const totalSize = backups.reduce((sum, b) => sum + b.size, 0);
|
|
142938
|
-
const formattedTotal =
|
|
144803
|
+
const formattedTotal = formatBytes7(totalSize);
|
|
142939
144804
|
console.log("Date Size Filename");
|
|
142940
144805
|
console.log("-".repeat(60));
|
|
142941
144806
|
for (const backup of backups) {
|
|
142942
144807
|
const date = new Date(backup.createdAt).toLocaleString();
|
|
142943
|
-
const size =
|
|
144808
|
+
const size = formatBytes7(backup.size).padEnd(8);
|
|
142944
144809
|
console.log(`${date} ${size} ${backup.filename}`);
|
|
142945
144810
|
}
|
|
142946
144811
|
console.log("-".repeat(60));
|
|
@@ -142969,7 +144834,7 @@ async function runBackupCleanup(projectName) {
|
|
|
142969
144834
|
console.log("No backups to clean up (within retention limit).");
|
|
142970
144835
|
}
|
|
142971
144836
|
}
|
|
142972
|
-
function
|
|
144837
|
+
function formatBytes7(bytes) {
|
|
142973
144838
|
if (bytes === 0) return "0 B";
|
|
142974
144839
|
const k = 1024;
|
|
142975
144840
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
@@ -144102,7 +145967,7 @@ __export(init_exports, {
|
|
|
144102
145967
|
import { existsSync as existsSync42, mkdirSync as mkdirSync9, writeFileSync as writeFileSync3, readFileSync as readFileSync15 } from "node:fs";
|
|
144103
145968
|
import { join as join55, resolve as resolve28, basename as basename14 } from "node:path";
|
|
144104
145969
|
import { exec as exec11 } from "node:child_process";
|
|
144105
|
-
import { promisify as
|
|
145970
|
+
import { promisify as promisify14 } from "node:util";
|
|
144106
145971
|
async function runInit(options = {}) {
|
|
144107
145972
|
const cwd = options.path ? resolve28(options.path) : process.cwd();
|
|
144108
145973
|
const fusionDir = join55(cwd, ".fusion");
|
|
@@ -144278,7 +146143,7 @@ var init_init = __esm({
|
|
|
144278
146143
|
init_src();
|
|
144279
146144
|
init_claude_skills_runner();
|
|
144280
146145
|
init_skill_installation();
|
|
144281
|
-
execAsync11 =
|
|
146146
|
+
execAsync11 = promisify14(exec11);
|
|
144282
146147
|
}
|
|
144283
146148
|
});
|
|
144284
146149
|
|