@defend-tech/opencode-optima 0.1.38 → 0.1.39
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/index.js +27 -77
- package/dist/sanitize_cli.js +27 -77
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7932,6 +7932,7 @@ var CLICKUP_WEBHOOK_EVENTS = ["taskStatusUpdated", "taskAssigneeUpdated", "taskC
|
|
|
7932
7932
|
var CLICKUP_WEBHOOK_TERMINAL_STATUSES = ["backlog", "done", "completed", "closed"];
|
|
7933
7933
|
var CLICKUP_PM_METADATA_KEY = "optima.sessions.product_manager";
|
|
7934
7934
|
var CLICKUP_PM_MENTION_NAME = "Defend Tech Product Manager";
|
|
7935
|
+
var CLICKUP_BLOCKER_TAG_NAME = "BLOCKER";
|
|
7935
7936
|
var CLICKUP_WEBHOOK_RUNTIME_VERSION = 1;
|
|
7936
7937
|
var CLICKUP_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
|
|
7937
7938
|
var CLICKUP_WEBHOOK_REQUEST_TIMEOUT_MS = 1e4;
|
|
@@ -9156,6 +9157,12 @@ function createClickUpApiClient(config, fetchImpl = globalThis.fetch) {
|
|
|
9156
9157
|
body: JSON.stringify({ comment_text: comment })
|
|
9157
9158
|
});
|
|
9158
9159
|
},
|
|
9160
|
+
async addTaskTag({ taskId, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
|
|
9161
|
+
return request(`https://api.clickup.com/api/v2/task/${encodeURIComponent(taskId)}/tag/${encodeURIComponent(tagName)}`, {
|
|
9162
|
+
method: "POST",
|
|
9163
|
+
body: JSON.stringify({})
|
|
9164
|
+
});
|
|
9165
|
+
},
|
|
9159
9166
|
async listAssignedTasks({ assigneeId, statuses = [], limit = CLICKUP_WEBHOOK_STARTUP_TASK_LIMIT } = {}) {
|
|
9160
9167
|
const params = new URLSearchParams();
|
|
9161
9168
|
if (assigneeId) params.append("assignees[]", assigneeId);
|
|
@@ -9651,26 +9658,18 @@ async function verifyOpenCodeSessionEventDelivery(client, { sessionId, beforeMes
|
|
|
9651
9658
|
}
|
|
9652
9659
|
return { ok: false, reason: lastError };
|
|
9653
9660
|
}
|
|
9654
|
-
function
|
|
9655
|
-
|
|
9656
|
-
|
|
9657
|
-
|
|
9658
|
-
"The webhook did not mark this event as successfully routed; please inspect/replay the event or route the task manually.",
|
|
9659
|
-
clickUpNoAbandonmentRuleText()
|
|
9660
|
-
].join("\n");
|
|
9661
|
-
}
|
|
9662
|
-
async function postClickUpMessageDeliveryBlocker({ clickupClient, worktree, taskId, sessionId, reason, action } = {}) {
|
|
9663
|
-
const comment = buildClickUpMessageDeliveryBlockerComment({ taskId, sessionId, reason, action });
|
|
9664
|
-
if (typeof clickupClient?.postTaskComment !== "function") {
|
|
9665
|
-
appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_blocker_comment_unavailable", taskId, sessionId, reason, action });
|
|
9666
|
-
return { ok: false, skipped: true, reason: "post_task_comment_unavailable", comment };
|
|
9661
|
+
async function applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
|
|
9662
|
+
if (typeof clickupClient?.addTaskTag !== "function") {
|
|
9663
|
+
appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_unavailable", taskId, reason, source, tagName });
|
|
9664
|
+
return { ok: false, skipped: true, reason: "add_task_tag_unavailable", tagName };
|
|
9667
9665
|
}
|
|
9668
9666
|
try {
|
|
9669
|
-
await clickupClient.
|
|
9670
|
-
|
|
9667
|
+
await clickupClient.addTaskTag({ taskId, tagName });
|
|
9668
|
+
appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_applied", taskId, reason, source, tagName });
|
|
9669
|
+
return { ok: true, tagName };
|
|
9671
9670
|
} catch (error) {
|
|
9672
|
-
appendClickUpWebhookLocalLog(worktree, { type: "
|
|
9673
|
-
return { ok: false, error: error.message,
|
|
9671
|
+
appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_failed", taskId, reason, source, tagName, message: error.message });
|
|
9672
|
+
return { ok: false, error: error.message, tagName };
|
|
9674
9673
|
}
|
|
9675
9674
|
}
|
|
9676
9675
|
async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery } = {}) {
|
|
@@ -9687,8 +9686,8 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
|
|
|
9687
9686
|
}
|
|
9688
9687
|
const reason = verification?.reason || "message_delivery_failed";
|
|
9689
9688
|
appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason, fallbackAttempted: canFallbackDirect });
|
|
9690
|
-
const blocker = await
|
|
9691
|
-
return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: canFallbackDirect,
|
|
9689
|
+
const blocker = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source: canFallbackDirect ? "delivery_fallback_failed" : "delivery_verification_failed" });
|
|
9690
|
+
return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: canFallbackDirect, blockerTag: blocker };
|
|
9692
9691
|
}
|
|
9693
9692
|
function formatClickUpWebhookPrompt({ eventType, taskId, payload, branch = "", worktree = "", deliveryEvidencePath = "" }) {
|
|
9694
9693
|
const comment = clickUpCommentFromPayload(payload);
|
|
@@ -9706,45 +9705,6 @@ function formatClickUpWebhookPrompt({ eventType, taskId, payload, branch = "", w
|
|
|
9706
9705
|
deliveryEvidencePath ? `Final merge-trackable evidence must be written under ${deliveryEvidencePath}; use .optima only as local mirror/staging.` : null
|
|
9707
9706
|
].filter((part) => part !== null).join("\n");
|
|
9708
9707
|
}
|
|
9709
|
-
function clickUpNoAbandonmentRuleText() {
|
|
9710
|
-
return "No-abandonment rule: PM must keep working, or before stopping must post a ClickUp comment, hand off, remove PM as assignee, and assign the next owner.";
|
|
9711
|
-
}
|
|
9712
|
-
function buildClickUpStartupResumeComment({ taskId, result = {} } = {}) {
|
|
9713
|
-
const contextParts = [
|
|
9714
|
-
result.branch ? `- Branch: ${result.branch}` : null,
|
|
9715
|
-
result.worktree ? `- Worktree: ${result.worktree}` : null,
|
|
9716
|
-
result.deliveryEvidencePath ? `- Delivery evidence path: ${result.deliveryEvidencePath}` : null,
|
|
9717
|
-
result.evidencePath ? `- Local evidence path: ${result.evidencePath}` : null
|
|
9718
|
-
].filter(Boolean);
|
|
9719
|
-
return [
|
|
9720
|
-
`Startup reconciliation resumed ClickUp task ${taskId}.`,
|
|
9721
|
-
`Route result: ${result.action || "unknown"}${result.ok === false ? " (failed)" : ""}.`,
|
|
9722
|
-
result.sessionId ? `Session id: ${result.sessionId}.` : "Session id: unavailable.",
|
|
9723
|
-
contextParts.length ? contextParts.join("\n") : "Worktree/branch/delivery evidence path: unavailable.",
|
|
9724
|
-
clickUpNoAbandonmentRuleText()
|
|
9725
|
-
].join("\n");
|
|
9726
|
-
}
|
|
9727
|
-
function buildClickUpStartupBlockerComment({ taskId, error } = {}) {
|
|
9728
|
-
const summary = error?.message || String(error || "unknown error");
|
|
9729
|
-
return [
|
|
9730
|
-
`Startup reconciliation blocker for ClickUp task ${taskId}: ${summary}`,
|
|
9731
|
-
"Optima skipped this task for this startup pass and continued with the next PM-assigned task.",
|
|
9732
|
-
clickUpNoAbandonmentRuleText()
|
|
9733
|
-
].join("\n");
|
|
9734
|
-
}
|
|
9735
|
-
async function postClickUpStartupComment({ clickupClient, worktree, taskId, comment, type } = {}) {
|
|
9736
|
-
if (typeof clickupClient?.postTaskComment !== "function") {
|
|
9737
|
-
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comment_unavailable", taskId, commentType: type });
|
|
9738
|
-
return { ok: false, skipped: true, reason: "post_task_comment_unavailable" };
|
|
9739
|
-
}
|
|
9740
|
-
try {
|
|
9741
|
-
await clickupClient.postTaskComment({ taskId, comment });
|
|
9742
|
-
return { ok: true };
|
|
9743
|
-
} catch (error) {
|
|
9744
|
-
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comment_failed", taskId, commentType: type, message: error.message });
|
|
9745
|
-
return { ok: false, error: error.message };
|
|
9746
|
-
}
|
|
9747
|
-
}
|
|
9748
9708
|
function appendClickUpWebhookLocalLog(worktree, entry) {
|
|
9749
9709
|
const logPath = clickUpWebhookLogPath(worktree);
|
|
9750
9710
|
fs2.mkdirSync(path2.dirname(logPath), { recursive: true });
|
|
@@ -9980,8 +9940,8 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
9980
9940
|
} catch (error) {
|
|
9981
9941
|
const message = `Optima webhook could not create or reuse a task worktree for ${taskId}: ${error.message}`;
|
|
9982
9942
|
appendClickUpWebhookLocalLog(worktree, { type: "task_worktree_failed", taskId, message });
|
|
9983
|
-
|
|
9984
|
-
return { ok: false, action: "error", reason: "task_worktree_failed", taskId, message };
|
|
9943
|
+
const blockerTag2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "task_worktree_failed", source: "route_worktree" });
|
|
9944
|
+
return { ok: false, action: "error", reason: "task_worktree_failed", taskId, message, blockerTag: blockerTag2 };
|
|
9985
9945
|
}
|
|
9986
9946
|
const deliveryEvidencePath = deliveryEvidencePathForClickUpTask(taskId);
|
|
9987
9947
|
const routingMetadata = {
|
|
@@ -10027,10 +9987,9 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
10027
9987
|
return finish({ ok: true, action: "sent_to_existing_session", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, deliveryVerification: delivery.verification, deliveryFallback: delivery.fallback });
|
|
10028
9988
|
}
|
|
10029
9989
|
const at = now().toISOString();
|
|
10030
|
-
const incidentComment = `Optima webhook could not route this ClickUp event because OpenCode session ${sessionId} is missing on host ${host} at ${at}. No replacement session was created automatically.`;
|
|
10031
9990
|
appendClickUpWebhookLocalLog(worktree, { type: "missing_session", taskId, sessionId, host, at });
|
|
10032
|
-
await
|
|
10033
|
-
return finish({ ok: true, action: "missing_session_reported", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
|
|
9991
|
+
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "missing_session", source: "route_existing_session" });
|
|
9992
|
+
return finish({ ok: true, action: "missing_session_reported", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag });
|
|
10034
9993
|
}
|
|
10035
9994
|
async function routeClickUpWebhookEvent(options = {}) {
|
|
10036
9995
|
const taskId = clickUpTaskIdFromPayload(options.payload || {});
|
|
@@ -10088,24 +10047,14 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
|
|
|
10088
10047
|
});
|
|
10089
10048
|
if (result?.ok && result.action !== "ignored") {
|
|
10090
10049
|
routed.assigned += 1;
|
|
10091
|
-
|
|
10092
|
-
|
|
10093
|
-
|
|
10094
|
-
taskId,
|
|
10095
|
-
type: "resume",
|
|
10096
|
-
comment: buildClickUpStartupResumeComment({ taskId, result })
|
|
10097
|
-
});
|
|
10050
|
+
} else if (result?.ok === false) {
|
|
10051
|
+
routed.errors += 1;
|
|
10052
|
+
if (!result.blockerTag) await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
|
|
10098
10053
|
}
|
|
10099
10054
|
} catch (error) {
|
|
10100
10055
|
routed.errors += 1;
|
|
10101
10056
|
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_failed", taskId, message: error.message });
|
|
10102
|
-
await
|
|
10103
|
-
clickupClient,
|
|
10104
|
-
worktree,
|
|
10105
|
-
taskId,
|
|
10106
|
-
type: "blocker",
|
|
10107
|
-
comment: buildClickUpStartupBlockerComment({ taskId, error })
|
|
10108
|
-
});
|
|
10057
|
+
await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "startup_reconciliation_task_failed", source: "startup_reconciliation_task" });
|
|
10109
10058
|
}
|
|
10110
10059
|
if (!lastWebhookMs || !clickupClient?.getTaskComments) continue;
|
|
10111
10060
|
try {
|
|
@@ -10135,6 +10084,7 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
|
|
|
10135
10084
|
} catch (error) {
|
|
10136
10085
|
routed.errors += 1;
|
|
10137
10086
|
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comments_failed", taskId, message: error.message });
|
|
10087
|
+
await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "startup_reconciliation_comments_failed", source: "startup_reconciliation_comments" });
|
|
10138
10088
|
}
|
|
10139
10089
|
}
|
|
10140
10090
|
clickUpWebhookLifecycleLog(worktree, { type: "startup_reconciliation_finished", ...routed });
|
package/dist/sanitize_cli.js
CHANGED
|
@@ -7939,6 +7939,7 @@ var CLICKUP_WEBHOOK_EVENTS = ["taskStatusUpdated", "taskAssigneeUpdated", "taskC
|
|
|
7939
7939
|
var CLICKUP_WEBHOOK_TERMINAL_STATUSES = ["backlog", "done", "completed", "closed"];
|
|
7940
7940
|
var CLICKUP_PM_METADATA_KEY = "optima.sessions.product_manager";
|
|
7941
7941
|
var CLICKUP_PM_MENTION_NAME = "Defend Tech Product Manager";
|
|
7942
|
+
var CLICKUP_BLOCKER_TAG_NAME = "BLOCKER";
|
|
7942
7943
|
var CLICKUP_WEBHOOK_RUNTIME_VERSION = 1;
|
|
7943
7944
|
var CLICKUP_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
|
|
7944
7945
|
var CLICKUP_WEBHOOK_REQUEST_TIMEOUT_MS = 1e4;
|
|
@@ -9163,6 +9164,12 @@ function createClickUpApiClient(config, fetchImpl = globalThis.fetch) {
|
|
|
9163
9164
|
body: JSON.stringify({ comment_text: comment })
|
|
9164
9165
|
});
|
|
9165
9166
|
},
|
|
9167
|
+
async addTaskTag({ taskId, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
|
|
9168
|
+
return request(`https://api.clickup.com/api/v2/task/${encodeURIComponent(taskId)}/tag/${encodeURIComponent(tagName)}`, {
|
|
9169
|
+
method: "POST",
|
|
9170
|
+
body: JSON.stringify({})
|
|
9171
|
+
});
|
|
9172
|
+
},
|
|
9166
9173
|
async listAssignedTasks({ assigneeId, statuses = [], limit = CLICKUP_WEBHOOK_STARTUP_TASK_LIMIT } = {}) {
|
|
9167
9174
|
const params = new URLSearchParams();
|
|
9168
9175
|
if (assigneeId) params.append("assignees[]", assigneeId);
|
|
@@ -9658,26 +9665,18 @@ async function verifyOpenCodeSessionEventDelivery(client, { sessionId, beforeMes
|
|
|
9658
9665
|
}
|
|
9659
9666
|
return { ok: false, reason: lastError };
|
|
9660
9667
|
}
|
|
9661
|
-
function
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
|
|
9665
|
-
"The webhook did not mark this event as successfully routed; please inspect/replay the event or route the task manually.",
|
|
9666
|
-
clickUpNoAbandonmentRuleText()
|
|
9667
|
-
].join("\n");
|
|
9668
|
-
}
|
|
9669
|
-
async function postClickUpMessageDeliveryBlocker({ clickupClient, worktree, taskId, sessionId, reason, action } = {}) {
|
|
9670
|
-
const comment = buildClickUpMessageDeliveryBlockerComment({ taskId, sessionId, reason, action });
|
|
9671
|
-
if (typeof clickupClient?.postTaskComment !== "function") {
|
|
9672
|
-
appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_blocker_comment_unavailable", taskId, sessionId, reason, action });
|
|
9673
|
-
return { ok: false, skipped: true, reason: "post_task_comment_unavailable", comment };
|
|
9668
|
+
async function applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
|
|
9669
|
+
if (typeof clickupClient?.addTaskTag !== "function") {
|
|
9670
|
+
appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_unavailable", taskId, reason, source, tagName });
|
|
9671
|
+
return { ok: false, skipped: true, reason: "add_task_tag_unavailable", tagName };
|
|
9674
9672
|
}
|
|
9675
9673
|
try {
|
|
9676
|
-
await clickupClient.
|
|
9677
|
-
|
|
9674
|
+
await clickupClient.addTaskTag({ taskId, tagName });
|
|
9675
|
+
appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_applied", taskId, reason, source, tagName });
|
|
9676
|
+
return { ok: true, tagName };
|
|
9678
9677
|
} catch (error) {
|
|
9679
|
-
appendClickUpWebhookLocalLog(worktree, { type: "
|
|
9680
|
-
return { ok: false, error: error.message,
|
|
9678
|
+
appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_failed", taskId, reason, source, tagName, message: error.message });
|
|
9679
|
+
return { ok: false, error: error.message, tagName };
|
|
9681
9680
|
}
|
|
9682
9681
|
}
|
|
9683
9682
|
async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery } = {}) {
|
|
@@ -9694,8 +9693,8 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
|
|
|
9694
9693
|
}
|
|
9695
9694
|
const reason = verification?.reason || "message_delivery_failed";
|
|
9696
9695
|
appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason, fallbackAttempted: canFallbackDirect });
|
|
9697
|
-
const blocker = await
|
|
9698
|
-
return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: canFallbackDirect,
|
|
9696
|
+
const blocker = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source: canFallbackDirect ? "delivery_fallback_failed" : "delivery_verification_failed" });
|
|
9697
|
+
return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: canFallbackDirect, blockerTag: blocker };
|
|
9699
9698
|
}
|
|
9700
9699
|
function formatClickUpWebhookPrompt({ eventType, taskId, payload, branch = "", worktree = "", deliveryEvidencePath = "" }) {
|
|
9701
9700
|
const comment = clickUpCommentFromPayload(payload);
|
|
@@ -9713,45 +9712,6 @@ function formatClickUpWebhookPrompt({ eventType, taskId, payload, branch = "", w
|
|
|
9713
9712
|
deliveryEvidencePath ? `Final merge-trackable evidence must be written under ${deliveryEvidencePath}; use .optima only as local mirror/staging.` : null
|
|
9714
9713
|
].filter((part) => part !== null).join("\n");
|
|
9715
9714
|
}
|
|
9716
|
-
function clickUpNoAbandonmentRuleText() {
|
|
9717
|
-
return "No-abandonment rule: PM must keep working, or before stopping must post a ClickUp comment, hand off, remove PM as assignee, and assign the next owner.";
|
|
9718
|
-
}
|
|
9719
|
-
function buildClickUpStartupResumeComment({ taskId, result = {} } = {}) {
|
|
9720
|
-
const contextParts = [
|
|
9721
|
-
result.branch ? `- Branch: ${result.branch}` : null,
|
|
9722
|
-
result.worktree ? `- Worktree: ${result.worktree}` : null,
|
|
9723
|
-
result.deliveryEvidencePath ? `- Delivery evidence path: ${result.deliveryEvidencePath}` : null,
|
|
9724
|
-
result.evidencePath ? `- Local evidence path: ${result.evidencePath}` : null
|
|
9725
|
-
].filter(Boolean);
|
|
9726
|
-
return [
|
|
9727
|
-
`Startup reconciliation resumed ClickUp task ${taskId}.`,
|
|
9728
|
-
`Route result: ${result.action || "unknown"}${result.ok === false ? " (failed)" : ""}.`,
|
|
9729
|
-
result.sessionId ? `Session id: ${result.sessionId}.` : "Session id: unavailable.",
|
|
9730
|
-
contextParts.length ? contextParts.join("\n") : "Worktree/branch/delivery evidence path: unavailable.",
|
|
9731
|
-
clickUpNoAbandonmentRuleText()
|
|
9732
|
-
].join("\n");
|
|
9733
|
-
}
|
|
9734
|
-
function buildClickUpStartupBlockerComment({ taskId, error } = {}) {
|
|
9735
|
-
const summary = error?.message || String(error || "unknown error");
|
|
9736
|
-
return [
|
|
9737
|
-
`Startup reconciliation blocker for ClickUp task ${taskId}: ${summary}`,
|
|
9738
|
-
"Optima skipped this task for this startup pass and continued with the next PM-assigned task.",
|
|
9739
|
-
clickUpNoAbandonmentRuleText()
|
|
9740
|
-
].join("\n");
|
|
9741
|
-
}
|
|
9742
|
-
async function postClickUpStartupComment({ clickupClient, worktree, taskId, comment, type } = {}) {
|
|
9743
|
-
if (typeof clickupClient?.postTaskComment !== "function") {
|
|
9744
|
-
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comment_unavailable", taskId, commentType: type });
|
|
9745
|
-
return { ok: false, skipped: true, reason: "post_task_comment_unavailable" };
|
|
9746
|
-
}
|
|
9747
|
-
try {
|
|
9748
|
-
await clickupClient.postTaskComment({ taskId, comment });
|
|
9749
|
-
return { ok: true };
|
|
9750
|
-
} catch (error) {
|
|
9751
|
-
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comment_failed", taskId, commentType: type, message: error.message });
|
|
9752
|
-
return { ok: false, error: error.message };
|
|
9753
|
-
}
|
|
9754
|
-
}
|
|
9755
9715
|
function appendClickUpWebhookLocalLog(worktree, entry) {
|
|
9756
9716
|
const logPath = clickUpWebhookLogPath(worktree);
|
|
9757
9717
|
fs2.mkdirSync(path2.dirname(logPath), { recursive: true });
|
|
@@ -9987,8 +9947,8 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
9987
9947
|
} catch (error) {
|
|
9988
9948
|
const message = `Optima webhook could not create or reuse a task worktree for ${taskId}: ${error.message}`;
|
|
9989
9949
|
appendClickUpWebhookLocalLog(worktree, { type: "task_worktree_failed", taskId, message });
|
|
9990
|
-
|
|
9991
|
-
return { ok: false, action: "error", reason: "task_worktree_failed", taskId, message };
|
|
9950
|
+
const blockerTag2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "task_worktree_failed", source: "route_worktree" });
|
|
9951
|
+
return { ok: false, action: "error", reason: "task_worktree_failed", taskId, message, blockerTag: blockerTag2 };
|
|
9992
9952
|
}
|
|
9993
9953
|
const deliveryEvidencePath = deliveryEvidencePathForClickUpTask(taskId);
|
|
9994
9954
|
const routingMetadata = {
|
|
@@ -10034,10 +9994,9 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
10034
9994
|
return finish({ ok: true, action: "sent_to_existing_session", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, deliveryVerification: delivery.verification, deliveryFallback: delivery.fallback });
|
|
10035
9995
|
}
|
|
10036
9996
|
const at = now().toISOString();
|
|
10037
|
-
const incidentComment = `Optima webhook could not route this ClickUp event because OpenCode session ${sessionId} is missing on host ${host} at ${at}. No replacement session was created automatically.`;
|
|
10038
9997
|
appendClickUpWebhookLocalLog(worktree, { type: "missing_session", taskId, sessionId, host, at });
|
|
10039
|
-
await
|
|
10040
|
-
return finish({ ok: true, action: "missing_session_reported", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
|
|
9998
|
+
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "missing_session", source: "route_existing_session" });
|
|
9999
|
+
return finish({ ok: true, action: "missing_session_reported", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag });
|
|
10041
10000
|
}
|
|
10042
10001
|
async function routeClickUpWebhookEvent(options = {}) {
|
|
10043
10002
|
const taskId = clickUpTaskIdFromPayload(options.payload || {});
|
|
@@ -10095,24 +10054,14 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
|
|
|
10095
10054
|
});
|
|
10096
10055
|
if (result?.ok && result.action !== "ignored") {
|
|
10097
10056
|
routed.assigned += 1;
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
taskId,
|
|
10102
|
-
type: "resume",
|
|
10103
|
-
comment: buildClickUpStartupResumeComment({ taskId, result })
|
|
10104
|
-
});
|
|
10057
|
+
} else if (result?.ok === false) {
|
|
10058
|
+
routed.errors += 1;
|
|
10059
|
+
if (!result.blockerTag) await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
|
|
10105
10060
|
}
|
|
10106
10061
|
} catch (error) {
|
|
10107
10062
|
routed.errors += 1;
|
|
10108
10063
|
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_failed", taskId, message: error.message });
|
|
10109
|
-
await
|
|
10110
|
-
clickupClient,
|
|
10111
|
-
worktree,
|
|
10112
|
-
taskId,
|
|
10113
|
-
type: "blocker",
|
|
10114
|
-
comment: buildClickUpStartupBlockerComment({ taskId, error })
|
|
10115
|
-
});
|
|
10064
|
+
await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "startup_reconciliation_task_failed", source: "startup_reconciliation_task" });
|
|
10116
10065
|
}
|
|
10117
10066
|
if (!lastWebhookMs || !clickupClient?.getTaskComments) continue;
|
|
10118
10067
|
try {
|
|
@@ -10142,6 +10091,7 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
|
|
|
10142
10091
|
} catch (error) {
|
|
10143
10092
|
routed.errors += 1;
|
|
10144
10093
|
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comments_failed", taskId, message: error.message });
|
|
10094
|
+
await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "startup_reconciliation_comments_failed", source: "startup_reconciliation_comments" });
|
|
10145
10095
|
}
|
|
10146
10096
|
}
|
|
10147
10097
|
clickUpWebhookLifecycleLog(worktree, { type: "startup_reconciliation_finished", ...routed });
|