@knowsuchagency/fulcrum 2.5.0 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/fulcrum.js +3 -3
- package/dist/assets/{index-DSaPCUvd.js → index-DNNOyQp7.js} +177 -177
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/server/index.js +145 -7
package/dist/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<link rel="icon" type="image/png" href="/logo.png" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Fulcrum</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DNNOyQp7.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-D6ht7k3-.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -1109,7 +1109,7 @@ function notInArray(column, values) {
|
|
|
1109
1109
|
function isNull(value) {
|
|
1110
1110
|
return sql`${value} is null`;
|
|
1111
1111
|
}
|
|
1112
|
-
function
|
|
1112
|
+
function isNotNull2(value) {
|
|
1113
1113
|
return sql`${value} is not null`;
|
|
1114
1114
|
}
|
|
1115
1115
|
function exists(subquery) {
|
|
@@ -1185,7 +1185,7 @@ function getOperators() {
|
|
|
1185
1185
|
ilike,
|
|
1186
1186
|
inArray,
|
|
1187
1187
|
isNull,
|
|
1188
|
-
isNotNull,
|
|
1188
|
+
isNotNull: isNotNull2,
|
|
1189
1189
|
like,
|
|
1190
1190
|
lt,
|
|
1191
1191
|
lte,
|
|
@@ -71282,7 +71282,10 @@ function getSession(id) {
|
|
|
71282
71282
|
function listSessions(options) {
|
|
71283
71283
|
const { limit: limit2 = 50, offset = 0, projectId, search, favorites } = options;
|
|
71284
71284
|
const conditions2 = [];
|
|
71285
|
-
|
|
71285
|
+
const assistantSessionIds = db2.select({ sessionId: messagingSessionMappings.sessionId }).from(messagingSessionMappings).where(like(messagingSessionMappings.connectionId, "assistant-%")).all().map((row) => row.sessionId);
|
|
71286
|
+
if (assistantSessionIds.length > 0) {
|
|
71287
|
+
conditions2.push(notInArray(chatSessions.id, assistantSessionIds));
|
|
71288
|
+
}
|
|
71286
71289
|
if (projectId) {
|
|
71287
71290
|
conditions2.push(eq(chatSessions.projectId, projectId));
|
|
71288
71291
|
}
|
|
@@ -71446,6 +71449,137 @@ This will automatically update the editor. Always provide the COMPLETE document,
|
|
|
71446
71449
|
|
|
71447
71450
|
${uiFeatures}`;
|
|
71448
71451
|
}
|
|
71452
|
+
function buildPageContextString(context) {
|
|
71453
|
+
const contextParts = [];
|
|
71454
|
+
contextParts.push(`Current page: ${context.path}`);
|
|
71455
|
+
switch (context.pageType) {
|
|
71456
|
+
case "task": {
|
|
71457
|
+
if (context.taskId) {
|
|
71458
|
+
const task = db2.select().from(tasks).where(eq(tasks.id, context.taskId)).get();
|
|
71459
|
+
if (task) {
|
|
71460
|
+
contextParts.push(`Viewing task: "${task.title}"`);
|
|
71461
|
+
contextParts.push(`Status: ${task.status}`);
|
|
71462
|
+
if (task.branch)
|
|
71463
|
+
contextParts.push(`Branch: ${task.branch}`);
|
|
71464
|
+
if (task.repoName)
|
|
71465
|
+
contextParts.push(`Repository: ${task.repoName}`);
|
|
71466
|
+
if (task.description)
|
|
71467
|
+
contextParts.push(`Description: ${task.description}`);
|
|
71468
|
+
if (task.worktreePath)
|
|
71469
|
+
contextParts.push(`Worktree: ${task.worktreePath}`);
|
|
71470
|
+
}
|
|
71471
|
+
}
|
|
71472
|
+
break;
|
|
71473
|
+
}
|
|
71474
|
+
case "tasks": {
|
|
71475
|
+
contextParts.push("Viewing the tasks kanban board");
|
|
71476
|
+
if (context.filters?.project) {
|
|
71477
|
+
if (context.filters.project === "inbox") {
|
|
71478
|
+
contextParts.push("Filtered to: Inbox (tasks without a project)");
|
|
71479
|
+
} else {
|
|
71480
|
+
const project = db2.select().from(projects).where(eq(projects.id, context.filters.project)).get();
|
|
71481
|
+
if (project) {
|
|
71482
|
+
contextParts.push(`Filtered to project: "${project.name}"`);
|
|
71483
|
+
}
|
|
71484
|
+
}
|
|
71485
|
+
}
|
|
71486
|
+
if (context.filters?.tags?.length) {
|
|
71487
|
+
contextParts.push(`Filtered by tags: ${context.filters.tags.join(", ")}`);
|
|
71488
|
+
}
|
|
71489
|
+
if (context.filters?.view) {
|
|
71490
|
+
contextParts.push(`View mode: ${context.filters.view}`);
|
|
71491
|
+
}
|
|
71492
|
+
break;
|
|
71493
|
+
}
|
|
71494
|
+
case "project": {
|
|
71495
|
+
if (context.projectId) {
|
|
71496
|
+
const project = db2.select().from(projects).where(eq(projects.id, context.projectId)).get();
|
|
71497
|
+
if (project) {
|
|
71498
|
+
contextParts.push(`Viewing project: "${project.name}"`);
|
|
71499
|
+
if (project.description)
|
|
71500
|
+
contextParts.push(`Description: ${project.description}`);
|
|
71501
|
+
if (project.status)
|
|
71502
|
+
contextParts.push(`Status: ${project.status}`);
|
|
71503
|
+
const repoLinks = db2.select().from(projectRepositories).where(eq(projectRepositories.projectId, context.projectId)).all();
|
|
71504
|
+
if (repoLinks.length > 0) {
|
|
71505
|
+
contextParts.push(`Linked repositories: ${repoLinks.length}`);
|
|
71506
|
+
}
|
|
71507
|
+
}
|
|
71508
|
+
}
|
|
71509
|
+
break;
|
|
71510
|
+
}
|
|
71511
|
+
case "projects": {
|
|
71512
|
+
contextParts.push("Viewing the projects list");
|
|
71513
|
+
break;
|
|
71514
|
+
}
|
|
71515
|
+
case "repository": {
|
|
71516
|
+
if (context.repositoryId) {
|
|
71517
|
+
const repo = db2.select().from(repositories).where(eq(repositories.id, context.repositoryId)).get();
|
|
71518
|
+
if (repo) {
|
|
71519
|
+
contextParts.push(`Viewing repository: "${repo.displayName}"`);
|
|
71520
|
+
contextParts.push(`Path: ${repo.path}`);
|
|
71521
|
+
if (repo.defaultAgent)
|
|
71522
|
+
contextParts.push(`Default agent: ${repo.defaultAgent}`);
|
|
71523
|
+
if (repo.remoteUrl)
|
|
71524
|
+
contextParts.push(`Remote: ${repo.remoteUrl}`);
|
|
71525
|
+
}
|
|
71526
|
+
}
|
|
71527
|
+
break;
|
|
71528
|
+
}
|
|
71529
|
+
case "repositories": {
|
|
71530
|
+
contextParts.push("Viewing the repositories list");
|
|
71531
|
+
break;
|
|
71532
|
+
}
|
|
71533
|
+
case "app": {
|
|
71534
|
+
if (context.appId) {
|
|
71535
|
+
const app23 = db2.select().from(apps).where(eq(apps.id, context.appId)).get();
|
|
71536
|
+
if (app23) {
|
|
71537
|
+
contextParts.push(`Viewing app: "${app23.name}"`);
|
|
71538
|
+
contextParts.push(`Status: ${app23.status}`);
|
|
71539
|
+
contextParts.push(`Branch: ${app23.branch}`);
|
|
71540
|
+
if (app23.lastDeployedAt)
|
|
71541
|
+
contextParts.push(`Last deployed: ${app23.lastDeployedAt}`);
|
|
71542
|
+
}
|
|
71543
|
+
}
|
|
71544
|
+
break;
|
|
71545
|
+
}
|
|
71546
|
+
case "apps": {
|
|
71547
|
+
contextParts.push("Viewing the apps deployment list");
|
|
71548
|
+
break;
|
|
71549
|
+
}
|
|
71550
|
+
case "monitoring": {
|
|
71551
|
+
contextParts.push("Viewing the monitoring dashboard");
|
|
71552
|
+
if (context.activeTab) {
|
|
71553
|
+
contextParts.push(`Active tab: ${context.activeTab}`);
|
|
71554
|
+
}
|
|
71555
|
+
break;
|
|
71556
|
+
}
|
|
71557
|
+
case "terminals": {
|
|
71558
|
+
contextParts.push("Viewing the persistent terminals page");
|
|
71559
|
+
break;
|
|
71560
|
+
}
|
|
71561
|
+
case "jobs":
|
|
71562
|
+
case "job": {
|
|
71563
|
+
contextParts.push(context.pageType === "jobs" ? "Viewing scheduled jobs list" : `Viewing job details`);
|
|
71564
|
+
if (context.jobId) {
|
|
71565
|
+
contextParts.push(`Job ID: ${context.jobId}`);
|
|
71566
|
+
}
|
|
71567
|
+
break;
|
|
71568
|
+
}
|
|
71569
|
+
case "settings": {
|
|
71570
|
+
contextParts.push("Viewing the settings page");
|
|
71571
|
+
break;
|
|
71572
|
+
}
|
|
71573
|
+
}
|
|
71574
|
+
if (contextParts.length > 0) {
|
|
71575
|
+
return `
|
|
71576
|
+
|
|
71577
|
+
Current Context:
|
|
71578
|
+
${contextParts.map((p) => `- ${p}`).join(`
|
|
71579
|
+
`)}`;
|
|
71580
|
+
}
|
|
71581
|
+
return "";
|
|
71582
|
+
}
|
|
71449
71583
|
async function* streamMessage2(sessionId, userMessage, modelIdOrOptions, editorContent) {
|
|
71450
71584
|
const options = typeof modelIdOrOptions === "object" ? modelIdOrOptions : { modelId: modelIdOrOptions, editorContent };
|
|
71451
71585
|
const session3 = getSession(sessionId);
|
|
@@ -71482,6 +71616,9 @@ async function* streamMessage2(sessionId, userMessage, modelIdOrOptions, editorC
|
|
|
71482
71616
|
${options.systemPromptAdditions}`;
|
|
71483
71617
|
} else {
|
|
71484
71618
|
systemPrompt = buildSystemPrompt2();
|
|
71619
|
+
if (options.context) {
|
|
71620
|
+
systemPrompt += buildPageContextString(options.context);
|
|
71621
|
+
}
|
|
71485
71622
|
}
|
|
71486
71623
|
let textMessage = userMessage;
|
|
71487
71624
|
if (options.editorContent && options.editorContent.trim()) {
|
|
@@ -463721,7 +463858,7 @@ mcpRoutes.all("/", async (c) => {
|
|
|
463721
463858
|
});
|
|
463722
463859
|
const server = new McpServer({
|
|
463723
463860
|
name: "fulcrum",
|
|
463724
|
-
version: "2.5.
|
|
463861
|
+
version: "2.5.2"
|
|
463725
463862
|
});
|
|
463726
463863
|
const client = new FulcrumClient(`http://localhost:${port}`);
|
|
463727
463864
|
registerTools(server, client);
|
|
@@ -465897,7 +466034,7 @@ assistantRoutes.delete("/sessions/:id", async (c) => {
|
|
|
465897
466034
|
});
|
|
465898
466035
|
assistantRoutes.post("/sessions/:id/messages", async (c) => {
|
|
465899
466036
|
const sessionId = c.req.param("id");
|
|
465900
|
-
const { message, model, editorContent, images } = await c.req.json();
|
|
466037
|
+
const { message, model, editorContent, images, context } = await c.req.json();
|
|
465901
466038
|
if ((!message || typeof message !== "string") && (!images || images.length === 0)) {
|
|
465902
466039
|
return c.json({ error: "Message or images required" }, 400);
|
|
465903
466040
|
}
|
|
@@ -465909,7 +466046,8 @@ assistantRoutes.post("/sessions/:id/messages", async (c) => {
|
|
|
465909
466046
|
for await (const event of streamMessage2(sessionId, message || "", {
|
|
465910
466047
|
modelId: model,
|
|
465911
466048
|
editorContent,
|
|
465912
|
-
images
|
|
466049
|
+
images,
|
|
466050
|
+
context
|
|
465913
466051
|
})) {
|
|
465914
466052
|
await stream3.writeSSE({
|
|
465915
466053
|
event: event.type,
|
|
@@ -467053,7 +467191,7 @@ function checkPrStatus(prUrl) {
|
|
|
467053
467191
|
}
|
|
467054
467192
|
}
|
|
467055
467193
|
async function pollPRs() {
|
|
467056
|
-
const tasksWithPR = db2.select().from(tasks).where(and(
|
|
467194
|
+
const tasksWithPR = db2.select().from(tasks).where(and(isNotNull2(tasks.prUrl), notInArray(tasks.status, ["DONE", "CANCELED"]))).all();
|
|
467057
467195
|
for (const task of tasksWithPR) {
|
|
467058
467196
|
if (!task.prUrl)
|
|
467059
467197
|
continue;
|