@defend-tech/opencode-optima 0.1.62 → 0.1.63

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.
@@ -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
- - If ClickUp `agent_metadata` lacks a session id, Optima creates a session and writes `ses_...`; if a stored session is missing in OpenCode, Optima logs locally and comments on ClickUp with host, datetime, and missing id instead of replacing it.
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 } = {}) {
@@ -10562,12 +10554,16 @@ function clearClickUpPendingSessionMetadata(metadata, metadataKey) {
10562
10554
  delete cursor[parts[parts.length - 1]];
10563
10555
  return JSON.stringify(sortJsonValue(root), null, 2);
10564
10556
  }
10565
- async function openCodeSessionExists(client, sessionId) {
10557
+ function withOptionalDirectoryQuery(payload, directory) {
10558
+ if (!directory) return payload;
10559
+ return { ...payload, query: { ...payload.query || {}, directory } };
10560
+ }
10561
+ async function openCodeSessionExists(client, sessionId, { directory = "" } = {}) {
10566
10562
  const getAttempts = [
10567
- { path: { id: sessionId } },
10568
- { path: { sessionID: sessionId } },
10569
- { sessionID: sessionId },
10570
- { id: sessionId }
10563
+ withOptionalDirectoryQuery({ path: { id: sessionId } }, directory),
10564
+ withOptionalDirectoryQuery({ path: { sessionID: sessionId } }, directory),
10565
+ directory ? { sessionID: sessionId, directory } : { sessionID: sessionId },
10566
+ directory ? { id: sessionId, directory } : { id: sessionId }
10571
10567
  ];
10572
10568
  if (typeof client?.session?.get === "function") {
10573
10569
  for (const attempt of getAttempts) {
@@ -10579,10 +10575,10 @@ async function openCodeSessionExists(client, sessionId) {
10579
10575
  }
10580
10576
  }
10581
10577
  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 }
10578
+ { path: { id: sessionId }, query: { limit: 1, ...directory ? { directory } : {} } },
10579
+ { path: { sessionID: sessionId }, query: { limit: 1, ...directory ? { directory } : {} } },
10580
+ directory ? { sessionID: sessionId, directory, limit: 1 } : { sessionID: sessionId, limit: 1 },
10581
+ directory ? { id: sessionId, directory, limit: 1 } : { id: sessionId, limit: 1 }
10586
10582
  ];
10587
10583
  if (typeof client?.session?.messages === "function") {
10588
10584
  for (const attempt of messageAttempts) {
@@ -10986,6 +10982,17 @@ async function verifyOpenCodeSessionEventDelivery(client, { sessionId, directory
10986
10982
  }
10987
10983
  return { ok: false, reason: lastError };
10988
10984
  }
10985
+ async function postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason, source } = {}) {
10986
+ if (typeof clickupClient?.postTaskComment !== "function") return { ok: false, skipped: true, reason: "post_comment_unavailable" };
10987
+ try {
10988
+ await clickupClient.postTaskComment({ taskId, comment: `Optima launch failure: ${reason || "launch_failed"}. Worktree visibility alone is not successful routing; Optima requires an OpenCode session plus verified prompt admission/delivery.` });
10989
+ appendClickUpWebhookLocalLog(worktree, { type: "launch_failure_comment_posted", taskId, reason, source });
10990
+ return { ok: true };
10991
+ } catch (error) {
10992
+ appendClickUpWebhookLocalLog(worktree, { type: "launch_failure_comment_failed", taskId, reason, source, message: error.message });
10993
+ return { ok: false, error: error.message };
10994
+ }
10995
+ }
10989
10996
  async function applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
10990
10997
  if (typeof clickupClient?.addTaskTag !== "function") {
10991
10998
  appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_unavailable", taskId, reason, source, tagName });
@@ -11015,7 +11022,17 @@ function openCodeBlockingPromptVerification(result, sessionId) {
11015
11022
  }
11016
11023
  async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, directPrompt = false, acceptPromptAdmission = false, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, applyBlockerOnFailure = true } = {}) {
11017
11024
  const beforeMessages = await readOpenCodeSessionMessages(openCodeClient, { sessionId, directory, limit: 50 }).catch(() => null);
11018
- const sendResult = await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, direct: directPrompt, allowDirectFallback: directPrompt });
11025
+ let sendResult;
11026
+ try {
11027
+ sendResult = await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, direct: directPrompt, allowDirectFallback: directPrompt });
11028
+ } catch (error) {
11029
+ const reason2 = error.message || "message_delivery_failed";
11030
+ appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason: reason2, fallbackAttempted: false });
11031
+ if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason: reason2, taskId, sessionId, fallbackAttempted: false };
11032
+ const blocker2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: reason2, source: "delivery_send_failed" });
11033
+ const launchFailureComment2 = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: reason2, source: "delivery_send_failed" });
11034
+ return { ok: false, action: "message_delivery_failed", reason: reason2, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2, launchFailureComment: launchFailureComment2 };
11035
+ }
11019
11036
  let blockingPromptVerification = null;
