@defend-tech/opencode-optima 0.1.62 → 0.1.64
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/assets/agents/workflow_product_manager.md +1 -1
- package/dist/index.js +78 -90
- package/dist/sanitize_cli.js +78 -90
- package/package.json +1 -1
|
@@ -33,7 +33,7 @@ You are Workflow_Product_Manager, Optima's ClickUp-first delivery orchestrator.
|
|
|
33
33
|
|
|
34
34
|
- Register only when Optima opt-in ClickUp webhook mode is configured and active/valid.
|
|
35
35
|
- Webhook wakeup requires signed `X-Signature` HMAC SHA-256 verification, duplicate suppression, PM assignment/non-terminal status checks, and comment mention gating for `@Defend Tech Product Manager`.
|
|
36
|
-
-
|
|
36
|
+
- Webhook routing is successful only after the worktree is OpenChamber-visible, an OpenCode `workflow_product_manager` session exists in that exact worktree directory, and prompt delivery/admission is verified. Worktree visibility alone is a launch failure, not successful routing.
|
|
37
37
|
- Delivery task types: `Tarea`, `Bug`, `Doc`, `PoC`. Ignore unless converted/linked to delivery: `Idea`, legacy `Backlog`, `Hito`, `Nota de reunión`, `Respuesta del formulario`. Treat `Backlog` task type as `Idea`, not `backlog` status.
|
|
38
38
|
- Branch-safe slugs: `Tarea` -> `tarea`, `Bug` -> `bug`, `Doc` -> `doc`, `PoC` -> `poc`. Unknown task type: pause and ask PMA/PO for clarification.
|
|
39
39
|
|
package/dist/index.js
CHANGED
|
@@ -8621,13 +8621,6 @@ var activeClickUpWebhookLifecycleRegistry = /* @__PURE__ */ new Map();
|
|
|
8621
8621
|
var CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS = 8e3;
|
|
8622
8622
|
var CLICKUP_WEBHOOK_SIGNAL_STATE = Symbol.for("opencode-optima.clickup-webhook.signal-state");
|
|
8623
8623
|
var activeClickUpTaskRoutes = /* @__PURE__ */ new Map();
|
|
8624
|
-
var objectIdentityMap = /* @__PURE__ */ new WeakMap();
|
|
8625
|
-
var objectIdentitySequence = 0;
|
|
8626
|
-
function objectIdentity(value) {
|
|
8627
|
-
if (!value || typeof value !== "object" && typeof value !== "function") return String(value ?? "");
|
|
8628
|
-
if (!objectIdentityMap.has(value)) objectIdentityMap.set(value, `obj_${++objectIdentitySequence}`);
|
|
8629
|
-
return objectIdentityMap.get(value);
|
|
8630
|
-
}
|
|
8631
8624
|
function isRootDirectory(candidate) {
|
|
8632
8625
|
const resolved = path5.resolve(candidate);
|
|
8633
8626
|
return resolved === path5.parse(resolved).root;
|
|
@@ -8753,7 +8746,6 @@ function hasActionableClickUpRoute(result = {}) {
|
|
|
8753
8746
|
if (!result.sessionId) return false;
|
|
8754
8747
|
if (result.action === "message_delivery_failed" || result.action === "error") return false;
|
|
8755
8748
|
if (result.deliveryVerification?.ok === false) return false;
|
|
8756
|
-
if (result.deliveryVerification?.method === "prompt_admission") return false;
|
|
8757
8749
|
return true;
|
|
8758
8750
|
}
|
|
8759
8751
|
function determineClickUpMergeAuthority({ isSubtask = false, clickupStatus = "", validationPassed = false, mergeFailed = false, finalApprovalRoles = CLICKUP_FINAL_APPROVER_ROLES, humansRegistry } = {}) {
|
|
@@ -9350,11 +9342,6 @@ async function syncOpenChamberWorktreeVisibility({ openchamberBaseUrl, opencodeB
|
|
|
9350
9342
|
}
|
|
9351
9343
|
return visibility;
|
|
9352
9344
|
}
|
|
9353
|
-
function assertOpenChamberClickUpWorktreePath({ baseWorktree, worktreePath } = {}) {
|
|
9354
|
-
if (!isClickUpDerivedWorktreeSibling(worktreePath, baseWorktree)) {
|
|
9355
|
-
throw new Error(`OpenChamber worktree path is outside the configured ClickUp sibling scope: ${worktreePath}`);
|
|
9356
|
-
}
|
|
9357
|
-
}
|
|
9358
9345
|
async function createOpenChamberClickUpWorktree({ openchamberBaseUrl, baseUrl, baseWorktree, branch, worktreePath, startPoint, branchExists = false, fetchImpl = globalThis.fetch } = {}) {
|
|
9359
9346
|
const effectiveOpenChamberBaseUrl = openchamberBaseUrl || baseUrl;
|
|
9360
9347
|
const worktreeName = clickUpOpenChamberWorktreeName(branch);
|
|
@@ -9377,7 +9364,6 @@ async function createOpenChamberClickUpWorktree({ openchamberBaseUrl, baseUrl, b
|
|
|
9377
9364
|
return { created, worktree: path5.resolve(createdDirectory), branch: createdBranch, verified };
|
|
9378
9365
|
}
|
|
9379
9366
|
async function registerOpenChamberClickUpWorktree({ openchamberBaseUrl, opencodeBaseUrl, baseUrl, baseWorktree, branch, worktreePath, fetchImpl = globalThis.fetch, source = "reuse" } = {}) {
|
|
9380
|
-
assertOpenChamberClickUpWorktreePath({ baseWorktree, worktreePath });
|
|
9381
9367
|
const visibility = await syncOpenChamberWorktreeVisibility({ openchamberBaseUrl: openchamberBaseUrl || baseUrl, opencodeBaseUrl: opencodeBaseUrl || baseUrl, baseWorktree, worktreePath, branch, fetchImpl });
|
|
9382
9368
|
return { branch, worktree: path5.resolve(worktreePath), reused: true, provider: "openchamber", openChamber: { source, visibility } };
|
|
9383
9369
|
}
|
|
@@ -9431,30 +9417,6 @@ async function ensureClickUpTaskWorktreeForWebhook({ opencodeBaseUrl = "", openc
|
|
|
9431
9417
|
} catch (error) {
|
|
9432
9418
|
const message = `OpenChamber worktree provisioning failed for ${options.taskId || "unknown task"}; raw git fallback is disabled to avoid invisible worktrees. ${error.message}`;
|
|
9433
9419
|
appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_failed", taskId: options.taskId || null, message });
|
|
9434
|
-
if (typeof clickupClient?.postTaskComment === "function") {
|
|
9435
|
-
const taskId = options.taskId || "unknown task";
|
|
9436
|
-
const ledgerPath = clickUpCommentLedgerPath(webhookWorktree);
|
|
9437
|
-
const comment = `${message}
|
|
9438
|
-
|
|
9439
|
-
Optima did not run raw git worktree fallback. Please verify clickup.openchamber.base_url and OpenCode/OpenChamber endpoint configuration.`;
|
|
9440
|
-
let dedupe = { post: true, key: clickUpWorktreeFailureCommentKey({ taskId, message }) };
|
|
9441
|
-
try {
|
|
9442
|
-
dedupe = shouldPostClickUpWorktreeFailureComment({ ledgerPath, taskId, message });
|
|
9443
|
-
} catch (ledgerError) {
|
|
9444
|
-
appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_comment_dedupe_failed", taskId, message: ledgerError.message });
|
|
9445
|
-
}
|
|
9446
|
-
if (dedupe.post) {
|
|
9447
|
-
try {
|
|
9448
|
-
await clickupClient.postTaskComment({ taskId: options.taskId, comment });
|
|
9449
|
-
recordClickUpWorktreeFailureComment({ ledgerPath, taskId, message, posted: true });
|
|
9450
|
-
} catch (commentError) {
|
|
9451
|
-
appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_blocker_comment_failed", taskId: options.taskId || null, message: commentError.message });
|
|
9452
|
-
}
|
|
9453
|
-
} else {
|
|
9454
|
-
appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_blocker_comment_deduped", taskId, key: dedupe.key, reason: dedupe.reason });
|
|
9455
|
-
recordClickUpWorktreeFailureComment({ ledgerPath, taskId, message, posted: false, skippedReason: dedupe.reason });
|
|
9456
|
-
}
|
|
9457
|
-
}
|
|
9458
9420
|
throw new Error(message);
|
|
9459
9421
|
}
|
|
9460
9422
|
}
|
|
@@ -10400,35 +10362,6 @@ function recordClickUpCommentVersionProcessed({ ledgerPath, key, taskId, eventTy
|
|
|
10400
10362
|
recordedAt: at.toISOString()
|
|
10401
10363
|
});
|
|
10402
10364
|
}
|
|
10403
|
-
function clickUpWorktreeFailureCommentKey({ taskId, message } = {}) {
|
|
10404
|
-
const hash = crypto.createHash("sha256").update(String(message || "")).digest("hex").slice(0, 16);
|
|
10405
|
-
return [String(taskId || "unknown").trim() || "unknown", "worktree_failure", hash].join(":");
|
|
10406
|
-
}
|
|
10407
|
-
function shouldPostClickUpWorktreeFailureComment({ ledgerPath, taskId, message, now = /* @__PURE__ */ new Date(), windowMs = CLICKUP_WORKTREE_FAILURE_COMMENT_DEDUPE_MS } = {}) {
|
|
10408
|
-
const key = clickUpWorktreeFailureCommentKey({ taskId, message });
|
|
10409
|
-
const nowMs = now instanceof Date ? now.getTime() : new Date(now).getTime();
|
|
10410
|
-
for (const entry of readClickUpCommentLedgerEntries(ledgerPath).reverse()) {
|
|
10411
|
-
if (entry?.key !== key) continue;
|
|
10412
|
-
const postedAtMs = new Date(entry.postedAt || entry.recordedAt || entry.at || 0).getTime();
|
|
10413
|
-
if (Number.isFinite(postedAtMs) && Number.isFinite(nowMs) && nowMs - postedAtMs <= windowMs) {
|
|
10414
|
-
return { post: false, key, reason: "recent_duplicate" };
|
|
10415
|
-
}
|
|
10416
|
-
if (entry?.message === message) return { post: false, key, reason: "latest_equivalent" };
|
|
10417
|
-
}
|
|
10418
|
-
return { post: true, key };
|
|
10419
|
-
}
|
|
10420
|
-
function recordClickUpWorktreeFailureComment({ ledgerPath, taskId, message, posted = true, skippedReason = null, at = /* @__PURE__ */ new Date() } = {}) {
|
|
10421
|
-
appendClickUpCommentLedgerEntry(ledgerPath, {
|
|
10422
|
-
key: clickUpWorktreeFailureCommentKey({ taskId, message }),
|
|
10423
|
-
taskId,
|
|
10424
|
-
eventType: "worktree_failure",
|
|
10425
|
-
action: posted ? "worktree_failure_comment_posted" : "worktree_failure_comment_skipped",
|
|
10426
|
-
message,
|
|
10427
|
-
posted,
|
|
10428
|
-
skippedReason,
|
|
10429
|
-
postedAt: at.toISOString()
|
|
10430
|
-
});
|
|
10431
|
-
}
|
|
10432
10365
|
function clickUpTaskIdFromPayload(payload = {}) {
|
|
10433
10366
|
return String(payload.task_id || payload.taskId || payload.task?.id || payload.task?.task_id || "").trim();
|
|
10434
10367
|
}
|
|
@@ -10562,12 +10495,16 @@ function clearClickUpPendingSessionMetadata(metadata, metadataKey) {
|
|
|
10562
10495
|
delete cursor[parts[parts.length - 1]];
|
|
10563
10496
|
return JSON.stringify(sortJsonValue(root), null, 2);
|
|
10564
10497
|
}
|
|
10565
|
-
|
|
10498
|
+
function withOptionalDirectoryQuery(payload, directory) {
|
|
10499
|
+
if (!directory) return payload;
|
|
10500
|
+
return { ...payload, query: { ...payload.query || {}, directory } };
|
|
10501
|
+
}
|
|
10502
|
+
async function openCodeSessionExists(client, sessionId, { directory = "" } = {}) {
|
|
10566
10503
|
const getAttempts = [
|
|
10567
|
-
{ path: { id: sessionId } },
|
|
10568
|
-
{ path: { sessionID: sessionId } },
|
|
10569
|
-
{ sessionID: sessionId },
|
|
10570
|
-
{ id: sessionId }
|
|
10504
|
+
withOptionalDirectoryQuery({ path: { id: sessionId } }, directory),
|
|
10505
|
+
withOptionalDirectoryQuery({ path: { sessionID: sessionId } }, directory),
|
|
10506
|
+
directory ? { sessionID: sessionId, directory } : { sessionID: sessionId },
|
|
10507
|
+
directory ? { id: sessionId, directory } : { id: sessionId }
|
|
10571
10508
|
];
|
|
10572
10509
|
if (typeof client?.session?.get === "function") {
|
|
10573
10510
|
for (const attempt of getAttempts) {
|
|
@@ -10579,10 +10516,10 @@ async function openCodeSessionExists(client, sessionId) {
|
|
|
10579
10516
|
}
|
|
10580
10517
|
}
|
|
10581
10518
|
const messageAttempts = [
|
|
10582
|
-
{ path: { id: sessionId }, query: { limit: 1 } },
|
|
10583
|
-
{ path: { sessionID: sessionId }, query: { limit: 1 } },
|
|
10584
|
-
{ sessionID: sessionId, limit: 1 },
|
|
10585
|
-
{ id: sessionId, limit: 1 }
|
|
10519
|
+
{ path: { id: sessionId }, query: { limit: 1, ...directory ? { directory } : {} } },
|
|
10520
|
+
{ path: { sessionID: sessionId }, query: { limit: 1, ...directory ? { directory } : {} } },
|
|
10521
|
+
directory ? { sessionID: sessionId, directory, limit: 1 } : { sessionID: sessionId, limit: 1 },
|
|
10522
|
+
directory ? { id: sessionId, directory, limit: 1 } : { id: sessionId, limit: 1 }
|
|
10586
10523
|
];
|
|
10587
10524
|
if (typeof client?.session?.messages === "function") {
|
|
10588
10525
|
for (const attempt of messageAttempts) {
|
|
@@ -10986,6 +10923,11 @@ async function verifyOpenCodeSessionEventDelivery(client, { sessionId, directory
|
|
|
10986
10923
|
}
|
|
10987
10924
|
return { ok: false, reason: lastError };
|
|
10988
10925
|
}
|
|
10926
|
+
async function postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason, source } = {}) {
|
|
10927
|
+
void clickupClient;
|
|
10928
|
+
appendClickUpWebhookLocalLog(worktree, { type: "launch_failure_comment_skipped", taskId, reason, source, policy: "local_log_only" });
|
|
10929
|
+
return { ok: false, skipped: true, reason: "local_log_only" };
|
|
10930
|
+
}
|
|
10989
10931
|
async function applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
|
|
10990
10932
|
if (typeof clickupClient?.addTaskTag !== "function") {
|
|
10991
10933
|
appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_unavailable", taskId, reason, source, tagName });
|
|
@@ -11015,7 +10957,17 @@ function openCodeBlockingPromptVerification(result, sessionId) {
|
|
|
11015
10957
|
}
|
|
11016
10958
|
async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, directPrompt = false, acceptPromptAdmission = false, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, applyBlockerOnFailure = true } = {}) {
|
|
11017
10959
|
const beforeMessages = await readOpenCodeSessionMessages(openCodeClient, { sessionId, directory, limit: 50 }).catch(() => null);
|
|
11018
|
-
|
|
10960
|
+
let sendResult;
|
|
10961
|
+
try {
|
|
10962
|
+
sendResult = await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, direct: directPrompt, allowDirectFallback: directPrompt });
|
|
10963
|
+
} catch (error) {
|
|
10964
|
+
const reason2 = error.message || "message_delivery_failed";
|
|
10965
|
+
appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason: reason2, fallbackAttempted: false });
|
|
10966
|
+
if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason: reason2, taskId, sessionId, fallbackAttempted: false };
|
|
10967
|
+
const blocker2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: reason2, source: "delivery_send_failed" });
|
|
10968
|
+
const launchFailureComment2 = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: reason2, source: "delivery_send_failed" });
|
|
10969
|
+
return { ok: false, action: "message_delivery_failed", reason: reason2, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2, launchFailureComment: launchFailureComment2 };
|
|
10970
|
+
}
|
|
11019
10971
|
let blockingPromptVerification = null;
|
|
11020
10972
|
let admissionVerification = null;
|
|
11021
10973
|
try {
|
|
@@ -11025,7 +10977,8 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
|
|
|
11025
10977
|
appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason: error.message, fallbackAttempted: false });
|
|
11026
10978
|
if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false };
|
|
11027
10979
|
const blocker2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: error.message, source: "delivery_admission_failed" });
|
|
11028
|
-
|
|
10980
|
+
const launchFailureComment2 = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: error.message, source: "delivery_admission_failed" });
|
|
10981
|
+
return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2, launchFailureComment: launchFailureComment2 };
|
|
11029
10982
|
}
|
|
11030
10983
|
if (blockingPromptVerification) return { ok: true, verification: blockingPromptVerification, admissionVerification: null, fallback: false };
|
|
11031
10984
|
if (admissionVerification && acceptPromptAdmission) {
|
|
@@ -11040,7 +10993,8 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
|
|
|
11040
10993
|
appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason, fallbackAttempted: false, httpFallbackDisabled: Boolean(opencodeBaseUrl) });
|
|
11041
10994
|
if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: false };
|
|
11042
10995
|
const blocker = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source: "delivery_verification_failed" });
|
|
11043
|
-
|
|
10996
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason, source: "delivery_verification_failed" });
|
|
10997
|
+
return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker, launchFailureComment };
|
|
11044
10998
|
}
|
|
11045
10999
|
async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, staleSessionId, sessionTitle, taskRoute, metadataWithRouting, config, prompt, eventMarkers = [], deliveryEvidencePath, evidencePath, eventKey, createSession, verifySessionEventDelivery } = {}) {
|
|
11046
11000
|
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_started", taskId, staleSessionId, worktree: taskRoute?.worktree });
|
|
@@ -11050,12 +11004,14 @@ async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, click
|
|
|
11050
11004
|
} catch (error) {
|
|
11051
11005
|
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_create_failed", taskId, staleSessionId, message: error.message });
|
|
11052
11006
|
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
|
|
11053
|
-
|
|
11007
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
|
|
11008
|
+
return { ok: false, action: "message_delivery_failed", reason: "replacement_session_create_failed", taskId, sessionId: staleSessionId, replacementAttempted: true, blockerTag, launchFailureComment, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
|
|
11054
11009
|
}
|
|
11055
11010
|
if (!String(replacementSessionId || "").startsWith("ses_")) {
|
|
11056
11011
|
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_create_invalid", taskId, staleSessionId, replacementSessionId });
|
|
11057
11012
|
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
|
|
11058
|
-
|
|
11013
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
|
|
11014
|
+
return { ok: false, action: "message_delivery_failed", reason: "replacement_session_create_failed", taskId, sessionId: staleSessionId, replacementAttempted: true, blockerTag, launchFailureComment, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
|
|
11059
11015
|
}
|
|
11060
11016
|
const replacementDelivery = await deliverClickUpSessionEventWithVerification({
|
|
11061
11017
|
openCodeClient,
|
|
@@ -11077,7 +11033,8 @@ async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, click
|
|
|
11077
11033
|
if (!replacementDelivery.ok) {
|
|
11078
11034
|
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_delivery_failed", taskId, staleSessionId, replacementSessionId, reason: replacementDelivery.reason });
|
|
11079
11035
|
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: replacementDelivery.reason || "replacement_delivery_failed", source: "pm_session_recovery" });
|
|
11080
|
-
|
|
11036
|
+
const launchFailureComment = replacementDelivery.launchFailureComment || await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: replacementDelivery.reason || "replacement_delivery_failed", source: "pm_session_recovery" });
|
|
11037
|
+
return { ...replacementDelivery, sessionId: staleSessionId, replacementSessionId, replacementAttempted: true, blockerTag, launchFailureComment, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
|
|
11081
11038
|
}
|
|
11082
11039
|
const replacementMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(metadataWithRouting, config.routing.metadataKey, replacementSessionId), config.routing.metadataKey);
|
|
11083
11040
|
await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: replacementMetadata });
|
|
@@ -11361,8 +11318,26 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
11361
11318
|
if (!existingSessionId) {
|
|
11362
11319
|
let pendingSessionId = getNestedMetadataValue(metadata, clickUpPendingSessionKey(config.routing.metadataKey)) || state.pendingSessions?.[taskId];
|
|
11363
11320
|
if (!pendingSessionId) {
|
|
11364
|
-
|
|
11365
|
-
|
|
11321
|
+
try {
|
|
11322
|
+
pendingSessionId = await createSession(openCodeClient, { title: sessionTitle, directory: taskRoute.worktree, agent: config.routing.targetAgent });
|
|
11323
|
+
} catch (error) {
|
|
11324
|
+
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_failed", taskId, worktree: taskRoute.worktree, message: error.message });
|
|
11325
|
+
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
|
|
11326
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
|
|
11327
|
+
return finish({ ok: false, action: "error", reason: "session_create_failed", taskId, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag, launchFailureComment });
|
|
11328
|
+
}
|
|
11329
|
+
if (!String(pendingSessionId || "").startsWith("ses_")) {
|
|
11330
|
+
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_invalid", taskId, worktree: taskRoute.worktree, sessionId: pendingSessionId || null });
|
|
11331
|
+
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
|
|
11332
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
|
|
11333
|
+
return finish({ ok: false, action: "error", reason: "session_create_failed", taskId, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag, launchFailureComment });
|
|
11334
|
+
}
|
|
11335
|
+
if (!await sessionExists(openCodeClient, pendingSessionId, { directory: taskRoute.worktree })) {
|
|
11336
|
+
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_directory_unverified", taskId, worktree: taskRoute.worktree, sessionId: pendingSessionId });
|
|
11337
|
+
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_directory_unverified", source: "route_create_session" });
|
|
11338
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_directory_unverified", source: "route_create_session" });
|
|
11339
|
+
return finish({ ok: false, action: "error", reason: "session_directory_unverified", taskId, sessionId: pendingSessionId, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag, launchFailureComment });
|
|
11340
|
+
}
|
|
11366
11341
|
if (saveState) {
|
|
11367
11342
|
saveState({
|
|
11368
11343
|
...state,
|
|
@@ -11378,7 +11353,20 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
11378
11353
|
throw error;
|
|
11379
11354
|
}
|
|
11380
11355
|
const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId: pendingSessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, directPrompt: config.opencode?.promptDelivery === "http", acceptPromptAdmission: config.opencode?.acceptPromptAdmission === true, eventMarkers: [taskId, eventType], verifySessionEventDelivery });
|
|
11381
|
-
if (!delivery.ok)
|
|
11356
|
+
if (!delivery.ok) {
|
|
11357
|
+
const failedMetadata = clearClickUpPendingSessionMetadata(metadataWithRouting, config.routing.metadataKey);
|
|
11358
|
+
let pendingCleared = false;
|
|
11359
|
+
try {
|
|
11360
|
+
await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: failedMetadata });
|
|
11361
|
+
pendingCleared = true;
|
|
11362
|
+
} catch (error) {
|
|
11363
|
+
appendClickUpWebhookLocalLog(worktree, { type: "pending_session_clear_failed", taskId, sessionId: pendingSessionId, message: error.message });
|
|
11364
|
+
}
|
|
11365
|
+
const { [taskId]: _failedPending, ...remainingPending2 } = stateToPersist.pendingSessions || {};
|
|
11366
|
+
stateToPersist = { ...stateToPersist, pendingSessions: remainingPending2 };
|
|
11367
|
+
appendClickUpWebhookLocalLog(worktree, { type: "pending_session_delivery_failed", taskId, sessionId: pendingSessionId, reason: delivery.reason || "message_delivery_failed", pendingCleared });
|
|
11368
|
+
return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, pendingCleared });
|
|
11369
|
+
}
|
|
11382
11370
|
const nextMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(pendingMetadata, config.routing.metadataKey, pendingSessionId), config.routing.metadataKey);
|
|
11383
11371
|
await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: nextMetadata });
|
|
11384
11372
|
const { [taskId]: _completedPending, ...remainingPending } = stateToPersist.pendingSessions || {};
|
|
@@ -11386,7 +11374,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
11386
11374
|
return finish({ ok: true, action: "created_session", taskId, sessionId: pendingSessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, deliveryVerification: delivery.verification, deliveryAdmission: delivery.admissionVerification, deliveryFallback: delivery.fallback, deliveryAttempts: delivery.fallback ? 2 : 1 });
|
|
11387
11375
|
}
|
|
11388
11376
|
const sessionId = String(existingSessionId);
|
|
11389
|
-
if (await sessionExists(openCodeClient, sessionId)) {
|
|
11377
|
+
if (await sessionExists(openCodeClient, sessionId, { directory: taskRoute.worktree })) {
|
|
11390
11378
|
if (typeof clickupClient?.updateTaskMetadata === "function") await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: metadataWithRouting });
|
|
11391
11379
|
const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, directPrompt: config.opencode?.promptDelivery === "http", acceptPromptAdmission: config.opencode?.acceptPromptAdmission === true, eventMarkers: [taskId, eventType], verifySessionEventDelivery, applyBlockerOnFailure: false });
|
|
11392
11380
|
if (!delivery.ok) {
|
|
@@ -11514,6 +11502,7 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
|
|
|
11514
11502
|
routed.undelivered += 1;
|
|
11515
11503
|
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_undelivered", taskId, action: result?.action || "error", sessionId: routeSummary.sessionId, reason: result.reason || "startup_reconciliation_route_failed" });
|
|
11516
11504
|
if (!result.blockerTag) await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
|
|
11505
|
+
if (!result.launchFailureComment) await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
|
|
11517
11506
|
} else {
|
|
11518
11507
|
routed.undelivered += 1;
|
|
11519
11508
|
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_undelivered", taskId, action: routeSummary.action, sessionId: routeSummary.sessionId, reason: "route_not_actionable" });
|
|
@@ -11621,14 +11610,13 @@ function clickUpListenerKey(config) {
|
|
|
11621
11610
|
}
|
|
11622
11611
|
function clickUpListenerFingerprint({ config, state, worktree, clickupClient, openCodeClient } = {}) {
|
|
11623
11612
|
return JSON.stringify({
|
|
11613
|
+
teamId: config?.teamId || "",
|
|
11624
11614
|
publicUrl: config?.webhook?.publicUrl || "",
|
|
11625
11615
|
path: clickUpWebhookExpectedPath(config),
|
|
11626
|
-
|
|
11616
|
+
location: config?.webhook?.location || {},
|
|
11627
11617
|
webhookId: state?.webhookId || "",
|
|
11628
11618
|
secret: state?.secret || "",
|
|
11629
|
-
events: config?.webhook?.events || []
|
|
11630
|
-
clickupClient: objectIdentity(clickupClient),
|
|
11631
|
-
openCodeClient: objectIdentity(openCodeClient)
|
|
11619
|
+
events: config?.webhook?.events || []
|
|
11632
11620
|
});
|
|
11633
11621
|
}
|
|
11634
11622
|
function startClickUpWebhookListener({ config, state, worktree, clickupClient, openCodeClient, listenerRegistry = activeClickUpWebhookListeners } = {}) {
|
package/dist/sanitize_cli.js
CHANGED
|
@@ -8628,13 +8628,6 @@ var activeClickUpWebhookLifecycleRegistry = /* @__PURE__ */ new Map();
|
|
|
8628
8628
|
var CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS = 8e3;
|
|
8629
8629
|
var CLICKUP_WEBHOOK_SIGNAL_STATE = Symbol.for("opencode-optima.clickup-webhook.signal-state");
|
|
8630
8630
|
var activeClickUpTaskRoutes = /* @__PURE__ */ new Map();
|
|
8631
|
-
var objectIdentityMap = /* @__PURE__ */ new WeakMap();
|
|
8632
|
-
var objectIdentitySequence = 0;
|
|
8633
|
-
function objectIdentity(value) {
|
|
8634
|
-
if (!value || typeof value !== "object" && typeof value !== "function") return String(value ?? "");
|
|
8635
|
-
if (!objectIdentityMap.has(value)) objectIdentityMap.set(value, `obj_${++objectIdentitySequence}`);
|
|
8636
|
-
return objectIdentityMap.get(value);
|
|
8637
|
-
}
|
|
8638
8631
|
function isRootDirectory(candidate) {
|
|
8639
8632
|
const resolved = path5.resolve(candidate);
|
|
8640
8633
|
return resolved === path5.parse(resolved).root;
|
|
@@ -8760,7 +8753,6 @@ function hasActionableClickUpRoute(result = {}) {
|
|
|
8760
8753
|
if (!result.sessionId) return false;
|
|
8761
8754
|
if (result.action === "message_delivery_failed" || result.action === "error") return false;
|
|
8762
8755
|
if (result.deliveryVerification?.ok === false) return false;
|
|
8763
|
-
if (result.deliveryVerification?.method === "prompt_admission") return false;
|
|
8764
8756
|
return true;
|
|
8765
8757
|
}
|
|
8766
8758
|
function determineClickUpMergeAuthority({ isSubtask = false, clickupStatus = "", validationPassed = false, mergeFailed = false, finalApprovalRoles = CLICKUP_FINAL_APPROVER_ROLES, humansRegistry } = {}) {
|
|
@@ -9357,11 +9349,6 @@ async function syncOpenChamberWorktreeVisibility({ openchamberBaseUrl, opencodeB
|
|
|
9357
9349
|
}
|
|
9358
9350
|
return visibility;
|
|
9359
9351
|
}
|
|
9360
|
-
function assertOpenChamberClickUpWorktreePath({ baseWorktree, worktreePath } = {}) {
|
|
9361
|
-
if (!isClickUpDerivedWorktreeSibling(worktreePath, baseWorktree)) {
|
|
9362
|
-
throw new Error(`OpenChamber worktree path is outside the configured ClickUp sibling scope: ${worktreePath}`);
|
|
9363
|
-
}
|
|
9364
|
-
}
|
|
9365
9352
|
async function createOpenChamberClickUpWorktree({ openchamberBaseUrl, baseUrl, baseWorktree, branch, worktreePath, startPoint, branchExists = false, fetchImpl = globalThis.fetch } = {}) {
|
|
9366
9353
|
const effectiveOpenChamberBaseUrl = openchamberBaseUrl || baseUrl;
|
|
9367
9354
|
const worktreeName = clickUpOpenChamberWorktreeName(branch);
|
|
@@ -9384,7 +9371,6 @@ async function createOpenChamberClickUpWorktree({ openchamberBaseUrl, baseUrl, b
|
|
|
9384
9371
|
return { created, worktree: path5.resolve(createdDirectory), branch: createdBranch, verified };
|
|
9385
9372
|
}
|
|
9386
9373
|
async function registerOpenChamberClickUpWorktree({ openchamberBaseUrl, opencodeBaseUrl, baseUrl, baseWorktree, branch, worktreePath, fetchImpl = globalThis.fetch, source = "reuse" } = {}) {
|
|
9387
|
-
assertOpenChamberClickUpWorktreePath({ baseWorktree, worktreePath });
|
|
9388
9374
|
const visibility = await syncOpenChamberWorktreeVisibility({ openchamberBaseUrl: openchamberBaseUrl || baseUrl, opencodeBaseUrl: opencodeBaseUrl || baseUrl, baseWorktree, worktreePath, branch, fetchImpl });
|
|
9389
9375
|
return { branch, worktree: path5.resolve(worktreePath), reused: true, provider: "openchamber", openChamber: { source, visibility } };
|
|
9390
9376
|
}
|
|
@@ -9438,30 +9424,6 @@ async function ensureClickUpTaskWorktreeForWebhook({ opencodeBaseUrl = "", openc
|
|
|
9438
9424
|
} catch (error) {
|
|
9439
9425
|
const message = `OpenChamber worktree provisioning failed for ${options.taskId || "unknown task"}; raw git fallback is disabled to avoid invisible worktrees. ${error.message}`;
|
|
9440
9426
|
appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_failed", taskId: options.taskId || null, message });
|
|
9441
|
-
if (typeof clickupClient?.postTaskComment === "function") {
|
|
9442
|
-
const taskId = options.taskId || "unknown task";
|
|
9443
|
-
const ledgerPath = clickUpCommentLedgerPath(webhookWorktree);
|
|
9444
|
-
const comment = `${message}
|
|
9445
|
-
|
|
9446
|
-
Optima did not run raw git worktree fallback. Please verify clickup.openchamber.base_url and OpenCode/OpenChamber endpoint configuration.`;
|
|
9447
|
-
let dedupe = { post: true, key: clickUpWorktreeFailureCommentKey({ taskId, message }) };
|
|
9448
|
-
try {
|
|
9449
|
-
dedupe = shouldPostClickUpWorktreeFailureComment({ ledgerPath, taskId, message });
|
|
9450
|
-
} catch (ledgerError) {
|
|
9451
|
-
appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_comment_dedupe_failed", taskId, message: ledgerError.message });
|
|
9452
|
-
}
|
|
9453
|
-
if (dedupe.post) {
|
|
9454
|
-
try {
|
|
9455
|
-
await clickupClient.postTaskComment({ taskId: options.taskId, comment });
|
|
9456
|
-
recordClickUpWorktreeFailureComment({ ledgerPath, taskId, message, posted: true });
|
|
9457
|
-
} catch (commentError) {
|
|
9458
|
-
appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_blocker_comment_failed", taskId: options.taskId || null, message: commentError.message });
|
|
9459
|
-
}
|
|
9460
|
-
} else {
|
|
9461
|
-
appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_blocker_comment_deduped", taskId, key: dedupe.key, reason: dedupe.reason });
|
|
9462
|
-
recordClickUpWorktreeFailureComment({ ledgerPath, taskId, message, posted: false, skippedReason: dedupe.reason });
|
|
9463
|
-
}
|
|
9464
|
-
}
|
|
9465
9427
|
throw new Error(message);
|
|
9466
9428
|
}
|
|
9467
9429
|
}
|
|
@@ -10407,35 +10369,6 @@ function recordClickUpCommentVersionProcessed({ ledgerPath, key, taskId, eventTy
|
|
|
10407
10369
|
recordedAt: at.toISOString()
|
|
10408
10370
|
});
|
|
10409
10371
|
}
|
|
10410
|
-
function clickUpWorktreeFailureCommentKey({ taskId, message } = {}) {
|
|
10411
|
-
const hash = crypto.createHash("sha256").update(String(message || "")).digest("hex").slice(0, 16);
|
|
10412
|
-
return [String(taskId || "unknown").trim() || "unknown", "worktree_failure", hash].join(":");
|
|
10413
|
-
}
|
|
10414
|
-
function shouldPostClickUpWorktreeFailureComment({ ledgerPath, taskId, message, now = /* @__PURE__ */ new Date(), windowMs = CLICKUP_WORKTREE_FAILURE_COMMENT_DEDUPE_MS } = {}) {
|
|
10415
|
-
const key = clickUpWorktreeFailureCommentKey({ taskId, message });
|
|
10416
|
-
const nowMs = now instanceof Date ? now.getTime() : new Date(now).getTime();
|
|
10417
|
-
for (const entry of readClickUpCommentLedgerEntries(ledgerPath).reverse()) {
|
|
10418
|
-
if (entry?.key !== key) continue;
|
|
10419
|
-
const postedAtMs = new Date(entry.postedAt || entry.recordedAt || entry.at || 0).getTime();
|
|
10420
|
-
if (Number.isFinite(postedAtMs) && Number.isFinite(nowMs) && nowMs - postedAtMs <= windowMs) {
|
|
10421
|
-
return { post: false, key, reason: "recent_duplicate" };
|
|
10422
|
-
}
|
|
10423
|
-
if (entry?.message === message) return { post: false, key, reason: "latest_equivalent" };
|
|
10424
|
-
}
|
|
10425
|
-
return { post: true, key };
|
|
10426
|
-
}
|
|
10427
|
-
function recordClickUpWorktreeFailureComment({ ledgerPath, taskId, message, posted = true, skippedReason = null, at = /* @__PURE__ */ new Date() } = {}) {
|
|
10428
|
-
appendClickUpCommentLedgerEntry(ledgerPath, {
|
|
10429
|
-
key: clickUpWorktreeFailureCommentKey({ taskId, message }),
|
|
10430
|
-
taskId,
|
|
10431
|
-
eventType: "worktree_failure",
|
|
10432
|
-
action: posted ? "worktree_failure_comment_posted" : "worktree_failure_comment_skipped",
|
|
10433
|
-
message,
|
|
10434
|
-
posted,
|
|
10435
|
-
skippedReason,
|
|
10436
|
-
postedAt: at.toISOString()
|
|
10437
|
-
});
|
|
10438
|
-
}
|
|
10439
10372
|
function clickUpTaskIdFromPayload(payload = {}) {
|
|
10440
10373
|
return String(payload.task_id || payload.taskId || payload.task?.id || payload.task?.task_id || "").trim();
|
|
10441
10374
|
}
|
|
@@ -10569,12 +10502,16 @@ function clearClickUpPendingSessionMetadata(metadata, metadataKey) {
|
|
|
10569
10502
|
delete cursor[parts[parts.length - 1]];
|
|
10570
10503
|
return JSON.stringify(sortJsonValue(root), null, 2);
|
|
10571
10504
|
}
|
|
10572
|
-
|
|
10505
|
+
function withOptionalDirectoryQuery(payload, directory) {
|
|
10506
|
+
if (!directory) return payload;
|
|
10507
|
+
return { ...payload, query: { ...payload.query || {}, directory } };
|
|
10508
|
+
}
|
|
10509
|
+
async function openCodeSessionExists(client, sessionId, { directory = "" } = {}) {
|
|
10573
10510
|
const getAttempts = [
|
|
10574
|
-
{ path: { id: sessionId } },
|
|
10575
|
-
{ path: { sessionID: sessionId } },
|
|
10576
|
-
{ sessionID: sessionId },
|
|
10577
|
-
{ id: sessionId }
|
|
10511
|
+
withOptionalDirectoryQuery({ path: { id: sessionId } }, directory),
|
|
10512
|
+
withOptionalDirectoryQuery({ path: { sessionID: sessionId } }, directory),
|
|
10513
|
+
directory ? { sessionID: sessionId, directory } : { sessionID: sessionId },
|
|
10514
|
+
directory ? { id: sessionId, directory } : { id: sessionId }
|
|
10578
10515
|
];
|
|
10579
10516
|
if (typeof client?.session?.get === "function") {
|
|
10580
10517
|
for (const attempt of getAttempts) {
|
|
@@ -10586,10 +10523,10 @@ async function openCodeSessionExists(client, sessionId) {
|
|
|
10586
10523
|
}
|
|
10587
10524
|
}
|
|
10588
10525
|
const messageAttempts = [
|
|
10589
|
-
{ path: { id: sessionId }, query: { limit: 1 } },
|
|
10590
|
-
{ path: { sessionID: sessionId }, query: { limit: 1 } },
|
|
10591
|
-
{ sessionID: sessionId, limit: 1 },
|
|
10592
|
-
{ id: sessionId, limit: 1 }
|
|
10526
|
+
{ path: { id: sessionId }, query: { limit: 1, ...directory ? { directory } : {} } },
|
|
10527
|
+
{ path: { sessionID: sessionId }, query: { limit: 1, ...directory ? { directory } : {} } },
|
|
10528
|
+
directory ? { sessionID: sessionId, directory, limit: 1 } : { sessionID: sessionId, limit: 1 },
|
|
10529
|
+
directory ? { id: sessionId, directory, limit: 1 } : { id: sessionId, limit: 1 }
|
|
10593
10530
|
];
|
|
10594
10531
|
if (typeof client?.session?.messages === "function") {
|
|
10595
10532
|
for (const attempt of messageAttempts) {
|
|
@@ -10993,6 +10930,11 @@ async function verifyOpenCodeSessionEventDelivery(client, { sessionId, directory
|
|
|
10993
10930
|
}
|
|
10994
10931
|
return { ok: false, reason: lastError };
|
|
10995
10932
|
}
|
|
10933
|
+
async function postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason, source } = {}) {
|
|
10934
|
+
void clickupClient;
|
|
10935
|
+
appendClickUpWebhookLocalLog(worktree, { type: "launch_failure_comment_skipped", taskId, reason, source, policy: "local_log_only" });
|
|
10936
|
+
return { ok: false, skipped: true, reason: "local_log_only" };
|
|
10937
|
+
}
|
|
10996
10938
|
async function applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
|
|
10997
10939
|
if (typeof clickupClient?.addTaskTag !== "function") {
|
|
10998
10940
|
appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_unavailable", taskId, reason, source, tagName });
|
|
@@ -11022,7 +10964,17 @@ function openCodeBlockingPromptVerification(result, sessionId) {
|
|
|
11022
10964
|
}
|
|
11023
10965
|
async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, directPrompt = false, acceptPromptAdmission = false, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, applyBlockerOnFailure = true } = {}) {
|
|
11024
10966
|
const beforeMessages = await readOpenCodeSessionMessages(openCodeClient, { sessionId, directory, limit: 50 }).catch(() => null);
|
|
11025
|
-
|
|
10967
|
+
let sendResult;
|
|
10968
|
+
try {
|
|
10969
|
+
sendResult = await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, direct: directPrompt, allowDirectFallback: directPrompt });
|
|
10970
|
+
} catch (error) {
|
|
10971
|
+
const reason2 = error.message || "message_delivery_failed";
|
|
10972
|
+
appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason: reason2, fallbackAttempted: false });
|
|
10973
|
+
if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason: reason2, taskId, sessionId, fallbackAttempted: false };
|
|
10974
|
+
const blocker2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: reason2, source: "delivery_send_failed" });
|
|
10975
|
+
const launchFailureComment2 = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: reason2, source: "delivery_send_failed" });
|
|
10976
|
+
return { ok: false, action: "message_delivery_failed", reason: reason2, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2, launchFailureComment: launchFailureComment2 };
|
|
10977
|
+
}
|
|
11026
10978
|
let blockingPromptVerification = null;
|
|
11027
10979
|
let admissionVerification = null;
|
|
11028
10980
|
try {
|
|
@@ -11032,7 +10984,8 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
|
|
|
11032
10984
|
appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason: error.message, fallbackAttempted: false });
|
|
11033
10985
|
if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false };
|
|
11034
10986
|
const blocker2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: error.message, source: "delivery_admission_failed" });
|
|
11035
|
-
|
|
10987
|
+
const launchFailureComment2 = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: error.message, source: "delivery_admission_failed" });
|
|
10988
|
+
return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2, launchFailureComment: launchFailureComment2 };
|
|
11036
10989
|
}
|
|
11037
10990
|
if (blockingPromptVerification) return { ok: true, verification: blockingPromptVerification, admissionVerification: null, fallback: false };
|
|
11038
10991
|
if (admissionVerification && acceptPromptAdmission) {
|
|
@@ -11047,7 +11000,8 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
|
|
|
11047
11000
|
appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason, fallbackAttempted: false, httpFallbackDisabled: Boolean(opencodeBaseUrl) });
|
|
11048
11001
|
if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: false };
|
|
11049
11002
|
const blocker = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source: "delivery_verification_failed" });
|
|
11050
|
-
|
|
11003
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason, source: "delivery_verification_failed" });
|
|
11004
|
+
return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker, launchFailureComment };
|
|
11051
11005
|
}
|
|
11052
11006
|
async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, staleSessionId, sessionTitle, taskRoute, metadataWithRouting, config, prompt, eventMarkers = [], deliveryEvidencePath, evidencePath, eventKey, createSession, verifySessionEventDelivery } = {}) {
|
|
11053
11007
|
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_started", taskId, staleSessionId, worktree: taskRoute?.worktree });
|
|
@@ -11057,12 +11011,14 @@ async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, click
|
|
|
11057
11011
|
} catch (error) {
|
|
11058
11012
|
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_create_failed", taskId, staleSessionId, message: error.message });
|
|
11059
11013
|
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
|
|
11060
|
-
|
|
11014
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
|
|
11015
|
+
return { ok: false, action: "message_delivery_failed", reason: "replacement_session_create_failed", taskId, sessionId: staleSessionId, replacementAttempted: true, blockerTag, launchFailureComment, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
|
|
11061
11016
|
}
|
|
11062
11017
|
if (!String(replacementSessionId || "").startsWith("ses_")) {
|
|
11063
11018
|
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_create_invalid", taskId, staleSessionId, replacementSessionId });
|
|
11064
11019
|
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
|
|
11065
|
-
|
|
11020
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
|
|
11021
|
+
return { ok: false, action: "message_delivery_failed", reason: "replacement_session_create_failed", taskId, sessionId: staleSessionId, replacementAttempted: true, blockerTag, launchFailureComment, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
|
|
11066
11022
|
}
|
|
11067
11023
|
const replacementDelivery = await deliverClickUpSessionEventWithVerification({
|
|
11068
11024
|
openCodeClient,
|
|
@@ -11084,7 +11040,8 @@ async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, click
|
|
|
11084
11040
|
if (!replacementDelivery.ok) {
|
|
11085
11041
|
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_delivery_failed", taskId, staleSessionId, replacementSessionId, reason: replacementDelivery.reason });
|
|
11086
11042
|
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: replacementDelivery.reason || "replacement_delivery_failed", source: "pm_session_recovery" });
|
|
11087
|
-
|
|
11043
|
+
const launchFailureComment = replacementDelivery.launchFailureComment || await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: replacementDelivery.reason || "replacement_delivery_failed", source: "pm_session_recovery" });
|
|
11044
|
+
return { ...replacementDelivery, sessionId: staleSessionId, replacementSessionId, replacementAttempted: true, blockerTag, launchFailureComment, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
|
|
11088
11045
|
}
|
|
11089
11046
|
const replacementMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(metadataWithRouting, config.routing.metadataKey, replacementSessionId), config.routing.metadataKey);
|
|
11090
11047
|
await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: replacementMetadata });
|
|
@@ -11368,8 +11325,26 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
11368
11325
|
if (!existingSessionId) {
|
|
11369
11326
|
let pendingSessionId = getNestedMetadataValue(metadata, clickUpPendingSessionKey(config.routing.metadataKey)) || state.pendingSessions?.[taskId];
|
|
11370
11327
|
if (!pendingSessionId) {
|
|
11371
|
-
|
|
11372
|
-
|
|
11328
|
+
try {
|
|
11329
|
+
pendingSessionId = await createSession(openCodeClient, { title: sessionTitle, directory: taskRoute.worktree, agent: config.routing.targetAgent });
|
|
11330
|
+
} catch (error) {
|
|
11331
|
+
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_failed", taskId, worktree: taskRoute.worktree, message: error.message });
|
|
11332
|
+
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
|
|
11333
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
|
|
11334
|
+
return finish({ ok: false, action: "error", reason: "session_create_failed", taskId, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag, launchFailureComment });
|
|
11335
|
+
}
|
|
11336
|
+
if (!String(pendingSessionId || "").startsWith("ses_")) {
|
|
11337
|
+
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_invalid", taskId, worktree: taskRoute.worktree, sessionId: pendingSessionId || null });
|
|
11338
|
+
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
|
|
11339
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
|
|
11340
|
+
return finish({ ok: false, action: "error", reason: "session_create_failed", taskId, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag, launchFailureComment });
|
|
11341
|
+
}
|
|
11342
|
+
if (!await sessionExists(openCodeClient, pendingSessionId, { directory: taskRoute.worktree })) {
|
|
11343
|
+
appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_directory_unverified", taskId, worktree: taskRoute.worktree, sessionId: pendingSessionId });
|
|
11344
|
+
const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_directory_unverified", source: "route_create_session" });
|
|
11345
|
+
const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_directory_unverified", source: "route_create_session" });
|
|
11346
|
+
return finish({ ok: false, action: "error", reason: "session_directory_unverified", taskId, sessionId: pendingSessionId, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag, launchFailureComment });
|
|
11347
|
+
}
|
|
11373
11348
|
if (saveState) {
|
|
11374
11349
|
saveState({
|
|
11375
11350
|
...state,
|
|
@@ -11385,7 +11360,20 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
11385
11360
|
throw error;
|
|
11386
11361
|
}
|
|
11387
11362
|
const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId: pendingSessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, directPrompt: config.opencode?.promptDelivery === "http", acceptPromptAdmission: config.opencode?.acceptPromptAdmission === true, eventMarkers: [taskId, eventType], verifySessionEventDelivery });
|
|
11388
|
-
if (!delivery.ok)
|
|
11363
|
+
if (!delivery.ok) {
|
|
11364
|
+
const failedMetadata = clearClickUpPendingSessionMetadata(metadataWithRouting, config.routing.metadataKey);
|
|
11365
|
+
let pendingCleared = false;
|
|
11366
|
+
try {
|
|
11367
|
+
await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: failedMetadata });
|
|
11368
|
+
pendingCleared = true;
|
|
11369
|
+
} catch (error) {
|
|
11370
|
+
appendClickUpWebhookLocalLog(worktree, { type: "pending_session_clear_failed", taskId, sessionId: pendingSessionId, message: error.message });
|
|
11371
|
+
}
|
|
11372
|
+
const { [taskId]: _failedPending, ...remainingPending2 } = stateToPersist.pendingSessions || {};
|
|
11373
|
+
stateToPersist = { ...stateToPersist, pendingSessions: remainingPending2 };
|
|
11374
|
+
appendClickUpWebhookLocalLog(worktree, { type: "pending_session_delivery_failed", taskId, sessionId: pendingSessionId, reason: delivery.reason || "message_delivery_failed", pendingCleared });
|
|
11375
|
+
return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, pendingCleared });
|
|
11376
|
+
}
|
|
11389
11377
|
const nextMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(pendingMetadata, config.routing.metadataKey, pendingSessionId), config.routing.metadataKey);
|
|
11390
11378
|
await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: nextMetadata });
|
|
11391
11379
|
const { [taskId]: _completedPending, ...remainingPending } = stateToPersist.pendingSessions || {};
|
|
@@ -11393,7 +11381,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
11393
11381
|
return finish({ ok: true, action: "created_session", taskId, sessionId: pendingSessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, deliveryVerification: delivery.verification, deliveryAdmission: delivery.admissionVerification, deliveryFallback: delivery.fallback, deliveryAttempts: delivery.fallback ? 2 : 1 });
|
|
11394
11382
|
}
|
|
11395
11383
|
const sessionId = String(existingSessionId);
|
|
11396
|
-
if (await sessionExists(openCodeClient, sessionId)) {
|
|
11384
|
+
if (await sessionExists(openCodeClient, sessionId, { directory: taskRoute.worktree })) {
|
|
11397
11385
|
if (typeof clickupClient?.updateTaskMetadata === "function") await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: metadataWithRouting });
|
|
11398
11386
|
const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, directPrompt: config.opencode?.promptDelivery === "http", acceptPromptAdmission: config.opencode?.acceptPromptAdmission === true, eventMarkers: [taskId, eventType], verifySessionEventDelivery, applyBlockerOnFailure: false });
|
|
11399
11387
|
if (!delivery.ok) {
|
|
@@ -11521,6 +11509,7 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
|
|
|
11521
11509
|
routed.undelivered += 1;
|
|
11522
11510
|
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_undelivered", taskId, action: result?.action || "error", sessionId: routeSummary.sessionId, reason: result.reason || "startup_reconciliation_route_failed" });
|
|
11523
11511
|
if (!result.blockerTag) await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
|
|
11512
|
+
if (!result.launchFailureComment) await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
|
|
11524
11513
|
} else {
|
|
11525
11514
|
routed.undelivered += 1;
|
|
11526
11515
|
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_undelivered", taskId, action: routeSummary.action, sessionId: routeSummary.sessionId, reason: "route_not_actionable" });
|
|
@@ -11628,14 +11617,13 @@ function clickUpListenerKey(config) {
|
|
|
11628
11617
|
}
|
|
11629
11618
|
function clickUpListenerFingerprint({ config, state, worktree, clickupClient, openCodeClient } = {}) {
|
|
11630
11619
|
return JSON.stringify({
|
|
11620
|
+
teamId: config?.teamId || "",
|
|
11631
11621
|
publicUrl: config?.webhook?.publicUrl || "",
|
|
11632
11622
|
path: clickUpWebhookExpectedPath(config),
|
|
11633
|
-
|
|
11623
|
+
location: config?.webhook?.location || {},
|
|
11634
11624
|
webhookId: state?.webhookId || "",
|
|
11635
11625
|
secret: state?.secret || "",
|
|
11636
|
-
events: config?.webhook?.events || []
|
|
11637
|
-
clickupClient: objectIdentity(clickupClient),
|
|
11638
|
-
openCodeClient: objectIdentity(openCodeClient)
|
|
11626
|
+
events: config?.webhook?.events || []
|
|
11639
11627
|
});
|
|
11640
11628
|
}
|
|
11641
11629
|
function startClickUpWebhookListener({ config, state, worktree, clickupClient, openCodeClient, listenerRegistry = activeClickUpWebhookListeners } = {}) {
|