whipped 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -3529,10 +3529,11 @@ function isResumableSessionState(state) {
|
|
|
3529
3529
|
function normalizeTag(raw2) {
|
|
3530
3530
|
return raw2.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3531
3531
|
}
|
|
3532
|
-
var runtimeAgentIdSchema, effortLevelSchema, agentModelChoiceSchema, workflowSlotTypeSchema, tierLevelSchema, LEVEL_ORDER, modelPairSchema, pairSelectionModeSchema, SLOT_TOOL_IDS, slotToolSchema, slotModelConfigSchema, cardModelConfigSchema, promptValueSchema, EMPTY_INLINE_PROMPT, workflowSlotSchema, DEFAULT_MODEL_PAIR, DEFAULT_SLOT_MODEL_FIELDS, workflowSchema, DEFAULT_WORKFLOW, DEFAULT_STORY_WORKFLOW, DEFAULT_GIT_INSTRUCTIONS, runtimeBoardColumnIdSchema, BOARD_COLUMNS, reviewActorSchema, reviewIssueSchema, reviewAttachmentSchema, runtimeReviewCommentSchema, runtimeActivityEntrySchema, runtimeTaskSessionStateSchema, runtimeTerminalSessionEntrySchema, runtimeCardPrioritySchema, cardTypeSchema, runtimePrMetaSchema, runtimeBoardCardSchema, runtimeBoardColumnSchema, runtimeBoardDataSchema, runtimeGlobalConfigSchema, runtimeGithubConfigSchema, runtimeWorktreeSetupSchema, runtimeProjectSecretSchema, runtimeProjectConfigSchema, runtimeWorkspaceStateResponseSchema, runtimeWorkspaceStateSaveRequestSchema, runtimeVisualElementSchema, runtimeVisualCommentSchema, runtimeCardCreateRequestSchema, runtimeCardMoveRequestSchema, runtimeCardUpdateRequestSchema, memoryScopeSchema, memoryTypeSchema, memorySourceTypeSchema, memoryStatusSchema, runtimeMemoryOriginAgentSchema, runtimeMemorySchema, recurringScheduleKindSchema, recurringScheduleSchema, recurringRunStatusSchema, recurringRunTriggerSchema, recurringAgentRunSchema, recurringAgentSchema, recurringAgentCreateRequestSchema, recurringAgentUpdateRequestSchema, projectFolderSchema, topLevelItemSchema, projectsLayoutSchema, runtimeProjectSchema;
|
|
3532
|
+
var ASSISTANT_AGENT_PREFIX, runtimeAgentIdSchema, effortLevelSchema, agentModelChoiceSchema, workflowSlotTypeSchema, tierLevelSchema, LEVEL_ORDER, modelPairSchema, pairSelectionModeSchema, SLOT_TOOL_IDS, slotToolSchema, slotModelConfigSchema, cardModelConfigSchema, promptValueSchema, EMPTY_INLINE_PROMPT, workflowSlotSchema, DEFAULT_MODEL_PAIR, DEFAULT_SLOT_MODEL_FIELDS, workflowSchema, DEFAULT_WORKFLOW, DEFAULT_STORY_WORKFLOW, DEFAULT_GIT_INSTRUCTIONS, runtimeBoardColumnIdSchema, BOARD_COLUMNS, reviewActorSchema, reviewIssueSchema, reviewAttachmentSchema, runtimeReviewCommentSchema, runtimeActivityEntrySchema, runtimeTaskSessionStateSchema, runtimeTerminalSessionEntrySchema, runtimeCardPrioritySchema, cardTypeSchema, runtimePrMetaSchema, runtimeBoardCardSchema, runtimeBoardColumnSchema, runtimeBoardDataSchema, runtimeGlobalConfigSchema, runtimeGithubConfigSchema, runtimeWorktreeSetupSchema, runtimeProjectSecretSchema, runtimeProjectConfigSchema, runtimeWorkspaceStateResponseSchema, runtimeWorkspaceStateSaveRequestSchema, runtimeVisualElementSchema, runtimeVisualCommentSchema, runtimeCardCreateRequestSchema, runtimeBulkCardImportItemSchema, runtimeBulkCardsCreateRequestSchema, runtimeCardMoveRequestSchema, runtimeCardUpdateRequestSchema, memoryScopeSchema, memoryTypeSchema, memorySourceTypeSchema, memoryStatusSchema, runtimeMemoryOriginAgentSchema, runtimeMemorySchema, recurringScheduleKindSchema, recurringScheduleSchema, recurringRunStatusSchema, recurringRunTriggerSchema, recurringAgentRunSchema, recurringAgentSchema, recurringAgentCreateRequestSchema, recurringAgentUpdateRequestSchema, projectFolderSchema, topLevelItemSchema, projectsLayoutSchema, runtimeProjectSchema;
|
|
3533
3533
|
var init_api_contract = __esm({
|
|
3534
3534
|
"src/core/api-contract.ts"() {
|
|
3535
3535
|
"use strict";
|
|
3536
|
+
ASSISTANT_AGENT_PREFIX = "__assistant__:";
|
|
3536
3537
|
runtimeAgentIdSchema = z.enum(["claude", "codex", "opencode", "cursor", "mimo"]);
|
|
3537
3538
|
effortLevelSchema = z.enum(["low", "medium", "high", "xhigh", "max"]);
|
|
3538
3539
|
agentModelChoiceSchema = z.object({
|
|
@@ -3961,6 +3962,14 @@ Do NOT include:
|
|
|
3961
3962
|
modelConfig: cardModelConfigSchema.optional(),
|
|
3962
3963
|
activeLevel: tierLevelSchema.optional()
|
|
3963
3964
|
});
|
|
3965
|
+
runtimeBulkCardImportItemSchema = runtimeCardCreateRequestSchema.extend({
|
|
3966
|
+
tempId: z.string().optional()
|
|
3967
|
+
});
|
|
3968
|
+
runtimeBulkCardsCreateRequestSchema = z.object({
|
|
3969
|
+
// Batch-wide base branch; an item's own baseRef overrides it, else resolved server-side.
|
|
3970
|
+
baseRef: z.string().optional(),
|
|
3971
|
+
cards: z.array(runtimeBulkCardImportItemSchema).min(1)
|
|
3972
|
+
});
|
|
3964
3973
|
runtimeCardMoveRequestSchema = z.object({
|
|
3965
3974
|
cardId: z.string(),
|
|
3966
3975
|
targetColumnId: runtimeBoardColumnIdSchema,
|
|
@@ -8000,6 +8009,7 @@ __export(workspace_state_exports, {
|
|
|
8000
8009
|
clearCardSession: () => clearCardSession,
|
|
8001
8010
|
closeAllOpenTerminalSessions: () => closeAllOpenTerminalSessions,
|
|
8002
8011
|
createCard: () => createCard,
|
|
8012
|
+
createCardsBulk: () => createCardsBulk,
|
|
8003
8013
|
deleteCard: () => deleteCard,
|
|
8004
8014
|
downloadGithubImages: () => downloadGithubImages,
|
|
8005
8015
|
endTerminalSession: () => endTerminalSession,
|
|
@@ -8550,6 +8560,79 @@ async function createCard(workspaceId, data, baseRef) {
|
|
|
8550
8560
|
tx();
|
|
8551
8561
|
return card;
|
|
8552
8562
|
}
|
|
8563
|
+
async function createCardsBulk(workspaceId, items, baseRef) {
|
|
8564
|
+
const db = getDb();
|
|
8565
|
+
const now = Date.now();
|
|
8566
|
+
const projectConfig = loadProjectConfigInternal(workspaceId);
|
|
8567
|
+
const realIds = items.map(() => generateTaskId());
|
|
8568
|
+
const tempIdToRealId = /* @__PURE__ */ new Map();
|
|
8569
|
+
items.forEach((item, i) => {
|
|
8570
|
+
if (item.tempId) tempIdToRealId.set(item.tempId, realIds[i]);
|
|
8571
|
+
});
|
|
8572
|
+
const resolveRef = (ref) => tempIdToRealId.get(ref) ?? ref;
|
|
8573
|
+
const cards = items.map((item, i) => {
|
|
8574
|
+
const type = item.type ?? "task";
|
|
8575
|
+
const columnId = item.columnId ?? "todo";
|
|
8576
|
+
const workflow = resolveWorkflowForCard(projectConfig.workflows, { workflowId: item.workflowId, type });
|
|
8577
|
+
const waitsFor = (item.waitsFor ?? []).map(resolveRef);
|
|
8578
|
+
const dependsOn = item.dependsOn ? resolveRef(item.dependsOn) : void 0;
|
|
8579
|
+
return {
|
|
8580
|
+
id: realIds[i],
|
|
8581
|
+
description: item.description,
|
|
8582
|
+
columnId,
|
|
8583
|
+
type,
|
|
8584
|
+
readyForDev: item.readyForDev ?? type === "story",
|
|
8585
|
+
agentId: item.agentId,
|
|
8586
|
+
priority: item.priority,
|
|
8587
|
+
// dependsOn (stacking) and waitsFor (gate) are mutually exclusive — waitsFor wins.
|
|
8588
|
+
dependsOn: waitsFor.length > 0 ? void 0 : dependsOn,
|
|
8589
|
+
waitsFor,
|
|
8590
|
+
subtaskIds: (item.subtaskIds ?? []).map(resolveRef),
|
|
8591
|
+
autoFixAttempts: 0,
|
|
8592
|
+
activeLevel: item.activeLevel ?? highestWorkflowLevel(workflow),
|
|
8593
|
+
modelConfig: item.modelConfig ?? snapshotModelConfig(workflow),
|
|
8594
|
+
baseRef: item.baseRef ?? baseRef,
|
|
8595
|
+
createdAt: now,
|
|
8596
|
+
updatedAt: now,
|
|
8597
|
+
githubIssueUrl: item.githubIssueUrl,
|
|
8598
|
+
workflowId: item.workflowId ?? workflow?.id,
|
|
8599
|
+
descriptionAttachments: item.descriptionAttachments ?? [],
|
|
8600
|
+
branchName: item.branchName,
|
|
8601
|
+
reviewComments: [],
|
|
8602
|
+
activityLog: [],
|
|
8603
|
+
terminalSessions: [],
|
|
8604
|
+
githubCommentIds: []
|
|
8605
|
+
};
|
|
8606
|
+
});
|
|
8607
|
+
const columnCounts = /* @__PURE__ */ new Map();
|
|
8608
|
+
const nextPosition = (columnId) => {
|
|
8609
|
+
if (!columnCounts.has(columnId)) {
|
|
8610
|
+
const row = db.prepare("SELECT COUNT(*) AS n FROM cards WHERE workspace_id = ? AND column_id = ?").get(workspaceId, columnId);
|
|
8611
|
+
columnCounts.set(columnId, row.n);
|
|
8612
|
+
}
|
|
8613
|
+
const pos = columnCounts.get(columnId);
|
|
8614
|
+
columnCounts.set(columnId, pos + 1);
|
|
8615
|
+
return pos;
|
|
8616
|
+
};
|
|
8617
|
+
const tx = db.transaction(() => {
|
|
8618
|
+
for (const card of cards) {
|
|
8619
|
+
upsertCardRow(db, workspaceId, { ...card, dependsOn: void 0 }, nextPosition(card.columnId));
|
|
8620
|
+
}
|
|
8621
|
+
const setDep = db.prepare("UPDATE cards SET depends_on_id = ? WHERE id = ?");
|
|
8622
|
+
for (const card of cards) {
|
|
8623
|
+
if (card.dependsOn && db.prepare("SELECT 1 FROM cards WHERE id = ?").get(card.dependsOn)) {
|
|
8624
|
+
setDep.run(card.dependsOn, card.id);
|
|
8625
|
+
} else if (card.dependsOn) {
|
|
8626
|
+
card.dependsOn = void 0;
|
|
8627
|
+
}
|
|
8628
|
+
replaceCardWaitsFor(db, card.id, card.waitsFor ?? []);
|
|
8629
|
+
replaceCardSubtasks(db, card.id, card.subtaskIds ?? []);
|
|
8630
|
+
}
|
|
8631
|
+
bumpBoardRevision(db, workspaceId);
|
|
8632
|
+
});
|
|
8633
|
+
tx();
|
|
8634
|
+
return cards;
|
|
8635
|
+
}
|
|
8553
8636
|
async function appendActivityLog(workspaceId, cardId, message) {
|
|
8554
8637
|
const db = getDb();
|
|
8555
8638
|
const tx = db.transaction(() => {
|
|
@@ -14307,6 +14390,7 @@ init_logger();
|
|
|
14307
14390
|
init_task_id();
|
|
14308
14391
|
|
|
14309
14392
|
// src/daemon/poller.ts
|
|
14393
|
+
init_runtime_config();
|
|
14310
14394
|
init_logger();
|
|
14311
14395
|
init_task_id();
|
|
14312
14396
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
@@ -18655,6 +18739,8 @@ var BoardPoller = class {
|
|
|
18655
18739
|
async poll() {
|
|
18656
18740
|
const { workspaceId, repoPath, scheduler, stateHub, onCardReadyForReview } = this.options;
|
|
18657
18741
|
const state = await loadWorkspaceState(workspaceId, repoPath);
|
|
18742
|
+
const effectiveLimit = state.projectConfig.maxParallelTasks ?? (await loadGlobalConfig()).maxParallelTasks;
|
|
18743
|
+
scheduler.setMaxParallelTasks(effectiveLimit);
|
|
18658
18744
|
const board = state.board;
|
|
18659
18745
|
const pendingCards = [];
|
|
18660
18746
|
const todoColumn = board.columns.find((c) => c.id === "todo");
|
|
@@ -18806,9 +18892,6 @@ var BoardPoller = class {
|
|
|
18806
18892
|
await moveCard(workspaceId, taskId, "reopened");
|
|
18807
18893
|
await appendActivityLog(workspaceId, taskId, `${reason} \u2192 Reopened`);
|
|
18808
18894
|
await clearCardSession(workspaceId, taskId);
|
|
18809
|
-
const refreshedBoard = await loadBoard(workspaceId);
|
|
18810
|
-
const refreshedCard = refreshedBoard.cards[taskId] ?? card;
|
|
18811
|
-
void scheduler.triggerParentReopenCascade(refreshedCard, refreshedBoard.cards);
|
|
18812
18895
|
updated = true;
|
|
18813
18896
|
}
|
|
18814
18897
|
if (updated) stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
@@ -19074,6 +19157,7 @@ function buildAgentArgs(agentId, prompt, ctx = {}) {
|
|
|
19074
19157
|
case "mimo": {
|
|
19075
19158
|
if (mode === "print") {
|
|
19076
19159
|
const args2 = ["run", "--agent", "build"];
|
|
19160
|
+
if (agentId === "mimo") args2.push("--never-ask", "--trust");
|
|
19077
19161
|
if (ctx.model) args2.push("-m", ctx.model);
|
|
19078
19162
|
if (ctx.effort) {
|
|
19079
19163
|
const OPENCODE_EFFORT_VARIANT = {
|
|
@@ -19089,6 +19173,7 @@ function buildAgentArgs(agentId, prompt, ctx = {}) {
|
|
|
19089
19173
|
return args2;
|
|
19090
19174
|
}
|
|
19091
19175
|
const args = ["--agent", "build"];
|
|
19176
|
+
if (agentId === "mimo") args.push("--never-ask", "--trust");
|
|
19092
19177
|
if (ctx.model) args.push("-m", ctx.model);
|
|
19093
19178
|
if (prompt.trim()) args.push("--prompt", prompt);
|
|
19094
19179
|
return args;
|
|
@@ -20010,38 +20095,6 @@ function markRecurringRan(recurringAgentId) {
|
|
|
20010
20095
|
getDb().prepare("UPDATE recurring_agents SET last_run_at = ?, next_run_at = ? WHERE id = ?").run(now, nextRunAt, recurringAgentId);
|
|
20011
20096
|
}
|
|
20012
20097
|
|
|
20013
|
-
// src/daemon/recurring-agent-scheduler.ts
|
|
20014
|
-
init_workspace_state();
|
|
20015
|
-
init_workspace_state();
|
|
20016
|
-
|
|
20017
|
-
// src/daemon/scheduler.ts
|
|
20018
|
-
import { spawn as spawn5 } from "node:child_process";
|
|
20019
|
-
import { cpSync, existsSync as existsSync10, mkdirSync as mkdirSync9 } from "node:fs";
|
|
20020
|
-
import { unlink as unlink2 } from "node:fs/promises";
|
|
20021
|
-
import { dirname as dirname5, join as join16, resolve as resolve2 } from "node:path";
|
|
20022
|
-
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
20023
|
-
init_api_contract();
|
|
20024
|
-
init_logger();
|
|
20025
|
-
|
|
20026
|
-
// src/core/prompt-resolver.ts
|
|
20027
|
-
init_logger();
|
|
20028
|
-
import { readFileSync as readFileSync5 } from "node:fs";
|
|
20029
|
-
import { isAbsolute, join as join14 } from "node:path";
|
|
20030
|
-
function resolvePromptText(prompt, repoPath) {
|
|
20031
|
-
if (!prompt) return "";
|
|
20032
|
-
if (prompt.source === "inline") return prompt.text;
|
|
20033
|
-
const path2 = isAbsolute(prompt.path) ? prompt.path : join14(repoPath, prompt.path);
|
|
20034
|
-
try {
|
|
20035
|
-
return readFileSync5(path2, "utf-8");
|
|
20036
|
-
} catch (err) {
|
|
20037
|
-
logger.warn({ err: err.message, path: path2 }, "Slot prompt file unreadable \u2014 falling back to empty prompt");
|
|
20038
|
-
return "";
|
|
20039
|
-
}
|
|
20040
|
-
}
|
|
20041
|
-
|
|
20042
|
-
// src/daemon/scheduler.ts
|
|
20043
|
-
init_task_id();
|
|
20044
|
-
|
|
20045
20098
|
// src/state/memory-store.ts
|
|
20046
20099
|
init_api_contract();
|
|
20047
20100
|
init_task_id();
|
|
@@ -20159,6 +20212,7 @@ function createMemory(input) {
|
|
|
20159
20212
|
throw new Error("global-scoped memory requires at least one tag");
|
|
20160
20213
|
}
|
|
20161
20214
|
const originWorkspaceId = input.originWorkspaceId ?? workspaceId;
|
|
20215
|
+
const originCardId = input.originCardId && db.prepare("SELECT 1 FROM cards WHERE id = ?").get(input.originCardId) ? input.originCardId : null;
|
|
20162
20216
|
const tx = db.transaction(() => {
|
|
20163
20217
|
db.prepare(
|
|
20164
20218
|
`INSERT INTO memories (
|
|
@@ -20175,7 +20229,7 @@ function createMemory(input) {
|
|
|
20175
20229
|
input.content,
|
|
20176
20230
|
input.sourceType,
|
|
20177
20231
|
input.importance ?? 1,
|
|
20178
|
-
|
|
20232
|
+
originCardId,
|
|
20179
20233
|
input.originAgent ? JSON.stringify(input.originAgent) : null,
|
|
20180
20234
|
input.status ?? "approved",
|
|
20181
20235
|
now,
|
|
@@ -20299,7 +20353,7 @@ function searchMemories(query, workspaceId, limit = 20) {
|
|
|
20299
20353
|
).all({ q: ftsQuery, ws: workspaceId, limit });
|
|
20300
20354
|
return hydrate(rows.map(rowToMemory));
|
|
20301
20355
|
}
|
|
20302
|
-
function buildMemoryContext(workspaceId, memoryLimit = 40) {
|
|
20356
|
+
function buildMemoryContext(workspaceId, memoryLimit = 40, opts) {
|
|
20303
20357
|
const sections = [];
|
|
20304
20358
|
const fmt = (m2) => {
|
|
20305
20359
|
const tagSuffix = m2.tags.length > 0 ? ` _(tags: ${m2.tags.join(", ")})_` : "";
|
|
@@ -20317,18 +20371,50 @@ ${projectMem.map(fmt).join("\n")}`);
|
|
|
20317
20371
|
${globalMem.map(fmt).join("\n")}`);
|
|
20318
20372
|
}
|
|
20319
20373
|
if (sections.length === 0) return "";
|
|
20374
|
+
const readOnly = opts?.readOnly ?? false;
|
|
20320
20375
|
const knownTags = listTags();
|
|
20321
|
-
const tagLine = knownTags.length > 0 ? `
|
|
20376
|
+
const tagLine = !readOnly && knownTags.length > 0 ? `
|
|
20322
20377
|
|
|
20323
20378
|
Existing tags (reuse before inventing new ones): ${knownTags.join(", ")}.` : "";
|
|
20379
|
+
const recallLine = readOnly ? "Use `whipped_search_memory` / `whipped_get_memory` to recall more." : "Use `whipped_search_memory` / `whipped_get_memory` to recall more, and `whipped_update_memory` to correct an entry that's now wrong.";
|
|
20324
20380
|
return [
|
|
20325
20381
|
"## Memory",
|
|
20326
|
-
`This is whipped's persistent project memory \u2014 durable knowledge from past work. Each entry is prefixed with its id.
|
|
20382
|
+
`This is whipped's persistent project memory \u2014 durable knowledge from past work. Each entry is prefixed with its id. ${recallLine} Treat these as hints, not gospel: if a memory references a file, symbol, or rule, verify it still holds before relying on it.${tagLine}`,
|
|
20327
20383
|
...sections
|
|
20328
20384
|
].join("\n\n");
|
|
20329
20385
|
}
|
|
20330
20386
|
|
|
20387
|
+
// src/daemon/recurring-agent-scheduler.ts
|
|
20388
|
+
init_workspace_state();
|
|
20389
|
+
init_workspace_state();
|
|
20390
|
+
|
|
20331
20391
|
// src/daemon/scheduler.ts
|
|
20392
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
20393
|
+
import { cpSync, existsSync as existsSync10, mkdirSync as mkdirSync9 } from "node:fs";
|
|
20394
|
+
import { unlink as unlink2 } from "node:fs/promises";
|
|
20395
|
+
import { dirname as dirname5, join as join16, resolve as resolve2 } from "node:path";
|
|
20396
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
20397
|
+
init_api_contract();
|
|
20398
|
+
init_logger();
|
|
20399
|
+
|
|
20400
|
+
// src/core/prompt-resolver.ts
|
|
20401
|
+
init_logger();
|
|
20402
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
20403
|
+
import { isAbsolute, join as join14 } from "node:path";
|
|
20404
|
+
function resolvePromptText(prompt, repoPath) {
|
|
20405
|
+
if (!prompt) return "";
|
|
20406
|
+
if (prompt.source === "inline") return prompt.text;
|
|
20407
|
+
const path2 = isAbsolute(prompt.path) ? prompt.path : join14(repoPath, prompt.path);
|
|
20408
|
+
try {
|
|
20409
|
+
return readFileSync5(path2, "utf-8");
|
|
20410
|
+
} catch (err) {
|
|
20411
|
+
logger.warn({ err: err.message, path: path2 }, "Slot prompt file unreadable \u2014 falling back to empty prompt");
|
|
20412
|
+
return "";
|
|
20413
|
+
}
|
|
20414
|
+
}
|
|
20415
|
+
|
|
20416
|
+
// src/daemon/scheduler.ts
|
|
20417
|
+
init_task_id();
|
|
20332
20418
|
init_workspace_state();
|
|
20333
20419
|
|
|
20334
20420
|
// src/daemon/review-pipeline.ts
|
|
@@ -21583,128 +21669,10 @@ function tryParseAgentJson(output) {
|
|
|
21583
21669
|
return null;
|
|
21584
21670
|
}
|
|
21585
21671
|
}
|
|
21586
|
-
async function runParentReopenCascade(parentCard, childCards, options) {
|
|
21587
|
-
const { workspaceId, repoPath, mcpBinary, serverUrl, stateHub, secrets, registerStopCallback, registerLiveProcess } = options;
|
|
21588
|
-
const streamId = `${parentCard.id}-cascade-${Date.now()}`;
|
|
21589
|
-
const mcpConfigPath = getMcpConfigPath(streamId);
|
|
21590
|
-
await writeClaudeMcpConfig(mcpBinary, serverUrl, workspaceId, "claude", mcpConfigPath).catch(() => {
|
|
21591
|
-
});
|
|
21592
|
-
const parentBranch = getCardBranch(parentCard);
|
|
21593
|
-
const systemPrompt = buildCascadeSystemPrompt(parentCard, parentBranch, childCards);
|
|
21594
|
-
logger.info(
|
|
21595
|
-
`[cascade] Spawning cascade agent for parent "${parentCard.description?.split("\n")[0]?.slice(0, 60) ?? parentCard.id}" (${childCards.length} children)`
|
|
21596
|
-
);
|
|
21597
|
-
await appendTerminalSession(workspaceId, parentCard.id, {
|
|
21598
|
-
streamId,
|
|
21599
|
-
type: "cascade",
|
|
21600
|
-
startedAt: Date.now(),
|
|
21601
|
-
state: "running"
|
|
21602
|
-
});
|
|
21603
|
-
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
21604
|
-
await runAgentOnce(
|
|
21605
|
-
"claude",
|
|
21606
|
-
"Evaluate each child ticket and take the appropriate action.",
|
|
21607
|
-
repoPath,
|
|
21608
|
-
workspaceId,
|
|
21609
|
-
streamId,
|
|
21610
|
-
stateHub,
|
|
21611
|
-
registerStopCallback,
|
|
21612
|
-
registerLiveProcess,
|
|
21613
|
-
mcpConfigPath,
|
|
21614
|
-
systemPrompt,
|
|
21615
|
-
void 0,
|
|
21616
|
-
buildSecretsEnv(secrets),
|
|
21617
|
-
"low"
|
|
21618
|
-
);
|
|
21619
|
-
const cascadeStopped = options.isStreamManuallyStopped(streamId);
|
|
21620
|
-
logger.info(`[cascade:${streamId}] Cascade agent done \u2014 manuallyStopped=${cascadeStopped}`);
|
|
21621
|
-
await endTerminalSession(workspaceId, parentCard.id, streamId, Date.now(), cascadeStopped ? "stopped" : "completed");
|
|
21622
|
-
if (cascadeStopped) return;
|
|
21623
|
-
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
21624
|
-
if (options.onChildReset) {
|
|
21625
|
-
const afterBoard = await loadBoard(workspaceId);
|
|
21626
|
-
const resetChildren = childCards.filter((child) => afterBoard.cards[child.id]?.columnId === "todo");
|
|
21627
|
-
for (const child of resetChildren) {
|
|
21628
|
-
logger.info(
|
|
21629
|
-
`[cascade] Recursing into reset child "${child.description?.split("\n")[0]?.slice(0, 60) ?? child.id}"`
|
|
21630
|
-
);
|
|
21631
|
-
await options.onChildReset(child);
|
|
21632
|
-
}
|
|
21633
|
-
}
|
|
21634
|
-
}
|
|
21635
|
-
function buildCascadeSystemPrompt(parentCard, parentBranch, childCards) {
|
|
21636
|
-
const comments = parentCard.reviewComments ?? [];
|
|
21637
|
-
const iterations = groupIntoIterations(parentCard);
|
|
21638
|
-
const current = iterations[iterations.length - 1];
|
|
21639
|
-
const currentInputSummaries = current?.input.map((c) => c.summary).filter(Boolean) ?? [];
|
|
21640
|
-
const reopenReason = currentInputSummaries.length > 0 ? currentInputSummaries.join("\n") : "Parent task was reopened.";
|
|
21641
|
-
const allDevSummaries = comments.filter((c) => c.type === "dev").map((c, i) => `Dev iteration ${i + 1}:
|
|
21642
|
-
${c.summary}`).join("\n\n");
|
|
21643
|
-
const childLines = childCards.map((child) => {
|
|
21644
|
-
const devComment = [...child.reviewComments ?? []].reverse().find((c) => c.type === "dev");
|
|
21645
|
-
const desc = child.description ? `
|
|
21646
|
-
${child.description}
|
|
21647
|
-
` : "";
|
|
21648
|
-
return [
|
|
21649
|
-
`### [${child.id}] (${child.columnId})`,
|
|
21650
|
-
desc,
|
|
21651
|
-
devComment ? `**Dev summary:** ${devComment.summary}` : "No dev work completed yet."
|
|
21652
|
-
].filter(Boolean).join("\n");
|
|
21653
|
-
}).join("\n\n");
|
|
21654
|
-
return `You are a Kanban board manager. A parent task was reopened and you must decide what to do with its dependent child tasks.
|
|
21655
|
-
|
|
21656
|
-
All data you need is already provided below \u2014 do NOT call \`kanban_get_board\`. Proceed directly to taking action.
|
|
21657
|
-
|
|
21658
|
-
|
|
21659
|
-
## Parent Task (Reopened)
|
|
21660
|
-
|
|
21661
|
-
**[${parentCard.id}]**
|
|
21662
|
-
${parentCard.description ? `
|
|
21663
|
-
${parentCard.description}
|
|
21664
|
-
` : ""}
|
|
21665
|
-
**Reason for reopening (= the parent's new direction, not yet implemented):** ${reopenReason}
|
|
21666
|
-
${allDevSummaries ? `
|
|
21667
|
-
Parent's full dev history (OLD state \u2014 do NOT use this to judge conflicts, use the reopening reason above):
|
|
21668
|
-
${allDevSummaries}
|
|
21669
|
-
` : ""}
|
|
21670
|
-
|
|
21671
|
-
## Child Tasks to Evaluate
|
|
21672
|
-
|
|
21673
|
-
${childLines}
|
|
21674
|
-
|
|
21675
|
-
## Decision Rules
|
|
21676
|
-
|
|
21677
|
-
CRITICAL: The cascade runs BEFORE the parent's dev agent implements the feedback. The parent's existing dev summary reflects its OLD state \u2014 do NOT use it to evaluate conflicts. Use ONLY the **reason for reopening** (the human feedback) to determine what the parent is about to change. That is the parent's new direction.
|
|
21678
|
-
|
|
21679
|
-
**Reset a child when:**
|
|
21680
|
-
- The reopening reason describes a change that directly conflicts with the child's purpose or existing work
|
|
21681
|
-
- e.g. reason is "Remove username field", child's purpose is "Add username field" \u2192 direct conflict \u2192 reset
|
|
21682
|
-
- e.g. reason is "Change the API response shape", child is building a UI that consumes that API \u2192 reset
|
|
21683
|
-
|
|
21684
|
-
**Leave a child alone when:**
|
|
21685
|
-
- The reopening reason describes a change to something completely unrelated to the child's purpose
|
|
21686
|
-
- e.g. reason is "Remove email field", child's purpose is "Add username field" \u2192 unrelated \u2192 leave alone
|
|
21687
|
-
- e.g. reason is "Fix a bug in the payment module", child is working on user profiles \u2192 leave alone
|
|
21688
|
-
|
|
21689
|
-
The default is to **leave children alone**. Only reset when the reopening reason directly conflicts with what the child is doing.
|
|
21690
|
-
|
|
21691
|
-
## Steps for EACH child you decide to reset
|
|
21692
|
-
|
|
21693
|
-
1. Call \`kanban_stop_task\` if the child is in_progress.
|
|
21694
|
-
2. Call \`kanban_add_comment\` on the **CHILD** card with:
|
|
21695
|
-
- type: "cascade"
|
|
21696
|
-
- status: "fail"
|
|
21697
|
-
- summary: Explain specifically what the parent changed and why this child's prior work needs to be revisited.
|
|
21698
|
-
- issues: include one blocking issue with severity "blocking" and message: "Run \`git merge ${parentBranch}\` \u2014 no fetch needed since all task worktrees in this project share the same local repo. After merging, implement this task's original goal on top of the parent's new state. The parent's changes are the new baseline \u2014 build on them, do not mirror them."
|
|
21699
|
-
3. Call \`kanban_move_card\` to "todo" for that child.
|
|
21700
|
-
|
|
21701
|
-
After handling all children, call \`kanban_add_comment\` on the PARENT card (${parentCard.id}) with type "cascade" and a brief summary of each decision.`;
|
|
21702
|
-
}
|
|
21703
21672
|
|
|
21704
21673
|
// src/daemon/scheduler.ts
|
|
21705
21674
|
var FAST_EXIT_THRESHOLD_MS = 8e3;
|
|
21706
21675
|
var MAX_RECENT_BUFFERS = 100;
|
|
21707
|
-
var ASSISTANT_AGENT_PREFIX = "__assistant__:";
|
|
21708
21676
|
var TaskScheduler = class {
|
|
21709
21677
|
constructor(options) {
|
|
21710
21678
|
this.options = options;
|
|
@@ -21729,10 +21697,8 @@ var TaskScheduler = class {
|
|
|
21729
21697
|
manuallyStoppedForHook = /* @__PURE__ */ new Set();
|
|
21730
21698
|
// Tasks stopped before the dev agent started (e.g. during plan phase).
|
|
21731
21699
|
planPhaseManuallyStopped = /* @__PURE__ */ new Set();
|
|
21732
|
-
// Individual review
|
|
21700
|
+
// Individual review stream IDs stopped by a manual stopTask() call.
|
|
21733
21701
|
manuallyStoppedStreams = /* @__PURE__ */ new Set();
|
|
21734
|
-
// Tasks stopped because their parent was reopened — session set to "stopped" in onExit.
|
|
21735
|
-
parentReopenedTasks = /* @__PURE__ */ new Set();
|
|
21736
21702
|
// Shared worktree IDs currently in use by a dev agent — prevents sibling cards from
|
|
21737
21703
|
// running concurrently in the same worktree directory.
|
|
21738
21704
|
runningSharedWorktrees = /* @__PURE__ */ new Set();
|
|
@@ -21872,6 +21838,11 @@ ${assistantSystemPrompt}` : assistantSystemPrompt;
|
|
|
21872
21838
|
get maxParallelTasks() {
|
|
21873
21839
|
return this.options.maxParallelTasks;
|
|
21874
21840
|
}
|
|
21841
|
+
// Config can change at runtime; the poller re-syncs this each tick so a
|
|
21842
|
+
// changed "Max Parallel Tasks" takes effect without restarting the daemon.
|
|
21843
|
+
setMaxParallelTasks(limit) {
|
|
21844
|
+
this.options.maxParallelTasks = limit;
|
|
21845
|
+
}
|
|
21875
21846
|
canAcceptTask(inFlightCount) {
|
|
21876
21847
|
const count = inFlightCount ?? this.running.size;
|
|
21877
21848
|
return count < this.options.maxParallelTasks;
|
|
@@ -22221,12 +22192,6 @@ ${devSystemPromptResult.text}`;
|
|
|
22221
22192
|
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
22222
22193
|
return;
|
|
22223
22194
|
}
|
|
22224
|
-
if (this.parentReopenedTasks.has(taskId)) {
|
|
22225
|
-
this.parentReopenedTasks.delete(taskId);
|
|
22226
|
-
await endTerminalSession(workspaceId, taskId, devStreamId, Date.now(), "stopped");
|
|
22227
|
-
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
22228
|
-
return;
|
|
22229
|
-
}
|
|
22230
22195
|
if (this.hookHandledTasks.has(taskId)) {
|
|
22231
22196
|
this.hookHandledTasks.delete(taskId);
|
|
22232
22197
|
const exitedAt2 = Date.now();
|
|
@@ -22392,45 +22357,6 @@ ${devSystemPromptResult.text}`;
|
|
|
22392
22357
|
isStreamManuallyStopped(streamId) {
|
|
22393
22358
|
return this.manuallyStoppedStreams.delete(streamId);
|
|
22394
22359
|
}
|
|
22395
|
-
// Stop a task because its parent was reopened — session becomes "stopped" rather than being removed.
|
|
22396
|
-
interruptForParentReopen(taskId) {
|
|
22397
|
-
const task = this.running.get(taskId);
|
|
22398
|
-
if (task) {
|
|
22399
|
-
logger.info(`[scheduler] Interrupting task ${taskId} due to parent reopen`);
|
|
22400
|
-
this.setRecentBuffer(task.streamId, task.outputBuffer);
|
|
22401
|
-
void saveTerminalBuffer(this.options.workspaceId, task.streamId, task.outputBuffer);
|
|
22402
|
-
this.parentReopenedTasks.add(taskId);
|
|
22403
|
-
task.process.kill();
|
|
22404
|
-
this.running.delete(taskId);
|
|
22405
|
-
}
|
|
22406
|
-
}
|
|
22407
|
-
async triggerParentReopenCascade(parentCard, boardCards) {
|
|
22408
|
-
if (parentCard.type !== "task") return;
|
|
22409
|
-
const { workspaceId, repoPath, serverUrl, stateHub } = this.options;
|
|
22410
|
-
const childCards = Object.values(boardCards).filter(
|
|
22411
|
-
(card) => card.dependsOn?.includes(parentCard.id) && (card.columnId === "in_progress" || card.columnId === "ready_for_review")
|
|
22412
|
-
);
|
|
22413
|
-
if (childCards.length === 0) return;
|
|
22414
|
-
logger.info(
|
|
22415
|
-
`[scheduler] triggerParentReopenCascade: ${childCards.length} children for parent "${parentCard.description?.split("\n")[0]?.slice(0, 60) ?? parentCard.id}"`
|
|
22416
|
-
);
|
|
22417
|
-
const projectConfig = await loadProjectConfig(workspaceId);
|
|
22418
|
-
void runParentReopenCascade(parentCard, childCards, {
|
|
22419
|
-
workspaceId,
|
|
22420
|
-
repoPath,
|
|
22421
|
-
serverUrl,
|
|
22422
|
-
mcpBinary: getMcpServerPath(),
|
|
22423
|
-
stateHub,
|
|
22424
|
-
secrets: projectConfig.secrets ?? [],
|
|
22425
|
-
registerStopCallback: this.registerStopCallback.bind(this),
|
|
22426
|
-
registerLiveProcess: this.registerLiveProcess.bind(this),
|
|
22427
|
-
isStreamManuallyStopped: this.isStreamManuallyStopped.bind(this),
|
|
22428
|
-
onChildReset: async (child) => {
|
|
22429
|
-
const latestBoard = await loadBoard(workspaceId);
|
|
22430
|
-
await this.triggerParentReopenCascade(child, latestBoard.cards);
|
|
22431
|
-
}
|
|
22432
|
-
});
|
|
22433
|
-
}
|
|
22434
22360
|
getOutputBuffer(streamId) {
|
|
22435
22361
|
for (const task of this.running.values()) {
|
|
22436
22362
|
if (task.streamId === streamId) return task.outputBuffer;
|
|
@@ -22868,7 +22794,7 @@ var RecurringAgentScheduler = class {
|
|
|
22868
22794
|
} catch (err) {
|
|
22869
22795
|
logger.warn({ err, agentId: agent.id }, "[recurring] failed to load project config");
|
|
22870
22796
|
}
|
|
22871
|
-
const
|
|
22797
|
+
const baseSystemPrompt = buildRecurringSystemPrompt(
|
|
22872
22798
|
repoPath,
|
|
22873
22799
|
agent.name,
|
|
22874
22800
|
agent.instructions,
|
|
@@ -22876,6 +22802,10 @@ var RecurringAgentScheduler = class {
|
|
|
22876
22802
|
secrets,
|
|
22877
22803
|
projectSystemPrompt
|
|
22878
22804
|
);
|
|
22805
|
+
const memContext = buildMemoryContext(workspaceId, 40, { readOnly: true });
|
|
22806
|
+
const appendSystemPrompt = memContext ? `${memContext}
|
|
22807
|
+
|
|
22808
|
+
${baseSystemPrompt}` : baseSystemPrompt;
|
|
22879
22809
|
const prompt = buildRecurringPrompt();
|
|
22880
22810
|
if (agentBinary === "claude" && mcpConfigPath) {
|
|
22881
22811
|
await writeClaudeMcpConfig(
|
|
@@ -23006,8 +22936,10 @@ ${journalBlock}
|
|
|
23006
22936
|
|
|
23007
22937
|
When you finish, call \`update_journal\` with the full updated notes to keep for next time (what you checked, what you filed, what you're watching). It REPLACES the journal, so include everything still relevant.
|
|
23008
22938
|
|
|
22939
|
+
If your task is a one-off that is now complete, or the condition you were watching for is resolved and there is nothing left to do on future runs, call \`disable_self\` to stop running on schedule. This only pauses future runs (the user can re-enable you); the current run still finishes normally. Update your journal before disabling.
|
|
22940
|
+
|
|
23009
22941
|
## Available tools
|
|
23010
|
-
\`kanban_get_board\`, \`kanban_create_card\`, \`kanban_add_comment\`, \`kanban_get_workflows\`, \`whipped_search_memory\`, \`whipped_get_memory\`, \`update_journal\`, plus read-only repo tools (Read, Grep, Glob).`;
|
|
22942
|
+
\`kanban_get_board\`, \`kanban_create_card\`, \`kanban_add_comment\`, \`kanban_get_workflows\`, \`whipped_search_memory\`, \`whipped_get_memory\`, \`update_journal\`, \`disable_self\`, plus read-only repo tools (Read, Grep, Glob).`;
|
|
23011
22943
|
const secretsSection = buildSecretsSection(secrets);
|
|
23012
22944
|
if (secretsSection) prompt += `
|
|
23013
22945
|
|
|
@@ -25742,6 +25674,36 @@ Stack: ${err instanceof Error ? err.stack : ""}`
|
|
|
25742
25674
|
throw err;
|
|
25743
25675
|
}
|
|
25744
25676
|
};
|
|
25677
|
+
var bulkCreateCardsService = async (workspaceId, items, requestedBase) => {
|
|
25678
|
+
const workspaces = await listWorkspaces();
|
|
25679
|
+
const ws = workspaces.find((w2) => w2.workspaceId === workspaceId);
|
|
25680
|
+
if (!ws) throw NotFoundError("Workspace");
|
|
25681
|
+
const config = await loadProjectConfig(workspaceId);
|
|
25682
|
+
if (config.workflows.filter((w2) => !w2.forStory).length === 0) {
|
|
25683
|
+
throw BadRequestError("Create at least one workflow before importing tickets.");
|
|
25684
|
+
}
|
|
25685
|
+
const hasStoryWorkflow = config.workflows.some((w2) => w2.forStory);
|
|
25686
|
+
const board = await loadBoard(workspaceId);
|
|
25687
|
+
const existingCardIds = new Set(Object.keys(board.cards));
|
|
25688
|
+
const tempIds = new Set(items.map((it) => it.tempId).filter((t) => Boolean(t)));
|
|
25689
|
+
const errors = [];
|
|
25690
|
+
items.forEach((item, index) => {
|
|
25691
|
+
if (!item.description?.trim()) errors.push({ index, message: "description is required" });
|
|
25692
|
+
if ((item.type === "story" || item.type === "subtask") && !hasStoryWorkflow) {
|
|
25693
|
+
errors.push({ index, message: "story/subtask tickets require a story workflow \u2014 create one first" });
|
|
25694
|
+
}
|
|
25695
|
+
const refs = [...item.dependsOn ? [item.dependsOn] : [], ...item.waitsFor ?? [], ...item.subtaskIds ?? []];
|
|
25696
|
+
for (const ref of refs) {
|
|
25697
|
+
if (!tempIds.has(ref) && !existingCardIds.has(ref)) {
|
|
25698
|
+
errors.push({ index, message: `unknown reference "${ref}"` });
|
|
25699
|
+
}
|
|
25700
|
+
}
|
|
25701
|
+
});
|
|
25702
|
+
if (errors.length > 0) throw BadRequestError("Import validation failed", errors);
|
|
25703
|
+
const baseRef = requestedBase || config.defaultBaseBranch || getDefaultBranch(ws.repoPath);
|
|
25704
|
+
const cards = await createCardsBulk(workspaceId, items, baseRef);
|
|
25705
|
+
return { cards };
|
|
25706
|
+
};
|
|
25745
25707
|
var listBranchesService = async (workspaceId, remote = false) => {
|
|
25746
25708
|
const workspaces = await listWorkspaces();
|
|
25747
25709
|
const ws = workspaces.find((w2) => w2.workspaceId === workspaceId);
|
|
@@ -25946,11 +25908,6 @@ var moveCardService = async (workspaceId, cardId, targetColumnId, targetIndex) =
|
|
|
25946
25908
|
}
|
|
25947
25909
|
if (targetColumnId === "reopened") {
|
|
25948
25910
|
await updateCard(workspaceId, cardId, { autoFixAttempts: 0 });
|
|
25949
|
-
const movedBoard = await loadBoard(workspaceId);
|
|
25950
|
-
const movedCard = movedBoard.cards[cardId];
|
|
25951
|
-
if (movedCard) {
|
|
25952
|
-
return { board, reopenCascade: { movedCard, boardCards: movedBoard.cards } };
|
|
25953
|
-
}
|
|
25954
25911
|
}
|
|
25955
25912
|
return { board };
|
|
25956
25913
|
};
|
|
@@ -26026,32 +25983,28 @@ var deleteReviewCommentService = async (input) => {
|
|
|
26026
25983
|
await updateCard(input.workspaceId, input.cardId, { reviewComments: next });
|
|
26027
25984
|
return { ok: true };
|
|
26028
25985
|
};
|
|
26029
|
-
var submitHumanFeedbackService = async (workspaceId, cardId, comment, attachments) => {
|
|
25986
|
+
var submitHumanFeedbackService = async (workspaceId, cardId, comment, attachments, type, metadata) => {
|
|
26030
25987
|
const board = await loadBoard(workspaceId);
|
|
26031
25988
|
const card = board.cards[cardId];
|
|
26032
25989
|
if (!card) throw NotFoundError("Card");
|
|
26033
25990
|
const trimmed = comment?.trim();
|
|
26034
|
-
const hasContent = trimmed || (attachments?.length ?? 0) > 0;
|
|
25991
|
+
const hasContent = trimmed || (attachments?.length ?? 0) > 0 || metadata != null;
|
|
26035
25992
|
const updatedComments = hasContent ? [
|
|
26036
25993
|
...card.reviewComments ?? [],
|
|
26037
25994
|
{
|
|
26038
25995
|
id: generateTaskId(),
|
|
26039
|
-
type: "human",
|
|
25996
|
+
type: type ?? "human",
|
|
26040
25997
|
actor: { type: "human", id: "human" },
|
|
26041
25998
|
createdAt: Date.now(),
|
|
26042
25999
|
summary: trimmed ?? "Feedback with attachments",
|
|
26043
|
-
attachments: attachments?.length ? attachments : void 0
|
|
26000
|
+
attachments: attachments?.length ? attachments : void 0,
|
|
26001
|
+
...metadata ? { metadata } : {}
|
|
26044
26002
|
}
|
|
26045
26003
|
] : card.reviewComments ?? [];
|
|
26046
26004
|
await updateCard(workspaceId, cardId, { reviewComments: updatedComments, autoFixAttempts: 0 });
|
|
26047
26005
|
await moveCard(workspaceId, cardId, "reopened");
|
|
26048
26006
|
await clearCardSession(workspaceId, cardId);
|
|
26049
26007
|
await appendActivityLog(workspaceId, cardId, "Human feedback submitted \u2192 moved to Reopened");
|
|
26050
|
-
const feedbackBoard = await loadBoard(workspaceId);
|
|
26051
|
-
const feedbackCard = feedbackBoard.cards[cardId];
|
|
26052
|
-
if (feedbackCard) {
|
|
26053
|
-
return { ok: true, reopenCascade: { feedbackCard, boardCards: feedbackBoard.cards } };
|
|
26054
|
-
}
|
|
26055
26008
|
return { ok: true };
|
|
26056
26009
|
};
|
|
26057
26010
|
var prepareStartAgentService = async (workspaceId, cardId) => {
|
|
@@ -26194,6 +26147,12 @@ var cardsController = new Hono2().post("/", zv("json", runtimeCardCreateRequestS
|
|
|
26194
26147
|
const card = await createCardService(workspaceId, cardData, baseRef);
|
|
26195
26148
|
ctx.stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
26196
26149
|
return c.json(card);
|
|
26150
|
+
}).post("/bulk", zv("json", runtimeBulkCardsCreateRequestSchema.extend({ workspaceId: z5.string() })), async (c) => {
|
|
26151
|
+
const ctx = c.var.ctx;
|
|
26152
|
+
const { workspaceId, baseRef, cards } = c.req.valid("json");
|
|
26153
|
+
const result = await bulkCreateCardsService(workspaceId, cards, baseRef);
|
|
26154
|
+
ctx.stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
26155
|
+
return c.json(result);
|
|
26197
26156
|
}).get(
|
|
26198
26157
|
"/branches",
|
|
26199
26158
|
zv("query", z5.object({ workspaceId: z5.string(), remote: z5.enum(["true", "false"]).optional() })),
|
|
@@ -26286,12 +26245,6 @@ var cardsController = new Hono2().post("/", zv("json", runtimeCardCreateRequestS
|
|
|
26286
26245
|
const ctx = c.var.ctx;
|
|
26287
26246
|
const { workspaceId, cardId, targetColumnId, targetIndex } = c.req.valid("json");
|
|
26288
26247
|
const result = await moveCardService(workspaceId, cardId, targetColumnId, targetIndex);
|
|
26289
|
-
if (result.reopenCascade) {
|
|
26290
|
-
const scheduler = ctx.getScheduler(workspaceId);
|
|
26291
|
-
if (scheduler) {
|
|
26292
|
-
void scheduler.triggerParentReopenCascade(result.reopenCascade.movedCard, result.reopenCascade.boardCards);
|
|
26293
|
-
}
|
|
26294
|
-
}
|
|
26295
26248
|
ctx.stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
26296
26249
|
return c.json(result.board);
|
|
26297
26250
|
}).delete(
|
|
@@ -26353,20 +26306,16 @@ var cardsController = new Hono2().post("/", zv("json", runtimeCardCreateRequestS
|
|
|
26353
26306
|
workspaceId: z5.string(),
|
|
26354
26307
|
cardId: z5.string(),
|
|
26355
26308
|
comment: z5.string().optional(),
|
|
26356
|
-
attachments: z5.array(reviewAttachmentSchema).optional()
|
|
26309
|
+
attachments: z5.array(reviewAttachmentSchema).optional(),
|
|
26310
|
+
type: z5.string().optional(),
|
|
26311
|
+
metadata: z5.record(z5.string(), z5.unknown()).optional()
|
|
26357
26312
|
})
|
|
26358
26313
|
),
|
|
26359
26314
|
async (c) => {
|
|
26360
26315
|
const ctx = c.var.ctx;
|
|
26361
|
-
const { workspaceId, cardId, comment, attachments } = c.req.valid("json");
|
|
26362
|
-
const result = await submitHumanFeedbackService(workspaceId, cardId, comment, attachments);
|
|
26316
|
+
const { workspaceId, cardId, comment, attachments, type, metadata } = c.req.valid("json");
|
|
26317
|
+
const result = await submitHumanFeedbackService(workspaceId, cardId, comment, attachments, type, metadata);
|
|
26363
26318
|
ctx.stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
26364
|
-
if (result.reopenCascade) {
|
|
26365
|
-
const scheduler = ctx.getScheduler(workspaceId);
|
|
26366
|
-
if (scheduler) {
|
|
26367
|
-
void scheduler.triggerParentReopenCascade(result.reopenCascade.feedbackCard, result.reopenCascade.boardCards);
|
|
26368
|
-
}
|
|
26369
|
-
}
|
|
26370
26319
|
return c.json({ ok: result.ok });
|
|
26371
26320
|
}
|
|
26372
26321
|
).post("/start-agent", zv("json", z5.object({ workspaceId: z5.string(), cardId: z5.string() })), async (c) => {
|
|
@@ -26383,12 +26332,6 @@ var cardsController = new Hono2().post("/", zv("json", runtimeCardCreateRequestS
|
|
|
26383
26332
|
ctx.getScheduler(workspaceId)?.stopTask(cardId);
|
|
26384
26333
|
ctx.stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
26385
26334
|
return c.json({ ok: true });
|
|
26386
|
-
}).post("/interrupt-task", zv("json", z5.object({ workspaceId: z5.string(), cardId: z5.string() })), async (c) => {
|
|
26387
|
-
const ctx = c.var.ctx;
|
|
26388
|
-
const { workspaceId, cardId } = c.req.valid("json");
|
|
26389
|
-
ctx.getScheduler(workspaceId)?.interruptForParentReopen(cardId);
|
|
26390
|
-
ctx.stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
26391
|
-
return c.json({ ok: true });
|
|
26392
26335
|
}).post(
|
|
26393
26336
|
"/set-pr-meta",
|
|
26394
26337
|
zv(
|
|
@@ -28618,7 +28561,7 @@ process.on("uncaughtException", (err) => {
|
|
|
28618
28561
|
if (err.code === "EPIPE" || err.code === "ECONNRESET") return;
|
|
28619
28562
|
throw err;
|
|
28620
28563
|
});
|
|
28621
|
-
var VERSION9 = true ? "0.
|
|
28564
|
+
var VERSION9 = true ? "0.5.0" : "0.0.0-dev";
|
|
28622
28565
|
async function isPortAvailable(port, host) {
|
|
28623
28566
|
return new Promise((resolve5) => {
|
|
28624
28567
|
const probe = createServer2();
|