11020
11037
  let admissionVerification = null;
11021
11038
  try {
@@ -11025,7 +11042,8 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
11025
11042
  appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason: error.message, fallbackAttempted: false });
11026
11043
  if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false };
11027
11044
  const blocker2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: error.message, source: "delivery_admission_failed" });
11028
- return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2 };
11045
+ const launchFailureComment2 = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: error.message, source: "delivery_admission_failed" });
11046
+ return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2, launchFailureComment: launchFailureComment2 };
11029
11047
  }
11030
11048
  if (blockingPromptVerification) return { ok: true, verification: blockingPromptVerification, admissionVerification: null, fallback: false };
11031
11049
  if (admissionVerification && acceptPromptAdmission) {
@@ -11040,7 +11058,8 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
11040
11058
  appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason, fallbackAttempted: false, httpFallbackDisabled: Boolean(opencodeBaseUrl) });
11041
11059
  if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: false };
11042
11060
  const blocker = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source: "delivery_verification_failed" });
11043
- return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker };
11061
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason, source: "delivery_verification_failed" });
11062
+ return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker, launchFailureComment };
11044
11063
  }
11045
11064
  async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, staleSessionId, sessionTitle, taskRoute, metadataWithRouting, config, prompt, eventMarkers = [], deliveryEvidencePath, evidencePath, eventKey, createSession, verifySessionEventDelivery } = {}) {
11046
11065
  appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_started", taskId, staleSessionId, worktree: taskRoute?.worktree });
@@ -11050,12 +11069,14 @@ async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, click
11050
11069
  } catch (error) {
11051
11070
  appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_create_failed", taskId, staleSessionId, message: error.message });
11052
11071
  const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
11053
- return { ok: false, action: "message_delivery_failed", reason: "replacement_session_create_failed", taskId, sessionId: staleSessionId, replacementAttempted: true, blockerTag, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
11072
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
11073
+ 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
11074
  }
11055
11075
  if (!String(replacementSessionId || "").startsWith("ses_")) {
11056
11076
  appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_create_invalid", taskId, staleSessionId, replacementSessionId });
11057
11077
  const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
11058
- return { ok: false, action: "message_delivery_failed", reason: "replacement_session_create_failed", taskId, sessionId: staleSessionId, replacementAttempted: true, blockerTag, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
11078
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
11079
+ 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
11080
  }
11060
11081
  const replacementDelivery = await deliverClickUpSessionEventWithVerification({
11061
11082
  openCodeClient,
@@ -11077,7 +11098,8 @@ async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, click
11077
11098
  if (!replacementDelivery.ok) {
11078
11099
  appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_delivery_failed", taskId, staleSessionId, replacementSessionId, reason: replacementDelivery.reason });
11079
11100
  const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: replacementDelivery.reason || "replacement_delivery_failed", source: "pm_session_recovery" });
11080
- return { ...replacementDelivery, sessionId: staleSessionId, replacementSessionId, replacementAttempted: true, blockerTag, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
11101
+ const launchFailureComment = replacementDelivery.launchFailureComment || await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: replacementDelivery.reason || "replacement_delivery_failed", source: "pm_session_recovery" });
11102
+ return { ...replacementDelivery, sessionId: staleSessionId, replacementSessionId, replacementAttempted: true, blockerTag, launchFailureComment, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
11081
11103
  }
11082
11104
  const replacementMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(metadataWithRouting, config.routing.metadataKey, replacementSessionId), config.routing.metadataKey);
11083
11105
  await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: replacementMetadata });
