@defend-tech/opencode-optima 0.1.37 → 0.1.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7932,6 +7932,7 @@ var CLICKUP_WEBHOOK_EVENTS = ["taskStatusUpdated", "taskAssigneeUpdated", "taskC
7932
7932
  var CLICKUP_WEBHOOK_TERMINAL_STATUSES = ["backlog", "done", "completed", "closed"];
7933
7933
  var CLICKUP_PM_METADATA_KEY = "optima.sessions.product_manager";
7934
7934
  var CLICKUP_PM_MENTION_NAME = "Defend Tech Product Manager";
7935
+ var CLICKUP_BLOCKER_TAG_NAME = "BLOCKER";
7935
7936
  var CLICKUP_WEBHOOK_RUNTIME_VERSION = 1;
7936
7937
  var CLICKUP_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
7937
7938
  var CLICKUP_WEBHOOK_REQUEST_TIMEOUT_MS = 1e4;
@@ -9156,6 +9157,12 @@ function createClickUpApiClient(config, fetchImpl = globalThis.fetch) {
9156
9157
  body: JSON.stringify({ comment_text: comment })
9157
9158
  });
9158
9159
  },
9160
+ async addTaskTag({ taskId, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
9161
+ return request(`https://api.clickup.com/api/v2/task/${encodeURIComponent(taskId)}/tag/${encodeURIComponent(tagName)}`, {
9162
+ method: "POST",
9163
+ body: JSON.stringify({})
9164
+ });
9165
+ },
9159
9166
  async listAssignedTasks({ assigneeId, statuses = [], limit = CLICKUP_WEBHOOK_STARTUP_TASK_LIMIT } = {}) {
9160
9167
  const params = new URLSearchParams();
9161
9168
  if (assigneeId) params.append("assignees[]", assigneeId);
@@ -9600,6 +9607,88 @@ async function sendOpenCodeSessionEvent(client, { sessionId, agent, text, direct
9600
9607
  if (directBaseUrl) return sendOpenCodeSessionEventDirect({ baseUrl: directBaseUrl, sessionId, text, fetchImpl });
9601
9608
  throw new Error("OpenCode client does not expose session.prompt or session.promptAsync.");
9602
9609
  }
9610
+ function normalizeOpenCodeSessionMessages(result) {
9611
+ const data = result?.data ?? result;
9612
+ if (Array.isArray(data)) return [...data];
9613
+ if (Array.isArray(data?.messages)) return [...data.messages];
9614
+ if (Array.isArray(data?.items)) return [...data.items];
9615
+ return [];
9616
+ }
9617
+ async function readOpenCodeSessionMessages(client, { sessionId, limit = 20 } = {}) {
9618
+ if (typeof client?.session?.messages !== "function") return null;
9619
+ const attempts = [
9620
+ { path: { id: sessionId }, query: { limit } },
9621
+ { path: { sessionID: sessionId }, query: { limit } },
9622
+ { id: sessionId, limit },
9623
+ { sessionID: sessionId, limit }
9624
+ ];
9625
+ let firstError = null;
9626
+ for (const attempt of attempts) {
9627
+ try {
9628
+ return normalizeOpenCodeSessionMessages(await client.session.messages(attempt));
9629
+ } catch (error) {
9630
+ firstError ??= error;
9631
+ }
9632
+ }
9633
+ throw firstError;
9634
+ }
9635
+ function openCodeMessageText(message) {
9636
+ const parts = [message?.text, message?.content, message?.message, message?.body?.text, message?.data?.text];
9637
+ const partList = Array.isArray(message?.parts) ? message.parts : Array.isArray(message?.body?.parts) ? message.body.parts : [];
9638
+ for (const part of partList) parts.push(part?.text, part?.content);
9639
+ return parts.filter((value) => typeof value === "string").join("\n");
9640
+ }
9641
+ async function verifyOpenCodeSessionEventDelivery(client, { sessionId, beforeMessages = null, expectedText = "", markers = [], attempts = 3, delayMs = 25 } = {}) {
9642
+ let lastError = "message_verification_unavailable";
9643
+ for (let attempt = 0; attempt < Math.max(1, attempts); attempt += 1) {
9644
+ try {
9645
+ const afterMessages = await readOpenCodeSessionMessages(client, { sessionId, limit: 50 });
9646
+ if (!afterMessages) return { ok: true, method: "verification_unavailable", skipped: true };
9647
+ const beforeCount = Array.isArray(beforeMessages) ? beforeMessages.length : null;
9648
+ if (beforeCount !== null && afterMessages.length > beforeCount) return { ok: true, method: "message_count", beforeCount, afterCount: afterMessages.length };
9649
+ const textNeedles = [expectedText, ...markers].map((value) => String(value || "").trim()).filter(Boolean);
9650
+ const haystack = afterMessages.slice(-20).map(openCodeMessageText).join("\n");
9651
+ const matched = textNeedles.find((needle) => haystack.includes(needle));
9652
+ if (matched) return { ok: true, method: "message_text", marker: matched, beforeCount, afterCount: afterMessages.length };
9653
+ lastError = "message_not_visible";
9654
+ } catch (error) {
9655
+ lastError = error.message || "message_verification_failed";
9656
+ }
9657
+ if (attempt < attempts - 1 && delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
9658
+ }
9659
+ return { ok: false, reason: lastError };
9660
+ }
9661
+ async function applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
9662
+ if (typeof clickupClient?.addTaskTag !== "function") {
9663
+ appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_unavailable", taskId, reason, source, tagName });
9664
+ return { ok: false, skipped: true, reason: "add_task_tag_unavailable", tagName };
9665
+ }
9666
+ try {
9667
+ await clickupClient.addTaskTag({ taskId, tagName });
9668
+ appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_applied", taskId, reason, source, tagName });
9669
+ return { ok: true, tagName };
9670
+ } catch (error) {
9671
+ appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_failed", taskId, reason, source, tagName, message: error.message });
9672
+ return { ok: false, error: error.message, tagName };
9673
+ }
9674
+ }
9675
+ async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery } = {}) {
9676
+ const beforeMessages = await readOpenCodeSessionMessages(openCodeClient, { sessionId, limit: 50 }).catch(() => null);
9677
+ await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl });
9678
+ let verification = await verifySessionEventDelivery(openCodeClient, { sessionId, beforeMessages, expectedText: text, markers: eventMarkers });
9679
+ if (verification?.ok) return { ok: true, verification, fallback: false };
9680
+ const canFallbackDirect = Boolean(opencodeBaseUrl);
9681
+ if (canFallbackDirect) {
9682
+ const retryBeforeMessages = await readOpenCodeSessionMessages(openCodeClient, { sessionId, limit: 50 }).catch(() => beforeMessages);
9683
+ await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, direct: true });
9684
+ verification = await verifySessionEventDelivery(openCodeClient, { sessionId, beforeMessages: retryBeforeMessages, expectedText: text, markers: eventMarkers });
9685
+ if (verification?.ok) return { ok: true, verification, fallback: true };
9686
+ }
9687
+ const reason = verification?.reason || "message_delivery_failed";
9688
+ appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason, fallbackAttempted: canFallbackDirect });
9689
+ const blocker = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source: canFallbackDirect ? "delivery_fallback_failed" : "delivery_verification_failed" });
9690
+ return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: canFallbackDirect, blockerTag: blocker };
9691
+ }
9603
9692
  function formatClickUpWebhookPrompt({ eventType, taskId, payload, branch = "", worktree = "", deliveryEvidencePath = "" }) {
9604
9693
  const comment = clickUpCommentFromPayload(payload);
9605
9694
  const commentText = clickUpCommentText(comment).trim();
@@ -9616,45 +9705,6 @@ function formatClickUpWebhookPrompt({ eventType, taskId, payload, branch = "", w
9616
9705
  deliveryEvidencePath ? `Final merge-trackable evidence must be written under ${deliveryEvidencePath}; use .optima only as local mirror/staging.` : null
9617
9706
  ].filter((part) => part !== null).join("\n");
9618
9707
  }
9619
- function clickUpNoAbandonmentRuleText() {
9620
- return "No-abandonment rule: PM must keep working, or before stopping must post a ClickUp comment, hand off, remove PM as assignee, and assign the next owner.";
9621
- }
9622
- function buildClickUpStartupResumeComment({ taskId, result = {} } = {}) {
9623
- const contextParts = [
9624
- result.branch ? `- Branch: ${result.branch}` : null,
9625
- result.worktree ? `- Worktree: ${result.worktree}` : null,
9626
- result.deliveryEvidencePath ? `- Delivery evidence path: ${result.deliveryEvidencePath}` : null,
9627
- result.evidencePath ? `- Local evidence path: ${result.evidencePath}` : null
9628
- ].filter(Boolean);
9629
- return [
9630
- `Startup reconciliation resumed ClickUp task ${taskId}.`,
9631
- `Route result: ${result.action || "unknown"}${result.ok === false ? " (failed)" : ""}.`,
9632
- result.sessionId ? `Session id: ${result.sessionId}.` : "Session id: unavailable.",
9633
- contextParts.length ? contextParts.join("\n") : "Worktree/branch/delivery evidence path: unavailable.",
9634
- clickUpNoAbandonmentRuleText()
9635
- ].join("\n");
9636
- }
9637
- function buildClickUpStartupBlockerComment({ taskId, error } = {}) {
9638
- const summary = error?.message || String(error || "unknown error");
9639
- return [
9640
- `Startup reconciliation blocker for ClickUp task ${taskId}: ${summary}`,
9641
- "Optima skipped this task for this startup pass and continued with the next PM-assigned task.",
9642
- clickUpNoAbandonmentRuleText()
9643
- ].join("\n");
9644
- }
9645
- async function postClickUpStartupComment({ clickupClient, worktree, taskId, comment, type } = {}) {
9646
- if (typeof clickupClient?.postTaskComment !== "function") {
9647
- appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comment_unavailable", taskId, commentType: type });
9648
- return { ok: false, skipped: true, reason: "post_task_comment_unavailable" };
9649
- }
9650
- try {
9651
- await clickupClient.postTaskComment({ taskId, comment });
9652
- return { ok: true };
9653
- } catch (error) {
9654
- appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comment_failed", taskId, commentType: type, message: error.message });
9655
- return { ok: false, error: error.message };
9656
- }
9657
- }
9658
9708
  function appendClickUpWebhookLocalLog(worktree, entry) {
9659
9709
  const logPath = clickUpWebhookLogPath(worktree);
9660
9710
  fs2.mkdirSync(path2.dirname(logPath), { recursive: true });
@@ -9831,7 +9881,7 @@ async function withClickUpTaskRouteLock(taskId, operation) {
9831
9881
  if (activeClickUpTaskRoutes.get(key) === current) activeClickUpTaskRoutes.delete(key);
9832
9882
  }
9833
9883
  }
9834
- async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, worktree = process.cwd(), clickupClient, openCodeClient, sessionExists = openCodeSessionExists, createSession = createOpenCodeSession, sendSessionEvent = sendOpenCodeSessionEvent, ensureTaskWorktree = ensureClickUpTaskWorktree, saveState = null, now = () => /* @__PURE__ */ new Date(), host = os.hostname(), commentLedgerPath = clickUpCommentLedgerPath(worktree) } = {}) {
9884
+ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, worktree = process.cwd(), clickupClient, openCodeClient, sessionExists = openCodeSessionExists, createSession = createOpenCodeSession, sendSessionEvent = sendOpenCodeSessionEvent, ensureTaskWorktree = ensureClickUpTaskWorktree, verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, saveState = null, now = () => /* @__PURE__ */ new Date(), host = os.hostname(), commentLedgerPath = clickUpCommentLedgerPath(worktree) } = {}) {
9835
9885
  const eventType = clickUpEventType(payload);
9836
9886
  const eventKey = clickUpWebhookEventKey(payload);
9837
9887
  const remembered = rememberClickUpWebhookEvent(state, eventKey);
@@ -9890,8 +9940,8 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
9890
9940
  } catch (error) {
9891
9941
  const message = `Optima webhook could not create or reuse a task worktree for ${taskId}: ${error.message}`;
9892
9942
  appendClickUpWebhookLocalLog(worktree, { type: "task_worktree_failed", taskId, message });
9893
- if (typeof clickupClient?.postTaskComment === "function") await clickupClient.postTaskComment({ taskId, comment: message });
9894
- return { ok: false, action: "error", reason: "task_worktree_failed", taskId, message };
9943
+ const blockerTag2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "task_worktree_failed", source: "route_worktree" });
9944
+ return { ok: false, action: "error", reason: "task_worktree_failed", taskId, message, blockerTag: blockerTag2 };
9895
9945
  }
