whipped 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -3529,7 +3529,7 @@ 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 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, 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";
|
|
@@ -3962,6 +3962,14 @@ Do NOT include:
|
|
|
3962
3962
|
modelConfig: cardModelConfigSchema.optional(),
|
|
3963
3963
|
activeLevel: tierLevelSchema.optional()
|
|
3964
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
|
+
});
|
|
3965
3973
|
runtimeCardMoveRequestSchema = z.object({
|
|
3966
3974
|
cardId: z.string(),
|
|
3967
3975
|
targetColumnId: runtimeBoardColumnIdSchema,
|
|
@@ -8001,6 +8009,7 @@ __export(workspace_state_exports, {
|
|
|
8001
8009
|
clearCardSession: () => clearCardSession,
|
|
8002
8010
|
closeAllOpenTerminalSessions: () => closeAllOpenTerminalSessions,
|
|
8003
8011
|
createCard: () => createCard,
|
|
8012
|
+
createCardsBulk: () => createCardsBulk,
|
|
8004
8013
|
deleteCard: () => deleteCard,
|
|
8005
8014
|
downloadGithubImages: () => downloadGithubImages,
|
|
8006
8015
|
endTerminalSession: () => endTerminalSession,
|
|
@@ -8551,6 +8560,79 @@ async function createCard(workspaceId, data, baseRef) {
|
|
|
8551
8560
|
tx();
|
|
8552
8561
|
return card;
|
|
8553
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
|
+
}
|
|
8554
8636
|
async function appendActivityLog(workspaceId, cardId, message) {
|
|
8555
8637
|
const db = getDb();
|
|
8556
8638
|
const tx = db.transaction(() => {
|
|
@@ -18810,9 +18892,6 @@ var BoardPoller = class {
|
|
|
18810
18892
|
await moveCard(workspaceId, taskId, "reopened");
|
|
18811
18893
|
await appendActivityLog(workspaceId, taskId, `${reason} \u2192 Reopened`);
|
|
18812
18894
|
await clearCardSession(workspaceId, taskId);
|
|
18813
|
-
const refreshedBoard = await loadBoard(workspaceId);
|
|
18814
|
-
const refreshedCard = refreshedBoard.cards[taskId] ?? card;
|
|
18815
|
-
void scheduler.triggerParentReopenCascade(refreshedCard, refreshedBoard.cards);
|
|
18816
18895
|
updated = true;
|
|
18817
18896
|
}
|
|
18818
18897
|
if (updated) stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
@@ -21590,123 +21669,6 @@ function tryParseAgentJson(output) {
|
|
|
21590
21669
|
return null;
|
|
21591
21670
|
}
|
|
21592
21671
|
}
|
|
21593
|
-
async function runParentReopenCascade(parentCard, childCards, options) {
|
|
21594
|
-
const { workspaceId, repoPath, mcpBinary, serverUrl, stateHub, secrets, registerStopCallback, registerLiveProcess } = options;
|
|
21595
|
-
const streamId = `${parentCard.id}-cascade-${Date.now()}`;
|
|
21596
|
-
const mcpConfigPath = getMcpConfigPath(streamId);
|
|
21597
|
-
await writeClaudeMcpConfig(mcpBinary, serverUrl, workspaceId, "claude", mcpConfigPath).catch(() => {
|
|
21598
|
-
});
|
|
21599
|
-
const parentBranch = getCardBranch(parentCard);
|
|
21600
|
-
const systemPrompt = buildCascadeSystemPrompt(parentCard, parentBranch, childCards);
|
|
21601
|
-
logger.info(
|
|
21602
|
-
`[cascade] Spawning cascade agent for parent "${parentCard.description?.split("\n")[0]?.slice(0, 60) ?? parentCard.id}" (${childCards.length} children)`
|
|
21603
|
-
);
|
|
21604
|
-
await appendTerminalSession(workspaceId, parentCard.id, {
|
|
21605
|
-
streamId,
|
|
21606
|
-
type: "cascade",
|
|
21607
|
-
startedAt: Date.now(),
|
|
21608
|
-
state: "running"
|
|
21609
|
-
});
|
|
21610
|
-
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
21611
|
-
await runAgentOnce(
|
|
21612
|
-
"claude",
|
|
21613
|
-
"Evaluate each child ticket and take the appropriate action.",
|
|
21614
|
-
repoPath,
|
|
21615
|
-
workspaceId,
|
|
21616
|
-
streamId,
|
|
21617
|
-
stateHub,
|
|
21618
|
-
registerStopCallback,
|
|
21619
|
-
registerLiveProcess,
|
|
21620
|
-
mcpConfigPath,
|
|
21621
|
-
systemPrompt,
|
|
21622
|
-
void 0,
|
|
21623
|
-
buildSecretsEnv(secrets),
|
|
21624
|
-
"low"
|
|
21625
|
-
);
|
|
21626
|
-
const cascadeStopped = options.isStreamManuallyStopped(streamId);
|
|
21627
|
-
logger.info(`[cascade:${streamId}] Cascade agent done \u2014 manuallyStopped=${cascadeStopped}`);
|
|
21628
|
-
await endTerminalSession(workspaceId, parentCard.id, streamId, Date.now(), cascadeStopped ? "stopped" : "completed");
|
|
21629
|
-
if (cascadeStopped) return;
|
|
21630
|
-
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
21631
|
-
if (options.onChildReset) {
|
|
21632
|
-
const afterBoard = await loadBoard(workspaceId);
|
|
21633
|
-
const resetChildren = childCards.filter((child) => afterBoard.cards[child.id]?.columnId === "todo");
|
|
21634
|
-
for (const child of resetChildren) {
|
|
21635
|
-
logger.info(
|
|
21636
|
-
`[cascade] Recursing into reset child "${child.description?.split("\n")[0]?.slice(0, 60) ?? child.id}"`
|
|
21637
|
-
);
|
|
21638
|
-
await options.onChildReset(child);
|
|
21639
|
-
}
|
|
21640
|
-
}
|
|
21641
|
-
}
|
|
21642
|
-
function buildCascadeSystemPrompt(parentCard, parentBranch, childCards) {
|
|
21643
|
-
const comments = parentCard.reviewComments ?? [];
|
|
21644
|
-
const iterations = groupIntoIterations(parentCard);
|
|
21645
|
-
const current = iterations[iterations.length - 1];
|
|
21646
|
-
const currentInputSummaries = current?.input.map((c) => c.summary).filter(Boolean) ?? [];
|
|
21647
|
-
const reopenReason = currentInputSummaries.length > 0 ? currentInputSummaries.join("\n") : "Parent task was reopened.";
|
|
21648
|
-
const allDevSummaries = comments.filter((c) => c.type === "dev").map((c, i) => `Dev iteration ${i + 1}:
|
|
21649
|
-
${c.summary}`).join("\n\n");
|
|
21650
|
-
const childLines = childCards.map((child) => {
|
|
21651
|
-
const devComment = [...child.reviewComments ?? []].reverse().find((c) => c.type === "dev");
|
|
21652
|
-
const desc = child.description ? `
|
|
21653
|
-
${child.description}
|
|
21654
|
-
` : "";
|
|
21655
|
-
return [
|
|
21656
|
-
`### [${child.id}] (${child.columnId})`,
|
|
21657
|
-
desc,
|
|
21658
|
-
devComment ? `**Dev summary:** ${devComment.summary}` : "No dev work completed yet."
|
|
21659
|
-
].filter(Boolean).join("\n");
|
|
21660
|
-
}).join("\n\n");
|
|
21661
|
-
return `You are a Kanban board manager. A parent task was reopened and you must decide what to do with its dependent child tasks.
|
|
21662
|
-
|
|
21663
|
-
All data you need is already provided below \u2014 do NOT call \`kanban_get_board\`. Proceed directly to taking action.
|
|
21664
|
-
|
|
21665
|
-
|
|
21666
|
-
## Parent Task (Reopened)
|
|
21667
|
-
|
|
21668
|
-
**[${parentCard.id}]**
|
|
21669
|
-
${parentCard.description ? `
|
|
21670
|
-
${parentCard.description}
|
|
21671
|
-
` : ""}
|
|
21672
|
-
**Reason for reopening (= the parent's new direction, not yet implemented):** ${reopenReason}
|
|
21673
|
-
${allDevSummaries ? `
|
|
21674
|
-
Parent's full dev history (OLD state \u2014 do NOT use this to judge conflicts, use the reopening reason above):
|
|
21675
|
-
${allDevSummaries}
|
|
21676
|
-
` : ""}
|
|
21677
|
-
|
|
21678
|
-
## Child Tasks to Evaluate
|
|
21679
|
-
|
|
21680
|
-
${childLines}
|
|
21681
|
-
|
|
21682
|
-
## Decision Rules
|
|
21683
|
-
|
|
21684
|
-
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.
|
|
21685
|
-
|
|
21686
|
-
**Reset a child when:**
|
|
21687
|
-
- The reopening reason describes a change that directly conflicts with the child's purpose or existing work
|
|
21688
|
-
- e.g. reason is "Remove username field", child's purpose is "Add username field" \u2192 direct conflict \u2192 reset
|
|
21689
|
-
- e.g. reason is "Change the API response shape", child is building a UI that consumes that API \u2192 reset
|
|
21690
|
-
|
|
21691
|
-
**Leave a child alone when:**
|
|
21692
|
-
- The reopening reason describes a change to something completely unrelated to the child's purpose
|
|
21693
|
-
- e.g. reason is "Remove email field", child's purpose is "Add username field" \u2192 unrelated \u2192 leave alone
|
|
21694
|
-
- e.g. reason is "Fix a bug in the payment module", child is working on user profiles \u2192 leave alone
|
|
21695
|
-
|
|
21696
|
-
The default is to **leave children alone**. Only reset when the reopening reason directly conflicts with what the child is doing.
|
|
21697
|
-
|
|
21698
|
-
## Steps for EACH child you decide to reset
|
|
21699
|
-
|
|
21700
|
-
1. Call \`kanban_stop_task\` if the child is in_progress.
|
|
21701
|
-
2. Call \`kanban_add_comment\` on the **CHILD** card with:
|
|
21702
|
-
- type: "cascade"
|
|
21703
|
-
- status: "fail"
|
|
21704
|
-
- summary: Explain specifically what the parent changed and why this child's prior work needs to be revisited.
|
|
21705
|
-
- 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."
|
|
21706
|
-
3. Call \`kanban_move_card\` to "todo" for that child.
|
|
21707
|
-
|
|
21708
|
-
After handling all children, call \`kanban_add_comment\` on the PARENT card (${parentCard.id}) with type "cascade" and a brief summary of each decision.`;
|
|
21709
|
-
}
|
|
21710
21672
|
|
|
21711
21673
|
// src/daemon/scheduler.ts
|
|
21712
21674
|
var FAST_EXIT_THRESHOLD_MS = 8e3;
|
|
@@ -21735,10 +21697,8 @@ var TaskScheduler = class {
|
|
|
21735
21697
|
manuallyStoppedForHook = /* @__PURE__ */ new Set();
|
|
21736
21698
|
// Tasks stopped before the dev agent started (e.g. during plan phase).
|
|
21737
21699
|
planPhaseManuallyStopped = /* @__PURE__ */ new Set();
|
|
21738
|
-
// Individual review
|
|
21700
|
+
// Individual review stream IDs stopped by a manual stopTask() call.
|
|
21739
21701
|
manuallyStoppedStreams = /* @__PURE__ */ new Set();
|
|
21740
|
-
// Tasks stopped because their parent was reopened — session set to "stopped" in onExit.
|
|
21741
|
-
parentReopenedTasks = /* @__PURE__ */ new Set();
|
|
21742
21702
|
// Shared worktree IDs currently in use by a dev agent — prevents sibling cards from
|
|
21743
21703
|
// running concurrently in the same worktree directory.
|
|
21744
21704
|
runningSharedWorktrees = /* @__PURE__ */ new Set();
|
|
@@ -22232,12 +22192,6 @@ ${devSystemPromptResult.text}`;
|
|
|
22232
22192
|
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
22233
22193
|
return;
|
|
22234
22194
|
}
|
|
22235
|
-
if (this.parentReopenedTasks.has(taskId)) {
|
|
22236
|
-
this.parentReopenedTasks.delete(taskId);
|
|
22237
|
-
await endTerminalSession(workspaceId, taskId, devStreamId, Date.now(), "stopped");
|
|
22238
|
-
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
22239
|
-
return;
|
|
22240
|
-
}
|
|
22241
22195
|
if (this.hookHandledTasks.has(taskId)) {
|
|
22242
22196
|
this.hookHandledTasks.delete(taskId);
|
|
22243
22197
|
const exitedAt2 = Date.now();
|
|
@@ -22403,45 +22357,6 @@ ${devSystemPromptResult.text}`;
|
|
|
22403
22357
|
isStreamManuallyStopped(streamId) {
|
|
22404
22358
|
return this.manuallyStoppedStreams.delete(streamId);
|
|
22405
22359
|
}
|
|
22406
|
-
// Stop a task because its parent was reopened — session becomes "stopped" rather than being removed.
|
|
22407
|
-
interruptForParentReopen(taskId) {
|
|
22408
|
-
const task = this.running.get(taskId);
|
|
22409
|
-
if (task) {
|
|
22410
|
-
logger.info(`[scheduler] Interrupting task ${taskId} due to parent reopen`);
|
|
22411
|
-
this.setRecentBuffer(task.streamId, task.outputBuffer);
|
|
22412
|
-
void saveTerminalBuffer(this.options.workspaceId, task.streamId, task.outputBuffer);
|
|
22413
|
-
this.parentReopenedTasks.add(taskId);
|
|
22414
|
-
task.process.kill();
|
|
22415
|
-
this.running.delete(taskId);
|
|
22416
|
-
}
|
|
22417
|
-
}
|
|
22418
|
-
async triggerParentReopenCascade(parentCard, boardCards) {
|
|
22419
|
-
if (parentCard.type !== "task") return;
|
|
22420
|
-
const { workspaceId, repoPath, serverUrl, stateHub } = this.options;
|
|
22421
|
-
const childCards = Object.values(boardCards).filter(
|
|
22422
|
-
(card) => card.dependsOn?.includes(parentCard.id) && (card.columnId === "in_progress" || card.columnId === "ready_for_review")
|
|
22423
|
-
);
|
|
22424
|
-
if (childCards.length === 0) return;
|
|
22425
|
-
logger.info(
|
|
22426
|
-
`[scheduler] triggerParentReopenCascade: ${childCards.length} children for parent "${parentCard.description?.split("\n")[0]?.slice(0, 60) ?? parentCard.id}"`
|
|
22427
|
-
);
|
|
22428
|
-
const projectConfig = await loadProjectConfig(workspaceId);
|
|
22429
|
-
void runParentReopenCascade(parentCard, childCards, {
|
|
22430
|
-
workspaceId,
|
|
22431
|
-
repoPath,
|
|
22432
|
-
serverUrl,
|
|
22433
|
-
mcpBinary: getMcpServerPath(),
|
|
22434
|
-
stateHub,
|
|
22435
|
-
secrets: projectConfig.secrets ?? [],
|
|
22436
|
-
registerStopCallback: this.registerStopCallback.bind(this),
|
|
22437
|
-
registerLiveProcess: this.registerLiveProcess.bind(this),
|
|
22438
|
-
isStreamManuallyStopped: this.isStreamManuallyStopped.bind(this),
|
|
22439
|
-
onChildReset: async (child) => {
|
|
22440
|
-
const latestBoard = await loadBoard(workspaceId);
|
|
22441
|
-
await this.triggerParentReopenCascade(child, latestBoard.cards);
|
|
22442
|
-
}
|
|
22443
|
-
});
|
|
22444
|
-
}
|
|
22445
22360
|
getOutputBuffer(streamId) {
|
|
22446
22361
|
for (const task of this.running.values()) {
|
|
22447
22362
|
if (task.streamId === streamId) return task.outputBuffer;
|
|
@@ -25759,6 +25674,36 @@ Stack: ${err instanceof Error ? err.stack : ""}`
|
|
|
25759
25674
|
throw err;
|
|
25760
25675
|
}
|
|
25761
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
|
+
};
|
|
25762
25707
|
var listBranchesService = async (workspaceId, remote = false) => {
|
|
25763
25708
|
const workspaces = await listWorkspaces();
|
|
25764
25709
|
const ws = workspaces.find((w2) => w2.workspaceId === workspaceId);
|
|
@@ -25963,11 +25908,6 @@ var moveCardService = async (workspaceId, cardId, targetColumnId, targetIndex) =
|
|
|
25963
25908
|
}
|
|
25964
25909
|
if (targetColumnId === "reopened") {
|
|
25965
25910
|
await updateCard(workspaceId, cardId, { autoFixAttempts: 0 });
|
|
25966
|
-
const movedBoard = await loadBoard(workspaceId);
|
|
25967
|
-
const movedCard = movedBoard.cards[cardId];
|
|
25968
|
-
if (movedCard) {
|
|
25969
|
-
return { board, reopenCascade: { movedCard, boardCards: movedBoard.cards } };
|
|
25970
|
-
}
|
|
25971
25911
|
}
|
|
25972
25912
|
return { board };
|
|
25973
25913
|
};
|
|
@@ -26065,11 +26005,6 @@ var submitHumanFeedbackService = async (workspaceId, cardId, comment, attachment
|
|
|
26065
26005
|
await moveCard(workspaceId, cardId, "reopened");
|
|
26066
26006
|
await clearCardSession(workspaceId, cardId);
|
|
26067
26007
|
await appendActivityLog(workspaceId, cardId, "Human feedback submitted \u2192 moved to Reopened");
|
|
26068
|
-
const feedbackBoard = await loadBoard(workspaceId);
|
|
26069
|
-
const feedbackCard = feedbackBoard.cards[cardId];
|
|
26070
|
-
if (feedbackCard) {
|
|
26071
|
-
return { ok: true, reopenCascade: { feedbackCard, boardCards: feedbackBoard.cards } };
|
|
26072
|
-
}
|
|
26073
26008
|
return { ok: true };
|
|
26074
26009
|
};
|
|
26075
26010
|
var prepareStartAgentService = async (workspaceId, cardId) => {
|
|
@@ -26212,6 +26147,12 @@ var cardsController = new Hono2().post("/", zv("json", runtimeCardCreateRequestS
|
|
|
26212
26147
|
const card = await createCardService(workspaceId, cardData, baseRef);
|
|
26213
26148
|
ctx.stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
26214
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);
|
|
26215
26156
|
}).get(
|
|
26216
26157
|
"/branches",
|
|
26217
26158
|
zv("query", z5.object({ workspaceId: z5.string(), remote: z5.enum(["true", "false"]).optional() })),
|
|
@@ -26304,12 +26245,6 @@ var cardsController = new Hono2().post("/", zv("json", runtimeCardCreateRequestS
|
|
|
26304
26245
|
const ctx = c.var.ctx;
|
|
26305
26246
|
const { workspaceId, cardId, targetColumnId, targetIndex } = c.req.valid("json");
|
|
26306
26247
|
const result = await moveCardService(workspaceId, cardId, targetColumnId, targetIndex);
|
|
26307
|
-
if (result.reopenCascade) {
|
|
26308
|
-
const scheduler = ctx.getScheduler(workspaceId);
|
|
26309
|
-
if (scheduler) {
|
|
26310
|
-
void scheduler.triggerParentReopenCascade(result.reopenCascade.movedCard, result.reopenCascade.boardCards);
|
|
26311
|
-
}
|
|
26312
|
-
}
|
|
26313
26248
|
ctx.stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
26314
26249
|
return c.json(result.board);
|
|
26315
26250
|
}).delete(
|
|
@@ -26381,12 +26316,6 @@ var cardsController = new Hono2().post("/", zv("json", runtimeCardCreateRequestS
|
|
|
26381
26316
|
const { workspaceId, cardId, comment, attachments, type, metadata } = c.req.valid("json");
|
|
26382
26317
|
const result = await submitHumanFeedbackService(workspaceId, cardId, comment, attachments, type, metadata);
|
|
26383
26318
|
ctx.stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
26384
|
-
if (result.reopenCascade) {
|
|
26385
|
-
const scheduler = ctx.getScheduler(workspaceId);
|
|
26386
|
-
if (scheduler) {
|
|
26387
|
-
void scheduler.triggerParentReopenCascade(result.reopenCascade.feedbackCard, result.reopenCascade.boardCards);
|
|
26388
|
-
}
|
|
26389
|
-
}
|
|
26390
26319
|
return c.json({ ok: result.ok });
|
|
26391
26320
|
}
|
|
26392
26321
|
).post("/start-agent", zv("json", z5.object({ workspaceId: z5.string(), cardId: z5.string() })), async (c) => {
|
|
@@ -26403,12 +26332,6 @@ var cardsController = new Hono2().post("/", zv("json", runtimeCardCreateRequestS
|
|
|
26403
26332
|
ctx.getScheduler(workspaceId)?.stopTask(cardId);
|
|
26404
26333
|
ctx.stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
26405
26334
|
return c.json({ ok: true });
|
|
26406
|
-
}).post("/interrupt-task", zv("json", z5.object({ workspaceId: z5.string(), cardId: z5.string() })), async (c) => {
|
|
26407
|
-
const ctx = c.var.ctx;
|
|
26408
|
-
const { workspaceId, cardId } = c.req.valid("json");
|
|
26409
|
-
ctx.getScheduler(workspaceId)?.interruptForParentReopen(cardId);
|
|
26410
|
-
ctx.stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
26411
|
-
return c.json({ ok: true });
|
|
26412
26335
|
}).post(
|
|
26413
26336
|
"/set-pr-meta",
|
|
26414
26337
|
zv(
|
|
@@ -28638,7 +28561,7 @@ process.on("uncaughtException", (err) => {
|
|
|
28638
28561
|
if (err.code === "EPIPE" || err.code === "ECONNRESET") return;
|
|
28639
28562
|
throw err;
|
|
28640
28563
|
});
|
|
28641
|
-
var VERSION9 = true ? "0.
|
|
28564
|
+
var VERSION9 = true ? "0.5.1" : "0.0.0-dev";
|
|
28642
28565
|
async function isPortAvailable(port, host) {
|
|
28643
28566
|
return new Promise((resolve5) => {
|
|
28644
28567
|
const probe = createServer2();
|
package/dist/mcp-server.js
CHANGED
|
@@ -33,7 +33,7 @@ function highestWorkflowLevel(workflow) {
|
|
|
33
33
|
}
|
|
34
34
|
return LEVEL_ORDER[bestIdx] ?? "medium";
|
|
35
35
|
}
|
|
36
|
-
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, runtimeCardMoveRequestSchema, runtimeCardUpdateRequestSchema, memoryScopeSchema, memoryTypeSchema, memorySourceTypeSchema, memoryStatusSchema, runtimeMemoryOriginAgentSchema, runtimeMemorySchema, recurringScheduleKindSchema, recurringScheduleSchema, recurringRunStatusSchema, recurringRunTriggerSchema, recurringAgentRunSchema, recurringAgentSchema, recurringAgentCreateRequestSchema, recurringAgentUpdateRequestSchema, projectFolderSchema, topLevelItemSchema, projectsLayoutSchema, runtimeProjectSchema;
|
|
36
|
+
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;
|
|
37
37
|
var init_api_contract = __esm({
|
|
38
38
|
"src/core/api-contract.ts"() {
|
|
39
39
|
"use strict";
|
|
@@ -466,6 +466,14 @@ Do NOT include:
|
|
|
466
466
|
modelConfig: cardModelConfigSchema.optional(),
|
|
467
467
|
activeLevel: tierLevelSchema.optional()
|
|
468
468
|
});
|
|
469
|
+
runtimeBulkCardImportItemSchema = runtimeCardCreateRequestSchema.extend({
|
|
470
|
+
tempId: z.string().optional()
|
|
471
|
+
});
|
|
472
|
+
runtimeBulkCardsCreateRequestSchema = z.object({
|
|
473
|
+
// Batch-wide base branch; an item's own baseRef overrides it, else resolved server-side.
|
|
474
|
+
baseRef: z.string().optional(),
|
|
475
|
+
cards: z.array(runtimeBulkCardImportItemSchema).min(1)
|
|
476
|
+
});
|
|
469
477
|
runtimeCardMoveRequestSchema = z.object({
|
|
470
478
|
cardId: z.string(),
|
|
471
479
|
targetColumnId: runtimeBoardColumnIdSchema,
|
|
@@ -794,6 +802,7 @@ __export(workspace_state_exports, {
|
|
|
794
802
|
clearCardSession: () => clearCardSession,
|
|
795
803
|
closeAllOpenTerminalSessions: () => closeAllOpenTerminalSessions,
|
|
796
804
|
createCard: () => createCard,
|
|
805
|
+
createCardsBulk: () => createCardsBulk,
|
|
797
806
|
deleteCard: () => deleteCard,
|
|
798
807
|
downloadGithubImages: () => downloadGithubImages,
|
|
799
808
|
endTerminalSession: () => endTerminalSession,
|
|
@@ -1344,6 +1353,79 @@ async function createCard(workspaceId2, data, baseRef) {
|
|
|
1344
1353
|
tx();
|
|
1345
1354
|
return card;
|
|
1346
1355
|
}
|
|
1356
|
+
async function createCardsBulk(workspaceId2, items, baseRef) {
|
|
1357
|
+
const db = getDb();
|
|
1358
|
+
const now = Date.now();
|
|
1359
|
+
const projectConfig = loadProjectConfigInternal(workspaceId2);
|
|
1360
|
+
const realIds = items.map(() => generateTaskId());
|
|
1361
|
+
const tempIdToRealId = /* @__PURE__ */ new Map();
|
|
1362
|
+
items.forEach((item, i) => {
|
|
1363
|
+
if (item.tempId) tempIdToRealId.set(item.tempId, realIds[i]);
|
|
1364
|
+
});
|
|
1365
|
+
const resolveRef = (ref) => tempIdToRealId.get(ref) ?? ref;
|
|
1366
|
+
const cards = items.map((item, i) => {
|
|
1367
|
+
const type = item.type ?? "task";
|
|
1368
|
+
const columnId = item.columnId ?? "todo";
|
|
1369
|
+
const workflow = resolveWorkflowForCard(projectConfig.workflows, { workflowId: item.workflowId, type });
|
|
1370
|
+
const waitsFor = (item.waitsFor ?? []).map(resolveRef);
|
|
1371
|
+
const dependsOn = item.dependsOn ? resolveRef(item.dependsOn) : void 0;
|
|
1372
|
+
return {
|
|
1373
|
+
id: realIds[i],
|
|
1374
|
+
description: item.description,
|
|
1375
|
+
columnId,
|
|
1376
|
+
type,
|
|
1377
|
+
readyForDev: item.readyForDev ?? type === "story",
|
|
1378
|
+
agentId: item.agentId,
|
|
1379
|
+
priority: item.priority,
|
|
1380
|
+
// dependsOn (stacking) and waitsFor (gate) are mutually exclusive — waitsFor wins.
|
|
1381
|
+
dependsOn: waitsFor.length > 0 ? void 0 : dependsOn,
|
|
1382
|
+
waitsFor,
|
|
1383
|
+
subtaskIds: (item.subtaskIds ?? []).map(resolveRef),
|
|
1384
|
+
autoFixAttempts: 0,
|
|
1385
|
+
activeLevel: item.activeLevel ?? highestWorkflowLevel(workflow),
|
|
1386
|
+
modelConfig: item.modelConfig ?? snapshotModelConfig(workflow),
|
|
1387
|
+
baseRef: item.baseRef ?? baseRef,
|
|
1388
|
+
createdAt: now,
|
|
1389
|
+
updatedAt: now,
|
|
1390
|
+
githubIssueUrl: item.githubIssueUrl,
|
|
1391
|
+
workflowId: item.workflowId ?? workflow?.id,
|
|
1392
|
+
descriptionAttachments: item.descriptionAttachments ?? [],
|
|
1393
|
+
branchName: item.branchName,
|
|
1394
|
+
reviewComments: [],
|
|
1395
|
+
activityLog: [],
|
|
1396
|
+
terminalSessions: [],
|
|
1397
|
+
githubCommentIds: []
|
|
1398
|
+
};
|
|
1399
|
+
});
|
|
1400
|
+
const columnCounts = /* @__PURE__ */ new Map();
|
|
1401
|
+
const nextPosition = (columnId) => {
|
|
1402
|
+
if (!columnCounts.has(columnId)) {
|
|
1403
|
+
const row = db.prepare("SELECT COUNT(*) AS n FROM cards WHERE workspace_id = ? AND column_id = ?").get(workspaceId2, columnId);
|
|
1404
|
+
columnCounts.set(columnId, row.n);
|
|
1405
|
+
}
|
|
1406
|
+
const pos = columnCounts.get(columnId);
|
|
1407
|
+
columnCounts.set(columnId, pos + 1);
|
|
1408
|
+
return pos;
|
|
1409
|
+
};
|
|
1410
|
+
const tx = db.transaction(() => {
|
|
1411
|
+
for (const card of cards) {
|
|
1412
|
+
upsertCardRow(db, workspaceId2, { ...card, dependsOn: void 0 }, nextPosition(card.columnId));
|
|
1413
|
+
}
|
|
1414
|
+
const setDep = db.prepare("UPDATE cards SET depends_on_id = ? WHERE id = ?");
|
|
1415
|
+
for (const card of cards) {
|
|
1416
|
+
if (card.dependsOn && db.prepare("SELECT 1 FROM cards WHERE id = ?").get(card.dependsOn)) {
|
|
1417
|
+
setDep.run(card.dependsOn, card.id);
|
|
1418
|
+
} else if (card.dependsOn) {
|
|
1419
|
+
card.dependsOn = void 0;
|
|
1420
|
+
}
|
|
1421
|
+
replaceCardWaitsFor(db, card.id, card.waitsFor ?? []);
|
|
1422
|
+
replaceCardSubtasks(db, card.id, card.subtaskIds ?? []);
|
|
1423
|
+
}
|
|
1424
|
+
bumpBoardRevision(db, workspaceId2);
|
|
1425
|
+
});
|
|
1426
|
+
tx();
|
|
1427
|
+
return cards;
|
|
1428
|
+
}
|
|
1347
1429
|
async function appendActivityLog(workspaceId2, cardId, message) {
|
|
1348
1430
|
const db = getDb();
|
|
1349
1431
|
const tx = db.transaction(() => {
|
|
@@ -1610,7 +1692,6 @@ var ROUTES = {
|
|
|
1610
1692
|
"cards.move": { method: "POST", path: () => "cards/move" },
|
|
1611
1693
|
"cards.delete": { method: "DELETE", path: (i) => `cards/${i.cardId}` },
|
|
1612
1694
|
"cards.addReviewComment": { method: "POST", path: () => "cards/add-review-comment" },
|
|
1613
|
-
"cards.interruptTask": { method: "POST", path: () => "cards/interrupt-task" },
|
|
1614
1695
|
"cards.setPrMeta": { method: "POST", path: () => "cards/set-pr-meta" },
|
|
1615
1696
|
"cards.setPlan": { method: "POST", path: () => "cards/set-plan" },
|
|
1616
1697
|
"workflows.upsert": { method: "POST", path: () => "workflows" },
|
|
@@ -2065,19 +2146,6 @@ registerTool(
|
|
|
2065
2146
|
return { content: [{ type: "text", text: `Deleted card ${cardId}.` }] };
|
|
2066
2147
|
}
|
|
2067
2148
|
);
|
|
2068
|
-
registerTool(
|
|
2069
|
-
"kanban_stop_task",
|
|
2070
|
-
{
|
|
2071
|
-
description: "Stop an in-progress agent task. The session is marked 'stopped' (preserving history) so the card can be restarted later. Use this before moving a child card to todo when its parent was reopened.",
|
|
2072
|
-
inputSchema: {
|
|
2073
|
-
cardId: z2.string().describe("The card ID of the in-progress task to stop")
|
|
2074
|
-
}
|
|
2075
|
-
},
|
|
2076
|
-
async ({ cardId }) => {
|
|
2077
|
-
await apiMutate("cards.interruptTask", { workspaceId, cardId });
|
|
2078
|
-
return { content: [{ type: "text", text: `Task ${cardId} interrupted.` }] };
|
|
2079
|
-
}
|
|
2080
|
-
);
|
|
2081
2149
|
registerTool(
|
|
2082
2150
|
"kanban_get_workflows",
|
|
2083
2151
|
{
|