@@ -11361,8 +11383,26 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
11361
11383
  if (!existingSessionId) {
11362
11384
  let pendingSessionId = getNestedMetadataValue(metadata, clickUpPendingSessionKey(config.routing.metadataKey)) || state.pendingSessions?.[taskId];
11363
11385
  if (!pendingSessionId) {
11364
- pendingSessionId = await createSession(openCodeClient, { title: sessionTitle, directory: taskRoute.worktree, agent: config.routing.targetAgent });
11365
- if (!String(pendingSessionId || "").startsWith("ses_")) return { ok: false, action: "error", reason: "session_create_failed", taskId };
11386
+ try {
11387
+ pendingSessionId = await createSession(openCodeClient, { title: sessionTitle, directory: taskRoute.worktree, agent: config.routing.targetAgent });
11388
+ } catch (error) {
11389
+ appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_failed", taskId, worktree: taskRoute.worktree, message: error.message });
11390
+ const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
11391
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
11392
+ return finish({ ok: false, action: "error", reason: "session_create_failed", taskId, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag, launchFailureComment });
11393
+ }
11394
+ if (!String(pendingSessionId || "").startsWith("ses_")) {
11395
+ appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_invalid", taskId, worktree: taskRoute.worktree, sessionId: pendingSessionId || null });
11396
+ const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
11397
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
11398
+ return finish({ ok: false, action: "error", reason: "session_create_failed", taskId, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag, launchFailureComment });
11399
+ }
11400
+ if (!await sessionExists(openCodeClient, pendingSessionId, { directory: taskRoute.worktree })) {
11401
+ appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_directory_unverified", taskId, worktree: taskRoute.worktree, sessionId: pendingSessionId });
11402
+ const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_directory_unverified", source: "route_create_session" });
11403
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_directory_unverified", source: "route_create_session" });
11404
+ 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 });
11405
+ }
11366
11406
  if (saveState) {
11367
11407
  saveState({
11368
11408
  ...state,
@@ -11378,7 +11418,20 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
11378
11418
  throw error;
11379
11419
  }
11380
11420
  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) return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
11421
+ if (!delivery.ok) {
11422
+ const failedMetadata = clearClickUpPendingSessionMetadata(metadataWithRouting, config.routing.metadataKey);
11423
+ let pendingCleared = false;
11424
+ try {
11425
+ await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: failedMetadata });
11426
+ pendingCleared = true;
11427
+ } catch (error) {
11428
+ appendClickUpWebhookLocalLog(worktree, { type: "pending_session_clear_failed", taskId, sessionId: pendingSessionId, message: error.message });
11429
+ }
11430
+ const { [taskId]: _failedPending, ...remainingPending2 } = stateToPersist.pendingSessions || {};
11431
+ stateToPersist = { ...stateToPersist, pendingSessions: remainingPending2 };
11432
+ appendClickUpWebhookLocalLog(worktree, { type: "pending_session_delivery_failed", taskId, sessionId: pendingSessionId, reason: delivery.reason || "message_delivery_failed", pendingCleared });
11433
+ return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, pendingCleared });
11434
+ }
11382
11435
  const nextMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(pendingMetadata, config.routing.metadataKey, pendingSessionId), config.routing.metadataKey);
11383
11436
  await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: nextMetadata });
11384
11437
  const { [taskId]: _completedPending, ...remainingPending } = stateToPersist.pendingSessions || {};
@@ -11386,7 +11439,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
11386
11439
  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
11440
  }
11388
11441
  const sessionId = String(existingSessionId);
11389
- if (await sessionExists(openCodeClient, sessionId)) {
11442
+ if (await sessionExists(openCodeClient, sessionId, { directory: taskRoute.worktree })) {
11390
11443
  if (typeof clickupClient?.updateTaskMetadata === "function") await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: metadataWithRouting });