9896
9946
  const deliveryEvidencePath = deliveryEvidencePathForClickUpTask(taskId);
9897
9947
  const routingMetadata = {
@@ -9921,24 +9971,25 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
9921
9971
  appendClickUpWebhookLocalLog(worktree, { type: "pending_session_metadata_failed", taskId, sessionId: pendingSessionId, message: error.message });
9922
9972
  throw error;
9923
9973
  }
9924
- await sendSessionEvent(openCodeClient, { sessionId: pendingSessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl });
9974
+ const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId: pendingSessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, eventMarkers: [taskId, eventType], verifySessionEventDelivery });
9975
+ if (!delivery.ok) return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
9925
9976
  const nextMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(pendingMetadata, config.routing.metadataKey, pendingSessionId), config.routing.metadataKey);
9926
9977
  await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: nextMetadata });
9927
9978
  const { [taskId]: _completedPending, ...remainingPending } = stateToPersist.pendingSessions || {};
9928
9979
  stateToPersist = { ...stateToPersist, pendingSessions: remainingPending };
9929
- return finish({ ok: true, action: "created_session", taskId, sessionId: pendingSessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
9980
+ 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, deliveryFallback: delivery.fallback });
9930
9981
  }
9931
9982
  const sessionId = String(existingSessionId);
