@saga-ai/dashboard 4.2.0 → 4.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/cli.cjs +137 -104
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -28,8 +28,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
));
|
|
29
29
|
|
|
30
30
|
// src/cli.ts
|
|
31
|
-
var
|
|
32
|
-
var
|
|
31
|
+
var import_node_fs6 = require("node:fs");
|
|
32
|
+
var import_node_path7 = require("node:path");
|
|
33
33
|
var import_node_process6 = __toESM(require("node:process"), 1);
|
|
34
34
|
var import_commander = require("commander");
|
|
35
35
|
|
|
@@ -38,14 +38,14 @@ var import_node_process4 = __toESM(require("node:process"), 1);
|
|
|
38
38
|
|
|
39
39
|
// src/server/index.ts
|
|
40
40
|
var import_node_http = require("node:http");
|
|
41
|
-
var
|
|
41
|
+
var import_node_path5 = require("node:path");
|
|
42
42
|
var import_express3 = __toESM(require("express"), 1);
|
|
43
43
|
|
|
44
44
|
// src/server/routes.ts
|
|
45
45
|
var import_express2 = require("express");
|
|
46
46
|
|
|
47
47
|
// src/server/parser.ts
|
|
48
|
-
var
|
|
48
|
+
var import_node_fs2 = require("node:fs");
|
|
49
49
|
var import_promises = require("node:fs/promises");
|
|
50
50
|
|
|
51
51
|
// ../saga-utils/src/directory.ts
|
|
@@ -74,6 +74,13 @@ function createStoryPaths(projectRoot, storyId) {
|
|
|
74
74
|
journalMd: `${storyDir}/journal.md`
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
|
+
function createWorktreePaths(projectRoot, storyId) {
|
|
78
|
+
const { worktrees } = createSagaPaths(projectRoot);
|
|
79
|
+
return {
|
|
80
|
+
storyId,
|
|
81
|
+
worktreeDir: `${worktrees}/${storyId}`
|
|
82
|
+
};
|
|
83
|
+
}
|
|
77
84
|
|
|
78
85
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
79
86
|
var external_exports = {};
|
|
@@ -4195,6 +4202,79 @@ var StorySchema = external_exports.object({
|
|
|
4195
4202
|
// ../saga-utils/src/storage.ts
|
|
4196
4203
|
var import_node_fs = require("node:fs");
|
|
4197
4204
|
var import_node_path = require("node:path");
|
|
4205
|
+
function buildScannedStory(storyDir, storyJsonPath, worktreePath) {
|
|
4206
|
+
if (!(0, import_node_fs.existsSync)(storyJsonPath)) {
|
|
4207
|
+
return null;
|
|
4208
|
+
}
|
|
4209
|
+
let storyData;
|
|
4210
|
+
try {
|
|
4211
|
+
const raw = (0, import_node_fs.readFileSync)(storyJsonPath, "utf-8");
|
|
4212
|
+
storyData = StorySchema.parse(JSON.parse(raw));
|
|
4213
|
+
} catch {
|
|
4214
|
+
return null;
|
|
4215
|
+
}
|
|
4216
|
+
let tasks = [];
|
|
4217
|
+
try {
|
|
4218
|
+
const files = (0, import_node_fs.readdirSync)(storyDir);
|
|
4219
|
+
tasks = files.filter((f) => f.endsWith(".json") && f !== "story.json").map((f) => {
|
|
4220
|
+
const raw = (0, import_node_fs.readFileSync)((0, import_node_path.join)(storyDir, f), "utf-8");
|
|
4221
|
+
return TaskSchema.parse(JSON.parse(raw));
|
|
4222
|
+
});
|
|
4223
|
+
} catch {
|
|
4224
|
+
}
|
|
4225
|
+
const status = deriveStoryStatus(tasks);
|
|
4226
|
+
const journalMdPath = (0, import_node_path.join)(storyDir, "journal.md");
|
|
4227
|
+
return {
|
|
4228
|
+
...storyData,
|
|
4229
|
+
status,
|
|
4230
|
+
storyPath: storyJsonPath,
|
|
4231
|
+
worktreePath,
|
|
4232
|
+
journalPath: (0, import_node_fs.existsSync)(journalMdPath) ? journalMdPath : void 0,
|
|
4233
|
+
tasks
|
|
4234
|
+
};
|
|
4235
|
+
}
|
|
4236
|
+
function scanMasterStories(projectRoot, storyMap) {
|
|
4237
|
+
const { stories } = createSagaPaths(projectRoot);
|
|
4238
|
+
if (!(0, import_node_fs.existsSync)(stories)) {
|
|
4239
|
+
return;
|
|
4240
|
+
}
|
|
4241
|
+
const entries = (0, import_node_fs.readdirSync)(stories, { withFileTypes: true });
|
|
4242
|
+
for (const entry of entries) {
|
|
4243
|
+
if (!entry.isDirectory()) {
|
|
4244
|
+
continue;
|
|
4245
|
+
}
|
|
4246
|
+
const storyPaths = createStoryPaths(projectRoot, entry.name);
|
|
4247
|
+
const scanned = buildScannedStory(storyPaths.storyDir, storyPaths.storyJson);
|
|
4248
|
+
if (!scanned) {
|
|
4249
|
+
continue;
|
|
4250
|
+
}
|
|
4251
|
+
const wtPaths = createWorktreePaths(projectRoot, entry.name);
|
|
4252
|
+
if ((0, import_node_fs.existsSync)(wtPaths.worktreeDir)) {
|
|
4253
|
+
scanned.worktreePath = wtPaths.worktreeDir;
|
|
4254
|
+
}
|
|
4255
|
+
storyMap.set(scanned.id, scanned);
|
|
4256
|
+
}
|
|
4257
|
+
}
|
|
4258
|
+
function scanWorktreeStories(projectRoot, storyMap) {
|
|
4259
|
+
const { worktrees } = createSagaPaths(projectRoot);
|
|
4260
|
+
if (!(0, import_node_fs.existsSync)(worktrees)) {
|
|
4261
|
+
return;
|
|
4262
|
+
}
|
|
4263
|
+
const entries = (0, import_node_fs.readdirSync)(worktrees, { withFileTypes: true });
|
|
4264
|
+
for (const wtEntry of entries) {
|
|
4265
|
+
if (!wtEntry.isDirectory()) {
|
|
4266
|
+
continue;
|
|
4267
|
+
}
|
|
4268
|
+
const storyId = wtEntry.name;
|
|
4269
|
+
const wtStoryDir = (0, import_node_path.join)(worktrees, storyId, ".saga", "stories", storyId);
|
|
4270
|
+
const wtStoryJson = (0, import_node_path.join)(wtStoryDir, "story.json");
|
|
4271
|
+
const wtPath = (0, import_node_path.join)(worktrees, storyId);
|
|
4272
|
+
const scanned = buildScannedStory(wtStoryDir, wtStoryJson, wtPath);
|
|
4273
|
+
if (scanned) {
|
|
4274
|
+
storyMap.set(scanned.id, scanned);
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4198
4278
|
function readStory(projectRoot, storyId) {
|
|
4199
4279
|
const { storyJson } = createStoryPaths(projectRoot, storyId);
|
|
4200
4280
|
if (!(0, import_node_fs.existsSync)(storyJson)) {
|
|
@@ -4245,27 +4325,6 @@ function listEpics(projectRoot) {
|
|
|
4245
4325
|
return EpicSchema.parse(parsed);
|
|
4246
4326
|
});
|
|
4247
4327
|
}
|
|
4248
|
-
function listStories(projectRoot) {
|
|
4249
|
-
const { stories } = createSagaPaths(projectRoot);
|
|
4250
|
-
if (!(0, import_node_fs.existsSync)(stories)) {
|
|
4251
|
-
throw new Error(`Stories directory not found: ${stories}`);
|
|
4252
|
-
}
|
|
4253
|
-
const entries = (0, import_node_fs.readdirSync)(stories, { withFileTypes: true });
|
|
4254
|
-
return entries.filter((entry) => entry.isDirectory()).map((entry) => {
|
|
4255
|
-
const storyJsonPath = (0, import_node_path.join)(stories, entry.name, "story.json");
|
|
4256
|
-
if (!(0, import_node_fs.existsSync)(storyJsonPath)) {
|
|
4257
|
-
return null;
|
|
4258
|
-
}
|
|
4259
|
-
const raw = (0, import_node_fs.readFileSync)(storyJsonPath, "utf-8");
|
|
4260
|
-
let parsed;
|
|
4261
|
-
try {
|
|
4262
|
-
parsed = JSON.parse(raw);
|
|
4263
|
-
} catch {
|
|
4264
|
-
throw new Error(`Malformed JSON in story file: ${storyJsonPath}`);
|
|
4265
|
-
}
|
|
4266
|
-
return StorySchema.parse(parsed);
|
|
4267
|
-
}).filter((story) => story !== null);
|
|
4268
|
-
}
|
|
4269
4328
|
function deriveStoryStatus(tasks) {
|
|
4270
4329
|
if (tasks.length === 0) {
|
|
4271
4330
|
return "pending";
|
|
@@ -4290,46 +4349,11 @@ function deriveEpicStatus(storyStatuses) {
|
|
|
4290
4349
|
}
|
|
4291
4350
|
return "pending";
|
|
4292
4351
|
}
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
const storiesDir = (0, import_node_path2.join)(sagaRoot, ".saga", "stories");
|
|
4299
|
-
if (!(0, import_node_fs2.existsSync)(storiesDir)) {
|
|
4300
|
-
return [];
|
|
4301
|
-
}
|
|
4302
|
-
const stories = listStories(sagaRoot);
|
|
4303
|
-
return stories.map((story) => {
|
|
4304
|
-
let tasks = [];
|
|
4305
|
-
try {
|
|
4306
|
-
tasks = listTasks(sagaRoot, story.id);
|
|
4307
|
-
} catch {
|
|
4308
|
-
}
|
|
4309
|
-
const { journalMd } = createStoryPaths(sagaRoot, story.id);
|
|
4310
|
-
const hasJournal = (0, import_node_fs2.existsSync)(journalMd);
|
|
4311
|
-
return {
|
|
4312
|
-
id: story.id,
|
|
4313
|
-
title: story.title,
|
|
4314
|
-
description: story.description,
|
|
4315
|
-
epicId: story.epic,
|
|
4316
|
-
guidance: story.guidance,
|
|
4317
|
-
doneWhen: story.doneWhen,
|
|
4318
|
-
avoid: story.avoid,
|
|
4319
|
-
branch: story.branch,
|
|
4320
|
-
pr: story.pr,
|
|
4321
|
-
worktree: story.worktree,
|
|
4322
|
-
journalPath: hasJournal ? journalMd : void 0,
|
|
4323
|
-
tasks
|
|
4324
|
-
};
|
|
4325
|
-
});
|
|
4326
|
-
}
|
|
4327
|
-
function scanEpics(sagaRoot) {
|
|
4328
|
-
const epicsDir = (0, import_node_path2.join)(sagaRoot, ".saga", "epics");
|
|
4329
|
-
if (!(0, import_node_fs2.existsSync)(epicsDir)) {
|
|
4330
|
-
return [];
|
|
4331
|
-
}
|
|
4332
|
-
return listEpics(sagaRoot);
|
|
4352
|
+
function scanStories(projectRoot) {
|
|
4353
|
+
const storyMap = /* @__PURE__ */ new Map();
|
|
4354
|
+
scanMasterStories(projectRoot, storyMap);
|
|
4355
|
+
scanWorktreeStories(projectRoot, storyMap);
|
|
4356
|
+
return Array.from(storyMap.values());
|
|
4333
4357
|
}
|
|
4334
4358
|
|
|
4335
4359
|
// src/server/parser.ts
|
|
@@ -4353,7 +4377,7 @@ function toStoryDetail(story) {
|
|
|
4353
4377
|
id: story.id,
|
|
4354
4378
|
title: story.title,
|
|
4355
4379
|
description: story.description,
|
|
4356
|
-
epic: story.
|
|
4380
|
+
epic: story.epic,
|
|
4357
4381
|
status: toApiStatus(derivedStatus),
|
|
4358
4382
|
tasks,
|
|
4359
4383
|
guidance: story.guidance,
|
|
@@ -4391,14 +4415,19 @@ function buildEpic(scannedEpic, epicStories) {
|
|
|
4391
4415
|
}
|
|
4392
4416
|
function parseStory(sagaRoot, storyId) {
|
|
4393
4417
|
try {
|
|
4394
|
-
const
|
|
4418
|
+
const wtPaths = createWorktreePaths(sagaRoot, storyId);
|
|
4419
|
+
const wtStoryDir = `${wtPaths.worktreeDir}/.saga/stories/${storyId}`;
|
|
4420
|
+
const wtStoryJson = `${wtStoryDir}/story.json`;
|
|
4421
|
+
const useWorktree = (0, import_node_fs2.existsSync)(wtStoryJson);
|
|
4422
|
+
const storyRoot = useWorktree ? wtPaths.worktreeDir : sagaRoot;
|
|
4423
|
+
const story = readStory(storyRoot, storyId);
|
|
4395
4424
|
let tasks = [];
|
|
4396
4425
|
try {
|
|
4397
|
-
tasks = listTasks(
|
|
4426
|
+
tasks = listTasks(storyRoot, storyId);
|
|
4398
4427
|
} catch {
|
|
4399
4428
|
}
|
|
4400
|
-
const { journalMd } = createStoryPaths(
|
|
4401
|
-
const hasJournal = (0,
|
|
4429
|
+
const { journalMd } = createStoryPaths(storyRoot, storyId);
|
|
4430
|
+
const hasJournal = (0, import_node_fs2.existsSync)(journalMd);
|
|
4402
4431
|
const derivedStatus = deriveStoryStatus(tasks);
|
|
4403
4432
|
return {
|
|
4404
4433
|
id: story.id,
|
|
@@ -4472,7 +4501,11 @@ async function parseJournal(journalPath) {
|
|
|
4472
4501
|
}
|
|
4473
4502
|
function scanSagaDirectory(sagaRoot) {
|
|
4474
4503
|
const scannedStories = scanStories(sagaRoot);
|
|
4475
|
-
|
|
4504
|
+
let scannedEpics = [];
|
|
4505
|
+
try {
|
|
4506
|
+
scannedEpics = listEpics(sagaRoot);
|
|
4507
|
+
} catch {
|
|
4508
|
+
}
|
|
4476
4509
|
const allStories = scannedStories.map(toStoryDetail);
|
|
4477
4510
|
const storiesByEpic = /* @__PURE__ */ new Map();
|
|
4478
4511
|
const standaloneStories = [];
|
|
@@ -4497,9 +4530,9 @@ var import_express = require("express");
|
|
|
4497
4530
|
|
|
4498
4531
|
// src/lib/sessions.ts
|
|
4499
4532
|
var import_node_child_process = require("node:child_process");
|
|
4500
|
-
var
|
|
4533
|
+
var import_node_fs3 = require("node:fs");
|
|
4501
4534
|
var import_promises2 = require("node:fs/promises");
|
|
4502
|
-
var
|
|
4535
|
+
var import_node_path2 = require("node:path");
|
|
4503
4536
|
var import_node_process = __toESM(require("node:process"), 1);
|
|
4504
4537
|
var PREVIEW_LINES_COUNT = 5;
|
|
4505
4538
|
var PREVIEW_MAX_LENGTH = 500;
|
|
@@ -4569,7 +4602,7 @@ function listSessions() {
|
|
|
4569
4602
|
name,
|
|
4570
4603
|
status: "running",
|
|
4571
4604
|
// If it shows up in tmux ls, it's running
|
|
4572
|
-
outputFile: (0,
|
|
4605
|
+
outputFile: (0, import_node_path2.join)(OUTPUT_DIR, `${name}.jsonl`)
|
|
4573
4606
|
});
|
|
4574
4607
|
}
|
|
4575
4608
|
}
|
|
@@ -4584,8 +4617,8 @@ function getSessionStatus(sessionName) {
|
|
|
4584
4617
|
};
|
|
4585
4618
|
}
|
|
4586
4619
|
function streamLogs(sessionName) {
|
|
4587
|
-
const outputFile = (0,
|
|
4588
|
-
if (!(0,
|
|
4620
|
+
const outputFile = (0, import_node_path2.join)(OUTPUT_DIR, `${sessionName}.jsonl`);
|
|
4621
|
+
if (!(0, import_node_fs3.existsSync)(outputFile)) {
|
|
4589
4622
|
throw new Error(`Output file not found: ${outputFile}`);
|
|
4590
4623
|
}
|
|
4591
4624
|
return new Promise((resolve, reject) => {
|
|
@@ -4638,8 +4671,8 @@ async function buildSessionInfo(name, status) {
|
|
|
4638
4671
|
if (!parsed) {
|
|
4639
4672
|
return null;
|
|
4640
4673
|
}
|
|
4641
|
-
const outputFile = (0,
|
|
4642
|
-
const outputAvailable = (0,
|
|
4674
|
+
const outputFile = (0, import_node_path2.join)(OUTPUT_DIR, `${name}.jsonl`);
|
|
4675
|
+
const outputAvailable = (0, import_node_fs3.existsSync)(outputFile);
|
|
4643
4676
|
let startTime = /* @__PURE__ */ new Date();
|
|
4644
4677
|
let endTime;
|
|
4645
4678
|
let outputPreview;
|
|
@@ -4885,9 +4918,9 @@ function createApiRouter(sagaRoot) {
|
|
|
4885
4918
|
var import_ws = require("ws");
|
|
4886
4919
|
|
|
4887
4920
|
// src/lib/log-stream-manager.ts
|
|
4888
|
-
var
|
|
4921
|
+
var import_node_fs4 = require("node:fs");
|
|
4889
4922
|
var import_promises3 = require("node:fs/promises");
|
|
4890
|
-
var
|
|
4923
|
+
var import_node_path3 = require("node:path");
|
|
4891
4924
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
4892
4925
|
function parseJsonlLines(content) {
|
|
4893
4926
|
const messages = [];
|
|
@@ -4969,8 +5002,8 @@ var LogStreamManager = class {
|
|
|
4969
5002
|
* Creates a file watcher if this is the first subscriber.
|
|
4970
5003
|
*/
|
|
4971
5004
|
async subscribe(sessionName, ws) {
|
|
4972
|
-
const outputFile = (0,
|
|
4973
|
-
if (!(0,
|
|
5005
|
+
const outputFile = (0, import_node_path3.join)(OUTPUT_DIR, `${sessionName}.jsonl`);
|
|
5006
|
+
if (!(0, import_node_fs4.existsSync)(outputFile)) {
|
|
4974
5007
|
this.sendToClient(ws, {
|
|
4975
5008
|
type: "logs:error",
|
|
4976
5009
|
sessionName,
|
|
@@ -5099,10 +5132,10 @@ var LogStreamManager = class {
|
|
|
5099
5132
|
if (!subs || subs.size === 0) {
|
|
5100
5133
|
return;
|
|
5101
5134
|
}
|
|
5102
|
-
const outputFile = (0,
|
|
5135
|
+
const outputFile = (0, import_node_path3.join)(OUTPUT_DIR, `${sessionName}.jsonl`);
|
|
5103
5136
|
const finalMessages = [];
|
|
5104
5137
|
try {
|
|
5105
|
-
if ((0,
|
|
5138
|
+
if ((0, import_node_fs4.existsSync)(outputFile)) {
|
|
5106
5139
|
const content = await (0, import_promises3.readFile)(outputFile, "utf-8");
|
|
5107
5140
|
const lastLineCount = this.lineCounts.get(sessionName) ?? 0;
|
|
5108
5141
|
const nonEmptyLines = content.split("\n").filter((l) => l.trim());
|
|
@@ -5148,7 +5181,7 @@ var LogStreamManager = class {
|
|
|
5148
5181
|
|
|
5149
5182
|
// src/server/watcher.ts
|
|
5150
5183
|
var import_node_events = require("node:events");
|
|
5151
|
-
var
|
|
5184
|
+
var import_node_path4 = require("node:path");
|
|
5152
5185
|
var import_node_process2 = __toESM(require("node:process"), 1);
|
|
5153
5186
|
var import_chokidar2 = __toESM(require("chokidar"), 1);
|
|
5154
5187
|
var EPIC_PATH_PARTS = 3;
|
|
@@ -5161,8 +5194,8 @@ function shouldUsePolling() {
|
|
|
5161
5194
|
function parseEpicsPath(parts) {
|
|
5162
5195
|
if (parts.length === EPIC_PATH_PARTS) {
|
|
5163
5196
|
const fileName = parts[2];
|
|
5164
|
-
if ((0,
|
|
5165
|
-
const epicId = (0,
|
|
5197
|
+
if ((0, import_node_path4.extname)(fileName) === ".json") {
|
|
5198
|
+
const epicId = (0, import_node_path4.basename)(fileName, ".json");
|
|
5166
5199
|
return {
|
|
5167
5200
|
epicId,
|
|
5168
5201
|
isEpicFile: true,
|
|
@@ -5193,7 +5226,7 @@ function parseStoriesPath(parts) {
|
|
|
5193
5226
|
isMainStoryFile: false
|
|
5194
5227
|
};
|
|
5195
5228
|
}
|
|
5196
|
-
if ((0,
|
|
5229
|
+
if ((0, import_node_path4.extname)(fileName) === ".json") {
|
|
5197
5230
|
return {
|
|
5198
5231
|
storyId,
|
|
5199
5232
|
isEpicFile: false,
|
|
@@ -5205,8 +5238,8 @@ function parseStoriesPath(parts) {
|
|
|
5205
5238
|
return null;
|
|
5206
5239
|
}
|
|
5207
5240
|
function parseFilePath(filePath, sagaRoot) {
|
|
5208
|
-
const relativePath = (0,
|
|
5209
|
-
const parts = relativePath.split(
|
|
5241
|
+
const relativePath = (0, import_node_path4.relative)(sagaRoot, filePath);
|
|
5242
|
+
const parts = relativePath.split(import_node_path4.sep);
|
|
5210
5243
|
if (parts[0] !== ".saga" || parts.length < MIN_PATH_PARTS) {
|
|
5211
5244
|
return null;
|
|
5212
5245
|
}
|
|
@@ -5278,8 +5311,8 @@ function createDebounceKey(parsed) {
|
|
|
5278
5311
|
return `epic:${parsed.epicId}`;
|
|
5279
5312
|
}
|
|
5280
5313
|
function createChokidarWatcher(sagaRoot) {
|
|
5281
|
-
const storiesDir = (0,
|
|
5282
|
-
const epicsDir = (0,
|
|
5314
|
+
const storiesDir = (0, import_node_path4.join)(sagaRoot, ".saga", "stories");
|
|
5315
|
+
const epicsDir = (0, import_node_path4.join)(sagaRoot, ".saga", "epics");
|
|
5283
5316
|
const usePolling = shouldUsePolling();
|
|
5284
5317
|
return import_chokidar2.default.watch([storiesDir, epicsDir], {
|
|
5285
5318
|
persistent: true,
|
|
@@ -5311,7 +5344,7 @@ function createFileEventHandler(sagaRoot, debouncer, emitter, state) {
|
|
|
5311
5344
|
type: watcherEventType,
|
|
5312
5345
|
epicId: parsed.epicId,
|
|
5313
5346
|
storyId: parsed.storyId,
|
|
5314
|
-
path: (0,
|
|
5347
|
+
path: (0, import_node_path4.relative)(sagaRoot, filePath)
|
|
5315
5348
|
};
|
|
5316
5349
|
debouncer.schedule(createDebounceKey(parsed), event, (e) => {
|
|
5317
5350
|
if (!state.closed) {
|
|
@@ -5633,8 +5666,8 @@ function createApp(sagaRoot) {
|
|
|
5633
5666
|
res.json({ status: "ok" });
|
|
5634
5667
|
});
|
|
5635
5668
|
app.use("/api", createApiRouter(sagaRoot));
|
|
5636
|
-
const clientDistPath = (0,
|
|
5637
|
-
const _indexHtmlPath = (0,
|
|
5669
|
+
const clientDistPath = (0, import_node_path5.join)(__dirname, "client");
|
|
5670
|
+
const _indexHtmlPath = (0, import_node_path5.join)(clientDistPath, "index.html");
|
|
5638
5671
|
app.use(import_express3.default.static(clientDistPath));
|
|
5639
5672
|
app.get("/{*splat}", (_req, res) => {
|
|
5640
5673
|
res.sendFile("index.html", { root: clientDistPath });
|
|
@@ -5672,17 +5705,17 @@ async function startServer(config) {
|
|
|
5672
5705
|
}
|
|
5673
5706
|
|
|
5674
5707
|
// src/utils/project-discovery.ts
|
|
5675
|
-
var
|
|
5676
|
-
var
|
|
5708
|
+
var import_node_fs5 = require("node:fs");
|
|
5709
|
+
var import_node_path6 = require("node:path");
|
|
5677
5710
|
var import_node_process3 = __toESM(require("node:process"), 1);
|
|
5678
5711
|
function findProjectRoot(startDir) {
|
|
5679
5712
|
let currentDir = startDir ?? import_node_process3.default.cwd();
|
|
5680
5713
|
while (true) {
|
|
5681
|
-
const sagaDir = (0,
|
|
5682
|
-
if ((0,
|
|
5714
|
+
const sagaDir = (0, import_node_path6.join)(currentDir, ".saga");
|
|
5715
|
+
if ((0, import_node_fs5.existsSync)(sagaDir)) {
|
|
5683
5716
|
return currentDir;
|
|
5684
5717
|
}
|
|
5685
|
-
const parentDir = (0,
|
|
5718
|
+
const parentDir = (0, import_node_path6.dirname)(currentDir);
|
|
5686
5719
|
if (parentDir === currentDir) {
|
|
5687
5720
|
return null;
|
|
5688
5721
|
}
|
|
@@ -5691,8 +5724,8 @@ function findProjectRoot(startDir) {
|
|
|
5691
5724
|
}
|
|
5692
5725
|
function resolveProjectPath(explicitPath) {
|
|
5693
5726
|
if (explicitPath) {
|
|
5694
|
-
const sagaDir = (0,
|
|
5695
|
-
if (!(0,
|
|
5727
|
+
const sagaDir = (0, import_node_path6.join)(explicitPath, ".saga");
|
|
5728
|
+
if (!(0, import_node_fs5.existsSync)(sagaDir)) {
|
|
5696
5729
|
throw new Error(
|
|
5697
5730
|
`No .saga/ directory found at specified path: ${explicitPath}
|
|
5698
5731
|
Make sure the path points to a SAGA project root.`
|
|
@@ -5758,8 +5791,8 @@ async function sessionsLogsCommand(sessionName) {
|
|
|
5758
5791
|
}
|
|
5759
5792
|
|
|
5760
5793
|
// src/cli.ts
|
|
5761
|
-
var packageJsonPath = (0,
|
|
5762
|
-
var packageJson = JSON.parse((0,
|
|
5794
|
+
var packageJsonPath = (0, import_node_path7.join)(__dirname, "..", "package.json");
|
|
5795
|
+
var packageJson = JSON.parse((0, import_node_fs6.readFileSync)(packageJsonPath, "utf-8"));
|
|
5763
5796
|
var program = new import_commander.Command();
|
|
5764
5797
|
program.name("saga").description("Dashboard and session monitoring for SAGA - Structured Autonomous Goal Achievement").version(packageJson.version).addHelpCommand("help [command]", "Display help for a command");
|
|
5765
5798
|
program.option("-p, --path <dir>", "Path to SAGA project directory (overrides auto-discovery)");
|