11391
11444
  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
11445
  if (!delivery.ok) {
@@ -11514,6 +11567,7 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
11514
11567
  routed.undelivered += 1;
11515
11568
  appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_undelivered", taskId, action: result?.action || "error", sessionId: routeSummary.sessionId, reason: result.reason || "startup_reconciliation_route_failed" });
11516
11569
  if (!result.blockerTag) await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
11570
+ if (!result.launchFailureComment) await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
11517
11571
  } else {
11518
11572
  routed.undelivered += 1;
11519
11573
  appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_undelivered", taskId, action: routeSummary.action, sessionId: routeSummary.sessionId, reason: "route_not_actionable" });
@@ -11621,14 +11675,13 @@ function clickUpListenerKey(config) {
11621
11675
  }
11622
11676
  function clickUpListenerFingerprint({ config, state, worktree, clickupClient, openCodeClient } = {}) {
11623
11677
  return JSON.stringify({
11678
+ teamId: config?.teamId || "",
11624
11679
  publicUrl: config?.webhook?.publicUrl || "",
11625
11680
  path: clickUpWebhookExpectedPath(config),
11626
- worktree: path5.resolve(worktree || process.cwd()),
11681
+ location: config?.webhook?.location || {},
11627
11682
  webhookId: state?.webhookId || "",
11628
11683
  secret: state?.secret || "",
11629
- events: config?.webhook?.events || [],
11630
- clickupClient: objectIdentity(clickupClient),
11631
- openCodeClient: objectIdentity(openCodeClient)
11684
+ events: config?.webhook?.events || []
11632
11685
  });
11633
11686
  }
11634
11687
  function startClickUpWebhookListener({ config, state, worktree, clickupClient, openCodeClient, listenerRegistry = activeClickUpWebhookListeners } = {}) {
@@ -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 } = {}) {
@@ -10569,12 +10561,16 @@ function clearClickUpPendingSessionMetadata(metadata, metadataKey) {
10569
10561
  delete cursor[parts[parts.length - 1]];
10570
10562
  return JSON.stringify(sortJsonValue(root), null, 2);
10571
10563
  }
10572
- async function openCodeSessionExists(client, sessionId) {
10564
+ function withOptionalDirectoryQuery(payload, directory) {
10565
+ if (!directory) return payload;
10566
+ return { ...payload, query: { ...payload.query || {}, directory } };
10567
+ }
10568
+ async function openCodeSessionExists(client, sessionId, { directory = "" } = {}) {
10573
10569
  const getAttempts = [
10574
- { path: { id: sessionId } },
10575
- { path: { sessionID: sessionId } },
10576
- { sessionID: sessionId },
10577
- { id: sessionId }
10570
+ withOptionalDirectoryQuery({ path: { id: sessionId } }, directory),
10571
+ withOptionalDirectoryQuery({ path: { sessionID: sessionId } }, directory),
10572
+ directory ? { sessionID: sessionId, directory } : { sessionID: sessionId },
10573
+ directory ? { id: sessionId, directory } : { id: sessionId }
10578
10574
  ];
10579
10575
  if (typeof client?.session?.get === "function") {
10580
10576
  for (const attempt of getAttempts) {
@@ -10586,10 +10582,10 @@ async function openCodeSessionExists(client, sessionId) {
10586
10582
  }
10587
10583
  }
10588
10584
  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 }
10585
+ { path: { id: sessionId }, query: { limit: 1, ...directory ? { directory } : {} } },
10586
+ { path: { sessionID: sessionId }, query: { limit: 1, ...directory ? { directory } : {} } },
10587
+ directory ? { sessionID: sessionId, directory, limit: 1 } : { sessionID: sessionId, limit: 1 },
10588
+ directory ? { id: sessionId, directory, limit: 1 } : { id: sessionId, limit: 1 }
10593
10589
  ];
10594
10590
  if (typeof client?.session?.messages === "function") {
10595
10591
  for (const attempt of messageAttempts) {
@@ -10993,6 +10989,17 @@ async function verifyOpenCodeSessionEventDelivery(client, { sessionId, directory
10993
10989
  }
10994
10990
  return { ok: false, reason: lastError };
10995
10991
  }
10992
+ async function postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason, source } = {}) {
10993
+ if (typeof clickupClient?.postTaskComment !== "function") return { ok: false, skipped: true, reason: "post_comment_unavailable" };
10994
+ try {
10995
+ await clickupClient.postTaskComment({ taskId, comment: `Optima launch failure: ${reason || "launch_failed"}. Worktree visibility alone is not successful routing; Optima requires an OpenCode session plus verified prompt admission/delivery.` });
10996
+ appendClickUpWebhookLocalLog(worktree, { type: "launch_failure_comment_posted", taskId, reason, source });
10997
+ return { ok: true };
10998
+ } catch (error) {
10999
+ appendClickUpWebhookLocalLog(worktree, { type: "launch_failure_comment_failed", taskId, reason, source, message: error.message });
11000
+ return { ok: false, error: error.message };
11001
+ }
11002
+ }
10996
11003
  async function applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
10997
11004
  if (typeof clickupClient?.addTaskTag !== "function") {
10998
11005
  appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_unavailable", taskId, reason, source, tagName });
@@ -11022,7 +11029,17 @@ function openCodeBlockingPromptVerification(result, sessionId) {
11022
11029
  }
11023
11030
  async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, directPrompt = false, acceptPromptAdmission = false, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, applyBlockerOnFailure = true } = {}) {
11024
11031
  const beforeMessages = await readOpenCodeSessionMessages(openCodeClient, { sessionId, directory, limit: 50 }).catch(() => null);
11025
- const sendResult = await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, direct: directPrompt, allowDirectFallback: directPrompt });
11032
+ let sendResult;
11033
+ try {
11034
+ sendResult = await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, direct: directPrompt, allowDirectFallback: directPrompt });
11035
+ } catch (error) {
11036
+ const reason2 = error.message || "message_delivery_failed";
11037
+ appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason: reason2, fallbackAttempted: false });
11038
+ if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason: reason2, taskId, sessionId, fallbackAttempted: false };
11039
+ const blocker2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: reason2, source: "delivery_send_failed" });
11040
+ const launchFailureComment2 = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: reason2, source: "delivery_send_failed" });
11041
+ return { ok: false, action: "message_delivery_failed", reason: reason2, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2, launchFailureComment: launchFailureComment2 };
11042
+ }
11026
11043
  let blockingPromptVerification = null;