9932
9983
  if (await sessionExists(openCodeClient, sessionId)) {
9933
9984
  if (typeof clickupClient?.updateTaskMetadata === "function") await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: metadataWithRouting });
9934
- await sendSessionEvent(openCodeClient, { sessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl });
9935
- return finish({ ok: true, action: "sent_to_existing_session", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
9985
+ const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, eventMarkers: [taskId, eventType], verifySessionEventDelivery });
9986
+ if (!delivery.ok) return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
9987
+ return finish({ ok: true, action: "sent_to_existing_session", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, deliveryVerification: delivery.verification, deliveryFallback: delivery.fallback });
9936
9988
  }
9937
9989
  const at = now().toISOString();
9938
- const incidentComment = `Optima webhook could not route this ClickUp event because OpenCode session ${sessionId} is missing on host ${host} at ${at}. No replacement session was created automatically.`;
9939
9990
  appendClickUpWebhookLocalLog(worktree, { type: "missing_session", taskId, sessionId, host, at });
9940
- await clickupClient.postTaskComment({ taskId, comment: incidentComment });
9941
- return finish({ ok: true, action: "missing_session_reported", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
9991
+ const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "missing_session", source: "route_existing_session" });
9992
+ return finish({ ok: true, action: "missing_session_reported", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag });
9942
9993
  }
