@kimuson/claude-code-viewer 0.5.7 → 0.5.9
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/README.md +3 -9
- package/dist/main.js +1942 -307
- package/dist/main.js.map +4 -4
- package/dist/static/assets/{ProtectedRoute-DcZogGcB.js → ProtectedRoute-BZvfrfXZ.js} +1 -1
- package/dist/static/assets/{eye-B29o7q5D.js → eye-BGsXRq_8.js} +1 -1
- package/dist/static/assets/{index-BLyHo0QH.js → index-D9d-SW2q.js} +1 -1
- package/dist/static/assets/{index-BjunoQqw.js → index-hJ5yiXvq.js} +14 -14
- package/dist/static/assets/index-kl3XSvPM.css +1 -0
- package/dist/static/assets/{index-D35NAeE6.js → index-sXgy7Ajd.js} +1 -1
- package/dist/static/assets/{label-Qp_e3OMm.js → label-gygRdIVO.js} +1 -1
- package/dist/static/assets/{login-8XN7uuCa.js → login-DRDs0jaq.js} +1 -1
- package/dist/static/assets/messages-5zx59L1k.js +1 -0
- package/dist/static/assets/messages-Diwakl7a.js +1 -0
- package/dist/static/assets/messages-Pr7vABlX.js +1 -0
- package/dist/static/assets/{session-CWyTWuSQ.js → session-B5BSJDkJ.js} +1 -1
- package/dist/static/assets/{session-DbDRJ-Wx.js → session-D2lB0w81.js} +32 -32
- package/dist/static/index.html +2 -2
- package/package.json +2 -2
- package/dist/static/assets/index-SnhT5nsw.css +0 -1
- package/dist/static/assets/messages-B8Pmi05i.js +0 -1
- package/dist/static/assets/messages-DGhO0Hga.js +0 -1
- package/dist/static/assets/messages-kG1PDYhH.js +0 -1
package/dist/main.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
// src/server/main.ts
|
|
4
4
|
import { Command as Command3 } from "commander";
|
|
5
|
-
import { Effect as
|
|
5
|
+
import { Effect as Effect53 } from "effect";
|
|
6
6
|
|
|
7
7
|
// package.json
|
|
8
8
|
var package_default = {
|
|
9
9
|
name: "@kimuson/claude-code-viewer",
|
|
10
|
-
version: "0.5.
|
|
10
|
+
version: "0.5.9",
|
|
11
11
|
description: "A full-featured web-based Claude Code client that provides complete interactive functionality for managing Claude Code projects.",
|
|
12
12
|
type: "module",
|
|
13
13
|
license: "MIT",
|
|
@@ -51,7 +51,7 @@ var package_default = {
|
|
|
51
51
|
prepare: "lefthook install"
|
|
52
52
|
},
|
|
53
53
|
dependencies: {
|
|
54
|
-
"@anthropic-ai/claude-agent-sdk": "0.2.
|
|
54
|
+
"@anthropic-ai/claude-agent-sdk": "0.2.20",
|
|
55
55
|
"@anthropic-ai/claude-code": "2.0.24",
|
|
56
56
|
"@anthropic-ai/sdk": "0.71.2",
|
|
57
57
|
"@effect/cluster": "0.56.1",
|
|
@@ -219,7 +219,7 @@ import { resolve as resolve6 } from "node:path";
|
|
|
219
219
|
import { NodeContext as NodeContext2 } from "@effect/platform-node";
|
|
220
220
|
import { serve } from "@hono/node-server";
|
|
221
221
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
222
|
-
import { Effect as
|
|
222
|
+
import { Effect as Effect52, Layer as Layer43 } from "effect";
|
|
223
223
|
|
|
224
224
|
// src/server/core/agent-session/index.ts
|
|
225
225
|
import { Layer as Layer3 } from "effect";
|
|
@@ -1077,12 +1077,28 @@ var ProjectRepository = class extends Context7.Tag("ProjectRepository")() {
|
|
|
1077
1077
|
// src/server/core/claude-code/functions/scanCommandFiles.ts
|
|
1078
1078
|
import { FileSystem as FileSystem5, Path as Path6 } from "@effect/platform";
|
|
1079
1079
|
import { Effect as Effect10 } from "effect";
|
|
1080
|
+
var parseCommandFrontmatter = (content) => {
|
|
1081
|
+
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
1082
|
+
if (!frontmatterMatch?.[1]) {
|
|
1083
|
+
return { description: null, argumentHint: null };
|
|
1084
|
+
}
|
|
1085
|
+
const frontmatter = frontmatterMatch[1];
|
|
1086
|
+
const descriptionMatch = frontmatter.match(
|
|
1087
|
+
/^description:\s*['"]?([^'"\n]+)['"]?\s*$/m
|
|
1088
|
+
);
|
|
1089
|
+
const description = descriptionMatch?.[1]?.trim() ?? null;
|
|
1090
|
+
const argumentHintMatch = frontmatter.match(
|
|
1091
|
+
/^argument-hint:\s*['"]?([^'"\n]+)['"]?\s*$/m
|
|
1092
|
+
);
|
|
1093
|
+
const argumentHint = argumentHintMatch?.[1]?.trim() ?? null;
|
|
1094
|
+
return { description, argumentHint };
|
|
1095
|
+
};
|
|
1080
1096
|
var pathToCommandName = (filePath, baseDir) => {
|
|
1081
1097
|
const normalizedBaseDir = baseDir.endsWith("/") ? baseDir.slice(0, -1) : baseDir;
|
|
1082
1098
|
const relativePath = filePath.startsWith(normalizedBaseDir) ? filePath.slice(normalizedBaseDir.length + 1) : filePath;
|
|
1083
1099
|
return relativePath.replace(/\.md$/, "").replace(/\//g, ":");
|
|
1084
1100
|
};
|
|
1085
|
-
var
|
|
1101
|
+
var scanCommandFilesWithMetadata = (dirPath) => Effect10.gen(function* () {
|
|
1086
1102
|
const fs = yield* FileSystem5.FileSystem;
|
|
1087
1103
|
const path = yield* Path6.Path;
|
|
1088
1104
|
const scanDirectory = (currentPath) => Effect10.gen(function* () {
|
|
@@ -1103,7 +1119,10 @@ var scanCommandFilesRecursively = (dirPath) => Effect10.gen(function* () {
|
|
|
1103
1119
|
return yield* scanDirectory(itemPath);
|
|
1104
1120
|
}
|
|
1105
1121
|
if (info.type === "File" && item.endsWith(".md")) {
|
|
1106
|
-
|
|
1122
|
+
const content = yield* fs.readFileString(itemPath);
|
|
1123
|
+
const { description, argumentHint } = parseCommandFrontmatter(content);
|
|
1124
|
+
const name = pathToCommandName(itemPath, dirPath);
|
|
1125
|
+
return [{ name, description, argumentHint }];
|
|
1107
1126
|
}
|
|
1108
1127
|
return [];
|
|
1109
1128
|
}),
|
|
@@ -1118,7 +1137,7 @@ var scanCommandFilesRecursively = (dirPath) => Effect10.gen(function* () {
|
|
|
1118
1137
|
})
|
|
1119
1138
|
);
|
|
1120
1139
|
});
|
|
1121
|
-
var
|
|
1140
|
+
var scanSkillFilesWithMetadata = (dirPath) => Effect10.gen(function* () {
|
|
1122
1141
|
const fs = yield* FileSystem5.FileSystem;
|
|
1123
1142
|
const path = yield* Path6.Path;
|
|
1124
1143
|
const scanDirectory = (currentPath, relativePath) => Effect10.gen(function* () {
|
|
@@ -1128,11 +1147,13 @@ var scanSkillFilesRecursively = (dirPath) => Effect10.gen(function* () {
|
|
|
1128
1147
|
}
|
|
1129
1148
|
const skillFilePath = path.join(currentPath, "SKILL.md");
|
|
1130
1149
|
const skillFileExists = yield* fs.exists(skillFilePath);
|
|
1131
|
-
const
|
|
1150
|
+
const skills = [];
|
|
1132
1151
|
if (skillFileExists) {
|
|
1133
1152
|
const skillName = relativePath.replace(/\//g, ":");
|
|
1134
1153
|
if (skillName) {
|
|
1135
|
-
|
|
1154
|
+
const content = yield* fs.readFileString(skillFilePath);
|
|
1155
|
+
const { description, argumentHint } = parseCommandFrontmatter(content);
|
|
1156
|
+
skills.push({ name: skillName, description, argumentHint });
|
|
1136
1157
|
}
|
|
1137
1158
|
}
|
|
1138
1159
|
const items = yield* fs.readDirectory(currentPath);
|
|
@@ -1152,7 +1173,7 @@ var scanSkillFilesRecursively = (dirPath) => Effect10.gen(function* () {
|
|
|
1152
1173
|
}),
|
|
1153
1174
|
{ concurrency: "unbounded" }
|
|
1154
1175
|
);
|
|
1155
|
-
return [...
|
|
1176
|
+
return [...skills, ...results.flat()];
|
|
1156
1177
|
});
|
|
1157
1178
|
return yield* scanDirectory(dirPath, "").pipe(
|
|
1158
1179
|
Effect10.match({
|
|
@@ -1203,9 +1224,15 @@ var parseMcpListOutput = (output) => {
|
|
|
1203
1224
|
if (colonIndex > 0) {
|
|
1204
1225
|
const name = line.substring(0, colonIndex).trim();
|
|
1205
1226
|
const rest = line.substring(colonIndex + 1).trim();
|
|
1227
|
+
let status = "unknown";
|
|
1228
|
+
if (rest.includes("\u2713") || rest.toLowerCase().includes("connected")) {
|
|
1229
|
+
status = "connected";
|
|
1230
|
+
} else if (rest.includes("\u2717") || rest.toLowerCase().includes("failed")) {
|
|
1231
|
+
status = "failed";
|
|
1232
|
+
}
|
|
1206
1233
|
const command = rest.replace(/\s*-\s*[✓✗].*$/, "").trim();
|
|
1207
1234
|
if (name && command) {
|
|
1208
|
-
servers.push({ name, command });
|
|
1235
|
+
servers.push({ name, command, status });
|
|
1209
1236
|
}
|
|
1210
1237
|
}
|
|
1211
1238
|
}
|
|
@@ -1437,25 +1464,55 @@ var LayerImpl9 = Effect13.gen(function* () {
|
|
|
1437
1464
|
const { projectId } = options;
|
|
1438
1465
|
const { project } = yield* projectRepository.getProject(projectId);
|
|
1439
1466
|
const features = yield* claudeCodeService.getAvailableFeatures();
|
|
1440
|
-
const globalCommands = yield*
|
|
1467
|
+
const globalCommands = yield* scanCommandFilesWithMetadata(
|
|
1441
1468
|
(yield* context.claudeCodePaths).claudeCommandsDirPath
|
|
1442
1469
|
);
|
|
1443
|
-
const projectCommands = project.meta.projectPath === null ? [] : yield*
|
|
1470
|
+
const projectCommands = project.meta.projectPath === null ? [] : yield* scanCommandFilesWithMetadata(
|
|
1444
1471
|
path.resolve(project.meta.projectPath, ".claude", "commands")
|
|
1445
1472
|
);
|
|
1446
|
-
const globalSkills = features.runSkillsDirectly ? yield*
|
|
1473
|
+
const globalSkills = features.runSkillsDirectly ? yield* scanSkillFilesWithMetadata(
|
|
1447
1474
|
(yield* context.claudeCodePaths).claudeSkillsDirPath
|
|
1448
1475
|
) : [];
|
|
1449
|
-
const projectSkills = features.runSkillsDirectly && project.meta.projectPath !== null ? yield*
|
|
1476
|
+
const projectSkills = features.runSkillsDirectly && project.meta.projectPath !== null ? yield* scanSkillFilesWithMetadata(
|
|
1450
1477
|
path.resolve(project.meta.projectPath, ".claude", "skills")
|
|
1451
1478
|
) : [];
|
|
1479
|
+
const defaultCommands = [
|
|
1480
|
+
{
|
|
1481
|
+
name: "init",
|
|
1482
|
+
description: "Initialize Claude Code in current project",
|
|
1483
|
+
argumentHint: null
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
name: "compact",
|
|
1487
|
+
description: "Compact conversation history",
|
|
1488
|
+
argumentHint: null
|
|
1489
|
+
},
|
|
1490
|
+
{
|
|
1491
|
+
name: "security-review",
|
|
1492
|
+
description: "Review code for security issues",
|
|
1493
|
+
argumentHint: null
|
|
1494
|
+
},
|
|
1495
|
+
{
|
|
1496
|
+
name: "review",
|
|
1497
|
+
description: "Review code changes",
|
|
1498
|
+
argumentHint: null
|
|
1499
|
+
}
|
|
1500
|
+
];
|
|
1501
|
+
const toNames = (commands) => commands.map((c) => c.name);
|
|
1452
1502
|
return {
|
|
1453
1503
|
response: {
|
|
1504
|
+
// New format: CommandInfo[] with metadata
|
|
1454
1505
|
globalCommands,
|
|
1455
1506
|
projectCommands,
|
|
1456
1507
|
globalSkills,
|
|
1457
1508
|
projectSkills,
|
|
1458
|
-
defaultCommands
|
|
1509
|
+
defaultCommands,
|
|
1510
|
+
// Legacy format: string[] for backward compatibility
|
|
1511
|
+
globalCommandsLegacy: toNames(globalCommands),
|
|
1512
|
+
projectCommandsLegacy: toNames(projectCommands),
|
|
1513
|
+
globalSkillsLegacy: toNames(globalSkills),
|
|
1514
|
+
projectSkillsLegacy: toNames(projectSkills),
|
|
1515
|
+
defaultCommandsLegacy: toNames(defaultCommands)
|
|
1459
1516
|
},
|
|
1460
1517
|
status: 200
|
|
1461
1518
|
};
|
|
@@ -1751,7 +1808,8 @@ var LayerImpl12 = Effect17.gen(function* () {
|
|
|
1751
1808
|
permissionMode: "default",
|
|
1752
1809
|
locale: DEFAULT_LOCALE,
|
|
1753
1810
|
theme: "system",
|
|
1754
|
-
searchHotkey: "command-k"
|
|
1811
|
+
searchHotkey: "command-k",
|
|
1812
|
+
autoScheduleContinueOnRateLimit: false
|
|
1755
1813
|
});
|
|
1756
1814
|
const setUserConfig = (newConfig) => Effect17.gen(function* () {
|
|
1757
1815
|
yield* Ref5.update(configRef, () => newConfig);
|
|
@@ -5254,6 +5312,10 @@ var ProjectController = class extends Context28.Tag("ProjectController")() {
|
|
|
5254
5312
|
}
|
|
5255
5313
|
};
|
|
5256
5314
|
|
|
5315
|
+
// src/server/core/rate-limit/services/RateLimitAutoScheduleService.ts
|
|
5316
|
+
import { FileSystem as FileSystem14, Path as Path17 } from "@effect/platform";
|
|
5317
|
+
import { Context as Context31, Effect as Effect40, Layer as Layer33, Ref as Ref12 } from "effect";
|
|
5318
|
+
|
|
5257
5319
|
// src/server/core/scheduler/config.ts
|
|
5258
5320
|
import { homedir as homedir4 } from "node:os";
|
|
5259
5321
|
import { FileSystem as FileSystem12, Path as Path16 } from "@effect/platform";
|
|
@@ -5675,18 +5737,321 @@ var SchedulerService = class extends Context30.Tag("SchedulerService")() {
|
|
|
5675
5737
|
}
|
|
5676
5738
|
};
|
|
5677
5739
|
|
|
5740
|
+
// src/server/core/rate-limit/schema.ts
|
|
5741
|
+
import { z as z25 } from "zod";
|
|
5742
|
+
var RateLimitEntrySchema = z25.object({
|
|
5743
|
+
type: z25.literal("assistant"),
|
|
5744
|
+
error: z25.literal("rate_limit"),
|
|
5745
|
+
isApiErrorMessage: z25.literal(true),
|
|
5746
|
+
sessionId: z25.string(),
|
|
5747
|
+
message: z25.object({
|
|
5748
|
+
content: z25.array(
|
|
5749
|
+
z25.object({
|
|
5750
|
+
type: z25.literal("text"),
|
|
5751
|
+
text: z25.string()
|
|
5752
|
+
})
|
|
5753
|
+
)
|
|
5754
|
+
})
|
|
5755
|
+
});
|
|
5756
|
+
|
|
5757
|
+
// src/server/core/rate-limit/functions/detectRateLimitFromLastLine.ts
|
|
5758
|
+
var detectRateLimitFromLastLine = (jsonLine) => {
|
|
5759
|
+
const trimmed = jsonLine.trim();
|
|
5760
|
+
if (trimmed === "") {
|
|
5761
|
+
return { detected: false };
|
|
5762
|
+
}
|
|
5763
|
+
let parsed;
|
|
5764
|
+
try {
|
|
5765
|
+
parsed = JSON.parse(trimmed);
|
|
5766
|
+
} catch {
|
|
5767
|
+
return { detected: false };
|
|
5768
|
+
}
|
|
5769
|
+
const validation = RateLimitEntrySchema.safeParse(parsed);
|
|
5770
|
+
if (!validation.success) {
|
|
5771
|
+
return { detected: false };
|
|
5772
|
+
}
|
|
5773
|
+
const entry = validation.data;
|
|
5774
|
+
const firstTextContent = entry.message.content[0];
|
|
5775
|
+
if (!firstTextContent) {
|
|
5776
|
+
return { detected: false };
|
|
5777
|
+
}
|
|
5778
|
+
return {
|
|
5779
|
+
detected: true,
|
|
5780
|
+
sessionId: entry.sessionId,
|
|
5781
|
+
resetTimeText: firstTextContent.text
|
|
5782
|
+
};
|
|
5783
|
+
};
|
|
5784
|
+
|
|
5785
|
+
// src/server/core/rate-limit/functions/parseRateLimitResetTime.ts
|
|
5786
|
+
var parseRateLimitResetTime = (resetTimeText) => {
|
|
5787
|
+
const pattern = /resets\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm|AM|PM)\s*\(([^)]+)\)/i;
|
|
5788
|
+
const match = pattern.exec(resetTimeText);
|
|
5789
|
+
if (!match) {
|
|
5790
|
+
return getFallbackTime();
|
|
5791
|
+
}
|
|
5792
|
+
const hoursStr = match[1];
|
|
5793
|
+
const minutesStr = match[2];
|
|
5794
|
+
const meridiem = match[3];
|
|
5795
|
+
const timezone = match[4];
|
|
5796
|
+
if (hoursStr === void 0 || meridiem === void 0 || timezone === void 0) {
|
|
5797
|
+
return getFallbackTime();
|
|
5798
|
+
}
|
|
5799
|
+
const hours = Number.parseInt(hoursStr, 10);
|
|
5800
|
+
const minutes = minutesStr !== void 0 ? Number.parseInt(minutesStr, 10) : 0;
|
|
5801
|
+
if (Number.isNaN(hours) || Number.isNaN(minutes)) {
|
|
5802
|
+
return getFallbackTime();
|
|
5803
|
+
}
|
|
5804
|
+
const hours24 = convertTo24Hour(hours, meridiem.toLowerCase());
|
|
5805
|
+
const resetDate = createDateInTimezone(hours24, minutes, timezone);
|
|
5806
|
+
if (resetDate === null) {
|
|
5807
|
+
return getFallbackTime();
|
|
5808
|
+
}
|
|
5809
|
+
resetDate.setMinutes(resetDate.getMinutes() + 1);
|
|
5810
|
+
return resetDate.toISOString();
|
|
5811
|
+
};
|
|
5812
|
+
var convertTo24Hour = (hours, meridiem) => {
|
|
5813
|
+
const isPM = meridiem === "pm";
|
|
5814
|
+
if (hours === 12) {
|
|
5815
|
+
return isPM ? 12 : 0;
|
|
5816
|
+
}
|
|
5817
|
+
return isPM ? hours + 12 : hours;
|
|
5818
|
+
};
|
|
5819
|
+
var getTimezoneOffsetMinutes = (timezone, date) => {
|
|
5820
|
+
const utcFormatter = new Intl.DateTimeFormat("en-US", {
|
|
5821
|
+
timeZone: "UTC",
|
|
5822
|
+
year: "numeric",
|
|
5823
|
+
month: "2-digit",
|
|
5824
|
+
day: "2-digit",
|
|
5825
|
+
hour: "2-digit",
|
|
5826
|
+
minute: "2-digit",
|
|
5827
|
+
hour12: false
|
|
5828
|
+
});
|
|
5829
|
+
const tzFormatter = new Intl.DateTimeFormat("en-US", {
|
|
5830
|
+
timeZone: timezone,
|
|
5831
|
+
year: "numeric",
|
|
5832
|
+
month: "2-digit",
|
|
5833
|
+
day: "2-digit",
|
|
5834
|
+
hour: "2-digit",
|
|
5835
|
+
minute: "2-digit",
|
|
5836
|
+
hour12: false
|
|
5837
|
+
});
|
|
5838
|
+
const utcParts = utcFormatter.formatToParts(date);
|
|
5839
|
+
const tzParts = tzFormatter.formatToParts(date);
|
|
5840
|
+
const extractDateTime = (parts) => ({
|
|
5841
|
+
day: Number.parseInt(parts.find((p) => p.type === "day")?.value ?? "0", 10),
|
|
5842
|
+
hour: Number.parseInt(
|
|
5843
|
+
parts.find((p) => p.type === "hour")?.value ?? "0",
|
|
5844
|
+
10
|
|
5845
|
+
),
|
|
5846
|
+
minute: Number.parseInt(
|
|
5847
|
+
parts.find((p) => p.type === "minute")?.value ?? "0",
|
|
5848
|
+
10
|
|
5849
|
+
)
|
|
5850
|
+
});
|
|
5851
|
+
const utc = extractDateTime(utcParts);
|
|
5852
|
+
const tz = extractDateTime(tzParts);
|
|
5853
|
+
let dayDiff = tz.day - utc.day;
|
|
5854
|
+
if (dayDiff > 15) dayDiff -= 31;
|
|
5855
|
+
if (dayDiff < -15) dayDiff += 31;
|
|
5856
|
+
const offsetMinutes = dayDiff * 24 * 60 + (tz.hour - utc.hour) * 60 + (tz.minute - utc.minute);
|
|
5857
|
+
return offsetMinutes;
|
|
5858
|
+
};
|
|
5859
|
+
var createDateInTimezone = (hours, minutes, timezone) => {
|
|
5860
|
+
const now = /* @__PURE__ */ new Date();
|
|
5861
|
+
try {
|
|
5862
|
+
const testFormatter = new Intl.DateTimeFormat("en-US", {
|
|
5863
|
+
timeZone: timezone
|
|
5864
|
+
});
|
|
5865
|
+
testFormatter.format(now);
|
|
5866
|
+
const offsetMinutes = getTimezoneOffsetMinutes(timezone, now);
|
|
5867
|
+
const tzFormatter = new Intl.DateTimeFormat("en-US", {
|
|
5868
|
+
timeZone: timezone,
|
|
5869
|
+
year: "numeric",
|
|
5870
|
+
month: "2-digit",
|
|
5871
|
+
day: "2-digit"
|
|
5872
|
+
});
|
|
5873
|
+
const parts = tzFormatter.formatToParts(now);
|
|
5874
|
+
const year = parts.find((p) => p.type === "year")?.value;
|
|
5875
|
+
const month = parts.find((p) => p.type === "month")?.value;
|
|
5876
|
+
const day = parts.find((p) => p.type === "day")?.value;
|
|
5877
|
+
if (!year || !month || !day) {
|
|
5878
|
+
return null;
|
|
5879
|
+
}
|
|
5880
|
+
const totalTargetMinutes = hours * 60 + minutes;
|
|
5881
|
+
const totalUtcMinutes = totalTargetMinutes - offsetMinutes;
|
|
5882
|
+
const baseDate = /* @__PURE__ */ new Date(`${year}-${month}-${day}T00:00:00.000Z`);
|
|
5883
|
+
const resetDate = new Date(
|
|
5884
|
+
baseDate.getTime() + totalUtcMinutes * 60 * 1e3
|
|
5885
|
+
);
|
|
5886
|
+
if (resetDate.getTime() <= now.getTime()) {
|
|
5887
|
+
resetDate.setTime(resetDate.getTime() + 24 * 60 * 60 * 1e3);
|
|
5888
|
+
}
|
|
5889
|
+
return resetDate;
|
|
5890
|
+
} catch {
|
|
5891
|
+
return null;
|
|
5892
|
+
}
|
|
5893
|
+
};
|
|
5894
|
+
var getFallbackTime = () => {
|
|
5895
|
+
const fallback = /* @__PURE__ */ new Date();
|
|
5896
|
+
fallback.setMinutes(fallback.getMinutes() + 30);
|
|
5897
|
+
return fallback.toISOString();
|
|
5898
|
+
};
|
|
5899
|
+
|
|
5900
|
+
// src/server/core/rate-limit/functions/readLastLine.ts
|
|
5901
|
+
import { FileSystem as FileSystem13 } from "@effect/platform";
|
|
5902
|
+
import { Effect as Effect39 } from "effect";
|
|
5903
|
+
var extractLastNonEmptyLine = (content) => {
|
|
5904
|
+
const lines = content.split(/\r?\n/);
|
|
5905
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
5906
|
+
const line = lines[i];
|
|
5907
|
+
if (line !== void 0 && line.trim() !== "") {
|
|
5908
|
+
return line;
|
|
5909
|
+
}
|
|
5910
|
+
}
|
|
5911
|
+
return "";
|
|
5912
|
+
};
|
|
5913
|
+
var readLastLine = (filePath) => Effect39.gen(function* () {
|
|
5914
|
+
const fs = yield* FileSystem13.FileSystem;
|
|
5915
|
+
const content = yield* fs.readFileString(filePath);
|
|
5916
|
+
return extractLastNonEmptyLine(content);
|
|
5917
|
+
});
|
|
5918
|
+
|
|
5919
|
+
// src/server/core/rate-limit/services/RateLimitAutoScheduleService.ts
|
|
5920
|
+
var LayerImpl25 = Effect40.gen(function* () {
|
|
5921
|
+
const eventBus = yield* EventBus;
|
|
5922
|
+
const userConfigService = yield* UserConfigService;
|
|
5923
|
+
const sessionProcessService = yield* ClaudeCodeSessionProcessService;
|
|
5924
|
+
const schedulerService = yield* SchedulerService;
|
|
5925
|
+
const fs = yield* FileSystem14.FileSystem;
|
|
5926
|
+
const pathService = yield* Path17.Path;
|
|
5927
|
+
const schedulerConfigBaseDir = yield* SchedulerConfigBaseDir;
|
|
5928
|
+
const projectRepository = yield* ProjectRepository;
|
|
5929
|
+
const lifeCycleService = yield* ClaudeCodeLifeCycleService;
|
|
5930
|
+
const listenerRef = yield* Ref12.make(null);
|
|
5931
|
+
const getSessionProcessProjectId = (sessionId) => Effect40.gen(function* () {
|
|
5932
|
+
const processes = yield* sessionProcessService.getSessionProcesses();
|
|
5933
|
+
const liveProcess = processes.find(
|
|
5934
|
+
(process2) => process2.sessionId === sessionId && (process2.type === "initialized" || process2.type === "file_created" || process2.type === "paused")
|
|
5935
|
+
);
|
|
5936
|
+
return liveProcess?.def.projectId;
|
|
5937
|
+
});
|
|
5938
|
+
const hasExistingReservedJobForSession = (sessionId) => Effect40.gen(function* () {
|
|
5939
|
+
const jobs = yield* schedulerService.getJobs().pipe(Effect40.catchAll(() => Effect40.succeed([])));
|
|
5940
|
+
return jobs.some(
|
|
5941
|
+
(job) => job.schedule.type === "reserved" && job.message.baseSessionId === sessionId && job.lastRunStatus === null
|
|
5942
|
+
// Not yet executed
|
|
5943
|
+
);
|
|
5944
|
+
});
|
|
5945
|
+
const handleSessionChanged = (event) => Effect40.gen(function* () {
|
|
5946
|
+
const { projectId, sessionId } = event;
|
|
5947
|
+
const config = yield* userConfigService.getUserConfig();
|
|
5948
|
+
if (!config.autoScheduleContinueOnRateLimit) {
|
|
5949
|
+
return;
|
|
5950
|
+
}
|
|
5951
|
+
const processProjectId = yield* getSessionProcessProjectId(sessionId);
|
|
5952
|
+
if (processProjectId === void 0) {
|
|
5953
|
+
return;
|
|
5954
|
+
}
|
|
5955
|
+
const hasExistingJob = yield* hasExistingReservedJobForSession(sessionId);
|
|
5956
|
+
if (hasExistingJob) {
|
|
5957
|
+
return;
|
|
5958
|
+
}
|
|
5959
|
+
const projectPath = decodeProjectId(projectId);
|
|
5960
|
+
const sessionFilePath = pathService.join(
|
|
5961
|
+
projectPath,
|
|
5962
|
+
`${sessionId}.jsonl`
|
|
5963
|
+
);
|
|
5964
|
+
const lastLine = yield* readLastLine(sessionFilePath).pipe(
|
|
5965
|
+
Effect40.catchAll(() => Effect40.succeed(""))
|
|
5966
|
+
);
|
|
5967
|
+
if (lastLine === "") {
|
|
5968
|
+
return;
|
|
5969
|
+
}
|
|
5970
|
+
const detection = detectRateLimitFromLastLine(lastLine);
|
|
5971
|
+
if (!detection.detected) {
|
|
5972
|
+
return;
|
|
5973
|
+
}
|
|
5974
|
+
const resetTime = parseRateLimitResetTime(detection.resetTimeText);
|
|
5975
|
+
yield* schedulerService.addJob({
|
|
5976
|
+
name: `Rate limit auto-continue: ${sessionId.slice(0, 8)}...`,
|
|
5977
|
+
schedule: {
|
|
5978
|
+
type: "reserved",
|
|
5979
|
+
reservedExecutionTime: resetTime
|
|
5980
|
+
},
|
|
5981
|
+
message: {
|
|
5982
|
+
content: "continue",
|
|
5983
|
+
projectId: processProjectId,
|
|
5984
|
+
baseSessionId: sessionId
|
|
5985
|
+
},
|
|
5986
|
+
enabled: true
|
|
5987
|
+
}).pipe(
|
|
5988
|
+
Effect40.catchAll((error) => {
|
|
5989
|
+
console.error(
|
|
5990
|
+
`[RateLimitAutoScheduleService] Failed to add job for session ${sessionId}:`,
|
|
5991
|
+
error
|
|
5992
|
+
);
|
|
5993
|
+
return Effect40.void;
|
|
5994
|
+
})
|
|
5995
|
+
);
|
|
5996
|
+
console.log(
|
|
5997
|
+
`[RateLimitAutoScheduleService] Scheduled continue task for session ${sessionId} at ${resetTime}`
|
|
5998
|
+
);
|
|
5999
|
+
});
|
|
6000
|
+
const runtimeLayer = Layer33.mergeAll(
|
|
6001
|
+
Layer33.succeed(FileSystem14.FileSystem, fs),
|
|
6002
|
+
Layer33.succeed(Path17.Path, pathService),
|
|
6003
|
+
Layer33.succeed(SchedulerConfigBaseDir, schedulerConfigBaseDir),
|
|
6004
|
+
Layer33.succeed(ProjectRepository, projectRepository),
|
|
6005
|
+
Layer33.succeed(UserConfigService, userConfigService),
|
|
6006
|
+
Layer33.succeed(ClaudeCodeLifeCycleService, lifeCycleService)
|
|
6007
|
+
);
|
|
6008
|
+
const start = () => Effect40.gen(function* () {
|
|
6009
|
+
const existingListener = yield* Ref12.get(listenerRef);
|
|
6010
|
+
if (existingListener !== null) {
|
|
6011
|
+
return;
|
|
6012
|
+
}
|
|
6013
|
+
const listener = (event) => {
|
|
6014
|
+
Effect40.runFork(
|
|
6015
|
+
handleSessionChanged(event).pipe(Effect40.provide(runtimeLayer))
|
|
6016
|
+
);
|
|
6017
|
+
};
|
|
6018
|
+
yield* Ref12.set(listenerRef, listener);
|
|
6019
|
+
yield* eventBus.on("sessionChanged", listener);
|
|
6020
|
+
console.log("[RateLimitAutoScheduleService] Started");
|
|
6021
|
+
});
|
|
6022
|
+
const stop = () => Effect40.gen(function* () {
|
|
6023
|
+
const listener = yield* Ref12.get(listenerRef);
|
|
6024
|
+
if (listener !== null) {
|
|
6025
|
+
yield* eventBus.off("sessionChanged", listener);
|
|
6026
|
+
yield* Ref12.set(listenerRef, null);
|
|
6027
|
+
}
|
|
6028
|
+
console.log("[RateLimitAutoScheduleService] Stopped");
|
|
6029
|
+
});
|
|
6030
|
+
return {
|
|
6031
|
+
start,
|
|
6032
|
+
stop
|
|
6033
|
+
};
|
|
6034
|
+
});
|
|
6035
|
+
var RateLimitAutoScheduleService = class extends Context31.Tag(
|
|
6036
|
+
"RateLimitAutoScheduleService"
|
|
6037
|
+
)() {
|
|
6038
|
+
static {
|
|
6039
|
+
this.Live = Layer33.effect(this, LayerImpl25);
|
|
6040
|
+
}
|
|
6041
|
+
};
|
|
6042
|
+
|
|
5678
6043
|
// src/server/core/scheduler/presentation/SchedulerController.ts
|
|
5679
|
-
import { Context as
|
|
5680
|
-
var
|
|
6044
|
+
import { Context as Context32, Effect as Effect41, Layer as Layer34 } from "effect";
|
|
6045
|
+
var LayerImpl26 = Effect41.gen(function* () {
|
|
5681
6046
|
const schedulerService = yield* SchedulerService;
|
|
5682
|
-
const getJobs = () =>
|
|
6047
|
+
const getJobs = () => Effect41.gen(function* () {
|
|
5683
6048
|
const jobs = yield* schedulerService.getJobs();
|
|
5684
6049
|
return {
|
|
5685
6050
|
response: jobs,
|
|
5686
6051
|
status: 200
|
|
5687
6052
|
};
|
|
5688
6053
|
});
|
|
5689
|
-
const addJob = (options) =>
|
|
6054
|
+
const addJob = (options) => Effect41.gen(function* () {
|
|
5690
6055
|
const { job } = options;
|
|
5691
6056
|
const result = yield* schedulerService.addJob(job);
|
|
5692
6057
|
return {
|
|
@@ -5694,12 +6059,12 @@ var LayerImpl25 = Effect39.gen(function* () {
|
|
|
5694
6059
|
status: 201
|
|
5695
6060
|
};
|
|
5696
6061
|
});
|
|
5697
|
-
const updateJob = (options) =>
|
|
6062
|
+
const updateJob = (options) => Effect41.gen(function* () {
|
|
5698
6063
|
const { id, job } = options;
|
|
5699
6064
|
const result = yield* schedulerService.updateJob(id, job).pipe(
|
|
5700
|
-
|
|
6065
|
+
Effect41.catchTag(
|
|
5701
6066
|
"SchedulerJobNotFoundError",
|
|
5702
|
-
() =>
|
|
6067
|
+
() => Effect41.succeed(null)
|
|
5703
6068
|
)
|
|
5704
6069
|
);
|
|
5705
6070
|
if (result === null) {
|
|
@@ -5713,14 +6078,14 @@ var LayerImpl25 = Effect39.gen(function* () {
|
|
|
5713
6078
|
status: 200
|
|
5714
6079
|
};
|
|
5715
6080
|
});
|
|
5716
|
-
const deleteJob = (options) =>
|
|
6081
|
+
const deleteJob = (options) => Effect41.gen(function* () {
|
|
5717
6082
|
const { id } = options;
|
|
5718
6083
|
const result = yield* schedulerService.deleteJob(id).pipe(
|
|
5719
|
-
|
|
6084
|
+
Effect41.catchTag(
|
|
5720
6085
|
"SchedulerJobNotFoundError",
|
|
5721
|
-
() =>
|
|
6086
|
+
() => Effect41.succeed(false)
|
|
5722
6087
|
),
|
|
5723
|
-
|
|
6088
|
+
Effect41.map(() => true)
|
|
5724
6089
|
);
|
|
5725
6090
|
if (!result) {
|
|
5726
6091
|
return {
|
|
@@ -5740,18 +6105,18 @@ var LayerImpl25 = Effect39.gen(function* () {
|
|
|
5740
6105
|
deleteJob
|
|
5741
6106
|
};
|
|
5742
6107
|
});
|
|
5743
|
-
var SchedulerController = class extends
|
|
6108
|
+
var SchedulerController = class extends Context32.Tag("SchedulerController")() {
|
|
5744
6109
|
static {
|
|
5745
|
-
this.Live =
|
|
6110
|
+
this.Live = Layer34.effect(this, LayerImpl26);
|
|
5746
6111
|
}
|
|
5747
6112
|
};
|
|
5748
6113
|
|
|
5749
6114
|
// src/server/core/search/presentation/SearchController.ts
|
|
5750
|
-
import { Context as
|
|
6115
|
+
import { Context as Context34, Effect as Effect43, Layer as Layer36 } from "effect";
|
|
5751
6116
|
|
|
5752
6117
|
// src/server/core/search/services/SearchService.ts
|
|
5753
|
-
import { FileSystem as
|
|
5754
|
-
import { Context as
|
|
6118
|
+
import { FileSystem as FileSystem15, Path as Path18 } from "@effect/platform";
|
|
6119
|
+
import { Context as Context33, Effect as Effect42, Layer as Layer35, Ref as Ref13 } from "effect";
|
|
5755
6120
|
import MiniSearch from "minisearch";
|
|
5756
6121
|
|
|
5757
6122
|
// src/server/core/search/functions/extractSearchableText.ts
|
|
@@ -5797,12 +6162,12 @@ var createMiniSearchIndex = () => new MiniSearch({
|
|
|
5797
6162
|
boost: { text: 1 }
|
|
5798
6163
|
}
|
|
5799
6164
|
});
|
|
5800
|
-
var
|
|
5801
|
-
const fs = yield*
|
|
5802
|
-
const path = yield*
|
|
6165
|
+
var LayerImpl27 = Effect42.gen(function* () {
|
|
6166
|
+
const fs = yield* FileSystem15.FileSystem;
|
|
6167
|
+
const path = yield* Path18.Path;
|
|
5803
6168
|
const context = yield* ApplicationContext;
|
|
5804
|
-
const indexCacheRef = yield*
|
|
5805
|
-
const buildIndex = () =>
|
|
6169
|
+
const indexCacheRef = yield* Ref13.make(null);
|
|
6170
|
+
const buildIndex = () => Effect42.gen(function* () {
|
|
5806
6171
|
const { claudeProjectsDirPath } = yield* context.claudeCodePaths;
|
|
5807
6172
|
const dirExists = yield* fs.exists(claudeProjectsDirPath);
|
|
5808
6173
|
if (!dirExists) {
|
|
@@ -5811,22 +6176,22 @@ var LayerImpl26 = Effect40.gen(function* () {
|
|
|
5811
6176
|
const projectEntries = yield* fs.readDirectory(claudeProjectsDirPath);
|
|
5812
6177
|
const miniSearch = createMiniSearchIndex();
|
|
5813
6178
|
const documentEffects = projectEntries.map(
|
|
5814
|
-
(projectEntry) =>
|
|
6179
|
+
(projectEntry) => Effect42.gen(function* () {
|
|
5815
6180
|
const projectPath = path.resolve(claudeProjectsDirPath, projectEntry);
|
|
5816
|
-
const stat = yield* fs.stat(projectPath).pipe(
|
|
6181
|
+
const stat = yield* fs.stat(projectPath).pipe(Effect42.catchAll(() => Effect42.succeed(null)));
|
|
5817
6182
|
if (stat?.type !== "Directory") {
|
|
5818
6183
|
return [];
|
|
5819
6184
|
}
|
|
5820
6185
|
const projectId = encodeProjectId(projectPath);
|
|
5821
6186
|
const projectName = path.basename(projectPath);
|
|
5822
|
-
const sessionEntries = yield* fs.readDirectory(projectPath).pipe(
|
|
6187
|
+
const sessionEntries = yield* fs.readDirectory(projectPath).pipe(Effect42.catchAll(() => Effect42.succeed([])));
|
|
5823
6188
|
const sessionFiles = sessionEntries.filter(isRegularSessionFile);
|
|
5824
|
-
const sessionDocuments = yield*
|
|
6189
|
+
const sessionDocuments = yield* Effect42.all(
|
|
5825
6190
|
sessionFiles.map(
|
|
5826
|
-
(sessionFile) =>
|
|
6191
|
+
(sessionFile) => Effect42.gen(function* () {
|
|
5827
6192
|
const sessionPath = path.resolve(projectPath, sessionFile);
|
|
5828
6193
|
const sessionId = encodeSessionId(sessionPath);
|
|
5829
|
-
const content = yield* fs.readFileString(sessionPath).pipe(
|
|
6194
|
+
const content = yield* fs.readFileString(sessionPath).pipe(Effect42.catchAll(() => Effect42.succeed("")));
|
|
5830
6195
|
if (!content) return [];
|
|
5831
6196
|
const conversations = parseJsonl(content);
|
|
5832
6197
|
const documents = [];
|
|
@@ -5861,7 +6226,7 @@ var LayerImpl26 = Effect40.gen(function* () {
|
|
|
5861
6226
|
return sessionDocuments.flat();
|
|
5862
6227
|
})
|
|
5863
6228
|
);
|
|
5864
|
-
const allDocuments = yield*
|
|
6229
|
+
const allDocuments = yield* Effect42.all(documentEffects, {
|
|
5865
6230
|
concurrency: 10
|
|
5866
6231
|
});
|
|
5867
6232
|
const flatDocuments = allDocuments.flat();
|
|
@@ -5872,17 +6237,17 @@ var LayerImpl26 = Effect40.gen(function* () {
|
|
|
5872
6237
|
}
|
|
5873
6238
|
return { index: miniSearch, documents: documentsMap };
|
|
5874
6239
|
});
|
|
5875
|
-
const getIndex = () =>
|
|
5876
|
-
const cached = yield*
|
|
6240
|
+
const getIndex = () => Effect42.gen(function* () {
|
|
6241
|
+
const cached = yield* Ref13.get(indexCacheRef);
|
|
5877
6242
|
const now = Date.now();
|
|
5878
6243
|
if (cached && now - cached.builtAt < INDEX_TTL_MS) {
|
|
5879
6244
|
return { index: cached.index, documents: cached.documents };
|
|
5880
6245
|
}
|
|
5881
6246
|
const { index, documents } = yield* buildIndex();
|
|
5882
|
-
yield*
|
|
6247
|
+
yield* Ref13.set(indexCacheRef, { index, documents, builtAt: now });
|
|
5883
6248
|
return { index, documents };
|
|
5884
6249
|
});
|
|
5885
|
-
const search = (query4, limit = 20, projectId) =>
|
|
6250
|
+
const search = (query4, limit = 20, projectId) => Effect42.gen(function* () {
|
|
5886
6251
|
const { claudeProjectsDirPath } = yield* context.claudeCodePaths;
|
|
5887
6252
|
const dirExists = yield* fs.exists(claudeProjectsDirPath);
|
|
5888
6253
|
if (!dirExists) {
|
|
@@ -5923,22 +6288,22 @@ var LayerImpl26 = Effect40.gen(function* () {
|
|
|
5923
6288
|
}
|
|
5924
6289
|
return { results };
|
|
5925
6290
|
});
|
|
5926
|
-
const invalidateIndex = () =>
|
|
6291
|
+
const invalidateIndex = () => Ref13.set(indexCacheRef, null);
|
|
5927
6292
|
return {
|
|
5928
6293
|
search,
|
|
5929
6294
|
invalidateIndex
|
|
5930
6295
|
};
|
|
5931
6296
|
});
|
|
5932
|
-
var SearchService = class extends
|
|
6297
|
+
var SearchService = class extends Context33.Tag("SearchService")() {
|
|
5933
6298
|
static {
|
|
5934
|
-
this.Live =
|
|
6299
|
+
this.Live = Layer35.effect(this, LayerImpl27);
|
|
5935
6300
|
}
|
|
5936
6301
|
};
|
|
5937
6302
|
|
|
5938
6303
|
// src/server/core/search/presentation/SearchController.ts
|
|
5939
|
-
var
|
|
6304
|
+
var LayerImpl28 = Effect43.gen(function* () {
|
|
5940
6305
|
const searchService = yield* SearchService;
|
|
5941
|
-
const search = (options) =>
|
|
6306
|
+
const search = (options) => Effect43.gen(function* () {
|
|
5942
6307
|
const { query: query4, limit, projectId } = options;
|
|
5943
6308
|
if (query4.trim().length < 2) {
|
|
5944
6309
|
return {
|
|
@@ -5962,18 +6327,18 @@ var LayerImpl27 = Effect41.gen(function* () {
|
|
|
5962
6327
|
search
|
|
5963
6328
|
};
|
|
5964
6329
|
});
|
|
5965
|
-
var SearchController = class extends
|
|
6330
|
+
var SearchController = class extends Context34.Tag("SearchController")() {
|
|
5966
6331
|
static {
|
|
5967
|
-
this.Live =
|
|
6332
|
+
this.Live = Layer36.effect(this, LayerImpl28);
|
|
5968
6333
|
}
|
|
5969
6334
|
};
|
|
5970
6335
|
|
|
5971
6336
|
// src/server/core/session/presentation/SessionController.ts
|
|
5972
|
-
import { FileSystem as
|
|
5973
|
-
import { Context as
|
|
6337
|
+
import { FileSystem as FileSystem16 } from "@effect/platform";
|
|
6338
|
+
import { Context as Context35, Effect as Effect45, Layer as Layer37 } from "effect";
|
|
5974
6339
|
|
|
5975
6340
|
// src/server/core/session/services/ExportService.ts
|
|
5976
|
-
import { Effect as
|
|
6341
|
+
import { Effect as Effect44 } from "effect";
|
|
5977
6342
|
var escapeHtml = (text) => {
|
|
5978
6343
|
const map = {
|
|
5979
6344
|
"&": "&",
|
|
@@ -6000,33 +6365,166 @@ var formatTimestamp = (timestamp) => {
|
|
|
6000
6365
|
});
|
|
6001
6366
|
};
|
|
6002
6367
|
var renderMarkdown = (content) => {
|
|
6003
|
-
|
|
6004
|
-
|
|
6368
|
+
const codeBlocks = [];
|
|
6369
|
+
let processedContent = content.replace(
|
|
6005
6370
|
/```(\w+)?\n([\s\S]*?)```/g,
|
|
6006
|
-
(_match, lang, code) =>
|
|
6371
|
+
(_match, lang, code) => {
|
|
6372
|
+
const placeholder = `__CODE_BLOCK_${codeBlocks.length}__`;
|
|
6373
|
+
codeBlocks.push(`
|
|
6007
6374
|
<div class="code-block">
|
|
6008
6375
|
${lang ? `<div class="code-header"><span class="code-lang">${escapeHtml(lang.toUpperCase())}</span></div>` : ""}
|
|
6009
|
-
<pre><code class="language-${escapeHtml(lang || "text")}">${code.trim()}</code></pre>
|
|
6376
|
+
<pre><code class="language-${escapeHtml(lang || "text")}">${escapeHtml(code.trim())}</code></pre>
|
|
6010
6377
|
</div>
|
|
6011
|
-
`
|
|
6378
|
+
`);
|
|
6379
|
+
return placeholder;
|
|
6380
|
+
}
|
|
6381
|
+
);
|
|
6382
|
+
processedContent = processedContent.replace(
|
|
6383
|
+
/(?:^\|.+\|$\n?)+/gm,
|
|
6384
|
+
(tableBlock) => {
|
|
6385
|
+
const rows = tableBlock.trim().split("\n");
|
|
6386
|
+
if (rows.length < 2) return escapeHtml(tableBlock);
|
|
6387
|
+
const headerRow = rows[0];
|
|
6388
|
+
const separatorRow = rows[1];
|
|
6389
|
+
if (!headerRow || !separatorRow || !/^\|[\s\-:|]+\|$/.test(separatorRow)) {
|
|
6390
|
+
return escapeHtml(tableBlock);
|
|
6391
|
+
}
|
|
6392
|
+
const parseRow = (row) => row.split("|").slice(1, -1).map((cell) => cell.trim());
|
|
6393
|
+
const headerCells = parseRow(headerRow);
|
|
6394
|
+
const dataRows = rows.slice(2);
|
|
6395
|
+
let tableHtml = '<table class="markdown-table"><thead><tr>';
|
|
6396
|
+
for (const cell of headerCells) {
|
|
6397
|
+
tableHtml += `<th>${escapeHtml(cell)}</th>`;
|
|
6398
|
+
}
|
|
6399
|
+
tableHtml += "</tr></thead><tbody>";
|
|
6400
|
+
for (const row of dataRows) {
|
|
6401
|
+
const cells = parseRow(row);
|
|
6402
|
+
tableHtml += "<tr>";
|
|
6403
|
+
for (const cell of cells) {
|
|
6404
|
+
tableHtml += `<td>${escapeHtml(cell)}</td>`;
|
|
6405
|
+
}
|
|
6406
|
+
tableHtml += "</tr>";
|
|
6407
|
+
}
|
|
6408
|
+
tableHtml += "</tbody></table>";
|
|
6409
|
+
return tableHtml;
|
|
6410
|
+
}
|
|
6411
|
+
);
|
|
6412
|
+
processedContent = processedContent.split(
|
|
6413
|
+
/(<table class="markdown-table">[\s\S]*?<\/table>|__CODE_BLOCK_\d+__)/
|
|
6414
|
+
).map((part) => {
|
|
6415
|
+
if (part.startsWith('<table class="markdown-table">') || /^__CODE_BLOCK_\d+__$/.test(part)) {
|
|
6416
|
+
return part;
|
|
6417
|
+
}
|
|
6418
|
+
return escapeHtml(part);
|
|
6419
|
+
}).join("");
|
|
6420
|
+
processedContent = processedContent.replace(
|
|
6421
|
+
/(?:^> .+$\n?)+/gm,
|
|
6422
|
+
(quoteBlock) => {
|
|
6423
|
+
const lines = quoteBlock.split("\n").filter((l) => l.trim()).map((l) => l.replace(/^> /, "")).join("<br>");
|
|
6424
|
+
return `<blockquote class="markdown-blockquote">${lines}</blockquote>`;
|
|
6425
|
+
}
|
|
6426
|
+
);
|
|
6427
|
+
processedContent = processedContent.replace(
|
|
6428
|
+
/^(\*{3,}|-{3,}|_{3,})$/gm,
|
|
6429
|
+
'<hr class="markdown-hr">'
|
|
6430
|
+
);
|
|
6431
|
+
processedContent = processedContent.replace(
|
|
6432
|
+
/(?:^- \[([ xX])\] .+$\n?)+/gm,
|
|
6433
|
+
(listBlock) => {
|
|
6434
|
+
const items = listBlock.trim().split("\n").map((line) => {
|
|
6435
|
+
const match = line.match(/^- \[([ xX])\] (.+)$/);
|
|
6436
|
+
if (match?.[1] !== void 0 && match[2] !== void 0) {
|
|
6437
|
+
const checked = match[1].toLowerCase() === "x";
|
|
6438
|
+
return `<li class="task-item"><input type="checkbox" class="task-checkbox" ${checked ? "checked" : ""} disabled>${match[2]}</li>`;
|
|
6439
|
+
}
|
|
6440
|
+
return "";
|
|
6441
|
+
}).join("");
|
|
6442
|
+
return `<ul class="markdown-task-list">${items}</ul>`;
|
|
6443
|
+
}
|
|
6444
|
+
);
|
|
6445
|
+
processedContent = processedContent.replace(
|
|
6446
|
+
/(?:^[-*+] .+$\n?)+/gm,
|
|
6447
|
+
(listBlock) => {
|
|
6448
|
+
const items = listBlock.trim().split("\n").map((line) => {
|
|
6449
|
+
const match = line.match(/^[-*+] (.+)$/);
|
|
6450
|
+
return match ? `<li>${match[1]}</li>` : "";
|
|
6451
|
+
}).join("");
|
|
6452
|
+
return `<ul class="markdown-ul">${items}</ul>`;
|
|
6453
|
+
}
|
|
6454
|
+
);
|
|
6455
|
+
processedContent = processedContent.replace(
|
|
6456
|
+
/(?:^\d+\. .+$\n?)+/gm,
|
|
6457
|
+
(listBlock) => {
|
|
6458
|
+
const items = listBlock.trim().split("\n").map((line) => {
|
|
6459
|
+
const match = line.match(/^\d+\. (.+)$/);
|
|
6460
|
+
return match ? `<li>${match[1]}</li>` : "";
|
|
6461
|
+
}).join("");
|
|
6462
|
+
return `<ol class="markdown-ol">${items}</ol>`;
|
|
6463
|
+
}
|
|
6464
|
+
);
|
|
6465
|
+
processedContent = processedContent.replace(
|
|
6466
|
+
/~~(.+?)~~/g,
|
|
6467
|
+
'<del class="markdown-del">$1</del>'
|
|
6468
|
+
);
|
|
6469
|
+
processedContent = processedContent.replace(
|
|
6470
|
+
/`([^`]+)`/g,
|
|
6471
|
+
'<code class="inline-code">$1</code>'
|
|
6012
6472
|
);
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6473
|
+
processedContent = processedContent.replace(
|
|
6474
|
+
/\*\*(.+?)\*\*/g,
|
|
6475
|
+
"<strong>$1</strong>"
|
|
6476
|
+
);
|
|
6477
|
+
processedContent = processedContent.replace(
|
|
6478
|
+
/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,
|
|
6479
|
+
"<em>$1</em>"
|
|
6480
|
+
);
|
|
6481
|
+
processedContent = processedContent.replace(
|
|
6482
|
+
/^### (.+)$/gm,
|
|
6483
|
+
'<h3 class="markdown-h3">$1</h3>'
|
|
6484
|
+
);
|
|
6485
|
+
processedContent = processedContent.replace(
|
|
6486
|
+
/^## (.+)$/gm,
|
|
6487
|
+
'<h2 class="markdown-h2">$1</h2>'
|
|
6488
|
+
);
|
|
6489
|
+
processedContent = processedContent.replace(
|
|
6490
|
+
/^# (.+)$/gm,
|
|
6491
|
+
'<h1 class="markdown-h1">$1</h1>'
|
|
6492
|
+
);
|
|
6493
|
+
processedContent = processedContent.replace(
|
|
6020
6494
|
/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
6021
6495
|
'<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'
|
|
6022
6496
|
);
|
|
6023
|
-
|
|
6024
|
-
|
|
6497
|
+
const blockElements = [
|
|
6498
|
+
"<h1",
|
|
6499
|
+
"<h2",
|
|
6500
|
+
"<h3",
|
|
6501
|
+
"<div",
|
|
6502
|
+
"<pre",
|
|
6503
|
+
"<table",
|
|
6504
|
+
"<ul",
|
|
6505
|
+
"<ol",
|
|
6506
|
+
"<blockquote",
|
|
6507
|
+
"<hr",
|
|
6508
|
+
"__CODE_BLOCK_"
|
|
6509
|
+
];
|
|
6510
|
+
processedContent = processedContent.split("\n\n").map((para) => {
|
|
6511
|
+
const trimmed = para.trim();
|
|
6512
|
+
if (trimmed === "") return "";
|
|
6513
|
+
if (blockElements.some((tag) => trimmed.startsWith(tag))) {
|
|
6025
6514
|
return para;
|
|
6026
6515
|
}
|
|
6027
6516
|
return `<p class="markdown-p">${para.replace(/\n/g, "<br>")}</p>`;
|
|
6028
|
-
}).join("\n");
|
|
6029
|
-
|
|
6517
|
+
}).filter((p) => p !== "").join("\n");
|
|
6518
|
+
for (let i = 0; i < codeBlocks.length; i++) {
|
|
6519
|
+
const codeBlock = codeBlocks[i];
|
|
6520
|
+
if (codeBlock !== void 0) {
|
|
6521
|
+
processedContent = processedContent.replace(
|
|
6522
|
+
`__CODE_BLOCK_${i}__`,
|
|
6523
|
+
codeBlock
|
|
6524
|
+
);
|
|
6525
|
+
}
|
|
6526
|
+
}
|
|
6527
|
+
return processedContent;
|
|
6030
6528
|
};
|
|
6031
6529
|
var renderUserEntry = (entry) => {
|
|
6032
6530
|
const contentArray = Array.isArray(entry.message.content) ? entry.message.content : [entry.message.content];
|
|
@@ -6063,7 +6561,289 @@ var renderUserEntry = (entry) => {
|
|
|
6063
6561
|
</div>
|
|
6064
6562
|
`;
|
|
6065
6563
|
};
|
|
6066
|
-
var
|
|
6564
|
+
var renderToolResultContent = (result) => {
|
|
6565
|
+
const isError = result.is_error === true;
|
|
6566
|
+
const errorClass = isError ? " tool-result-error" : "";
|
|
6567
|
+
let contentHtml;
|
|
6568
|
+
if (typeof result.content === "string") {
|
|
6569
|
+
contentHtml = `<pre class="tool-result-text">${escapeHtml(result.content)}</pre>`;
|
|
6570
|
+
} else {
|
|
6571
|
+
contentHtml = result.content.map((item) => {
|
|
6572
|
+
if (item.type === "text") {
|
|
6573
|
+
return `<pre class="tool-result-text">${escapeHtml(item.text)}</pre>`;
|
|
6574
|
+
}
|
|
6575
|
+
if (item.type === "image") {
|
|
6576
|
+
return `<img src="data:${item.source.media_type};base64,${item.source.data}" alt="Tool result image" class="tool-result-image" />`;
|
|
6577
|
+
}
|
|
6578
|
+
return "";
|
|
6579
|
+
}).join("");
|
|
6580
|
+
}
|
|
6581
|
+
return `
|
|
6582
|
+
<div class="tool-result-block${errorClass}">
|
|
6583
|
+
<div class="tool-result-header">
|
|
6584
|
+
<svg class="icon-check" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
6585
|
+
${isError ? '<path d="M18 6L6 18M6 6l12 12"/>' : '<path d="M20 6L9 17l-5-5"/>'}
|
|
6586
|
+
</svg>
|
|
6587
|
+
<span class="tool-result-label">${isError ? "Error" : "Result"}</span>
|
|
6588
|
+
</div>
|
|
6589
|
+
<div class="tool-result-content">
|
|
6590
|
+
${contentHtml}
|
|
6591
|
+
</div>
|
|
6592
|
+
</div>
|
|
6593
|
+
`;
|
|
6594
|
+
};
|
|
6595
|
+
var hasAgentId = (toolUseResult) => {
|
|
6596
|
+
return typeof toolUseResult === "object" && toolUseResult !== null && "agentId" in toolUseResult && typeof toolUseResult.agentId === "string";
|
|
6597
|
+
};
|
|
6598
|
+
var buildSidechainData = (conversations) => {
|
|
6599
|
+
const sidechainConversations = conversations.filter(
|
|
6600
|
+
(conv) => conv.type !== "summary" && conv.type !== "file-history-snapshot" && conv.type !== "queue-operation" && conv.type !== "progress" && conv.isSidechain === true
|
|
6601
|
+
);
|
|
6602
|
+
const uuidMap = new Map(
|
|
6603
|
+
sidechainConversations.map((conv) => [conv.uuid, conv])
|
|
6604
|
+
);
|
|
6605
|
+
const getRootConversation = (conv) => {
|
|
6606
|
+
if (conv.parentUuid === null) {
|
|
6607
|
+
return conv;
|
|
6608
|
+
}
|
|
6609
|
+
const parent = uuidMap.get(conv.parentUuid);
|
|
6610
|
+
if (parent === void 0) {
|
|
6611
|
+
return conv;
|
|
6612
|
+
}
|
|
6613
|
+
return getRootConversation(parent);
|
|
6614
|
+
};
|
|
6615
|
+
const groupsByRootUuid = /* @__PURE__ */ new Map();
|
|
6616
|
+
for (const conv of sidechainConversations) {
|
|
6617
|
+
const root = getRootConversation(conv);
|
|
6618
|
+
const existing = groupsByRootUuid.get(root.uuid);
|
|
6619
|
+
if (existing) {
|
|
6620
|
+
existing.push(conv);
|
|
6621
|
+
} else {
|
|
6622
|
+
groupsByRootUuid.set(root.uuid, [conv]);
|
|
6623
|
+
}
|
|
6624
|
+
}
|
|
6625
|
+
for (const [, convs] of groupsByRootUuid) {
|
|
6626
|
+
convs.sort(
|
|
6627
|
+
(a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
|
|
6628
|
+
);
|
|
6629
|
+
}
|
|
6630
|
+
const promptToRoot = /* @__PURE__ */ new Map();
|
|
6631
|
+
for (const conv of sidechainConversations) {
|
|
6632
|
+
if (conv.type === "user" && conv.parentUuid === null && typeof conv.message.content === "string") {
|
|
6633
|
+
promptToRoot.set(conv.message.content, conv);
|
|
6634
|
+
}
|
|
6635
|
+
}
|
|
6636
|
+
const agentIdToRoot = /* @__PURE__ */ new Map();
|
|
6637
|
+
for (const conv of sidechainConversations) {
|
|
6638
|
+
if (conv.parentUuid === null && conv.agentId !== void 0) {
|
|
6639
|
+
agentIdToRoot.set(conv.agentId, conv);
|
|
6640
|
+
}
|
|
6641
|
+
}
|
|
6642
|
+
const toolUseIdToAgentId = /* @__PURE__ */ new Map();
|
|
6643
|
+
for (const conv of conversations) {
|
|
6644
|
+
if (conv.type === "summary" || conv.type === "file-history-snapshot" || conv.type === "queue-operation" || conv.type === "progress") {
|
|
6645
|
+
continue;
|
|
6646
|
+
}
|
|
6647
|
+
if (conv.type !== "user") continue;
|
|
6648
|
+
const messageContent = conv.message.content;
|
|
6649
|
+
if (typeof messageContent === "string") continue;
|
|
6650
|
+
for (const content of messageContent) {
|
|
6651
|
+
if (typeof content === "string") continue;
|
|
6652
|
+
if (content.type === "tool_result") {
|
|
6653
|
+
const toolUseResult = conv.toolUseResult;
|
|
6654
|
+
if (hasAgentId(toolUseResult)) {
|
|
6655
|
+
toolUseIdToAgentId.set(content.tool_use_id, toolUseResult.agentId);
|
|
6656
|
+
}
|
|
6657
|
+
}
|
|
6658
|
+
}
|
|
6659
|
+
}
|
|
6660
|
+
return { groupsByRootUuid, promptToRoot, agentIdToRoot, toolUseIdToAgentId };
|
|
6661
|
+
};
|
|
6662
|
+
var renderSidechainEntry = (entry, toolResultMap, sidechainData) => {
|
|
6663
|
+
if (entry.type === "user") {
|
|
6664
|
+
const contentArray = Array.isArray(entry.message.content) ? entry.message.content : [entry.message.content];
|
|
6665
|
+
const contentHtml = contentArray.map((msg) => {
|
|
6666
|
+
if (typeof msg === "string") {
|
|
6667
|
+
return `<div class="markdown-content">${renderMarkdown(msg)}</div>`;
|
|
6668
|
+
}
|
|
6669
|
+
if (msg.type === "text") {
|
|
6670
|
+
return `<div class="markdown-content">${renderMarkdown(msg.text)}</div>`;
|
|
6671
|
+
}
|
|
6672
|
+
if (msg.type === "tool_result") {
|
|
6673
|
+
return "";
|
|
6674
|
+
}
|
|
6675
|
+
return "";
|
|
6676
|
+
}).join("");
|
|
6677
|
+
if (!contentHtml.trim()) return "";
|
|
6678
|
+
return `
|
|
6679
|
+
<div class="sidechain-entry sidechain-user-entry">
|
|
6680
|
+
<div class="sidechain-entry-header">
|
|
6681
|
+
<span class="sidechain-role">User</span>
|
|
6682
|
+
<span class="sidechain-timestamp">${formatTimestamp(entry.timestamp)}</span>
|
|
6683
|
+
</div>
|
|
6684
|
+
<div class="sidechain-entry-content">${contentHtml}</div>
|
|
6685
|
+
</div>
|
|
6686
|
+
`;
|
|
6687
|
+
}
|
|
6688
|
+
if (entry.type === "assistant") {
|
|
6689
|
+
const contentHtml = entry.message.content.map((msg) => {
|
|
6690
|
+
if (msg.type === "text") {
|
|
6691
|
+
return `<div class="markdown-content">${renderMarkdown(msg.text)}</div>`;
|
|
6692
|
+
}
|
|
6693
|
+
if (msg.type === "thinking") {
|
|
6694
|
+
const charCount = msg.thinking.length;
|
|
6695
|
+
return `
|
|
6696
|
+
<div class="thinking-block collapsible collapsed">
|
|
6697
|
+
<div class="thinking-header collapsible-trigger">
|
|
6698
|
+
<svg class="icon-lightbulb" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
6699
|
+
<path d="M12 2v1m0 18v1m9-10h1M2 12H1m17.66-7.66l.71.71M3.63 20.37l.71.71m0-14.14l-.71.71m17.02 12.73l-.71.71M12 7a5 5 0 0 1 5 5 5 5 0 0 1-1.47 3.53c-.6.6-.94 1.42-.94 2.27V18a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-.2c0-.85-.34-1.67-.94-2.27A5 5 0 0 1 7 12a5 5 0 0 1 5-5Z"/>
|
|
6700
|
+
</svg>
|
|
6701
|
+
<span class="thinking-title">Thinking</span>
|
|
6702
|
+
<span class="expand-hint">(${charCount} chars)</span>
|
|
6703
|
+
<svg class="icon-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
6704
|
+
<polyline points="6 9 12 15 18 9"></polyline>
|
|
6705
|
+
</svg>
|
|
6706
|
+
</div>
|
|
6707
|
+
<div class="thinking-content collapsible-content">
|
|
6708
|
+
<pre class="thinking-text">${escapeHtml(msg.thinking)}</pre>
|
|
6709
|
+
</div>
|
|
6710
|
+
</div>
|
|
6711
|
+
`;
|
|
6712
|
+
}
|
|
6713
|
+
if (msg.type === "tool_use") {
|
|
6714
|
+
const toolResult = toolResultMap.get(msg.id);
|
|
6715
|
+
if (msg.name === "Task") {
|
|
6716
|
+
return renderTaskTool(
|
|
6717
|
+
msg.id,
|
|
6718
|
+
msg.input,
|
|
6719
|
+
toolResult,
|
|
6720
|
+
sidechainData,
|
|
6721
|
+
toolResultMap
|
|
6722
|
+
);
|
|
6723
|
+
}
|
|
6724
|
+
const inputKeys = Object.keys(msg.input).length;
|
|
6725
|
+
const toolResultHtml = toolResult ? renderToolResultContent(toolResult) : "";
|
|
6726
|
+
return `
|
|
6727
|
+
<div class="tool-use-block collapsible collapsed">
|
|
6728
|
+
<div class="tool-use-header collapsible-trigger">
|
|
6729
|
+
<svg class="icon-wrench" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
6730
|
+
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
|
|
6731
|
+
</svg>
|
|
6732
|
+
<span class="tool-name">${escapeHtml(msg.name)}</span>
|
|
6733
|
+
<span class="expand-hint">(${inputKeys} params)</span>
|
|
6734
|
+
<svg class="icon-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
6735
|
+
<polyline points="6 9 12 15 18 9"></polyline>
|
|
6736
|
+
</svg>
|
|
6737
|
+
</div>
|
|
6738
|
+
<div class="tool-use-content collapsible-content">
|
|
6739
|
+
<div class="tool-id"><strong>Tool ID:</strong> <code>${escapeHtml(msg.id)}</code></div>
|
|
6740
|
+
<div class="tool-input">
|
|
6741
|
+
<strong>Input:</strong>
|
|
6742
|
+
<pre class="json-input">${escapeHtml(formatJsonWithNewlines(msg.input))}</pre>
|
|
6743
|
+
</div>
|
|
6744
|
+
${toolResultHtml}
|
|
6745
|
+
</div>
|
|
6746
|
+
</div>
|
|
6747
|
+
`;
|
|
6748
|
+
}
|
|
6749
|
+
return "";
|
|
6750
|
+
}).join("");
|
|
6751
|
+
return `
|
|
6752
|
+
<div class="sidechain-entry sidechain-assistant-entry">
|
|
6753
|
+
<div class="sidechain-entry-header">
|
|
6754
|
+
<span class="sidechain-role">Subagent</span>
|
|
6755
|
+
<span class="sidechain-timestamp">${formatTimestamp(entry.timestamp)}</span>
|
|
6756
|
+
</div>
|
|
6757
|
+
<div class="sidechain-entry-content">${contentHtml}</div>
|
|
6758
|
+
</div>
|
|
6759
|
+
`;
|
|
6760
|
+
}
|
|
6761
|
+
if (entry.type === "system") {
|
|
6762
|
+
const content = "content" in entry && typeof entry.content === "string" ? entry.content : "System message";
|
|
6763
|
+
return `
|
|
6764
|
+
<div class="sidechain-entry sidechain-system-entry">
|
|
6765
|
+
<div class="sidechain-entry-header">
|
|
6766
|
+
<span class="sidechain-role">System</span>
|
|
6767
|
+
<span class="sidechain-timestamp">${formatTimestamp(entry.timestamp)}</span>
|
|
6768
|
+
</div>
|
|
6769
|
+
<div class="sidechain-entry-content">
|
|
6770
|
+
<div class="system-message">${escapeHtml(content)}</div>
|
|
6771
|
+
</div>
|
|
6772
|
+
</div>
|
|
6773
|
+
`;
|
|
6774
|
+
}
|
|
6775
|
+
return "";
|
|
6776
|
+
};
|
|
6777
|
+
var renderTaskTool = (toolId, input, toolResult, sidechainData, toolResultMap) => {
|
|
6778
|
+
const prompt = typeof input.prompt === "string" ? input.prompt : "";
|
|
6779
|
+
const truncatedPrompt = prompt.length > 200 ? `${prompt.slice(0, 200)}...` : prompt;
|
|
6780
|
+
let sidechainConversations = [];
|
|
6781
|
+
const agentId = sidechainData.toolUseIdToAgentId.get(toolId);
|
|
6782
|
+
if (agentId) {
|
|
6783
|
+
const rootByAgentId = sidechainData.agentIdToRoot.get(agentId);
|
|
6784
|
+
if (rootByAgentId) {
|
|
6785
|
+
const convs = sidechainData.groupsByRootUuid.get(rootByAgentId.uuid);
|
|
6786
|
+
if (convs) {
|
|
6787
|
+
sidechainConversations = convs;
|
|
6788
|
+
}
|
|
6789
|
+
}
|
|
6790
|
+
}
|
|
6791
|
+
if (sidechainConversations.length === 0) {
|
|
6792
|
+
const rootConversation = sidechainData.promptToRoot.get(prompt);
|
|
6793
|
+
if (rootConversation) {
|
|
6794
|
+
const convs = sidechainData.groupsByRootUuid.get(rootConversation.uuid);
|
|
6795
|
+
if (convs) {
|
|
6796
|
+
sidechainConversations = convs;
|
|
6797
|
+
}
|
|
6798
|
+
}
|
|
6799
|
+
}
|
|
6800
|
+
const hasSidechain = sidechainConversations.length > 0;
|
|
6801
|
+
const sidechainHtml = hasSidechain ? `
|
|
6802
|
+
<div class="sidechain-container collapsible">
|
|
6803
|
+
<div class="sidechain-header collapsible-trigger">
|
|
6804
|
+
<svg class="icon-layers" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
6805
|
+
<polygon points="12 2 2 7 12 12 22 7 12 2"/>
|
|
6806
|
+
<polyline points="2 17 12 22 22 17"/>
|
|
6807
|
+
<polyline points="2 12 12 17 22 12"/>
|
|
6808
|
+
</svg>
|
|
6809
|
+
<span>Subagent Work Log (${sidechainConversations.length} entries)</span>
|
|
6810
|
+
<svg class="icon-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
6811
|
+
<polyline points="6 9 12 15 18 9"></polyline>
|
|
6812
|
+
</svg>
|
|
6813
|
+
</div>
|
|
6814
|
+
<div class="sidechain-content collapsible-content">
|
|
6815
|
+
${sidechainConversations.map(
|
|
6816
|
+
(conv) => renderSidechainEntry(conv, toolResultMap, sidechainData)
|
|
6817
|
+
).filter((html) => html !== "").join("\n")}
|
|
6818
|
+
</div>
|
|
6819
|
+
</div>
|
|
6820
|
+
` : "";
|
|
6821
|
+
return `
|
|
6822
|
+
<div class="task-tool-block collapsible">
|
|
6823
|
+
<div class="task-tool-header collapsible-trigger">
|
|
6824
|
+
<svg class="icon-task" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
6825
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
|
|
6826
|
+
<path d="M9 12l2 2 4-4"/>
|
|
6827
|
+
</svg>
|
|
6828
|
+
<span class="task-tool-name">Task${hasSidechain ? ` (${sidechainConversations.length} steps)` : ""}</span>
|
|
6829
|
+
<span class="task-prompt-preview">${escapeHtml(truncatedPrompt)}</span>
|
|
6830
|
+
<svg class="icon-chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
6831
|
+
<polyline points="6 9 12 15 18 9"></polyline>
|
|
6832
|
+
</svg>
|
|
6833
|
+
</div>
|
|
6834
|
+
<div class="task-tool-content collapsible-content">
|
|
6835
|
+
<div class="task-tool-id"><strong>Task ID:</strong> <code>${escapeHtml(toolId)}</code></div>
|
|
6836
|
+
<div class="task-prompt">
|
|
6837
|
+
<strong>Prompt:</strong>
|
|
6838
|
+
<div class="task-prompt-text">${renderMarkdown(prompt)}</div>
|
|
6839
|
+
</div>
|
|
6840
|
+
${toolResult ? renderToolResultContent(toolResult) : ""}
|
|
6841
|
+
${sidechainHtml}
|
|
6842
|
+
</div>
|
|
6843
|
+
</div>
|
|
6844
|
+
`;
|
|
6845
|
+
};
|
|
6846
|
+
var renderAssistantEntry = (entry, toolResultMap, sidechainData) => {
|
|
6067
6847
|
const contentHtml = entry.message.content.map((msg) => {
|
|
6068
6848
|
if (msg.type === "text") {
|
|
6069
6849
|
return `<div class="markdown-content">${renderMarkdown(msg.text)}</div>`;
|
|
@@ -6089,7 +6869,18 @@ var renderAssistantEntry = (entry) => {
|
|
|
6089
6869
|
`;
|
|
6090
6870
|
}
|
|
6091
6871
|
if (msg.type === "tool_use") {
|
|
6872
|
+
const toolResult = toolResultMap.get(msg.id);
|
|
6873
|
+
if (msg.name === "Task") {
|
|
6874
|
+
return renderTaskTool(
|
|
6875
|
+
msg.id,
|
|
6876
|
+
msg.input,
|
|
6877
|
+
toolResult,
|
|
6878
|
+
sidechainData,
|
|
6879
|
+
toolResultMap
|
|
6880
|
+
);
|
|
6881
|
+
}
|
|
6092
6882
|
const inputKeys = Object.keys(msg.input).length;
|
|
6883
|
+
const toolResultHtml = toolResult ? renderToolResultContent(toolResult) : "";
|
|
6093
6884
|
return `
|
|
6094
6885
|
<div class="tool-use-block collapsible">
|
|
6095
6886
|
<div class="tool-use-header collapsible-trigger">
|
|
@@ -6108,6 +6899,7 @@ var renderAssistantEntry = (entry) => {
|
|
|
6108
6899
|
<strong>Input Parameters:</strong>
|
|
6109
6900
|
<pre class="json-input">${escapeHtml(formatJsonWithNewlines(msg.input))}</pre>
|
|
6110
6901
|
</div>
|
|
6902
|
+
${toolResultHtml}
|
|
6111
6903
|
</div>
|
|
6112
6904
|
</div>
|
|
6113
6905
|
`;
|
|
@@ -6175,7 +6967,7 @@ var groupConsecutiveAssistantMessages = (conversations) => {
|
|
|
6175
6967
|
}
|
|
6176
6968
|
return grouped;
|
|
6177
6969
|
};
|
|
6178
|
-
var renderGroupedAssistantEntries = (entries) => {
|
|
6970
|
+
var renderGroupedAssistantEntries = (entries, toolResultMap, sidechainData) => {
|
|
6179
6971
|
const allContent = entries.flatMap((entry) => entry.message.content);
|
|
6180
6972
|
const firstEntry = entries[0];
|
|
6181
6973
|
if (!firstEntry) {
|
|
@@ -6206,7 +6998,18 @@ var renderGroupedAssistantEntries = (entries) => {
|
|
|
6206
6998
|
`;
|
|
6207
6999
|
}
|
|
6208
7000
|
if (msg.type === "tool_use") {
|
|
7001
|
+
const toolResult = toolResultMap.get(msg.id);
|
|
7002
|
+
if (msg.name === "Task") {
|
|
7003
|
+
return renderTaskTool(
|
|
7004
|
+
msg.id,
|
|
7005
|
+
msg.input,
|
|
7006
|
+
toolResult,
|
|
7007
|
+
sidechainData,
|
|
7008
|
+
toolResultMap
|
|
7009
|
+
);
|
|
7010
|
+
}
|
|
6209
7011
|
const inputKeys = Object.keys(msg.input).length;
|
|
7012
|
+
const toolResultHtml = toolResult ? renderToolResultContent(toolResult) : "";
|
|
6210
7013
|
return `
|
|
6211
7014
|
<div class="tool-use-block collapsible">
|
|
6212
7015
|
<div class="tool-use-header collapsible-trigger">
|
|
@@ -6225,6 +7028,7 @@ var renderGroupedAssistantEntries = (entries) => {
|
|
|
6225
7028
|
<strong>Input Parameters:</strong>
|
|
6226
7029
|
<pre class="json-input">${escapeHtml(formatJsonWithNewlines(msg.input))}</pre>
|
|
6227
7030
|
</div>
|
|
7031
|
+
${toolResultHtml}
|
|
6228
7032
|
</div>
|
|
6229
7033
|
</div>
|
|
6230
7034
|
`;
|
|
@@ -6243,12 +7047,88 @@ var renderGroupedAssistantEntries = (entries) => {
|
|
|
6243
7047
|
</div>
|
|
6244
7048
|
`;
|
|
6245
7049
|
};
|
|
6246
|
-
var generateSessionHtml = (session, projectId) =>
|
|
7050
|
+
var generateSessionHtml = (session, projectId, agentSessionRepo) => Effect44.gen(function* () {
|
|
7051
|
+
const agentIds = /* @__PURE__ */ new Set();
|
|
7052
|
+
for (const conv of session.conversations) {
|
|
7053
|
+
if (conv.type !== "user" || typeof conv.message.content === "string") {
|
|
7054
|
+
continue;
|
|
7055
|
+
}
|
|
7056
|
+
for (const content of conv.message.content) {
|
|
7057
|
+
if (typeof content === "string") continue;
|
|
7058
|
+
if (content.type === "tool_result") {
|
|
7059
|
+
const toolUseResult = conv.toolUseResult;
|
|
7060
|
+
if (hasAgentId(toolUseResult)) {
|
|
7061
|
+
agentIds.add(toolUseResult.agentId);
|
|
7062
|
+
}
|
|
7063
|
+
}
|
|
7064
|
+
}
|
|
7065
|
+
}
|
|
7066
|
+
const existingAgentIds = /* @__PURE__ */ new Set();
|
|
7067
|
+
for (const conv of session.conversations) {
|
|
7068
|
+
if (conv.type === "x-error") continue;
|
|
7069
|
+
if (conv.type !== "summary" && conv.type !== "file-history-snapshot" && conv.type !== "queue-operation" && conv.type !== "progress" && conv.isSidechain === true && conv.agentId !== void 0) {
|
|
7070
|
+
existingAgentIds.add(conv.agentId);
|
|
7071
|
+
}
|
|
7072
|
+
}
|
|
7073
|
+
const missingAgentIds = Array.from(agentIds).filter(
|
|
7074
|
+
(id) => !existingAgentIds.has(id)
|
|
7075
|
+
);
|
|
7076
|
+
const loadedConversations = [];
|
|
7077
|
+
if (missingAgentIds.length > 0) {
|
|
7078
|
+
const loadedSessions = yield* Effect44.all(
|
|
7079
|
+
missingAgentIds.map(
|
|
7080
|
+
(agentId) => agentSessionRepo.getAgentSessionByAgentId(
|
|
7081
|
+
projectId,
|
|
7082
|
+
agentId,
|
|
7083
|
+
session.id
|
|
7084
|
+
)
|
|
7085
|
+
),
|
|
7086
|
+
{ concurrency: 5 }
|
|
7087
|
+
);
|
|
7088
|
+
for (const sess of loadedSessions) {
|
|
7089
|
+
if (sess) {
|
|
7090
|
+
const validConvs = sess.filter(
|
|
7091
|
+
(c) => c.type === "user" || c.type === "assistant" || c.type === "system"
|
|
7092
|
+
);
|
|
7093
|
+
loadedConversations.push(
|
|
7094
|
+
...validConvs.map((c) => ({
|
|
7095
|
+
...c,
|
|
7096
|
+
isSidechain: true
|
|
7097
|
+
// Ensure they are marked as sidechain
|
|
7098
|
+
}))
|
|
7099
|
+
);
|
|
7100
|
+
}
|
|
7101
|
+
}
|
|
7102
|
+
}
|
|
7103
|
+
const allConversations = [
|
|
7104
|
+
...session.conversations.filter(
|
|
7105
|
+
(conv) => conv.type !== "x-error"
|
|
7106
|
+
),
|
|
7107
|
+
...loadedConversations
|
|
7108
|
+
];
|
|
7109
|
+
const sidechainData = buildSidechainData(allConversations);
|
|
7110
|
+
const toolResultMap = /* @__PURE__ */ new Map();
|
|
7111
|
+
for (const conv of allConversations) {
|
|
7112
|
+
if (conv.type === "summary" || conv.type === "file-history-snapshot" || conv.type === "queue-operation" || conv.type === "progress") {
|
|
7113
|
+
continue;
|
|
7114
|
+
}
|
|
7115
|
+
if (conv.type !== "user") continue;
|
|
7116
|
+
const content = conv.message.content;
|
|
7117
|
+
if (typeof content === "string") continue;
|
|
7118
|
+
for (const msg of content) {
|
|
7119
|
+
if (typeof msg === "string") continue;
|
|
7120
|
+
if (msg.type === "tool_result") {
|
|
7121
|
+
toolResultMap.set(msg.tool_use_id, msg);
|
|
7122
|
+
}
|
|
7123
|
+
}
|
|
7124
|
+
}
|
|
6247
7125
|
const grouped = groupConsecutiveAssistantMessages(session.conversations);
|
|
6248
7126
|
const conversationsHtml = grouped.map((group) => {
|
|
6249
7127
|
if (group.type === "grouped") {
|
|
6250
7128
|
return renderGroupedAssistantEntries(
|
|
6251
|
-
group.entries
|
|
7129
|
+
group.entries,
|
|
7130
|
+
toolResultMap,
|
|
7131
|
+
sidechainData
|
|
6252
7132
|
);
|
|
6253
7133
|
}
|
|
6254
7134
|
const conv = group.entries[0];
|
|
@@ -6259,7 +7139,7 @@ var generateSessionHtml = (session, projectId) => Effect42.gen(function* () {
|
|
|
6259
7139
|
return renderUserEntry(conv);
|
|
6260
7140
|
}
|
|
6261
7141
|
if (conv.type === "assistant") {
|
|
6262
|
-
return renderAssistantEntry(conv);
|
|
7142
|
+
return renderAssistantEntry(conv, toolResultMap, sidechainData);
|
|
6263
7143
|
}
|
|
6264
7144
|
if (conv.type === "system") {
|
|
6265
7145
|
return renderSystemEntry(conv);
|
|
@@ -6422,7 +7302,7 @@ var generateSessionHtml = (session, projectId) => Effect42.gen(function* () {
|
|
|
6422
7302
|
.markdown-p {
|
|
6423
7303
|
margin-bottom: 1rem;
|
|
6424
7304
|
line-height: 1.75;
|
|
6425
|
-
word-break: break-
|
|
7305
|
+
word-break: break-word;
|
|
6426
7306
|
}
|
|
6427
7307
|
|
|
6428
7308
|
.inline-code {
|
|
@@ -6536,7 +7416,6 @@ var generateSessionHtml = (session, projectId) => Effect42.gen(function* () {
|
|
|
6536
7416
|
}
|
|
6537
7417
|
|
|
6538
7418
|
.collapsible-content {
|
|
6539
|
-
max-height: 1000px;
|
|
6540
7419
|
overflow: hidden;
|
|
6541
7420
|
transition: max-height 0.3s ease-out, opacity 0.2s ease-out;
|
|
6542
7421
|
}
|
|
@@ -6692,9 +7571,328 @@ var generateSessionHtml = (session, projectId) => Effect42.gen(function* () {
|
|
|
6692
7571
|
color: hsl(var(--muted-foreground));
|
|
6693
7572
|
font-size: 0.875rem;
|
|
6694
7573
|
}
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
7574
|
+
|
|
7575
|
+
/* Enhanced Markdown Styles */
|
|
7576
|
+
.markdown-table {
|
|
7577
|
+
width: 100%;
|
|
7578
|
+
border-collapse: collapse;
|
|
7579
|
+
margin: 1rem 0;
|
|
7580
|
+
font-size: 0.875rem;
|
|
7581
|
+
}
|
|
7582
|
+
|
|
7583
|
+
.markdown-table th,
|
|
7584
|
+
.markdown-table td {
|
|
7585
|
+
border: 1px solid hsl(var(--border));
|
|
7586
|
+
padding: 0.5rem 0.75rem;
|
|
7587
|
+
text-align: left;
|
|
7588
|
+
}
|
|
7589
|
+
|
|
7590
|
+
.markdown-table th {
|
|
7591
|
+
background: hsl(var(--muted) / 0.5);
|
|
7592
|
+
font-weight: 600;
|
|
7593
|
+
}
|
|
7594
|
+
|
|
7595
|
+
.markdown-table tr:nth-child(even) {
|
|
7596
|
+
background: hsl(var(--muted) / 0.2);
|
|
7597
|
+
}
|
|
7598
|
+
|
|
7599
|
+
.markdown-blockquote {
|
|
7600
|
+
border-left: 4px solid hsl(var(--blue-600));
|
|
7601
|
+
padding: 0.75rem 1rem;
|
|
7602
|
+
margin: 1rem 0;
|
|
7603
|
+
background: hsl(var(--muted) / 0.3);
|
|
7604
|
+
color: hsl(var(--muted-foreground));
|
|
7605
|
+
font-style: italic;
|
|
7606
|
+
}
|
|
7607
|
+
|
|
7608
|
+
.markdown-ul,
|
|
7609
|
+
.markdown-ol {
|
|
7610
|
+
margin: 1rem 0;
|
|
7611
|
+
padding-left: 1.5rem;
|
|
7612
|
+
}
|
|
7613
|
+
|
|
7614
|
+
.markdown-ul li,
|
|
7615
|
+
.markdown-ol li {
|
|
7616
|
+
margin-bottom: 0.25rem;
|
|
7617
|
+
line-height: 1.6;
|
|
7618
|
+
}
|
|
7619
|
+
|
|
7620
|
+
.markdown-task-list {
|
|
7621
|
+
list-style: none;
|
|
7622
|
+
padding-left: 0;
|
|
7623
|
+
margin: 1rem 0;
|
|
7624
|
+
}
|
|
7625
|
+
|
|
7626
|
+
.task-item {
|
|
7627
|
+
display: flex;
|
|
7628
|
+
align-items: flex-start;
|
|
7629
|
+
gap: 0.5rem;
|
|
7630
|
+
margin-bottom: 0.25rem;
|
|
7631
|
+
}
|
|
7632
|
+
|
|
7633
|
+
.task-checkbox {
|
|
7634
|
+
margin-top: 0.25rem;
|
|
7635
|
+
width: 1rem;
|
|
7636
|
+
height: 1rem;
|
|
7637
|
+
accent-color: hsl(var(--blue-600));
|
|
7638
|
+
}
|
|
7639
|
+
|
|
7640
|
+
.markdown-hr {
|
|
7641
|
+
border: none;
|
|
7642
|
+
border-top: 2px solid hsl(var(--border));
|
|
7643
|
+
margin: 2rem 0;
|
|
7644
|
+
}
|
|
7645
|
+
|
|
7646
|
+
.markdown-del {
|
|
7647
|
+
text-decoration: line-through;
|
|
7648
|
+
color: hsl(var(--muted-foreground));
|
|
7649
|
+
}
|
|
7650
|
+
|
|
7651
|
+
/* Tool Result Styles */
|
|
7652
|
+
.tool-result-block {
|
|
7653
|
+
margin-top: 0.75rem;
|
|
7654
|
+
border: 1px solid hsl(var(--border));
|
|
7655
|
+
border-radius: 0.375rem;
|
|
7656
|
+
overflow: scroll;
|
|
7657
|
+
}
|
|
7658
|
+
|
|
7659
|
+
.tool-result-error {
|
|
7660
|
+
border-color: hsl(0 84% 60%);
|
|
7661
|
+
}
|
|
7662
|
+
|
|
7663
|
+
.tool-result-header {
|
|
7664
|
+
display: flex;
|
|
7665
|
+
align-items: center;
|
|
7666
|
+
gap: 0.5rem;
|
|
7667
|
+
padding: 0.375rem 0.75rem;
|
|
7668
|
+
background: hsl(var(--muted) / 0.3);
|
|
7669
|
+
font-size: 0.75rem;
|
|
7670
|
+
font-weight: 500;
|
|
7671
|
+
}
|
|
7672
|
+
|
|
7673
|
+
.tool-result-error .tool-result-header {
|
|
7674
|
+
background: hsl(0 84% 60% / 0.1);
|
|
7675
|
+
color: hsl(0 84% 40%);
|
|
7676
|
+
}
|
|
7677
|
+
|
|
7678
|
+
.icon-check {
|
|
7679
|
+
flex-shrink: 0;
|
|
7680
|
+
color: hsl(142 76% 36%);
|
|
7681
|
+
}
|
|
7682
|
+
|
|
7683
|
+
.tool-result-error .icon-check {
|
|
7684
|
+
color: hsl(0 84% 60%);
|
|
7685
|
+
}
|
|
7686
|
+
|
|
7687
|
+
.tool-result-label {
|
|
7688
|
+
font-weight: 500;
|
|
7689
|
+
}
|
|
7690
|
+
|
|
7691
|
+
.tool-result-content {
|
|
7692
|
+
padding: 0.75rem;
|
|
7693
|
+
background: hsl(var(--background));
|
|
7694
|
+
}
|
|
7695
|
+
|
|
7696
|
+
.tool-result-text {
|
|
7697
|
+
font-family: monospace;
|
|
7698
|
+
font-size: 0.75rem;
|
|
7699
|
+
white-space: pre-wrap;
|
|
7700
|
+
word-break: break-word;
|
|
7701
|
+
overflow-wrap: break-word;
|
|
7702
|
+
margin: 0;
|
|
7703
|
+
}
|
|
7704
|
+
|
|
7705
|
+
.tool-result-image {
|
|
7706
|
+
max-width: 100%;
|
|
7707
|
+
height: auto;
|
|
7708
|
+
border-radius: 0.25rem;
|
|
7709
|
+
}
|
|
7710
|
+
|
|
7711
|
+
/* Task Tool Styles */
|
|
7712
|
+
.task-tool-block {
|
|
7713
|
+
border: 1px solid hsl(142 76% 36% / 0.3);
|
|
7714
|
+
background: hsl(142 76% 36% / 0.05);
|
|
7715
|
+
border-radius: 0.5rem;
|
|
7716
|
+
margin-bottom: 0.5rem;
|
|
7717
|
+
overflow: hidden;
|
|
7718
|
+
}
|
|
7719
|
+
|
|
7720
|
+
.task-tool-header {
|
|
7721
|
+
display: flex;
|
|
7722
|
+
align-items: center;
|
|
7723
|
+
gap: 0.5rem;
|
|
7724
|
+
padding: 0.5rem 0.75rem;
|
|
7725
|
+
cursor: pointer;
|
|
7726
|
+
background: hsl(142 76% 36% / 0.1);
|
|
7727
|
+
transition: background 0.2s;
|
|
7728
|
+
}
|
|
7729
|
+
|
|
7730
|
+
.task-tool-header:hover {
|
|
7731
|
+
background: hsl(142 76% 36% / 0.15);
|
|
7732
|
+
}
|
|
7733
|
+
|
|
7734
|
+
.icon-task {
|
|
7735
|
+
color: hsl(142 76% 36%);
|
|
7736
|
+
flex-shrink: 0;
|
|
7737
|
+
}
|
|
7738
|
+
|
|
7739
|
+
.task-tool-name {
|
|
7740
|
+
font-size: 0.875rem;
|
|
7741
|
+
font-weight: 600;
|
|
7742
|
+
color: hsl(142 76% 30%);
|
|
7743
|
+
}
|
|
7744
|
+
|
|
7745
|
+
.task-prompt-preview {
|
|
7746
|
+
flex: 1;
|
|
7747
|
+
font-size: 0.75rem;
|
|
7748
|
+
color: hsl(var(--muted-foreground));
|
|
7749
|
+
overflow: hidden;
|
|
7750
|
+
text-overflow: ellipsis;
|
|
7751
|
+
white-space: nowrap;
|
|
7752
|
+
}
|
|
7753
|
+
|
|
7754
|
+
.task-tool-content {
|
|
7755
|
+
padding: 0.75rem 1rem;
|
|
7756
|
+
border-top: 1px solid hsl(142 76% 36% / 0.2);
|
|
7757
|
+
display: flex;
|
|
7758
|
+
flex-direction: column;
|
|
7759
|
+
gap: 0.75rem;
|
|
7760
|
+
}
|
|
7761
|
+
|
|
7762
|
+
.task-tool-id {
|
|
7763
|
+
font-size: 0.75rem;
|
|
7764
|
+
}
|
|
7765
|
+
|
|
7766
|
+
.task-tool-id code {
|
|
7767
|
+
background: hsl(var(--background) / 0.5);
|
|
7768
|
+
padding: 0.25rem 0.5rem;
|
|
7769
|
+
border-radius: 0.25rem;
|
|
7770
|
+
border: 1px solid hsl(142 76% 36% / 0.2);
|
|
7771
|
+
font-family: monospace;
|
|
7772
|
+
font-size: 0.75rem;
|
|
7773
|
+
}
|
|
7774
|
+
|
|
7775
|
+
.task-prompt {
|
|
7776
|
+
font-size: 0.875rem;
|
|
7777
|
+
}
|
|
7778
|
+
|
|
7779
|
+
.task-prompt-text {
|
|
7780
|
+
background: hsl(var(--background));
|
|
7781
|
+
border: 1px solid hsl(var(--border));
|
|
7782
|
+
border-radius: 0.375rem;
|
|
7783
|
+
padding: 0.75rem;
|
|
7784
|
+
margin-top: 0.5rem;
|
|
7785
|
+
}
|
|
7786
|
+
|
|
7787
|
+
/* Sidechain / Subagent Styles */
|
|
7788
|
+
.sidechain-container {
|
|
7789
|
+
margin-top: 1rem;
|
|
7790
|
+
border: 1px solid hsl(217 91% 60% / 0.3);
|
|
7791
|
+
border-radius: 0.5rem;
|
|
7792
|
+
overflow: hidden;
|
|
7793
|
+
}
|
|
7794
|
+
|
|
7795
|
+
.sidechain-header {
|
|
7796
|
+
display: flex;
|
|
7797
|
+
align-items: center;
|
|
7798
|
+
gap: 0.5rem;
|
|
7799
|
+
padding: 0.5rem 0.75rem;
|
|
7800
|
+
background: hsl(217 91% 60% / 0.1);
|
|
7801
|
+
color: hsl(217 91% 40%);
|
|
7802
|
+
font-size: 0.8rem;
|
|
7803
|
+
font-weight: 500;
|
|
7804
|
+
cursor: pointer;
|
|
7805
|
+
}
|
|
7806
|
+
|
|
7807
|
+
.sidechain-header:hover {
|
|
7808
|
+
background: hsl(217 91% 60% / 0.15);
|
|
7809
|
+
}
|
|
7810
|
+
|
|
7811
|
+
.icon-layers {
|
|
7812
|
+
flex-shrink: 0;
|
|
7813
|
+
}
|
|
7814
|
+
|
|
7815
|
+
.sidechain-content {
|
|
7816
|
+
padding: 0.75rem;
|
|
7817
|
+
background: hsl(217 91% 60% / 0.02);
|
|
7818
|
+
border-top: 1px solid hsl(217 91% 60% / 0.2);
|
|
7819
|
+
}
|
|
7820
|
+
|
|
7821
|
+
.sidechain-entry {
|
|
7822
|
+
margin-left: 1rem;
|
|
7823
|
+
padding: 0.5rem 0.75rem;
|
|
7824
|
+
border-left: 2px solid hsl(217 91% 60% / 0.3);
|
|
7825
|
+
margin-bottom: 0.5rem;
|
|
7826
|
+
}
|
|
7827
|
+
|
|
7828
|
+
.sidechain-entry:last-child {
|
|
7829
|
+
margin-bottom: 0;
|
|
7830
|
+
}
|
|
7831
|
+
|
|
7832
|
+
.sidechain-entry-header {
|
|
7833
|
+
display: flex;
|
|
7834
|
+
align-items: center;
|
|
7835
|
+
gap: 0.5rem;
|
|
7836
|
+
margin-bottom: 0.25rem;
|
|
7837
|
+
font-size: 0.75rem;
|
|
7838
|
+
}
|
|
7839
|
+
|
|
7840
|
+
.sidechain-role {
|
|
7841
|
+
font-weight: 600;
|
|
7842
|
+
padding: 0.125rem 0.375rem;
|
|
7843
|
+
border-radius: 0.25rem;
|
|
7844
|
+
}
|
|
7845
|
+
|
|
7846
|
+
.sidechain-user-entry .sidechain-role {
|
|
7847
|
+
background: hsl(var(--muted));
|
|
7848
|
+
color: hsl(var(--foreground));
|
|
7849
|
+
}
|
|
7850
|
+
|
|
7851
|
+
.sidechain-assistant-entry .sidechain-role {
|
|
7852
|
+
background: hsl(217 91% 60% / 0.1);
|
|
7853
|
+
color: hsl(217 91% 40%);
|
|
7854
|
+
}
|
|
7855
|
+
|
|
7856
|
+
.sidechain-system-entry .sidechain-role {
|
|
7857
|
+
background: hsl(var(--muted) / 0.5);
|
|
7858
|
+
color: hsl(var(--muted-foreground));
|
|
7859
|
+
}
|
|
7860
|
+
|
|
7861
|
+
.sidechain-timestamp {
|
|
7862
|
+
color: hsl(var(--muted-foreground));
|
|
7863
|
+
}
|
|
7864
|
+
|
|
7865
|
+
.sidechain-entry-content {
|
|
7866
|
+
font-size: 0.875rem;
|
|
7867
|
+
}
|
|
7868
|
+
|
|
7869
|
+
.sidechain-entry .thinking-block,
|
|
7870
|
+
.sidechain-entry .tool-use-block {
|
|
7871
|
+
margin: 0.5rem 0;
|
|
7872
|
+
font-size: 0.8rem;
|
|
7873
|
+
}
|
|
7874
|
+
|
|
7875
|
+
.sidechain-entry .thinking-header,
|
|
7876
|
+
.sidechain-entry .tool-use-header {
|
|
7877
|
+
padding: 0.375rem 0.5rem;
|
|
7878
|
+
}
|
|
7879
|
+
|
|
7880
|
+
.sidechain-entry .thinking-content,
|
|
7881
|
+
.sidechain-entry .tool-use-content {
|
|
7882
|
+
padding: 0.5rem;
|
|
7883
|
+
}
|
|
7884
|
+
|
|
7885
|
+
/* Optimize content display */
|
|
7886
|
+
.entry-content > *:first-child {
|
|
7887
|
+
margin-top: 0;
|
|
7888
|
+
}
|
|
7889
|
+
|
|
7890
|
+
.entry-content > *:last-child {
|
|
7891
|
+
margin-bottom: 0;
|
|
7892
|
+
}
|
|
7893
|
+
</style>
|
|
7894
|
+
</head>
|
|
7895
|
+
<body>
|
|
6698
7896
|
<div class="header">
|
|
6699
7897
|
<div class="header-top">
|
|
6700
7898
|
<h1>Claude Code Session Export</h1>
|
|
@@ -6763,11 +7961,12 @@ var generateSessionHtml = (session, projectId) => Effect42.gen(function* () {
|
|
|
6763
7961
|
});
|
|
6764
7962
|
|
|
6765
7963
|
// src/server/core/session/presentation/SessionController.ts
|
|
6766
|
-
var
|
|
7964
|
+
var LayerImpl29 = Effect45.gen(function* () {
|
|
6767
7965
|
const sessionRepository = yield* SessionRepository;
|
|
6768
|
-
const
|
|
7966
|
+
const agentSessionRepository = yield* AgentSessionRepository;
|
|
7967
|
+
const fs = yield* FileSystem16.FileSystem;
|
|
6769
7968
|
const eventBus = yield* EventBus;
|
|
6770
|
-
const getSession = (options) =>
|
|
7969
|
+
const getSession = (options) => Effect45.gen(function* () {
|
|
6771
7970
|
const { projectId, sessionId } = options;
|
|
6772
7971
|
const { session } = yield* sessionRepository.getSession(
|
|
6773
7972
|
projectId,
|
|
@@ -6778,7 +7977,7 @@ var LayerImpl28 = Effect43.gen(function* () {
|
|
|
6778
7977
|
response: { session }
|
|
6779
7978
|
};
|
|
6780
7979
|
});
|
|
6781
|
-
const exportSessionHtml = (options) =>
|
|
7980
|
+
const exportSessionHtml = (options) => Effect45.gen(function* () {
|
|
6782
7981
|
const { projectId, sessionId } = options;
|
|
6783
7982
|
const { session } = yield* sessionRepository.getSession(
|
|
6784
7983
|
projectId,
|
|
@@ -6790,13 +7989,17 @@ var LayerImpl28 = Effect43.gen(function* () {
|
|
|
6790
7989
|
response: { error: "Session not found" }
|
|
6791
7990
|
};
|
|
6792
7991
|
}
|
|
6793
|
-
const html = yield* generateSessionHtml(
|
|
7992
|
+
const html = yield* generateSessionHtml(
|
|
7993
|
+
session,
|
|
7994
|
+
projectId,
|
|
7995
|
+
agentSessionRepository
|
|
7996
|
+
);
|
|
6794
7997
|
return {
|
|
6795
7998
|
status: 200,
|
|
6796
7999
|
response: { html }
|
|
6797
8000
|
};
|
|
6798
8001
|
});
|
|
6799
|
-
const deleteSession = (options) =>
|
|
8002
|
+
const deleteSession = (options) => Effect45.gen(function* () {
|
|
6800
8003
|
const { projectId, sessionId } = options;
|
|
6801
8004
|
const sessionPath = decodeSessionId(projectId, sessionId);
|
|
6802
8005
|
const exists = yield* fs.exists(sessionPath);
|
|
@@ -6807,9 +8010,9 @@ var LayerImpl28 = Effect43.gen(function* () {
|
|
|
6807
8010
|
};
|
|
6808
8011
|
}
|
|
6809
8012
|
const deleteResult = yield* fs.remove(sessionPath).pipe(
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
(error) =>
|
|
8013
|
+
Effect45.map(() => ({ success: true, error: null })),
|
|
8014
|
+
Effect45.catchAll(
|
|
8015
|
+
(error) => Effect45.succeed({
|
|
6813
8016
|
success: false,
|
|
6814
8017
|
error: `Failed to delete session: ${error.message}`
|
|
6815
8018
|
})
|
|
@@ -6833,9 +8036,347 @@ var LayerImpl28 = Effect43.gen(function* () {
|
|
|
6833
8036
|
deleteSession
|
|
6834
8037
|
};
|
|
6835
8038
|
});
|
|
6836
|
-
var SessionController = class extends
|
|
8039
|
+
var SessionController = class extends Context35.Tag("SessionController")() {
|
|
6837
8040
|
static {
|
|
6838
|
-
this.Live =
|
|
8041
|
+
this.Live = Layer37.effect(this, LayerImpl29);
|
|
8042
|
+
}
|
|
8043
|
+
};
|
|
8044
|
+
|
|
8045
|
+
// src/server/core/tasks/presentation/TasksController.ts
|
|
8046
|
+
import { Context as Context37, Effect as Effect47, Layer as Layer39 } from "effect";
|
|
8047
|
+
|
|
8048
|
+
// src/server/core/tasks/services/TasksService.ts
|
|
8049
|
+
import { homedir as homedir5 } from "node:os";
|
|
8050
|
+
import { join as join3 } from "node:path";
|
|
8051
|
+
import { FileSystem as FileSystem17, Path as Path19 } from "@effect/platform";
|
|
8052
|
+
import { Context as Context36, Effect as Effect46, Layer as Layer38, Option as Option4 } from "effect";
|
|
8053
|
+
|
|
8054
|
+
// src/server/core/tasks/schema.ts
|
|
8055
|
+
import { z as z26 } from "zod";
|
|
8056
|
+
var TaskStatusSchema = z26.enum([
|
|
8057
|
+
"pending",
|
|
8058
|
+
"in_progress",
|
|
8059
|
+
"completed",
|
|
8060
|
+
"failed"
|
|
8061
|
+
]);
|
|
8062
|
+
var TaskSchema = z26.object({
|
|
8063
|
+
id: z26.string(),
|
|
8064
|
+
subject: z26.string(),
|
|
8065
|
+
description: z26.string().optional(),
|
|
8066
|
+
status: TaskStatusSchema,
|
|
8067
|
+
owner: z26.string().optional(),
|
|
8068
|
+
blocks: z26.array(z26.string()).optional(),
|
|
8069
|
+
blockedBy: z26.array(z26.string()).optional(),
|
|
8070
|
+
metadata: z26.record(z26.string(), z26.any()).optional(),
|
|
8071
|
+
activeForm: z26.string().optional()
|
|
8072
|
+
});
|
|
8073
|
+
var TaskCreateSchema = z26.object({
|
|
8074
|
+
subject: z26.string(),
|
|
8075
|
+
description: z26.string().optional(),
|
|
8076
|
+
activeForm: z26.string().optional(),
|
|
8077
|
+
metadata: z26.record(z26.string(), z26.any()).optional()
|
|
8078
|
+
});
|
|
8079
|
+
var TaskUpdateSchema = z26.object({
|
|
8080
|
+
taskId: z26.string(),
|
|
8081
|
+
status: TaskStatusSchema.optional(),
|
|
8082
|
+
subject: z26.string().optional(),
|
|
8083
|
+
description: z26.string().optional(),
|
|
8084
|
+
activeForm: z26.string().optional(),
|
|
8085
|
+
owner: z26.string().optional(),
|
|
8086
|
+
addBlockedBy: z26.array(z26.string()).optional(),
|
|
8087
|
+
addBlocks: z26.array(z26.string()).optional(),
|
|
8088
|
+
metadata: z26.record(z26.string(), z26.any()).optional()
|
|
8089
|
+
});
|
|
8090
|
+
|
|
8091
|
+
// src/server/core/tasks/services/TasksService.ts
|
|
8092
|
+
var TASKS_DIR_NAME = "tasks";
|
|
8093
|
+
var PROJECTS_DIR_NAME = "projects";
|
|
8094
|
+
var CLAUDE_DIR_NAME = ".claude";
|
|
8095
|
+
var TasksService = class extends Context36.Tag("TasksService")() {
|
|
8096
|
+
static {
|
|
8097
|
+
this.Live = Layer38.effect(
|
|
8098
|
+
this,
|
|
8099
|
+
Effect46.gen(function* () {
|
|
8100
|
+
const fs = yield* FileSystem17.FileSystem;
|
|
8101
|
+
const path = yield* Path19.Path;
|
|
8102
|
+
const getClaudeDir = () => Effect46.succeed(join3(homedir5(), CLAUDE_DIR_NAME));
|
|
8103
|
+
const normalizeProjectPath = (projectPath) => {
|
|
8104
|
+
const normalized = projectPath.replaceAll(path.sep, "-");
|
|
8105
|
+
return normalized.startsWith("-") ? normalized : `-${normalized}`;
|
|
8106
|
+
};
|
|
8107
|
+
const resolveProjectUuid = (projectPath, specificSessionId) => Effect46.gen(function* () {
|
|
8108
|
+
const claudeDir = yield* getClaudeDir();
|
|
8109
|
+
if (specificSessionId) {
|
|
8110
|
+
const sessionTasksDir = path.join(
|
|
8111
|
+
claudeDir,
|
|
8112
|
+
TASKS_DIR_NAME,
|
|
8113
|
+
specificSessionId
|
|
8114
|
+
);
|
|
8115
|
+
if (yield* fs.exists(sessionTasksDir)) {
|
|
8116
|
+
return Option4.some(specificSessionId);
|
|
8117
|
+
}
|
|
8118
|
+
return Option4.none();
|
|
8119
|
+
}
|
|
8120
|
+
const isMetadataPath = projectPath.includes(join3(CLAUDE_DIR_NAME, PROJECTS_DIR_NAME)) && projectPath.split(path.sep).pop()?.startsWith("-");
|
|
8121
|
+
let projectMetaDir;
|
|
8122
|
+
if (isMetadataPath && (yield* fs.exists(projectPath))) {
|
|
8123
|
+
projectMetaDir = projectPath;
|
|
8124
|
+
} else {
|
|
8125
|
+
const identifier = normalizeProjectPath(projectPath);
|
|
8126
|
+
projectMetaDir = path.join(
|
|
8127
|
+
claudeDir,
|
|
8128
|
+
PROJECTS_DIR_NAME,
|
|
8129
|
+
identifier
|
|
8130
|
+
);
|
|
8131
|
+
}
|
|
8132
|
+
const exists = yield* fs.exists(projectMetaDir);
|
|
8133
|
+
if (!exists) {
|
|
8134
|
+
return Option4.none();
|
|
8135
|
+
}
|
|
8136
|
+
const files = yield* fs.readDirectory(projectMetaDir);
|
|
8137
|
+
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
|
|
8138
|
+
const candidates = files.filter((f) => uuidPattern.test(f));
|
|
8139
|
+
if (candidates.length === 0) {
|
|
8140
|
+
return Option4.none();
|
|
8141
|
+
}
|
|
8142
|
+
const candidateInfo = yield* Effect46.all(
|
|
8143
|
+
candidates.map(
|
|
8144
|
+
(file) => Effect46.gen(function* () {
|
|
8145
|
+
const fullPath = path.join(projectMetaDir, file);
|
|
8146
|
+
const stat = yield* fs.stat(fullPath);
|
|
8147
|
+
const match = file.match(uuidPattern);
|
|
8148
|
+
const uuid = match ? match[0] : file;
|
|
8149
|
+
const tasksPath = path.join(claudeDir, TASKS_DIR_NAME, uuid);
|
|
8150
|
+
const hasTasks = yield* fs.exists(tasksPath);
|
|
8151
|
+
return {
|
|
8152
|
+
file,
|
|
8153
|
+
uuid,
|
|
8154
|
+
mtime: Option4.getOrElse(stat.mtime, () => /* @__PURE__ */ new Date(0)),
|
|
8155
|
+
hasTasks
|
|
8156
|
+
};
|
|
8157
|
+
})
|
|
8158
|
+
),
|
|
8159
|
+
{ concurrency: "unbounded" }
|
|
8160
|
+
);
|
|
8161
|
+
const sorted = candidateInfo.sort((a, b) => {
|
|
8162
|
+
if (a.hasTasks && !b.hasTasks) return -1;
|
|
8163
|
+
if (!a.hasTasks && b.hasTasks) return 1;
|
|
8164
|
+
return b.mtime.getTime() - a.mtime.getTime();
|
|
8165
|
+
});
|
|
8166
|
+
const best = sorted[0];
|
|
8167
|
+
if (!best) {
|
|
8168
|
+
return Option4.none();
|
|
8169
|
+
}
|
|
8170
|
+
return Option4.some(best.uuid);
|
|
8171
|
+
});
|
|
8172
|
+
const resolveProjectUuidOrFail = (projectPath, specificSessionId) => Effect46.gen(function* () {
|
|
8173
|
+
const uuidOption = yield* resolveProjectUuid(
|
|
8174
|
+
projectPath,
|
|
8175
|
+
specificSessionId
|
|
8176
|
+
);
|
|
8177
|
+
if (Option4.isNone(uuidOption)) {
|
|
8178
|
+
if (specificSessionId) {
|
|
8179
|
+
return yield* Effect46.fail(
|
|
8180
|
+
new Error(
|
|
8181
|
+
`Requested session ${specificSessionId} has no tasks directory`
|
|
8182
|
+
)
|
|
8183
|
+
);
|
|
8184
|
+
}
|
|
8185
|
+
const claudeDir = yield* getClaudeDir();
|
|
8186
|
+
const identifier = normalizeProjectPath(projectPath);
|
|
8187
|
+
const projectMetaDir = path.join(
|
|
8188
|
+
claudeDir,
|
|
8189
|
+
PROJECTS_DIR_NAME,
|
|
8190
|
+
identifier
|
|
8191
|
+
);
|
|
8192
|
+
return yield* Effect46.fail(
|
|
8193
|
+
new Error(
|
|
8194
|
+
`Project metadata directory not found or no UUID: ${projectMetaDir}`
|
|
8195
|
+
)
|
|
8196
|
+
);
|
|
8197
|
+
}
|
|
8198
|
+
return uuidOption.value;
|
|
8199
|
+
});
|
|
8200
|
+
const getTasksDir = (projectPath, specificSessionId) => Effect46.gen(function* () {
|
|
8201
|
+
const claudeDir = yield* getClaudeDir();
|
|
8202
|
+
const uuidOption = yield* resolveProjectUuid(
|
|
8203
|
+
projectPath,
|
|
8204
|
+
specificSessionId
|
|
8205
|
+
);
|
|
8206
|
+
return Option4.map(
|
|
8207
|
+
uuidOption,
|
|
8208
|
+
(uuid) => path.join(claudeDir, TASKS_DIR_NAME, uuid)
|
|
8209
|
+
);
|
|
8210
|
+
});
|
|
8211
|
+
const getTasksDirOrFail = (projectPath, specificSessionId) => Effect46.gen(function* () {
|
|
8212
|
+
const claudeDir = yield* getClaudeDir();
|
|
8213
|
+
const uuid = yield* resolveProjectUuidOrFail(
|
|
8214
|
+
projectPath,
|
|
8215
|
+
specificSessionId
|
|
8216
|
+
);
|
|
8217
|
+
return path.join(claudeDir, TASKS_DIR_NAME, uuid);
|
|
8218
|
+
});
|
|
8219
|
+
const listTasks = (projectPath, specificSessionId) => Effect46.gen(function* () {
|
|
8220
|
+
const tasksDirOption = yield* getTasksDir(
|
|
8221
|
+
projectPath,
|
|
8222
|
+
specificSessionId
|
|
8223
|
+
);
|
|
8224
|
+
if (Option4.isNone(tasksDirOption)) {
|
|
8225
|
+
return [];
|
|
8226
|
+
}
|
|
8227
|
+
const tasksDir = tasksDirOption.value;
|
|
8228
|
+
const exists = yield* fs.exists(tasksDir);
|
|
8229
|
+
if (!exists) {
|
|
8230
|
+
return [];
|
|
8231
|
+
}
|
|
8232
|
+
const files = yield* fs.readDirectory(tasksDir);
|
|
8233
|
+
const tasks = [];
|
|
8234
|
+
for (const file of files) {
|
|
8235
|
+
if (!file.endsWith(".json")) continue;
|
|
8236
|
+
const content = yield* fs.readFileString(path.join(tasksDir, file));
|
|
8237
|
+
try {
|
|
8238
|
+
const task = JSON.parse(content);
|
|
8239
|
+
const parsed = TaskSchema.safeParse(task);
|
|
8240
|
+
if (parsed.success) {
|
|
8241
|
+
tasks.push(parsed.data);
|
|
8242
|
+
} else {
|
|
8243
|
+
console.warn(`Invalid task file ${file}:`, parsed.error);
|
|
8244
|
+
const fallbackTask = {
|
|
8245
|
+
id: typeof task === "object" && task !== null && "id" in task && typeof task.id === "string" ? task.id : file.replace(".json", ""),
|
|
8246
|
+
subject: typeof task === "object" && task !== null && "subject" in task && typeof task.subject === "string" ? task.subject : typeof task === "object" && task !== null && "title" in task && typeof task.title === "string" ? task.title : "Invalid Task Schema",
|
|
8247
|
+
description: `Validation Error: ${JSON.stringify(parsed.error.format())}. Raw: ${JSON.stringify(task)}`,
|
|
8248
|
+
status: typeof task === "object" && task !== null && "status" in task && typeof task.status === "string" && (task.status === "pending" || task.status === "in_progress" || task.status === "completed" || task.status === "failed") ? task.status : "failed",
|
|
8249
|
+
blocks: [],
|
|
8250
|
+
blockedBy: []
|
|
8251
|
+
};
|
|
8252
|
+
tasks.push(fallbackTask);
|
|
8253
|
+
}
|
|
8254
|
+
} catch (e) {
|
|
8255
|
+
console.error(`Failed to parse task file ${file}`, e);
|
|
8256
|
+
const fallbackTask = {
|
|
8257
|
+
id: file.replace(".json", ""),
|
|
8258
|
+
subject: "Corrupted Task File",
|
|
8259
|
+
description: String(e),
|
|
8260
|
+
status: "failed",
|
|
8261
|
+
blocks: [],
|
|
8262
|
+
blockedBy: []
|
|
8263
|
+
};
|
|
8264
|
+
tasks.push(fallbackTask);
|
|
8265
|
+
}
|
|
8266
|
+
}
|
|
8267
|
+
return tasks.sort((a, b) => parseInt(a.id, 10) - parseInt(b.id, 10));
|
|
8268
|
+
});
|
|
8269
|
+
const getTask = (projectPath, taskId, specificSessionId) => Effect46.gen(function* () {
|
|
8270
|
+
const tasksDir = yield* getTasksDirOrFail(
|
|
8271
|
+
projectPath,
|
|
8272
|
+
specificSessionId
|
|
8273
|
+
);
|
|
8274
|
+
const taskFile = path.join(tasksDir, `${taskId}.json`);
|
|
8275
|
+
const exists = yield* fs.exists(taskFile);
|
|
8276
|
+
if (!exists) {
|
|
8277
|
+
return yield* Effect46.fail(new Error(`Task ${taskId} not found`));
|
|
8278
|
+
}
|
|
8279
|
+
const content = yield* fs.readFileString(taskFile);
|
|
8280
|
+
const task = JSON.parse(content);
|
|
8281
|
+
return yield* Effect46.try(() => TaskSchema.parse(task));
|
|
8282
|
+
});
|
|
8283
|
+
const createTask = (projectPath, taskDef, specificSessionId) => Effect46.gen(function* () {
|
|
8284
|
+
const tasksDir = yield* getTasksDirOrFail(
|
|
8285
|
+
projectPath,
|
|
8286
|
+
specificSessionId
|
|
8287
|
+
);
|
|
8288
|
+
const dirExists = yield* fs.exists(tasksDir);
|
|
8289
|
+
if (!dirExists) {
|
|
8290
|
+
yield* fs.makeDirectory(tasksDir, { recursive: true });
|
|
8291
|
+
}
|
|
8292
|
+
const files = yield* fs.readDirectory(tasksDir);
|
|
8293
|
+
let maxId = 0;
|
|
8294
|
+
for (const file of files) {
|
|
8295
|
+
if (file.endsWith(".json")) {
|
|
8296
|
+
const idPart = file.replace(".json", "");
|
|
8297
|
+
const idNum = parseInt(idPart, 10);
|
|
8298
|
+
if (!Number.isNaN(idNum) && idNum > maxId) {
|
|
8299
|
+
maxId = idNum;
|
|
8300
|
+
}
|
|
8301
|
+
}
|
|
8302
|
+
}
|
|
8303
|
+
const newId = (maxId + 1).toString();
|
|
8304
|
+
const newTask = {
|
|
8305
|
+
id: newId,
|
|
8306
|
+
status: "pending",
|
|
8307
|
+
blocks: [],
|
|
8308
|
+
blockedBy: [],
|
|
8309
|
+
...taskDef
|
|
8310
|
+
};
|
|
8311
|
+
const filePath = path.join(tasksDir, `${newId}.json`);
|
|
8312
|
+
yield* fs.writeFileString(filePath, JSON.stringify(newTask, null, 2));
|
|
8313
|
+
return newTask;
|
|
8314
|
+
});
|
|
8315
|
+
const updateTask = (projectPath, update, specificSessionId) => Effect46.gen(function* () {
|
|
8316
|
+
const tasksDir = yield* getTasksDirOrFail(
|
|
8317
|
+
projectPath,
|
|
8318
|
+
specificSessionId
|
|
8319
|
+
);
|
|
8320
|
+
const filePath = path.join(tasksDir, `${update.taskId}.json`);
|
|
8321
|
+
const exists = yield* fs.exists(filePath);
|
|
8322
|
+
if (!exists) {
|
|
8323
|
+
return yield* Effect46.fail(
|
|
8324
|
+
new Error(`Task ${update.taskId} not found`)
|
|
8325
|
+
);
|
|
8326
|
+
}
|
|
8327
|
+
const content = yield* fs.readFileString(filePath);
|
|
8328
|
+
const currentTask = TaskSchema.parse(JSON.parse(content));
|
|
8329
|
+
const updatedTask = {
|
|
8330
|
+
...currentTask,
|
|
8331
|
+
// User cannot update status via Viewer, it is managed by Claude Agent
|
|
8332
|
+
status: currentTask.status,
|
|
8333
|
+
subject: update.subject ?? currentTask.subject,
|
|
8334
|
+
description: update.description ?? currentTask.description,
|
|
8335
|
+
activeForm: update.activeForm ?? currentTask.activeForm,
|
|
8336
|
+
owner: update.owner ?? currentTask.owner,
|
|
8337
|
+
blockedBy: update.addBlockedBy ? [...currentTask.blockedBy || [], ...update.addBlockedBy] : currentTask.blockedBy,
|
|
8338
|
+
blocks: update.addBlocks ? [...currentTask.blocks || [], ...update.addBlocks] : currentTask.blocks,
|
|
8339
|
+
metadata: update.metadata ? { ...currentTask.metadata, ...update.metadata } : currentTask.metadata
|
|
8340
|
+
};
|
|
8341
|
+
if (updatedTask.metadata) {
|
|
8342
|
+
for (const key in updatedTask.metadata) {
|
|
8343
|
+
if (updatedTask.metadata[key] === null) {
|
|
8344
|
+
delete updatedTask.metadata[key];
|
|
8345
|
+
}
|
|
8346
|
+
}
|
|
8347
|
+
}
|
|
8348
|
+
yield* fs.writeFileString(
|
|
8349
|
+
filePath,
|
|
8350
|
+
JSON.stringify(updatedTask, null, 2)
|
|
8351
|
+
);
|
|
8352
|
+
return updatedTask;
|
|
8353
|
+
});
|
|
8354
|
+
return {
|
|
8355
|
+
listTasks,
|
|
8356
|
+
getTask,
|
|
8357
|
+
createTask,
|
|
8358
|
+
updateTask
|
|
8359
|
+
};
|
|
8360
|
+
})
|
|
8361
|
+
);
|
|
8362
|
+
}
|
|
8363
|
+
};
|
|
8364
|
+
|
|
8365
|
+
// src/server/core/tasks/presentation/TasksController.ts
|
|
8366
|
+
var make = Effect47.gen(function* () {
|
|
8367
|
+
const service = yield* TasksService;
|
|
8368
|
+
const listTasks = (projectPath, specificSessionId) => service.listTasks(projectPath, specificSessionId);
|
|
8369
|
+
const createTask = (projectPath, task, specificSessionId) => service.createTask(projectPath, task, specificSessionId);
|
|
8370
|
+
const updateTask = (projectPath, task, specificSessionId) => service.updateTask(projectPath, task, specificSessionId);
|
|
8371
|
+
return {
|
|
8372
|
+
listTasks,
|
|
8373
|
+
createTask,
|
|
8374
|
+
updateTask
|
|
8375
|
+
};
|
|
8376
|
+
});
|
|
8377
|
+
var TasksController = class extends Context37.Tag("TasksController")() {
|
|
8378
|
+
static {
|
|
8379
|
+
this.Live = Layer39.effect(this, make);
|
|
6839
8380
|
}
|
|
6840
8381
|
};
|
|
6841
8382
|
|
|
@@ -6844,12 +8385,12 @@ import { Hono } from "hono";
|
|
|
6844
8385
|
var honoApp = new Hono();
|
|
6845
8386
|
|
|
6846
8387
|
// src/server/hono/initialize.ts
|
|
6847
|
-
import { Context as
|
|
6848
|
-
var InitializeService = class extends
|
|
8388
|
+
import { Context as Context38, Effect as Effect48, Layer as Layer40, Ref as Ref14, Schedule as Schedule2 } from "effect";
|
|
8389
|
+
var InitializeService = class extends Context38.Tag("InitializeService")() {
|
|
6849
8390
|
static {
|
|
6850
|
-
this.Live =
|
|
8391
|
+
this.Live = Layer40.effect(
|
|
6851
8392
|
this,
|
|
6852
|
-
|
|
8393
|
+
Effect48.gen(function* () {
|
|
6853
8394
|
const eventBus = yield* EventBus;
|
|
6854
8395
|
const fileWatcher = yield* FileWatcherService;
|
|
6855
8396
|
const projectRepository = yield* ProjectRepository;
|
|
@@ -6857,22 +8398,24 @@ var InitializeService = class extends Context35.Tag("InitializeService")() {
|
|
|
6857
8398
|
const projectMetaService = yield* ProjectMetaService;
|
|
6858
8399
|
const sessionMetaService = yield* SessionMetaService;
|
|
6859
8400
|
const virtualConversationDatabase = yield* VirtualConversationDatabase;
|
|
6860
|
-
const
|
|
8401
|
+
const rateLimitAutoScheduleService = yield* RateLimitAutoScheduleService;
|
|
8402
|
+
const listenersRef = yield* Ref14.make({});
|
|
6861
8403
|
const startInitialization = () => {
|
|
6862
|
-
return
|
|
8404
|
+
return Effect48.gen(function* () {
|
|
6863
8405
|
yield* fileWatcher.startWatching();
|
|
6864
|
-
|
|
8406
|
+
yield* rateLimitAutoScheduleService.start();
|
|
8407
|
+
const daemon = Effect48.repeat(
|
|
6865
8408
|
eventBus.emit("heartbeat", {}),
|
|
6866
8409
|
Schedule2.fixed("10 seconds")
|
|
6867
8410
|
);
|
|
6868
8411
|
console.log("start heartbeat");
|
|
6869
|
-
yield*
|
|
8412
|
+
yield* Effect48.forkDaemon(daemon);
|
|
6870
8413
|
console.log("after starting heartbeat fork");
|
|
6871
8414
|
const onSessionChanged = (event) => {
|
|
6872
|
-
|
|
8415
|
+
Effect48.runFork(
|
|
6873
8416
|
projectMetaService.invalidateProject(event.projectId)
|
|
6874
8417
|
);
|
|
6875
|
-
|
|
8418
|
+
Effect48.runFork(
|
|
6876
8419
|
sessionMetaService.invalidateSession(
|
|
6877
8420
|
event.projectId,
|
|
6878
8421
|
event.sessionId
|
|
@@ -6881,7 +8424,7 @@ var InitializeService = class extends Context35.Tag("InitializeService")() {
|
|
|
6881
8424
|
};
|
|
6882
8425
|
const onSessionProcessChanged = (event) => {
|
|
6883
8426
|
if ((event.changed.type === "completed" || event.changed.type === "paused") && event.changed.sessionId !== void 0) {
|
|
6884
|
-
|
|
8427
|
+
Effect48.runFork(
|
|
6885
8428
|
virtualConversationDatabase.deleteVirtualConversations(
|
|
6886
8429
|
event.changed.sessionId
|
|
6887
8430
|
)
|
|
@@ -6889,18 +8432,18 @@ var InitializeService = class extends Context35.Tag("InitializeService")() {
|
|
|
6889
8432
|
return;
|
|
6890
8433
|
}
|
|
6891
8434
|
};
|
|
6892
|
-
yield*
|
|
8435
|
+
yield* Ref14.set(listenersRef, {
|
|
6893
8436
|
sessionChanged: onSessionChanged,
|
|
6894
8437
|
sessionProcessChanged: onSessionProcessChanged
|
|
6895
8438
|
});
|
|
6896
8439
|
yield* eventBus.on("sessionChanged", onSessionChanged);
|
|
6897
8440
|
yield* eventBus.on("sessionProcessChanged", onSessionProcessChanged);
|
|
6898
|
-
yield*
|
|
8441
|
+
yield* Effect48.gen(function* () {
|
|
6899
8442
|
console.log("Initializing projects cache");
|
|
6900
8443
|
const { projects } = yield* projectRepository.getProjects();
|
|
6901
8444
|
console.log(`${projects.length} projects cache initialized`);
|
|
6902
8445
|
console.log("Initializing sessions cache");
|
|
6903
|
-
const results = yield*
|
|
8446
|
+
const results = yield* Effect48.all(
|
|
6904
8447
|
projects.map(
|
|
6905
8448
|
(project) => sessionRepository.getSessions(project.id)
|
|
6906
8449
|
),
|
|
@@ -6912,13 +8455,13 @@ var InitializeService = class extends Context35.Tag("InitializeService")() {
|
|
|
6912
8455
|
);
|
|
6913
8456
|
console.log(`${totalSessions} sessions cache initialized`);
|
|
6914
8457
|
}).pipe(
|
|
6915
|
-
|
|
6916
|
-
|
|
8458
|
+
Effect48.catchAll(() => Effect48.void),
|
|
8459
|
+
Effect48.withSpan("initialize-cache")
|
|
6917
8460
|
);
|
|
6918
|
-
}).pipe(
|
|
8461
|
+
}).pipe(Effect48.withSpan("start-initialization"));
|
|
6919
8462
|
};
|
|
6920
|
-
const stopCleanup = () =>
|
|
6921
|
-
const listeners = yield*
|
|
8463
|
+
const stopCleanup = () => Effect48.gen(function* () {
|
|
8464
|
+
const listeners = yield* Ref14.get(listenersRef);
|
|
6922
8465
|
if (listeners.sessionChanged) {
|
|
6923
8466
|
yield* eventBus.off("sessionChanged", listeners.sessionChanged);
|
|
6924
8467
|
}
|
|
@@ -6928,7 +8471,8 @@ var InitializeService = class extends Context35.Tag("InitializeService")() {
|
|
|
6928
8471
|
listeners.sessionProcessChanged
|
|
6929
8472
|
);
|
|
6930
8473
|
}
|
|
6931
|
-
yield*
|
|
8474
|
+
yield* Ref14.set(listenersRef, {});
|
|
8475
|
+
yield* rateLimitAutoScheduleService.stop();
|
|
6932
8476
|
yield* fileWatcher.stop();
|
|
6933
8477
|
});
|
|
6934
8478
|
return {
|
|
@@ -6941,7 +8485,7 @@ var InitializeService = class extends Context35.Tag("InitializeService")() {
|
|
|
6941
8485
|
};
|
|
6942
8486
|
|
|
6943
8487
|
// src/server/hono/middleware/auth.middleware.ts
|
|
6944
|
-
import { Context as
|
|
8488
|
+
import { Context as Context39, Effect as Effect49, Layer as Layer41 } from "effect";
|
|
6945
8489
|
import { getCookie } from "hono/cookie";
|
|
6946
8490
|
import { createMiddleware } from "hono/factory";
|
|
6947
8491
|
var generateSessionToken = (password) => {
|
|
@@ -6956,9 +8500,9 @@ var PUBLIC_API_ROUTES = [
|
|
|
6956
8500
|
// Allow config access for theme/locale loading
|
|
6957
8501
|
"/api/version"
|
|
6958
8502
|
];
|
|
6959
|
-
var
|
|
8503
|
+
var LayerImpl30 = Effect49.gen(function* () {
|
|
6960
8504
|
const ccvOptionsService = yield* CcvOptionsService;
|
|
6961
|
-
return
|
|
8505
|
+
return Effect49.gen(function* () {
|
|
6962
8506
|
const anthPassword = yield* ccvOptionsService.getCcvOptions("password");
|
|
6963
8507
|
const authEnabled = anthPassword !== void 0;
|
|
6964
8508
|
const validSessionToken = generateSessionToken(anthPassword);
|
|
@@ -6986,77 +8530,77 @@ var LayerImpl29 = Effect45.gen(function* () {
|
|
|
6986
8530
|
};
|
|
6987
8531
|
});
|
|
6988
8532
|
});
|
|
6989
|
-
var AuthMiddleware = class extends
|
|
8533
|
+
var AuthMiddleware = class extends Context39.Tag("AuthMiddleware")() {
|
|
6990
8534
|
static {
|
|
6991
|
-
this.Live =
|
|
8535
|
+
this.Live = Layer41.effect(this, LayerImpl30);
|
|
6992
8536
|
}
|
|
6993
8537
|
};
|
|
6994
8538
|
|
|
6995
8539
|
// src/server/hono/route.ts
|
|
6996
8540
|
import { zValidator } from "@hono/zod-validator";
|
|
6997
|
-
import { Effect as
|
|
8541
|
+
import { Effect as Effect51, Runtime as Runtime3 } from "effect";
|
|
6998
8542
|
import { deleteCookie, getCookie as getCookie3, setCookie as setCookie2 } from "hono/cookie";
|
|
6999
8543
|
import { streamSSE } from "hono/streaming";
|
|
7000
8544
|
import prexit from "prexit";
|
|
7001
|
-
import { z as
|
|
8545
|
+
import { z as z31 } from "zod";
|
|
7002
8546
|
|
|
7003
8547
|
// src/server/core/claude-code/schema.ts
|
|
7004
|
-
import { z as
|
|
7005
|
-
var mediaTypeSchema =
|
|
8548
|
+
import { z as z27 } from "zod";
|
|
8549
|
+
var mediaTypeSchema = z27.enum([
|
|
7006
8550
|
"image/png",
|
|
7007
8551
|
"image/jpeg",
|
|
7008
8552
|
"image/gif",
|
|
7009
8553
|
"image/webp"
|
|
7010
8554
|
]);
|
|
7011
|
-
var imageBlockSchema =
|
|
7012
|
-
type:
|
|
7013
|
-
source:
|
|
7014
|
-
type:
|
|
8555
|
+
var imageBlockSchema = z27.object({
|
|
8556
|
+
type: z27.literal("image"),
|
|
8557
|
+
source: z27.object({
|
|
8558
|
+
type: z27.literal("base64"),
|
|
7015
8559
|
media_type: mediaTypeSchema,
|
|
7016
|
-
data:
|
|
8560
|
+
data: z27.string()
|
|
7017
8561
|
})
|
|
7018
8562
|
});
|
|
7019
|
-
var documentBlockSchema =
|
|
7020
|
-
type:
|
|
7021
|
-
source:
|
|
7022
|
-
|
|
7023
|
-
type:
|
|
7024
|
-
media_type:
|
|
7025
|
-
data:
|
|
8563
|
+
var documentBlockSchema = z27.object({
|
|
8564
|
+
type: z27.literal("document"),
|
|
8565
|
+
source: z27.union([
|
|
8566
|
+
z27.object({
|
|
8567
|
+
type: z27.literal("text"),
|
|
8568
|
+
media_type: z27.enum(["text/plain"]),
|
|
8569
|
+
data: z27.string()
|
|
7026
8570
|
}),
|
|
7027
|
-
|
|
7028
|
-
type:
|
|
7029
|
-
media_type:
|
|
7030
|
-
data:
|
|
8571
|
+
z27.object({
|
|
8572
|
+
type: z27.literal("base64"),
|
|
8573
|
+
media_type: z27.enum(["application/pdf"]),
|
|
8574
|
+
data: z27.string()
|
|
7031
8575
|
})
|
|
7032
8576
|
])
|
|
7033
8577
|
});
|
|
7034
|
-
var userMessageInputSchema =
|
|
7035
|
-
text:
|
|
7036
|
-
images:
|
|
7037
|
-
documents:
|
|
8578
|
+
var userMessageInputSchema = z27.object({
|
|
8579
|
+
text: z27.string().min(1),
|
|
8580
|
+
images: z27.array(imageBlockSchema).optional(),
|
|
8581
|
+
documents: z27.array(documentBlockSchema).optional()
|
|
7038
8582
|
});
|
|
7039
8583
|
|
|
7040
8584
|
// src/server/core/git/schema.ts
|
|
7041
|
-
import { z as
|
|
7042
|
-
var CommitRequestSchema =
|
|
7043
|
-
projectId:
|
|
7044
|
-
files:
|
|
7045
|
-
message:
|
|
8585
|
+
import { z as z28 } from "zod";
|
|
8586
|
+
var CommitRequestSchema = z28.object({
|
|
8587
|
+
projectId: z28.string().min(1),
|
|
8588
|
+
files: z28.array(z28.string().min(1)).min(1),
|
|
8589
|
+
message: z28.string().trim().min(1)
|
|
7046
8590
|
});
|
|
7047
|
-
var PushRequestSchema =
|
|
7048
|
-
projectId:
|
|
8591
|
+
var PushRequestSchema = z28.object({
|
|
8592
|
+
projectId: z28.string().min(1)
|
|
7049
8593
|
});
|
|
7050
|
-
var CommitResultSuccessSchema =
|
|
7051
|
-
success:
|
|
7052
|
-
commitSha:
|
|
7053
|
-
filesCommitted:
|
|
7054
|
-
message:
|
|
8594
|
+
var CommitResultSuccessSchema = z28.object({
|
|
8595
|
+
success: z28.literal(true),
|
|
8596
|
+
commitSha: z28.string().length(40),
|
|
8597
|
+
filesCommitted: z28.number().int().positive(),
|
|
8598
|
+
message: z28.string()
|
|
7055
8599
|
});
|
|
7056
|
-
var CommitResultErrorSchema =
|
|
7057
|
-
success:
|
|
7058
|
-
error:
|
|
7059
|
-
errorCode:
|
|
8600
|
+
var CommitResultErrorSchema = z28.object({
|
|
8601
|
+
success: z28.literal(false),
|
|
8602
|
+
error: z28.string(),
|
|
8603
|
+
errorCode: z28.enum([
|
|
7060
8604
|
"EMPTY_MESSAGE",
|
|
7061
8605
|
"NO_FILES",
|
|
7062
8606
|
"PROJECT_NOT_FOUND",
|
|
@@ -7064,22 +8608,22 @@ var CommitResultErrorSchema = z26.object({
|
|
|
7064
8608
|
"HOOK_FAILED",
|
|
7065
8609
|
"GIT_COMMAND_ERROR"
|
|
7066
8610
|
]),
|
|
7067
|
-
details:
|
|
8611
|
+
details: z28.string().optional()
|
|
7068
8612
|
});
|
|
7069
|
-
var CommitResultSchema =
|
|
8613
|
+
var CommitResultSchema = z28.discriminatedUnion("success", [
|
|
7070
8614
|
CommitResultSuccessSchema,
|
|
7071
8615
|
CommitResultErrorSchema
|
|
7072
8616
|
]);
|
|
7073
|
-
var PushResultSuccessSchema =
|
|
7074
|
-
success:
|
|
7075
|
-
remote:
|
|
7076
|
-
branch:
|
|
7077
|
-
objectsPushed:
|
|
8617
|
+
var PushResultSuccessSchema = z28.object({
|
|
8618
|
+
success: z28.literal(true),
|
|
8619
|
+
remote: z28.string(),
|
|
8620
|
+
branch: z28.string(),
|
|
8621
|
+
objectsPushed: z28.number().int().optional()
|
|
7078
8622
|
});
|
|
7079
|
-
var PushResultErrorSchema =
|
|
7080
|
-
success:
|
|
7081
|
-
error:
|
|
7082
|
-
errorCode:
|
|
8623
|
+
var PushResultErrorSchema = z28.object({
|
|
8624
|
+
success: z28.literal(false),
|
|
8625
|
+
error: z28.string(),
|
|
8626
|
+
errorCode: z28.enum([
|
|
7083
8627
|
"PROJECT_NOT_FOUND",
|
|
7084
8628
|
"NOT_A_REPOSITORY",
|
|
7085
8629
|
"NO_UPSTREAM",
|
|
@@ -7089,26 +8633,26 @@ var PushResultErrorSchema = z26.object({
|
|
|
7089
8633
|
"TIMEOUT",
|
|
7090
8634
|
"GIT_COMMAND_ERROR"
|
|
7091
8635
|
]),
|
|
7092
|
-
details:
|
|
8636
|
+
details: z28.string().optional()
|
|
7093
8637
|
});
|
|
7094
|
-
var PushResultSchema =
|
|
8638
|
+
var PushResultSchema = z28.discriminatedUnion("success", [
|
|
7095
8639
|
PushResultSuccessSchema,
|
|
7096
8640
|
PushResultErrorSchema
|
|
7097
8641
|
]);
|
|
7098
|
-
var CommitAndPushResultSuccessSchema =
|
|
7099
|
-
success:
|
|
7100
|
-
commitSha:
|
|
7101
|
-
filesCommitted:
|
|
7102
|
-
message:
|
|
7103
|
-
remote:
|
|
7104
|
-
branch:
|
|
8642
|
+
var CommitAndPushResultSuccessSchema = z28.object({
|
|
8643
|
+
success: z28.literal(true),
|
|
8644
|
+
commitSha: z28.string().length(40),
|
|
8645
|
+
filesCommitted: z28.number().int().positive(),
|
|
8646
|
+
message: z28.string(),
|
|
8647
|
+
remote: z28.string(),
|
|
8648
|
+
branch: z28.string()
|
|
7105
8649
|
});
|
|
7106
|
-
var CommitAndPushResultErrorSchema =
|
|
7107
|
-
success:
|
|
7108
|
-
commitSucceeded:
|
|
7109
|
-
commitSha:
|
|
7110
|
-
error:
|
|
7111
|
-
errorCode:
|
|
8650
|
+
var CommitAndPushResultErrorSchema = z28.object({
|
|
8651
|
+
success: z28.literal(false),
|
|
8652
|
+
commitSucceeded: z28.boolean(),
|
|
8653
|
+
commitSha: z28.string().length(40).optional(),
|
|
8654
|
+
error: z28.string(),
|
|
8655
|
+
errorCode: z28.enum([
|
|
7112
8656
|
"EMPTY_MESSAGE",
|
|
7113
8657
|
"NO_FILES",
|
|
7114
8658
|
"PROJECT_NOT_FOUND",
|
|
@@ -7121,36 +8665,37 @@ var CommitAndPushResultErrorSchema = z26.object({
|
|
|
7121
8665
|
"NETWORK_ERROR",
|
|
7122
8666
|
"TIMEOUT"
|
|
7123
8667
|
]),
|
|
7124
|
-
details:
|
|
8668
|
+
details: z28.string().optional()
|
|
7125
8669
|
});
|
|
7126
|
-
var CommitAndPushResultSchema =
|
|
8670
|
+
var CommitAndPushResultSchema = z28.discriminatedUnion("success", [
|
|
7127
8671
|
CommitAndPushResultSuccessSchema,
|
|
7128
8672
|
CommitAndPushResultErrorSchema
|
|
7129
8673
|
]);
|
|
7130
8674
|
|
|
7131
8675
|
// src/server/lib/config/config.ts
|
|
7132
|
-
import
|
|
8676
|
+
import z30 from "zod";
|
|
7133
8677
|
|
|
7134
8678
|
// src/lib/i18n/schema.ts
|
|
7135
|
-
import
|
|
7136
|
-
var localeSchema =
|
|
8679
|
+
import z29 from "zod";
|
|
8680
|
+
var localeSchema = z29.enum(["ja", "en", "zh_CN"]);
|
|
7137
8681
|
|
|
7138
8682
|
// src/server/lib/config/config.ts
|
|
7139
|
-
var userConfigSchema =
|
|
7140
|
-
hideNoUserMessageSession:
|
|
7141
|
-
unifySameTitleSession:
|
|
7142
|
-
enterKeyBehavior:
|
|
7143
|
-
permissionMode:
|
|
8683
|
+
var userConfigSchema = z30.object({
|
|
8684
|
+
hideNoUserMessageSession: z30.boolean().optional().default(true),
|
|
8685
|
+
unifySameTitleSession: z30.boolean().optional().default(false),
|
|
8686
|
+
enterKeyBehavior: z30.enum(["shift-enter-send", "enter-send", "command-enter-send"]).optional().default("shift-enter-send"),
|
|
8687
|
+
permissionMode: z30.enum(["acceptEdits", "bypassPermissions", "default", "plan"]).optional().default("default"),
|
|
7144
8688
|
locale: localeSchema.optional().default("en"),
|
|
7145
|
-
theme:
|
|
7146
|
-
searchHotkey:
|
|
8689
|
+
theme: z30.enum(["light", "dark", "system"]).optional().default("system"),
|
|
8690
|
+
searchHotkey: z30.enum(["ctrl-k", "command-k"]).optional().default("command-k"),
|
|
8691
|
+
autoScheduleContinueOnRateLimit: z30.boolean().optional().default(false)
|
|
7147
8692
|
});
|
|
7148
8693
|
var defaultUserConfig = userConfigSchema.parse({});
|
|
7149
8694
|
|
|
7150
8695
|
// src/server/lib/effect/toEffectResponse.ts
|
|
7151
|
-
import { Effect as
|
|
8696
|
+
import { Effect as Effect50 } from "effect";
|
|
7152
8697
|
var effectToResponse = async (ctx, effect) => {
|
|
7153
|
-
const result = await
|
|
8698
|
+
const result = await Effect50.runPromise(effect);
|
|
7154
8699
|
const result2 = ctx.json(result.response, result.status);
|
|
7155
8700
|
return result2;
|
|
7156
8701
|
};
|
|
@@ -7193,7 +8738,7 @@ var configMiddleware = createMiddleware2(
|
|
|
7193
8738
|
);
|
|
7194
8739
|
|
|
7195
8740
|
// src/server/hono/route.ts
|
|
7196
|
-
var routes = (app, options) =>
|
|
8741
|
+
var routes = (app, options) => Effect51.gen(function* () {
|
|
7197
8742
|
const ccvOptionsService = yield* CcvOptionsService;
|
|
7198
8743
|
yield* ccvOptionsService.loadCliOptions(options);
|
|
7199
8744
|
const envService = yield* EnvService;
|
|
@@ -7212,9 +8757,10 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7212
8757
|
const schedulerController = yield* SchedulerController;
|
|
7213
8758
|
const featureFlagController = yield* FeatureFlagController;
|
|
7214
8759
|
const searchController = yield* SearchController;
|
|
8760
|
+
const tasksController = yield* TasksController;
|
|
7215
8761
|
const authMiddlewareService = yield* AuthMiddleware;
|
|
7216
8762
|
const { authMiddleware, validSessionToken, authEnabled, anthPassword } = yield* authMiddlewareService;
|
|
7217
|
-
const runtime = yield*
|
|
8763
|
+
const runtime = yield* Effect51.runtime();
|
|
7218
8764
|
if ((yield* envService.getEnv("NEXT_PHASE")) !== "phase-production-build") {
|
|
7219
8765
|
yield* initializeService.startInitialization();
|
|
7220
8766
|
prexit(async () => {
|
|
@@ -7222,7 +8768,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7222
8768
|
});
|
|
7223
8769
|
}
|
|
7224
8770
|
return app.use(configMiddleware).use(authMiddleware).use(async (c, next) => {
|
|
7225
|
-
await
|
|
8771
|
+
await Effect51.runPromise(
|
|
7226
8772
|
userConfigService.setUserConfig({
|
|
7227
8773
|
...c.get("userConfig")
|
|
7228
8774
|
})
|
|
@@ -7230,7 +8776,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7230
8776
|
await next();
|
|
7231
8777
|
}).post(
|
|
7232
8778
|
"/api/auth/login",
|
|
7233
|
-
zValidator("json",
|
|
8779
|
+
zValidator("json", z31.object({ password: z31.string() })),
|
|
7234
8780
|
async (c) => {
|
|
7235
8781
|
const { password } = c.req.valid("json");
|
|
7236
8782
|
if (!authEnabled) {
|
|
@@ -7284,14 +8830,14 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7284
8830
|
return response;
|
|
7285
8831
|
}).get(
|
|
7286
8832
|
"/api/projects/:projectId",
|
|
7287
|
-
zValidator("query",
|
|
8833
|
+
zValidator("query", z31.object({ cursor: z31.string().optional() })),
|
|
7288
8834
|
async (c) => {
|
|
7289
8835
|
const response = await effectToResponse(
|
|
7290
8836
|
c,
|
|
7291
8837
|
projectController.getProject({
|
|
7292
8838
|
...c.req.param(),
|
|
7293
8839
|
...c.req.valid("query")
|
|
7294
|
-
}).pipe(
|
|
8840
|
+
}).pipe(Effect51.provide(runtime))
|
|
7295
8841
|
);
|
|
7296
8842
|
return response;
|
|
7297
8843
|
}
|
|
@@ -7299,8 +8845,8 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7299
8845
|
"/api/projects",
|
|
7300
8846
|
zValidator(
|
|
7301
8847
|
"json",
|
|
7302
|
-
|
|
7303
|
-
projectPath:
|
|
8848
|
+
z31.object({
|
|
8849
|
+
projectPath: z31.string().min(1, "Project path is required")
|
|
7304
8850
|
})
|
|
7305
8851
|
),
|
|
7306
8852
|
async (c) => {
|
|
@@ -7308,7 +8854,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7308
8854
|
c,
|
|
7309
8855
|
projectController.createProject({
|
|
7310
8856
|
...c.req.valid("json")
|
|
7311
|
-
}).pipe(
|
|
8857
|
+
}).pipe(Effect51.provide(runtime))
|
|
7312
8858
|
);
|
|
7313
8859
|
return response;
|
|
7314
8860
|
}
|
|
@@ -7317,13 +8863,13 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7317
8863
|
c,
|
|
7318
8864
|
projectController.getProjectLatestSession({
|
|
7319
8865
|
...c.req.param()
|
|
7320
|
-
}).pipe(
|
|
8866
|
+
}).pipe(Effect51.provide(runtime))
|
|
7321
8867
|
);
|
|
7322
8868
|
return response;
|
|
7323
8869
|
}).get("/api/projects/:projectId/sessions/:sessionId", async (c) => {
|
|
7324
8870
|
const response = await effectToResponse(
|
|
7325
8871
|
c,
|
|
7326
|
-
sessionController.getSession({ ...c.req.param() }).pipe(
|
|
8872
|
+
sessionController.getSession({ ...c.req.param() }).pipe(Effect51.provide(runtime))
|
|
7327
8873
|
);
|
|
7328
8874
|
return response;
|
|
7329
8875
|
}).get(
|
|
@@ -7331,19 +8877,19 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7331
8877
|
async (c) => {
|
|
7332
8878
|
const response = await effectToResponse(
|
|
7333
8879
|
c,
|
|
7334
|
-
sessionController.exportSessionHtml({ ...c.req.param() }).pipe(
|
|
8880
|
+
sessionController.exportSessionHtml({ ...c.req.param() }).pipe(Effect51.provide(runtime))
|
|
7335
8881
|
);
|
|
7336
8882
|
return response;
|
|
7337
8883
|
}
|
|
7338
8884
|
).delete("/api/projects/:projectId/sessions/:sessionId", async (c) => {
|
|
7339
8885
|
const response = await effectToResponse(
|
|
7340
8886
|
c,
|
|
7341
|
-
sessionController.deleteSession({ ...c.req.param() }).pipe(
|
|
8887
|
+
sessionController.deleteSession({ ...c.req.param() }).pipe(Effect51.provide(runtime))
|
|
7342
8888
|
);
|
|
7343
8889
|
return response;
|
|
7344
8890
|
}).get(
|
|
7345
8891
|
"/api/projects/:projectId/agent-sessions/:agentId",
|
|
7346
|
-
zValidator("query",
|
|
8892
|
+
zValidator("query", z31.object({ sessionId: z31.string().optional() })),
|
|
7347
8893
|
async (c) => {
|
|
7348
8894
|
const { projectId, agentId } = c.req.param();
|
|
7349
8895
|
const { sessionId } = c.req.valid("query");
|
|
@@ -7353,7 +8899,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7353
8899
|
projectId,
|
|
7354
8900
|
agentId,
|
|
7355
8901
|
sessionId
|
|
7356
|
-
}).pipe(
|
|
8902
|
+
}).pipe(Effect51.provide(runtime))
|
|
7357
8903
|
);
|
|
7358
8904
|
return response;
|
|
7359
8905
|
}
|
|
@@ -7362,16 +8908,16 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7362
8908
|
c,
|
|
7363
8909
|
gitController.getCurrentRevisions({
|
|
7364
8910
|
...c.req.param()
|
|
7365
|
-
}).pipe(
|
|
8911
|
+
}).pipe(Effect51.provide(runtime))
|
|
7366
8912
|
);
|
|
7367
8913
|
return response;
|
|
7368
8914
|
}).post(
|
|
7369
8915
|
"/api/projects/:projectId/git/diff",
|
|
7370
8916
|
zValidator(
|
|
7371
8917
|
"json",
|
|
7372
|
-
|
|
7373
|
-
fromRef:
|
|
7374
|
-
toRef:
|
|
8918
|
+
z31.object({
|
|
8919
|
+
fromRef: z31.string().min(1, "fromRef is required"),
|
|
8920
|
+
toRef: z31.string().min(1, "toRef is required")
|
|
7375
8921
|
})
|
|
7376
8922
|
),
|
|
7377
8923
|
async (c) => {
|
|
@@ -7380,7 +8926,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7380
8926
|
gitController.getGitDiff({
|
|
7381
8927
|
...c.req.param(),
|
|
7382
8928
|
...c.req.valid("json")
|
|
7383
|
-
}).pipe(
|
|
8929
|
+
}).pipe(Effect51.provide(runtime))
|
|
7384
8930
|
);
|
|
7385
8931
|
return response;
|
|
7386
8932
|
}
|
|
@@ -7393,7 +8939,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7393
8939
|
gitController.commitFiles({
|
|
7394
8940
|
...c.req.param(),
|
|
7395
8941
|
...c.req.valid("json")
|
|
7396
|
-
}).pipe(
|
|
8942
|
+
}).pipe(Effect51.provide(runtime))
|
|
7397
8943
|
);
|
|
7398
8944
|
return response;
|
|
7399
8945
|
}
|
|
@@ -7406,7 +8952,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7406
8952
|
gitController.pushCommits({
|
|
7407
8953
|
...c.req.param(),
|
|
7408
8954
|
...c.req.valid("json")
|
|
7409
|
-
}).pipe(
|
|
8955
|
+
}).pipe(Effect51.provide(runtime))
|
|
7410
8956
|
);
|
|
7411
8957
|
return response;
|
|
7412
8958
|
}
|
|
@@ -7419,7 +8965,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7419
8965
|
gitController.commitAndPush({
|
|
7420
8966
|
...c.req.param(),
|
|
7421
8967
|
...c.req.valid("json")
|
|
7422
|
-
}).pipe(
|
|
8968
|
+
}).pipe(Effect51.provide(runtime))
|
|
7423
8969
|
);
|
|
7424
8970
|
return response;
|
|
7425
8971
|
}
|
|
@@ -7428,7 +8974,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7428
8974
|
c,
|
|
7429
8975
|
claudeCodeController.getClaudeCommands({
|
|
7430
8976
|
...c.req.param()
|
|
7431
|
-
}).pipe(
|
|
8977
|
+
}).pipe(Effect51.provide(runtime))
|
|
7432
8978
|
);
|
|
7433
8979
|
return response;
|
|
7434
8980
|
}).get("/api/projects/:projectId/mcp/list", async (c) => {
|
|
@@ -7436,19 +8982,19 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7436
8982
|
c,
|
|
7437
8983
|
claudeCodeController.getMcpListRoute({
|
|
7438
8984
|
...c.req.param()
|
|
7439
|
-
}).pipe(
|
|
8985
|
+
}).pipe(Effect51.provide(runtime))
|
|
7440
8986
|
);
|
|
7441
8987
|
return response;
|
|
7442
8988
|
}).get("/api/cc/meta", async (c) => {
|
|
7443
8989
|
const response = await effectToResponse(
|
|
7444
8990
|
c,
|
|
7445
|
-
claudeCodeController.getClaudeCodeMeta().pipe(
|
|
8991
|
+
claudeCodeController.getClaudeCodeMeta().pipe(Effect51.provide(runtime))
|
|
7446
8992
|
);
|
|
7447
8993
|
return response;
|
|
7448
8994
|
}).get("/api/cc/features", async (c) => {
|
|
7449
8995
|
const response = await effectToResponse(
|
|
7450
8996
|
c,
|
|
7451
|
-
claudeCodeController.getAvailableFeatures().pipe(
|
|
8997
|
+
claudeCodeController.getAvailableFeatures().pipe(Effect51.provide(runtime))
|
|
7452
8998
|
);
|
|
7453
8999
|
return response;
|
|
7454
9000
|
}).get("/api/cc/session-processes", async (c) => {
|
|
@@ -7461,10 +9007,10 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7461
9007
|
"/api/cc/session-processes",
|
|
7462
9008
|
zValidator(
|
|
7463
9009
|
"json",
|
|
7464
|
-
|
|
7465
|
-
projectId:
|
|
9010
|
+
z31.object({
|
|
9011
|
+
projectId: z31.string(),
|
|
7466
9012
|
input: userMessageInputSchema,
|
|
7467
|
-
baseSessionId:
|
|
9013
|
+
baseSessionId: z31.string().optional()
|
|
7468
9014
|
})
|
|
7469
9015
|
),
|
|
7470
9016
|
async (c) => {
|
|
@@ -7480,10 +9026,10 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7480
9026
|
"/api/cc/session-processes/:sessionProcessId/continue",
|
|
7481
9027
|
zValidator(
|
|
7482
9028
|
"json",
|
|
7483
|
-
|
|
7484
|
-
projectId:
|
|
9029
|
+
z31.object({
|
|
9030
|
+
projectId: z31.string(),
|
|
7485
9031
|
input: userMessageInputSchema,
|
|
7486
|
-
baseSessionId:
|
|
9032
|
+
baseSessionId: z31.string()
|
|
7487
9033
|
})
|
|
7488
9034
|
),
|
|
7489
9035
|
async (c) => {
|
|
@@ -7492,16 +9038,16 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7492
9038
|
claudeCodeSessionProcessController.continueSessionProcess({
|
|
7493
9039
|
...c.req.param(),
|
|
7494
9040
|
...c.req.valid("json")
|
|
7495
|
-
}).pipe(
|
|
9041
|
+
}).pipe(Effect51.provide(runtime))
|
|
7496
9042
|
);
|
|
7497
9043
|
return response;
|
|
7498
9044
|
}
|
|
7499
9045
|
).post(
|
|
7500
9046
|
"/api/cc/session-processes/:sessionProcessId/abort",
|
|
7501
|
-
zValidator("json",
|
|
9047
|
+
zValidator("json", z31.object({ projectId: z31.string() })),
|
|
7502
9048
|
async (c) => {
|
|
7503
9049
|
const { sessionProcessId } = c.req.param();
|
|
7504
|
-
void
|
|
9050
|
+
void Effect51.runFork(
|
|
7505
9051
|
claudeCodeLifeCycleService.abortTask(sessionProcessId)
|
|
7506
9052
|
);
|
|
7507
9053
|
return c.json({ message: "Task aborted" });
|
|
@@ -7510,9 +9056,9 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7510
9056
|
"/api/cc/permission-response",
|
|
7511
9057
|
zValidator(
|
|
7512
9058
|
"json",
|
|
7513
|
-
|
|
7514
|
-
permissionRequestId:
|
|
7515
|
-
decision:
|
|
9059
|
+
z31.object({
|
|
9060
|
+
permissionRequestId: z31.string(),
|
|
9061
|
+
decision: z31.enum(["allow", "deny"])
|
|
7516
9062
|
})
|
|
7517
9063
|
),
|
|
7518
9064
|
async (c) => {
|
|
@@ -7529,7 +9075,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7529
9075
|
c,
|
|
7530
9076
|
async (rawStream) => {
|
|
7531
9077
|
await Runtime3.runPromise(runtime)(
|
|
7532
|
-
sseController.handleSSE(rawStream).pipe(
|
|
9078
|
+
sseController.handleSSE(rawStream).pipe(Effect51.provide(TypeSafeSSE.make(rawStream)))
|
|
7533
9079
|
);
|
|
7534
9080
|
},
|
|
7535
9081
|
async (err) => {
|
|
@@ -7539,7 +9085,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7539
9085
|
}).get("/api/scheduler/jobs", async (c) => {
|
|
7540
9086
|
const response = await effectToResponse(
|
|
7541
9087
|
c,
|
|
7542
|
-
schedulerController.getJobs().pipe(
|
|
9088
|
+
schedulerController.getJobs().pipe(Effect51.provide(runtime))
|
|
7543
9089
|
);
|
|
7544
9090
|
return response;
|
|
7545
9091
|
}).post(
|
|
@@ -7550,7 +9096,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7550
9096
|
c,
|
|
7551
9097
|
schedulerController.addJob({
|
|
7552
9098
|
job: c.req.valid("json")
|
|
7553
|
-
}).pipe(
|
|
9099
|
+
}).pipe(Effect51.provide(runtime))
|
|
7554
9100
|
);
|
|
7555
9101
|
return response;
|
|
7556
9102
|
}
|
|
@@ -7563,7 +9109,7 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7563
9109
|
schedulerController.updateJob({
|
|
7564
9110
|
id: c.req.param("id"),
|
|
7565
9111
|
job: c.req.valid("json")
|
|
7566
|
-
}).pipe(
|
|
9112
|
+
}).pipe(Effect51.provide(runtime))
|
|
7567
9113
|
);
|
|
7568
9114
|
return response;
|
|
7569
9115
|
}
|
|
@@ -7572,16 +9118,16 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7572
9118
|
c,
|
|
7573
9119
|
schedulerController.deleteJob({
|
|
7574
9120
|
id: c.req.param("id")
|
|
7575
|
-
}).pipe(
|
|
9121
|
+
}).pipe(Effect51.provide(runtime))
|
|
7576
9122
|
);
|
|
7577
9123
|
return response;
|
|
7578
9124
|
}).get(
|
|
7579
9125
|
"/api/fs/file-completion",
|
|
7580
9126
|
zValidator(
|
|
7581
9127
|
"query",
|
|
7582
|
-
|
|
7583
|
-
projectId:
|
|
7584
|
-
basePath:
|
|
9128
|
+
z31.object({
|
|
9129
|
+
projectId: z31.string(),
|
|
9130
|
+
basePath: z31.string().optional().default("/api/")
|
|
7585
9131
|
})
|
|
7586
9132
|
),
|
|
7587
9133
|
async (c) => {
|
|
@@ -7597,9 +9143,9 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7597
9143
|
"/api/fs/directory-browser",
|
|
7598
9144
|
zValidator(
|
|
7599
9145
|
"query",
|
|
7600
|
-
|
|
7601
|
-
currentPath:
|
|
7602
|
-
showHidden:
|
|
9146
|
+
z31.object({
|
|
9147
|
+
currentPath: z31.string().optional(),
|
|
9148
|
+
showHidden: z31.string().optional().transform((val) => val === "true")
|
|
7603
9149
|
})
|
|
7604
9150
|
),
|
|
7605
9151
|
async (c) => {
|
|
@@ -7615,42 +9161,119 @@ var routes = (app, options) => Effect47.gen(function* () {
|
|
|
7615
9161
|
"/api/search",
|
|
7616
9162
|
zValidator(
|
|
7617
9163
|
"query",
|
|
7618
|
-
|
|
7619
|
-
q:
|
|
7620
|
-
limit:
|
|
7621
|
-
projectId:
|
|
9164
|
+
z31.object({
|
|
9165
|
+
q: z31.string().min(2),
|
|
9166
|
+
limit: z31.string().optional().transform((val) => val ? parseInt(val, 10) : void 0),
|
|
9167
|
+
projectId: z31.string().optional()
|
|
7622
9168
|
})
|
|
7623
9169
|
),
|
|
7624
9170
|
async (c) => {
|
|
7625
9171
|
const { q, limit, projectId } = c.req.valid("query");
|
|
7626
9172
|
const response = await effectToResponse(
|
|
7627
9173
|
c,
|
|
7628
|
-
searchController.search({ query: q, limit, projectId }).pipe(
|
|
9174
|
+
searchController.search({ query: q, limit, projectId }).pipe(Effect51.provide(runtime))
|
|
7629
9175
|
);
|
|
7630
9176
|
return response;
|
|
7631
9177
|
}
|
|
7632
9178
|
).get("/api/flags", async (c) => {
|
|
7633
9179
|
const response = await effectToResponse(
|
|
7634
9180
|
c,
|
|
7635
|
-
featureFlagController.getFlags().pipe(
|
|
9181
|
+
featureFlagController.getFlags().pipe(Effect51.provide(runtime))
|
|
7636
9182
|
);
|
|
7637
9183
|
return response;
|
|
7638
|
-
})
|
|
9184
|
+
}).get(
|
|
9185
|
+
"/api/tasks",
|
|
9186
|
+
zValidator(
|
|
9187
|
+
"query",
|
|
9188
|
+
z31.object({
|
|
9189
|
+
projectId: z31.string(),
|
|
9190
|
+
sessionId: z31.string().optional()
|
|
9191
|
+
})
|
|
9192
|
+
),
|
|
9193
|
+
async (c) => {
|
|
9194
|
+
const { projectId, sessionId } = c.req.valid("query");
|
|
9195
|
+
const projectPath = decodeProjectId(projectId);
|
|
9196
|
+
const response = await effectToResponse(
|
|
9197
|
+
c,
|
|
9198
|
+
tasksController.listTasks(projectPath, sessionId).pipe(
|
|
9199
|
+
Effect51.map((tasks) => ({
|
|
9200
|
+
status: 200,
|
|
9201
|
+
response: tasks
|
|
9202
|
+
})),
|
|
9203
|
+
Effect51.provide(runtime)
|
|
9204
|
+
)
|
|
9205
|
+
);
|
|
9206
|
+
return response;
|
|
9207
|
+
}
|
|
9208
|
+
).post(
|
|
9209
|
+
"/api/tasks",
|
|
9210
|
+
zValidator(
|
|
9211
|
+
"query",
|
|
9212
|
+
z31.object({
|
|
9213
|
+
projectId: z31.string(),
|
|
9214
|
+
sessionId: z31.string().optional()
|
|
9215
|
+
})
|
|
9216
|
+
),
|
|
9217
|
+
zValidator("json", TaskCreateSchema),
|
|
9218
|
+
async (c) => {
|
|
9219
|
+
const { projectId, sessionId } = c.req.valid("query");
|
|
9220
|
+
const body = c.req.valid("json");
|
|
9221
|
+
const projectPath = decodeProjectId(projectId);
|
|
9222
|
+
const response = await effectToResponse(
|
|
9223
|
+
c,
|
|
9224
|
+
tasksController.createTask(projectPath, body, sessionId).pipe(
|
|
9225
|
+
Effect51.map((task) => ({
|
|
9226
|
+
status: 200,
|
|
9227
|
+
response: task
|
|
9228
|
+
})),
|
|
9229
|
+
Effect51.provide(runtime)
|
|
9230
|
+
)
|
|
9231
|
+
);
|
|
9232
|
+
return response;
|
|
9233
|
+
}
|
|
9234
|
+
).patch(
|
|
9235
|
+
"/api/tasks/:id",
|
|
9236
|
+
zValidator(
|
|
9237
|
+
"query",
|
|
9238
|
+
z31.object({
|
|
9239
|
+
projectId: z31.string(),
|
|
9240
|
+
sessionId: z31.string().optional()
|
|
9241
|
+
})
|
|
9242
|
+
),
|
|
9243
|
+
zValidator("json", TaskUpdateSchema.omit({ taskId: true })),
|
|
9244
|
+
async (c) => {
|
|
9245
|
+
const { id } = c.req.param();
|
|
9246
|
+
const { projectId, sessionId } = c.req.valid("query");
|
|
9247
|
+
const body = c.req.valid("json");
|
|
9248
|
+
const projectPath = decodeProjectId(projectId);
|
|
9249
|
+
const response = await effectToResponse(
|
|
9250
|
+
c,
|
|
9251
|
+
tasksController.updateTask(projectPath, { ...body, taskId: id }, sessionId).pipe(
|
|
9252
|
+
Effect51.map((task) => ({
|
|
9253
|
+
status: 200,
|
|
9254
|
+
response: task
|
|
9255
|
+
})),
|
|
9256
|
+
Effect51.provide(runtime)
|
|
9257
|
+
)
|
|
9258
|
+
);
|
|
9259
|
+
return response;
|
|
9260
|
+
}
|
|
9261
|
+
);
|
|
7639
9262
|
});
|
|
7640
9263
|
|
|
7641
9264
|
// src/server/lib/effect/layers.ts
|
|
7642
9265
|
import { NodeContext } from "@effect/platform-node";
|
|
7643
|
-
import { Layer as
|
|
7644
|
-
var platformLayer =
|
|
9266
|
+
import { Layer as Layer42 } from "effect";
|
|
9267
|
+
var platformLayer = Layer42.mergeAll(
|
|
7645
9268
|
ApplicationContext.Live,
|
|
7646
9269
|
UserConfigService.Live,
|
|
7647
9270
|
EventBus.Live,
|
|
7648
9271
|
EnvService.Live,
|
|
7649
9272
|
CcvOptionsService.Live
|
|
7650
9273
|
).pipe(
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
9274
|
+
Layer42.provide(EnvService.Live),
|
|
9275
|
+
Layer42.provide(CcvOptionsService.Live),
|
|
9276
|
+
Layer42.provide(NodeContext.layer)
|
|
7654
9277
|
);
|
|
7655
9278
|
|
|
7656
9279
|
// src/server/startServer.ts
|
|
@@ -7673,49 +9296,8 @@ var startServer = async (options) => {
|
|
|
7673
9296
|
return c.html(html);
|
|
7674
9297
|
});
|
|
7675
9298
|
}
|
|
7676
|
-
const program2 = routes(honoApp, options).pipe(
|
|
7677
|
-
|
|
7678
|
-
Effect48.provide(ProjectController.Live),
|
|
7679
|
-
Effect48.provide(SessionController.Live),
|
|
7680
|
-
Effect48.provide(AgentSessionController.Live),
|
|
7681
|
-
Effect48.provide(GitController.Live),
|
|
7682
|
-
Effect48.provide(ClaudeCodeController.Live),
|
|
7683
|
-
Effect48.provide(ClaudeCodeSessionProcessController.Live),
|
|
7684
|
-
Effect48.provide(ClaudeCodePermissionController.Live),
|
|
7685
|
-
Effect48.provide(FileSystemController.Live),
|
|
7686
|
-
Effect48.provide(SSEController.Live),
|
|
7687
|
-
Effect48.provide(SchedulerController.Live),
|
|
7688
|
-
Effect48.provide(FeatureFlagController.Live),
|
|
7689
|
-
Effect48.provide(SearchController.Live)
|
|
7690
|
-
).pipe(
|
|
7691
|
-
/** Application */
|
|
7692
|
-
Effect48.provide(InitializeService.Live),
|
|
7693
|
-
Effect48.provide(FileWatcherService.Live),
|
|
7694
|
-
Effect48.provide(AuthMiddleware.Live)
|
|
7695
|
-
).pipe(
|
|
7696
|
-
/** Domain */
|
|
7697
|
-
Effect48.provide(ClaudeCodeLifeCycleService.Live),
|
|
7698
|
-
Effect48.provide(ClaudeCodePermissionService.Live),
|
|
7699
|
-
Effect48.provide(ClaudeCodeSessionProcessService.Live),
|
|
7700
|
-
Effect48.provide(ClaudeCodeService.Live),
|
|
7701
|
-
Effect48.provide(GitService.Live),
|
|
7702
|
-
Effect48.provide(SchedulerService.Live),
|
|
7703
|
-
Effect48.provide(SchedulerConfigBaseDir.Live),
|
|
7704
|
-
Effect48.provide(SearchService.Live)
|
|
7705
|
-
).pipe(
|
|
7706
|
-
/** Infrastructure */
|
|
7707
|
-
Effect48.provide(ProjectRepository.Live),
|
|
7708
|
-
Effect48.provide(SessionRepository.Live),
|
|
7709
|
-
Effect48.provide(ProjectMetaService.Live),
|
|
7710
|
-
Effect48.provide(SessionMetaService.Live),
|
|
7711
|
-
Effect48.provide(VirtualConversationDatabase.Live),
|
|
7712
|
-
Effect48.provide(AgentSessionLayer)
|
|
7713
|
-
).pipe(
|
|
7714
|
-
/** Platform */
|
|
7715
|
-
Effect48.provide(platformLayer),
|
|
7716
|
-
Effect48.provide(NodeContext2.layer)
|
|
7717
|
-
);
|
|
7718
|
-
await Effect48.runPromise(program2);
|
|
9299
|
+
const program2 = routes(honoApp, options).pipe(Effect52.provide(MainLayer));
|
|
9300
|
+
await Effect52.runPromise(program2);
|
|
7719
9301
|
const port = isDevelopment ? (
|
|
7720
9302
|
// biome-ignore lint/style/noProcessEnv: allow only here
|
|
7721
9303
|
process.env.DEV_BE_PORT ?? "3401"
|
|
@@ -7735,12 +9317,65 @@ var startServer = async (options) => {
|
|
|
7735
9317
|
}
|
|
7736
9318
|
);
|
|
7737
9319
|
};
|
|
9320
|
+
var PlatformLayer = Layer43.mergeAll(platformLayer, NodeContext2.layer);
|
|
9321
|
+
var InfraBasics = Layer43.mergeAll(
|
|
9322
|
+
VirtualConversationDatabase.Live,
|
|
9323
|
+
ProjectMetaService.Live,
|
|
9324
|
+
SessionMetaService.Live
|
|
9325
|
+
);
|
|
9326
|
+
var InfraRepos = Layer43.mergeAll(
|
|
9327
|
+
ProjectRepository.Live,
|
|
9328
|
+
SessionRepository.Live
|
|
9329
|
+
).pipe(Layer43.provideMerge(InfraBasics));
|
|
9330
|
+
var InfraLayer = AgentSessionLayer.pipe(Layer43.provideMerge(InfraRepos));
|
|
9331
|
+
var DomainBase = Layer43.mergeAll(
|
|
9332
|
+
ClaudeCodePermissionService.Live,
|
|
9333
|
+
ClaudeCodeSessionProcessService.Live,
|
|
9334
|
+
ClaudeCodeService.Live,
|
|
9335
|
+
GitService.Live,
|
|
9336
|
+
SchedulerService.Live,
|
|
9337
|
+
SchedulerConfigBaseDir.Live,
|
|
9338
|
+
SearchService.Live,
|
|
9339
|
+
TasksService.Live
|
|
9340
|
+
);
|
|
9341
|
+
var DomainLayer = ClaudeCodeLifeCycleService.Live.pipe(
|
|
9342
|
+
Layer43.provideMerge(DomainBase)
|
|
9343
|
+
);
|
|
9344
|
+
var AppServices = Layer43.mergeAll(
|
|
9345
|
+
FileWatcherService.Live,
|
|
9346
|
+
RateLimitAutoScheduleService.Live,
|
|
9347
|
+
AuthMiddleware.Live
|
|
9348
|
+
);
|
|
9349
|
+
var ApplicationLayer = InitializeService.Live.pipe(
|
|
9350
|
+
Layer43.provideMerge(AppServices)
|
|
9351
|
+
);
|
|
9352
|
+
var PresentationLayer = Layer43.mergeAll(
|
|
9353
|
+
ProjectController.Live,
|
|
9354
|
+
SessionController.Live,
|
|
9355
|
+
AgentSessionController.Live,
|
|
9356
|
+
GitController.Live,
|
|
9357
|
+
ClaudeCodeController.Live,
|
|
9358
|
+
ClaudeCodeSessionProcessController.Live,
|
|
9359
|
+
ClaudeCodePermissionController.Live,
|
|
9360
|
+
FileSystemController.Live,
|
|
9361
|
+
SSEController.Live,
|
|
9362
|
+
SchedulerController.Live,
|
|
9363
|
+
FeatureFlagController.Live,
|
|
9364
|
+
SearchController.Live,
|
|
9365
|
+
TasksController.Live
|
|
9366
|
+
);
|
|
9367
|
+
var MainLayer = PresentationLayer.pipe(
|
|
9368
|
+
Layer43.provideMerge(ApplicationLayer),
|
|
9369
|
+
Layer43.provideMerge(DomainLayer),
|
|
9370
|
+
Layer43.provideMerge(InfraLayer),
|
|
9371
|
+
Layer43.provideMerge(PlatformLayer)
|
|
9372
|
+
);
|
|
7738
9373
|
|
|
7739
9374
|
// src/server/main.ts
|
|
7740
9375
|
var program = new Command3();
|
|
7741
9376
|
program.name(package_default.name).version(package_default.version).description(package_default.description);
|
|
7742
9377
|
program.option("-p, --port <port>", "port to listen on").option("-h, --hostname <hostname>", "hostname to listen on").option("-P, --password <password>", "password to authenticate").option("-e, --executable <executable>", "path to claude code executable").option("--claude-dir <claude-dir>", "path to claude directory").action(async (options) => {
|
|
7743
|
-
await
|
|
9378
|
+
await Effect53.runPromise(checkDeprecatedEnvs);
|
|
7744
9379
|
await startServer(options);
|
|
7745
9380
|
});
|
|
7746
9381
|
var main = async () => {
|