11027
11044
  let admissionVerification = null;
11028
11045
  try {
@@ -11032,7 +11049,8 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
11032
11049
  appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason: error.message, fallbackAttempted: false });
11033
11050
  if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false };
11034
11051
  const blocker2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: error.message, source: "delivery_admission_failed" });
11035
- return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2 };
11052
+ const launchFailureComment2 = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: error.message, source: "delivery_admission_failed" });
11053
+ return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2, launchFailureComment: launchFailureComment2 };
11036
11054
  }
11037
11055
  if (blockingPromptVerification) return { ok: true, verification: blockingPromptVerification, admissionVerification: null, fallback: false };
11038
11056
  if (admissionVerification && acceptPromptAdmission) {
@@ -11047,7 +11065,8 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
11047
11065
  appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason, fallbackAttempted: false, httpFallbackDisabled: Boolean(opencodeBaseUrl) });
11048
11066
  if (!applyBlockerOnFailure) return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: false };
11049
11067
  const blocker = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source: "delivery_verification_failed" });
11050
- return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker };
11068
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason, source: "delivery_verification_failed" });
11069
+ return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker, launchFailureComment };
11051
11070
  }
11052
11071
  async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, staleSessionId, sessionTitle, taskRoute, metadataWithRouting, config, prompt, eventMarkers = [], deliveryEvidencePath, evidencePath, eventKey, createSession, verifySessionEventDelivery } = {}) {
11053
11072
  appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_started", taskId, staleSessionId, worktree: taskRoute?.worktree });
@@ -11057,12 +11076,14 @@ async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, click
11057
11076
  } catch (error) {
11058
11077
  appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_create_failed", taskId, staleSessionId, message: error.message });
11059
11078
  const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
11060
- return { ok: false, action: "message_delivery_failed", reason: "replacement_session_create_failed", taskId, sessionId: staleSessionId, replacementAttempted: true, blockerTag, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
11079
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
11080
+ 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
11081
  }
11062
11082
  if (!String(replacementSessionId || "").startsWith("ses_")) {
11063
11083
  appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_create_invalid", taskId, staleSessionId, replacementSessionId });
11064
11084
  const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
11065
- return { ok: false, action: "message_delivery_failed", reason: "replacement_session_create_failed", taskId, sessionId: staleSessionId, replacementAttempted: true, blockerTag, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
11085
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "replacement_session_create_failed", source: "pm_session_recovery" });
11086
+ 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
11087
  }