9943
9994
  async function routeClickUpWebhookEvent(options = {}) {
9944
9995
  const taskId = clickUpTaskIdFromPayload(options.payload || {});
@@ -9996,24 +10047,14 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
9996
10047
  });
9997
10048
  if (result?.ok && result.action !== "ignored") {
9998
10049
  routed.assigned += 1;
9999
- await postClickUpStartupComment({
10000
- clickupClient,
10001
- worktree,
10002
- taskId,
10003
- type: "resume",
10004
- comment: buildClickUpStartupResumeComment({ taskId, result })
10005
- });
10050
+ } else if (result?.ok === false) {
10051
+ routed.errors += 1;
10052
+ if (!result.blockerTag) await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
10006
10053
  }
10007
10054
  } catch (error) {
10008
10055
  routed.errors += 1;
10009
10056
  appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_failed", taskId, message: error.message });
10010
- await postClickUpStartupComment({
10011
- clickupClient,
10012
- worktree,
10013
- taskId,
10014
- type: "blocker",
10015
- comment: buildClickUpStartupBlockerComment({ taskId, error })
10016
- });
10057
+ await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "startup_reconciliation_task_failed", source: "startup_reconciliation_task" });
10017
10058
  }
10018
10059
  if (!lastWebhookMs || !clickupClient?.getTaskComments) continue;
10019
10060
  try {
@@ -10043,6 +10084,7 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
10043
10084
  } catch (error) {
10044
10085
  routed.errors += 1;
10045
10086
  appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comments_failed", taskId, message: error.message });
10087
+ await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "startup_reconciliation_comments_failed", source: "startup_reconciliation_comments" });
10046
10088
  }
10047
10089
  }
10048
10090
  clickUpWebhookLifecycleLog(worktree, { type: "startup_reconciliation_finished", ...routed });
@@ -11827,7 +11869,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
11827
11869
  }
11828
11870
  };
11829
11871
  }
11830
- OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, BUNDLE_ASSETS_DIR, CLICKUP_DEFINITION_DOC_PARENT, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentLedgerKey, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, readClickUpCommentLedger, readClickUpWebhookState, reconcileClickUpStartup, recordClickUpCommentVersionProcessed, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
11872
+ OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, BUNDLE_ASSETS_DIR, CLICKUP_DEFINITION_DOC_PARENT, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentLedgerKey, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, readClickUpCommentLedger, readClickUpWebhookState, reconcileClickUpStartup, recordClickUpCommentVersionProcessed, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
11831
11873
  export {
11832
11874
  OptimaPlugin as default
11833
11875
  };
@@ -7939,6 +7939,7 @@ var CLICKUP_WEBHOOK_EVENTS = ["taskStatusUpdated", "taskAssigneeUpdated", "taskC
7939
7939
  var CLICKUP_WEBHOOK_TERMINAL_STATUSES = ["backlog", "done", "completed", "closed"];
7940
7940
  var CLICKUP_PM_METADATA_KEY = "optima.sessions.product_manager";
7941
7941
  var CLICKUP_PM_MENTION_NAME = "Defend Tech Product Manager";
7942
+ var CLICKUP_BLOCKER_TAG_NAME = "BLOCKER";
7942
7943
  var CLICKUP_WEBHOOK_RUNTIME_VERSION = 1;
7943
7944
  var CLICKUP_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
7944
7945
  var CLICKUP_WEBHOOK_REQUEST_TIMEOUT_MS = 1e4;
@@ -9163,6 +9164,12 @@ function createClickUpApiClient(config, fetchImpl = globalThis.fetch) {
9163
9164
  body: JSON.stringify({ comment_text: comment })
9164
9165
  });
9165
9166
  },
9167
+ async addTaskTag({ taskId, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
9168
+ return request(`https://api.clickup.com/api/v2/task/${encodeURIComponent(taskId)}/tag/${encodeURIComponent(tagName)}`, {
9169
+ method: "POST",
9170
+ body: JSON.stringify({})
9171
+ });
9172
+ },
9166
9173
  async listAssignedTasks({ assigneeId, statuses = [], limit = CLICKUP_WEBHOOK_STARTUP_TASK_LIMIT } = {}) {
9167
9174
  const params = new URLSearchParams();
9168
9175
  if (assigneeId) params.append("assignees[]", assigneeId);
@@ -9607,6 +9614,88 @@ async function sendOpenCodeSessionEvent(client, { sessionId, agent, text, direct
9607
9614
  if (directBaseUrl) return sendOpenCodeSessionEventDirect({ baseUrl: directBaseUrl, sessionId, text, fetchImpl });
9608
9615
  throw new Error("OpenCode client does not expose session.prompt or session.promptAsync.");
9609
9616
  }
9617
+ function normalizeOpenCodeSessionMessages(result) {
9618
+ const data = result?.data ?? result;
9619
+ if (Array.isArray(data)) return [...data];
9620
+ if (Array.isArray(data?.messages)) return [...data.messages];
9621
+ if (Array.isArray(data?.items)) return [...data.items];
9622
+ return [];
9623
+ }
9624
+ async function readOpenCodeSessionMessages(client, { sessionId, limit = 20 } = {}) {
9625
+ if (typeof client?.session?.messages !== "function") return null;
9626
+ const attempts = [
9627
+ { path: { id: sessionId }, query: { limit } },
9628
+ { path: { sessionID: sessionId }, query: { limit } },
9629
+ { id: sessionId, limit },
9630
+ { sessionID: sessionId, limit }
9631
+ ];
9632
+ let firstError = null;
9633
+ for (const attempt of attempts) {
9634
+ try {
9635
+ return normalizeOpenCodeSessionMessages(await client.session.messages(attempt));
9636
+ } catch (error) {
9637
+ firstError ??= error;
9638
+ }
9639
+ }
9640
+ throw firstError;
9641
+ }
9642
+ function openCodeMessageText(message) {
9643
+ const parts = [message?.text, message?.content, message?.message, message?.body?.text, message?.data?.text];
9644
+ const partList = Array.isArray(message?.parts) ? message.parts : Array.isArray(message?.body?.parts) ? message.body.parts : [];
9645
+ for (const part of partList) parts.push(part?.text, part?.content);
9646
+ return parts.filter((value) => typeof value === "string").join("\n");
9647
+ }
9648
+ async function verifyOpenCodeSessionEventDelivery(client, { sessionId, beforeMessages = null, expectedText = "", markers = [], attempts = 3, delayMs = 25 } = {}) {
9649
+ let lastError = "message_verification_unavailable";
9650
+ for (let attempt = 0; attempt < Math.max(1, attempts); attempt += 1) {
9651
+ try {
9652
+ const afterMessages = await readOpenCodeSessionMessages(client, { sessionId, limit: 50 });
9653
+ if (!afterMessages) return { ok: true, method: "verification_unavailable", skipped: true };
9654
+ const beforeCount = Array.isArray(beforeMessages) ? beforeMessages.length : null;
9655
+ if (beforeCount !== null && afterMessages.length > beforeCount) return { ok: true, method: "message_count", beforeCount, afterCount: afterMessages.length };
9656
+ const textNeedles = [expectedText, ...markers].map((value) => String(value || "").trim()).filter(Boolean);
9657
+ const haystack = afterMessages.slice(-20).map(openCodeMessageText).join("\n");
9658
+ const matched = textNeedles.find((needle) => haystack.includes(needle));
9659
+ if (matched) return { ok: true, method: "message_text", marker: matched, beforeCount, afterCount: afterMessages.length };
9660
+ lastError = "message_not_visible";
9661
+ } catch (error) {
9662
+ lastError = error.message || "message_verification_failed";
9663
+ }
9664
+ if (attempt < attempts - 1 && delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
9665
+ }
9666
+ return { ok: false, reason: lastError };
9667
+ }
9668
+ async function applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source, tagName = CLICKUP_BLOCKER_TAG_NAME } = {}) {
9669
+ if (typeof clickupClient?.addTaskTag !== "function") {
9670
+ appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_unavailable", taskId, reason, source, tagName });
9671
+ return { ok: false, skipped: true, reason: "add_task_tag_unavailable", tagName };
9672
+ }
9673
+ try {
9674
+ await clickupClient.addTaskTag({ taskId, tagName });
9675
+ appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_applied", taskId, reason, source, tagName });
9676
+ return { ok: true, tagName };
9677
+ } catch (error) {
9678
+ appendClickUpWebhookLocalLog(worktree, { type: "blocker_tag_failed", taskId, reason, source, tagName, message: error.message });
9679
+ return { ok: false, error: error.message, tagName };
9680
+ }
9681
+ }
9682
+ async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery } = {}) {
9683
+ const beforeMessages = await readOpenCodeSessionMessages(openCodeClient, { sessionId, limit: 50 }).catch(() => null);
9684
+ await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl });
9685
+ let verification = await verifySessionEventDelivery(openCodeClient, { sessionId, beforeMessages, expectedText: text, markers: eventMarkers });
9686
+ if (verification?.ok) return { ok: true, verification, fallback: false };
9687
+ const canFallbackDirect = Boolean(opencodeBaseUrl);
9688
+ if (canFallbackDirect) {
9689
+ const retryBeforeMessages = await readOpenCodeSessionMessages(openCodeClient, { sessionId, limit: 50 }).catch(() => beforeMessages);
9690
+ await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, direct: true });
9691
+ verification = await verifySessionEventDelivery(openCodeClient, { sessionId, beforeMessages: retryBeforeMessages, expectedText: text, markers: eventMarkers });
9692
+ if (verification?.ok) return { ok: true, verification, fallback: true };
9693
+ }
9694
+ const reason = verification?.reason || "message_delivery_failed";
9695
+ appendClickUpWebhookLocalLog(worktree, { type: "message_delivery_failed", taskId, sessionId, reason, fallbackAttempted: canFallbackDirect });
9696
+ const blocker = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason, source: canFallbackDirect ? "delivery_fallback_failed" : "delivery_verification_failed" });
9697
+ return { ok: false, action: "message_delivery_failed", reason, taskId, sessionId, fallbackAttempted: canFallbackDirect, blockerTag: blocker };
9698
+ }
9610
9699
  function formatClickUpWebhookPrompt({ eventType, taskId, payload, branch = "", worktree = "", deliveryEvidencePath = "" }) {
9611
9700
  const comment = clickUpCommentFromPayload(payload);
9612
9701
  const commentText = clickUpCommentText(comment).trim();
@@ -9623,45 +9712,6 @@ function formatClickUpWebhookPrompt({ eventType, taskId, payload, branch = "", w
9623
9712
  deliveryEvidencePath ? `Final merge-trackable evidence must be written under ${deliveryEvidencePath}; use .optima only as local mirror/staging.` : null
9624
9713
  ].filter((part) => part !== null).join("\n");
9625
9714
  }
9626
- function clickUpNoAbandonmentRuleText() {
9627
- return "No-abandonment rule: PM must keep working, or before stopping must post a ClickUp comment, hand off, remove PM as assignee, and assign the next owner.";
9628
- }
9629
- function buildClickUpStartupResumeComment({ taskId, result = {} } = {}) {
9630
- const contextParts = [
9631
- result.branch ? `- Branch: ${result.branch}` : null,
9632
- result.worktree ? `- Worktree: ${result.worktree}` : null,
9633
- result.deliveryEvidencePath ? `- Delivery evidence path: ${result.deliveryEvidencePath}` : null,
9634
- result.evidencePath ? `- Local evidence path: ${result.evidencePath}` : null
9635
- ].filter(Boolean);
9636
- return [
9637
- `Startup reconciliation resumed ClickUp task ${taskId}.`,
9638
- `Route result: ${result.action || "unknown"}${result.ok === false ? " (failed)" : ""}.`,
9639
- result.sessionId ? `Session id: ${result.sessionId}.` : "Session id: unavailable.",
9640
- contextParts.length ? contextParts.join("\n") : "Worktree/branch/delivery evidence path: unavailable.",
9641
- clickUpNoAbandonmentRuleText()
9642
- ].join("\n");
9643
- }
9644
- function buildClickUpStartupBlockerComment({ taskId, error } = {}) {
9645
- const summary = error?.message || String(error || "unknown error");
9646
- return [
9647
- `Startup reconciliation blocker for ClickUp task ${taskId}: ${summary}`,
9648
- "Optima skipped this task for this startup pass and continued with the next PM-assigned task.",
9649
- clickUpNoAbandonmentRuleText()
9650
- ].join("\n");
9651
- }
9652
- async function postClickUpStartupComment({ clickupClient, worktree, taskId, comment, type } = {}) {
9653
- if (typeof clickupClient?.postTaskComment !== "function") {
9654
- appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comment_unavailable", taskId, commentType: type });
9655
- return { ok: false, skipped: true, reason: "post_task_comment_unavailable" };
9656
- }
9657
- try {
9658
- await clickupClient.postTaskComment({ taskId, comment });
9659
- return { ok: true };
9660
- } catch (error) {
9661
- appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comment_failed", taskId, commentType: type, message: error.message });
9662
- return { ok: false, error: error.message };
9663
- }
9664
- }
9665
9715
  function appendClickUpWebhookLocalLog(worktree, entry) {
9666
9716
  const logPath = clickUpWebhookLogPath(worktree);
9667
9717
  fs2.mkdirSync(path2.dirname(logPath), { recursive: true });
@@ -9838,7 +9888,7 @@ async function withClickUpTaskRouteLock(taskId, operation) {
9838
9888
  if (activeClickUpTaskRoutes.get(key) === current) activeClickUpTaskRoutes.delete(key);
9839
9889
  }
9840
9890
  }
9841
- async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, worktree = process.cwd(), clickupClient, openCodeClient, sessionExists = openCodeSessionExists, createSession = createOpenCodeSession, sendSessionEvent = sendOpenCodeSessionEvent, ensureTaskWorktree = ensureClickUpTaskWorktree, saveState = null, now = () => /* @__PURE__ */ new Date(), host = os.hostname(), commentLedgerPath = clickUpCommentLedgerPath(worktree) } = {}) {
9891
+ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, worktree = process.cwd(), clickupClient, openCodeClient, sessionExists = openCodeSessionExists, createSession = createOpenCodeSession, sendSessionEvent = sendOpenCodeSessionEvent, ensureTaskWorktree = ensureClickUpTaskWorktree, verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, saveState = null, now = () => /* @__PURE__ */ new Date(), host = os.hostname(), commentLedgerPath = clickUpCommentLedgerPath(worktree) } = {}) {
9842
9892
  const eventType = clickUpEventType(payload);
9843
9893
  const eventKey = clickUpWebhookEventKey(payload);
9844
9894
  const remembered = rememberClickUpWebhookEvent(state, eventKey);
@@ -9897,8 +9947,8 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
9897
9947
  } catch (error) {
9898
9948
  const message = `Optima webhook could not create or reuse a task worktree for ${taskId}: ${error.message}`;
9899
9949
  appendClickUpWebhookLocalLog(worktree, { type: "task_worktree_failed", taskId, message });
9900
- if (typeof clickupClient?.postTaskComment === "function") await clickupClient.postTaskComment({ taskId, comment: message });
9901
- return { ok: false, action: "error", reason: "task_worktree_failed", taskId, message };
9950
+ const blockerTag2 = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "task_worktree_failed", source: "route_worktree" });
9951
+ return { ok: false, action: "error", reason: "task_worktree_failed", taskId, message, blockerTag: blockerTag2 };
9902
9952
  }