11067
11088
  const replacementDelivery = await deliverClickUpSessionEventWithVerification({
11068
11089
  openCodeClient,
@@ -11084,7 +11105,8 @@ async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, click
11084
11105
  if (!replacementDelivery.ok) {
11085
11106
  appendClickUpWebhookLocalLog(worktree, { type: "pm_session_recovery_delivery_failed", taskId, staleSessionId, replacementSessionId, reason: replacementDelivery.reason });
11086
11107
  const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: replacementDelivery.reason || "replacement_delivery_failed", source: "pm_session_recovery" });
11087
- return { ...replacementDelivery, sessionId: staleSessionId, replacementSessionId, replacementAttempted: true, blockerTag, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
11108
+ const launchFailureComment = replacementDelivery.launchFailureComment || await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: replacementDelivery.reason || "replacement_delivery_failed", source: "pm_session_recovery" });
11109
+ return { ...replacementDelivery, sessionId: staleSessionId, replacementSessionId, replacementAttempted: true, blockerTag, launchFailureComment, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath };
11088
11110
  }
11089
11111
  const replacementMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(metadataWithRouting, config.routing.metadataKey, replacementSessionId), config.routing.metadataKey);
11090
11112
  await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: replacementMetadata });
@@ -11368,8 +11390,26 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
11368
11390
  if (!existingSessionId) {
11369
11391
  let pendingSessionId = getNestedMetadataValue(metadata, clickUpPendingSessionKey(config.routing.metadataKey)) || state.pendingSessions?.[taskId];
11370
11392
  if (!pendingSessionId) {
11371
- pendingSessionId = await createSession(openCodeClient, { title: sessionTitle, directory: taskRoute.worktree, agent: config.routing.targetAgent });
11372
- if (!String(pendingSessionId || "").startsWith("ses_")) return { ok: false, action: "error", reason: "session_create_failed", taskId };
11393
+ try {
11394
+ pendingSessionId = await createSession(openCodeClient, { title: sessionTitle, directory: taskRoute.worktree, agent: config.routing.targetAgent });
11395
+ } catch (error) {
11396
+ appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_failed", taskId, worktree: taskRoute.worktree, message: error.message });
11397
+ const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
11398
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
11399
+ return finish({ ok: false, action: "error", reason: "session_create_failed", taskId, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag, launchFailureComment });
11400
+ }
11401
+ if (!String(pendingSessionId || "").startsWith("ses_")) {
11402
+ appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_invalid", taskId, worktree: taskRoute.worktree, sessionId: pendingSessionId || null });
11403
+ const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
11404
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_create_failed", source: "route_create_session" });
11405
+ return finish({ ok: false, action: "error", reason: "session_create_failed", taskId, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag, launchFailureComment });
11406
+ }
11407
+ if (!await sessionExists(openCodeClient, pendingSessionId, { directory: taskRoute.worktree })) {
11408
+ appendClickUpWebhookLocalLog(worktree, { type: "pm_session_create_directory_unverified", taskId, worktree: taskRoute.worktree, sessionId: pendingSessionId });
11409
+ const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "session_directory_unverified", source: "route_create_session" });
11410
+ const launchFailureComment = await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: "session_directory_unverified", source: "route_create_session" });
11411
+ 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 });
11412
+ }
11373
11413
  if (saveState) {
11374
11414
  saveState({
11375
11415
  ...state,
@@ -11385,7 +11425,20 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
11385
11425
  throw error;
11386
11426
  }
11387
11427
  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) return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
11428
+ if (!delivery.ok) {
11429
+ const failedMetadata = clearClickUpPendingSessionMetadata(metadataWithRouting, config.routing.metadataKey);
11430
+ let pendingCleared = false;
11431
+ try {
11432
+ await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: failedMetadata });
11433
+ pendingCleared = true;
11434
+ } catch (error) {
11435
+ appendClickUpWebhookLocalLog(worktree, { type: "pending_session_clear_failed", taskId, sessionId: pendingSessionId, message: error.message });
11436
+ }
11437
+ const { [taskId]: _failedPending, ...remainingPending2 } = stateToPersist.pendingSessions || {};
11438
+ stateToPersist = { ...stateToPersist, pendingSessions: remainingPending2 };
11439
+ appendClickUpWebhookLocalLog(worktree, { type: "pending_session_delivery_failed", taskId, sessionId: pendingSessionId, reason: delivery.reason || "message_delivery_failed", pendingCleared });
11440
+ return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, pendingCleared });
11441
+ }
11389
11442
  const nextMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(pendingMetadata, config.routing.metadataKey, pendingSessionId), config.routing.metadataKey);