9903
9953
  const deliveryEvidencePath = deliveryEvidencePathForClickUpTask(taskId);
9904
9954
  const routingMetadata = {
@@ -9928,24 +9978,25 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
9928
9978
  appendClickUpWebhookLocalLog(worktree, { type: "pending_session_metadata_failed", taskId, sessionId: pendingSessionId, message: error.message });
9929
9979
  throw error;
9930
9980
  }
9931
- await sendSessionEvent(openCodeClient, { sessionId: pendingSessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl });
9981
+ const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId: pendingSessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, eventMarkers: [taskId, eventType], verifySessionEventDelivery });
9982
+ if (!delivery.ok) return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
9932
9983
  const nextMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(pendingMetadata, config.routing.metadataKey, pendingSessionId), config.routing.metadataKey);
9933
9984
  await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: nextMetadata });
9934
9985
  const { [taskId]: _completedPending, ...remainingPending } = stateToPersist.pendingSessions || {};
9935
9986
  stateToPersist = { ...stateToPersist, pendingSessions: remainingPending };
9936
- return finish({ ok: true, action: "created_session", taskId, sessionId: pendingSessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
9987
+ 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, deliveryFallback: delivery.fallback });
9937
9988
  }
9938
9989
  const sessionId = String(existingSessionId);
9939
9990
  if (await sessionExists(openCodeClient, sessionId)) {
9940
9991
  if (typeof clickupClient?.updateTaskMetadata === "function") await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: metadataWithRouting });
9941
- await sendSessionEvent(openCodeClient, { sessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl });
9942
- return finish({ ok: true, action: "sent_to_existing_session", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
9992
+ const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, eventMarkers: [taskId, eventType], verifySessionEventDelivery });
9993
+ if (!delivery.ok) return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
9994
+ return finish({ ok: true, action: "sent_to_existing_session", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, deliveryVerification: delivery.verification, deliveryFallback: delivery.fallback });
9943
9995
  }
9944
9996
  const at = now().toISOString();
9945
- const incidentComment = `Optima webhook could not route this ClickUp event because OpenCode session ${sessionId} is missing on host ${host} at ${at}. No replacement session was created automatically.`;
9946
9997
  appendClickUpWebhookLocalLog(worktree, { type: "missing_session", taskId, sessionId, host, at });
9947
- await clickupClient.postTaskComment({ taskId, comment: incidentComment });
9948
- return finish({ ok: true, action: "missing_session_reported", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
9998
+ const blockerTag = await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "missing_session", source: "route_existing_session" });
9999
+ return finish({ ok: true, action: "missing_session_reported", taskId, sessionId, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, blockerTag });
9949
10000
  }