11390
11443
  await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: nextMetadata });
11391
11444
  const { [taskId]: _completedPending, ...remainingPending } = stateToPersist.pendingSessions || {};
@@ -11393,7 +11446,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
11393
11446
  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
11447
  }
11395
11448
  const sessionId = String(existingSessionId);
11396
- if (await sessionExists(openCodeClient, sessionId)) {
11449
+ if (await sessionExists(openCodeClient, sessionId, { directory: taskRoute.worktree })) {
11397
11450
  if (typeof clickupClient?.updateTaskMetadata === "function") await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: metadataWithRouting });
11398
11451
  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
11452
  if (!delivery.ok) {
@@ -11521,6 +11574,7 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
11521
11574
  routed.undelivered += 1;
11522
11575
  appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_undelivered", taskId, action: result?.action || "error", sessionId: routeSummary.sessionId, reason: result.reason || "startup_reconciliation_route_failed" });
11523
11576
  if (!result.blockerTag) await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
11577
+ if (!result.launchFailureComment) await postClickUpLaunchFailureComment({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
11524
11578
  } else {
11525
11579
  routed.undelivered += 1;
11526
11580
  appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_undelivered", taskId, action: routeSummary.action, sessionId: routeSummary.sessionId, reason: "route_not_actionable" });
@@ -11628,14 +11682,13 @@ function clickUpListenerKey(config) {
11628
11682
  }
11629
11683
  function clickUpListenerFingerprint({ config, state, worktree, clickupClient, openCodeClient } = {}) {
11630
11684
  return JSON.stringify({
11685
+ teamId: config?.teamId || "",
11631
11686
  publicUrl: config?.webhook?.publicUrl || "",
11632
11687
  path: clickUpWebhookExpectedPath(config),
11633
- worktree: path5.resolve(worktree || process.cwd()),
11688
+ location: config?.webhook?.location || {},
11634
11689
  webhookId: state?.webhookId || "",
11635
11690
  secret: state?.secret || "",
11636
- events: config?.webhook?.events || [],
11637
- clickupClient: objectIdentity(clickupClient),
11638
- openCodeClient: objectIdentity(openCodeClient)
11691
+ events: config?.webhook?.events || []
11639
11692
  });
11640
11693
  }
11641
11694
  function startClickUpWebhookListener({ config, state, worktree, clickupClient, openCodeClient, listenerRegistry = activeClickUpWebhookListeners } = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defend-tech/opencode-optima",
3
- "version": "0.1.62",
3
+ "version": "0.1.63",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+ssh://git@github.com/defend-tech/opencode-optima.git"