9950
10001
  async function routeClickUpWebhookEvent(options = {}) {
9951
10002
  const taskId = clickUpTaskIdFromPayload(options.payload || {});
@@ -10003,24 +10054,14 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
10003
10054
  });
10004
10055
  if (result?.ok && result.action !== "ignored") {
10005
10056
  routed.assigned += 1;
10006
- await postClickUpStartupComment({
10007
- clickupClient,
10008
- worktree,
10009
- taskId,
10010
- type: "resume",
10011
- comment: buildClickUpStartupResumeComment({ taskId, result })
10012
- });
10057
+ } else if (result?.ok === false) {
10058
+ routed.errors += 1;
10059
+ if (!result.blockerTag) await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: result.reason || "startup_reconciliation_route_failed", source: "startup_reconciliation_task" });
10013
10060
  }
10014
10061
  } catch (error) {
10015
10062
  routed.errors += 1;
10016
10063
  appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_failed", taskId, message: error.message });
10017
- await postClickUpStartupComment({
10018
- clickupClient,
10019
- worktree,
10020
- taskId,
10021
- type: "blocker",
10022
- comment: buildClickUpStartupBlockerComment({ taskId, error })
10023
- });
10064
+ await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "startup_reconciliation_task_failed", source: "startup_reconciliation_task" });
10024
10065
  }
10025
10066
  if (!lastWebhookMs || !clickupClient?.getTaskComments) continue;
10026
10067
  try {
@@ -10050,6 +10091,7 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
10050
10091
  } catch (error) {
10051
10092
  routed.errors += 1;
10052
10093
  appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_comments_failed", taskId, message: error.message });
10094
+ await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "startup_reconciliation_comments_failed", source: "startup_reconciliation_comments" });
10053
10095
  }
10054
10096
  }
10055
10097
  clickUpWebhookLifecycleLog(worktree, { type: "startup_reconciliation_finished", ...routed });
@@ -11834,7 +11876,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
11834
11876
  }
11835
11877
  };
11836
11878
  }
11837
- OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, BUNDLE_ASSETS_DIR, CLICKUP_DEFINITION_DOC_PARENT, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentLedgerKey, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, readClickUpCommentLedger, readClickUpWebhookState, reconcileClickUpStartup, recordClickUpCommentVersionProcessed, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
11879
+ OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, BUNDLE_ASSETS_DIR, CLICKUP_DEFINITION_DOC_PARENT, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentLedgerKey, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, readClickUpCommentLedger, readClickUpWebhookState, reconcileClickUpStartup, recordClickUpCommentVersionProcessed, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
11838
11880
 
11839
11881
  // src/sanitize_cli.js
11840
11882
  var { migrateLegacyOptimaLayout: migrateLegacyOptimaLayout2 } = OptimaPlugin.__internals;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defend-tech/opencode-optima",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+ssh://git@github.com/defend-tech/opencode-optima.git"