@defend-tech/opencode-optima 0.1.15 → 0.1.17
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 +114 -12
- package/dist/sanitize_cli.js +114 -12
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8017,6 +8017,9 @@ var REPO_LOCAL_POLICIES_README = [
|
|
|
8017
8017
|
].join("\n");
|
|
8018
8018
|
var activeWorkflows = /* @__PURE__ */ new Map();
|
|
8019
8019
|
var activeClickUpWebhookListeners = /* @__PURE__ */ new Map();
|
|
8020
|
+
var activeClickUpWebhookLifecycleRegistry = /* @__PURE__ */ new Map();
|
|
8021
|
+
var CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS = 8e3;
|
|
8022
|
+
var CLICKUP_WEBHOOK_SIGNAL_STATE = Symbol.for("opencode-optima.clickup-webhook.signal-state");
|
|
8020
8023
|
var activeClickUpTaskRoutes = /* @__PURE__ */ new Map();
|
|
8021
8024
|
var objectIdentityMap = /* @__PURE__ */ new WeakMap();
|
|
8022
8025
|
var objectIdentitySequence = 0;
|
|
@@ -9041,8 +9044,13 @@ async function ensureClickUpWebhookSubscription({ validation, worktree, clickupC
|
|
|
9041
9044
|
const existingValidation = await validateClickUpWebhookState(existing, config, clickupClient);
|
|
9042
9045
|
if (existingValidation.valid) {
|
|
9043
9046
|
const state = writeClickUpWebhookState(worktree, { ...existingValidation.state, recentEventKeys: existing.recentEventKeys || [] }, config);
|
|
9047
|
+
clickUpWebhookLifecycleLog(worktree, { type: "remote_webhook_reused", webhookId: state.webhookId, mode: existingValidation.mode });
|
|
9044
9048
|
return { active: true, valid: true, mode: existingValidation.mode, limitation: existingValidation.limitation, state };
|
|
9045
9049
|
}
|
|
9050
|
+
if (existing.webhookId && clickupClient?.deleteWebhook) {
|
|
9051
|
+
await deleteClickUpWebhookBestEffort({ webhookId: existing.webhookId, clickupClient, worktree, reason: existingValidation.reason || "startup_self_heal" });
|
|
9052
|
+
markClickUpWebhookInactive(worktree, existing, config);
|
|
9053
|
+
}
|
|
9046
9054
|
if (!clickupClient?.createWebhook) {
|
|
9047
9055
|
return { active: false, valid: false, reason: "clickup_client_unavailable", state: existing };
|
|
9048
9056
|
}
|
|
@@ -9062,15 +9070,12 @@ async function ensureClickUpWebhookSubscription({ validation, worktree, clickupC
|
|
|
9062
9070
|
}
|
|
9063
9071
|
}
|
|
9064
9072
|
if (!createdValidation.valid) {
|
|
9065
|
-
|
|
9066
|
-
|
|
9067
|
-
await clickupClient.deleteWebhook(stateForValidation.webhookId);
|
|
9068
|
-
} catch {
|
|
9069
|
-
}
|
|
9070
|
-
}
|
|
9073
|
+
await deleteClickUpWebhookBestEffort({ webhookId: stateForValidation.webhookId, clickupClient, worktree, reason: "created_state_invalid" });
|
|
9074
|
+
clickUpWebhookLifecycleLog(worktree, { type: "remote_webhook_create_invalid", webhookId: stateForValidation.webhookId, reason: createdValidation.reason });
|
|
9071
9075
|
return { active: false, valid: false, reason: "created_state_invalid", validation: createdValidation, state: stateForValidation };
|
|
9072
9076
|
}
|
|
9073
9077
|
const next = writeClickUpWebhookState(worktree, createdValidation.state || stateForValidation, config);
|
|
9078
|
+
clickUpWebhookLifecycleLog(worktree, { type: "remote_webhook_created", webhookId: next.webhookId, mode: createdValidation.mode || "created" });
|
|
9074
9079
|
const mode = createdValidation.mode === "created_pending_remote_validation" ? "created_pending_remote_validation" : clickupClient?.listWebhooks ? "created_remote_validated" : "created";
|
|
9075
9080
|
return { active: true, valid: true, mode, limitation: createdValidation.limitation, state: next };
|
|
9076
9081
|
}
|
|
@@ -9253,6 +9258,93 @@ function appendClickUpWebhookLocalLog(worktree, entry) {
|
|
|
9253
9258
|
fs2.appendFileSync(logPath, `${JSON.stringify(safeEntry)}
|
|
9254
9259
|
`, "utf8");
|
|
9255
9260
|
}
|
|
9261
|
+
function clickUpWebhookLifecycleLog(worktree, entry) {
|
|
9262
|
+
try {
|
|
9263
|
+
appendClickUpWebhookLocalLog(worktree, { scope: "lifecycle", ...entry });
|
|
9264
|
+
} catch {
|
|
9265
|
+
}
|
|
9266
|
+
}
|
|
9267
|
+
function promiseWithTimeout(promise, timeoutMs, timeoutValue) {
|
|
9268
|
+
let timeout;
|
|
9269
|
+
return Promise.race([
|
|
9270
|
+
Promise.resolve(promise),
|
|
9271
|
+
new Promise((resolve) => {
|
|
9272
|
+
timeout = setTimeout(() => resolve(timeoutValue), Math.max(1, Number(timeoutMs) || CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS));
|
|
9273
|
+
})
|
|
9274
|
+
]).finally(() => clearTimeout(timeout));
|
|
9275
|
+
}
|
|
9276
|
+
function closeClickUpWebhookServer(server) {
|
|
9277
|
+
if (!server || typeof server.close !== "function") return Promise.resolve({ ok: true, skipped: true });
|
|
9278
|
+
return new Promise((resolve) => {
|
|
9279
|
+
try {
|
|
9280
|
+
server.close((error) => resolve(error ? { ok: false, error: error.message } : { ok: true }));
|
|
9281
|
+
} catch (error) {
|
|
9282
|
+
resolve({ ok: false, error: error.message });
|
|
9283
|
+
}
|
|
9284
|
+
});
|
|
9285
|
+
}
|
|
9286
|
+
function managedClickUpWebhookKey({ worktree, state, config } = {}) {
|
|
9287
|
+
return [path2.resolve(worktree || process.cwd()), state?.webhookId || "", config?.webhook?.publicUrl || ""].join("|");
|
|
9288
|
+
}
|
|
9289
|
+
async function deleteClickUpWebhookBestEffort({ webhookId, clickupClient, worktree, reason = "cleanup" } = {}) {
|
|
9290
|
+
const id = String(webhookId || "").trim();
|
|
9291
|
+
if (!id || !clickupClient?.deleteWebhook) return { ok: false, skipped: true, reason: "delete_unavailable" };
|
|
9292
|
+
try {
|
|
9293
|
+
await clickupClient.deleteWebhook(id);
|
|
9294
|
+
clickUpWebhookLifecycleLog(worktree, { type: "remote_webhook_deleted", reason, webhookId: id });
|
|
9295
|
+
return { ok: true };
|
|
9296
|
+
} catch (error) {
|
|
9297
|
+
clickUpWebhookLifecycleLog(worktree, { type: "remote_webhook_delete_failed", reason, webhookId: id, message: error.message });
|
|
9298
|
+
return { ok: false, error: error.message };
|
|
9299
|
+
}
|
|
9300
|
+
}
|
|
9301
|
+
function markClickUpWebhookInactive(worktree, state = {}, config = null) {
|
|
9302
|
+
if (!worktree || !state?.webhookId) return null;
|
|
9303
|
+
return writeClickUpWebhookState(worktree, { ...state, active: false, listener: {}, lastValidatedAt: (/* @__PURE__ */ new Date()).toISOString() }, config);
|
|
9304
|
+
}
|
|
9305
|
+
async function cleanupManagedClickUpWebhook(entry = {}, { timeoutMs = CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS, reason = "shutdown" } = {}) {
|
|
9306
|
+
if (!entry || entry.cleaning) return { ok: true, skipped: true, reason: "already_cleaning" };
|
|
9307
|
+
entry.cleaning = true;
|
|
9308
|
+
const cleanup = (async () => {
|
|
9309
|
+
clickUpWebhookLifecycleLog(entry.worktree, { type: "cleanup_started", reason, key: entry.key, webhookId: entry.state?.webhookId });
|
|
9310
|
+
const closeResult = await closeClickUpWebhookServer(entry.listener?.server);
|
|
9311
|
+
if (entry.listenerRegistry && entry.listener?.key) entry.listenerRegistry.delete(entry.listener.key);
|
|
9312
|
+
const deleteResult = await deleteClickUpWebhookBestEffort({ webhookId: entry.state?.webhookId, clickupClient: entry.clickupClient, worktree: entry.worktree, reason });
|
|
9313
|
+
if (deleteResult.ok) markClickUpWebhookInactive(entry.worktree, entry.state, entry.config);
|
|
9314
|
+
activeClickUpWebhookLifecycleRegistry.delete(entry.key);
|
|
9315
|
+
clickUpWebhookLifecycleLog(entry.worktree, { type: "cleanup_finished", reason, close_ok: closeResult.ok, delete_ok: deleteResult.ok, delete_reason: deleteResult.reason });
|
|
9316
|
+
return { ok: closeResult.ok !== false && deleteResult.ok !== false, closeResult, deleteResult };
|
|
9317
|
+
})();
|
|
9318
|
+
const result = await promiseWithTimeout(cleanup, timeoutMs, { ok: false, timeout: true, reason: "cleanup_timeout" });
|
|
9319
|
+
if (result?.timeout) clickUpWebhookLifecycleLog(entry.worktree, { type: "cleanup_timeout", reason, webhookId: entry.state?.webhookId });
|
|
9320
|
+
return result;
|
|
9321
|
+
}
|
|
9322
|
+
function registerClickUpWebhookLifecycle({ config, state, worktree, clickupClient, listener, listenerRegistry = activeClickUpWebhookListeners } = {}) {
|
|
9323
|
+
if (!isClickUpWebhookStateActive(state, config)) return null;
|
|
9324
|
+
const key = managedClickUpWebhookKey({ worktree, state, config });
|
|
9325
|
+
const entry = { key, config, state, worktree, clickupClient, listener, listenerRegistry, registeredAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
9326
|
+
activeClickUpWebhookLifecycleRegistry.set(key, entry);
|
|
9327
|
+
installClickUpWebhookSignalHandlers();
|
|
9328
|
+
clickUpWebhookLifecycleLog(worktree, { type: "lifecycle_registered", key, webhookId: state.webhookId });
|
|
9329
|
+
return entry;
|
|
9330
|
+
}
|
|
9331
|
+
function installClickUpWebhookSignalHandlers() {
|
|
9332
|
+
const globalState = globalThis[CLICKUP_WEBHOOK_SIGNAL_STATE] || { installed: false, running: false };
|
|
9333
|
+
if (globalState.installed) return;
|
|
9334
|
+
const handler = (signal) => {
|
|
9335
|
+
if (globalState.running) return;
|
|
9336
|
+
globalState.running = true;
|
|
9337
|
+
const timeoutMs = CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS;
|
|
9338
|
+
const cleanup = Promise.allSettled([...activeClickUpWebhookLifecycleRegistry.values()].map((entry) => cleanupManagedClickUpWebhook(entry, { timeoutMs, reason: signal })));
|
|
9339
|
+
promiseWithTimeout(cleanup, timeoutMs + 500, { timeout: true }).finally(() => {
|
|
9340
|
+
process.exit(signal === "SIGINT" ? 130 : 143);
|
|
9341
|
+
});
|
|
9342
|
+
};
|
|
9343
|
+
process.once("SIGTERM", handler);
|
|
9344
|
+
process.once("SIGINT", handler);
|
|
9345
|
+
globalState.installed = true;
|
|
9346
|
+
globalThis[CLICKUP_WEBHOOK_SIGNAL_STATE] = globalState;
|
|
9347
|
+
}
|
|
9256
9348
|
function redactClickUpWebhookAuditValue(value, secretValues = []) {
|
|
9257
9349
|
if (typeof value === "string") {
|
|
9258
9350
|
return secretValues.reduce((next, secret) => secret ? next.split(secret).join(CLICKUP_WEBHOOK_REDACTED) : next, value);
|
|
@@ -10566,25 +10658,35 @@ async function OptimaPlugin(input = {}, pluginOptions = {}) {
|
|
|
10566
10658
|
let clickUpWebhookActive = clickUpWebhookRuntime.active === true && clickUpWebhookRuntime.valid === true;
|
|
10567
10659
|
if (clickUpWebhookActive && input.startClickUpWebhookListener !== false) {
|
|
10568
10660
|
try {
|
|
10661
|
+
const lifecycleClickUpClient = input.clickupClient || createClickUpApiClient(clickUpWebhookValidation.config, input.fetch);
|
|
10662
|
+
const listenerRegistry = input.clickUpWebhookListenerRegistry || activeClickUpWebhookListeners;
|
|
10663
|
+
const listenerState = clickUpWebhookRuntime.state || readClickUpWebhookState(worktree, clickUpWebhookValidation.config);
|
|
10569
10664
|
const listener = startClickUpWebhookListener({
|
|
10570
10665
|
config: clickUpWebhookValidation.config,
|
|
10571
|
-
state:
|
|
10666
|
+
state: listenerState,
|
|
10572
10667
|
worktree,
|
|
10573
|
-
clickupClient:
|
|
10668
|
+
clickupClient: lifecycleClickUpClient,
|
|
10574
10669
|
openCodeClient: input.client,
|
|
10575
|
-
listenerRegistry
|
|
10670
|
+
listenerRegistry
|
|
10576
10671
|
});
|
|
10577
10672
|
const readyListener = listener.readyPromise ? await listener.readyPromise : listener;
|
|
10578
10673
|
if (readyListener.active && readyListener.ready !== false) {
|
|
10579
|
-
writeClickUpWebhookState(worktree, {
|
|
10580
|
-
...
|
|
10674
|
+
const activeState = writeClickUpWebhookState(worktree, {
|
|
10675
|
+
...listenerState,
|
|
10581
10676
|
listener: { bindHost: clickUpWebhookValidation.config.webhook.bindHost, bindPort: clickUpWebhookValidation.config.webhook.bindPort, startedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
10582
10677
|
}, clickUpWebhookValidation.config);
|
|
10678
|
+
registerClickUpWebhookLifecycle({ config: clickUpWebhookValidation.config, state: activeState, worktree, clickupClient: lifecycleClickUpClient, listener: readyListener, listenerRegistry });
|
|
10583
10679
|
} else {
|
|
10680
|
+
await deleteClickUpWebhookBestEffort({ webhookId: listenerState.webhookId, clickupClient: lifecycleClickUpClient, worktree, reason: readyListener.reason || "listener_unavailable" });
|
|
10681
|
+
markClickUpWebhookInactive(worktree, listenerState, clickUpWebhookValidation.config);
|
|
10584
10682
|
clickUpWebhookActive = false;
|
|
10585
10683
|
clickUpWebhookRuntime = { ...clickUpWebhookRuntime, active: false, valid: false, reason: readyListener.reason || "listener_unavailable" };
|
|
10586
10684
|
}
|
|
10587
10685
|
} catch (error) {
|
|
10686
|
+
const failureState = clickUpWebhookRuntime.state || readClickUpWebhookState(worktree, clickUpWebhookValidation.config);
|
|
10687
|
+
const failureClient = input.clickupClient || createClickUpApiClient(clickUpWebhookValidation.config, input.fetch);
|
|
10688
|
+
await deleteClickUpWebhookBestEffort({ webhookId: failureState.webhookId, clickupClient: failureClient, worktree, reason: "listener_failed" });
|
|
10689
|
+
markClickUpWebhookInactive(worktree, failureState, clickUpWebhookValidation.config);
|
|
10588
10690
|
clickUpWebhookActive = false;
|
|
10589
10691
|
clickUpWebhookRuntime = { ...clickUpWebhookRuntime, active: false, valid: false, reason: "listener_failed", error: error.message };
|
|
10590
10692
|
appendClickUpWebhookLocalLog(worktree, { type: "listener_failed", message: error.message });
|
|
@@ -11139,7 +11241,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
|
|
|
11139
11241
|
}
|
|
11140
11242
|
};
|
|
11141
11243
|
}
|
|
11142
|
-
OptimaPlugin.__internals = { buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, readClickUpWebhookState, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, 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 };
|
|
11244
|
+
OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, readClickUpWebhookState, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, 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 };
|
|
11143
11245
|
export {
|
|
11144
11246
|
OptimaPlugin as default
|
|
11145
11247
|
};
|
package/dist/sanitize_cli.js
CHANGED
|
@@ -8024,6 +8024,9 @@ var REPO_LOCAL_POLICIES_README = [
|
|
|
8024
8024
|
].join("\n");
|
|
8025
8025
|
var activeWorkflows = /* @__PURE__ */ new Map();
|
|
8026
8026
|
var activeClickUpWebhookListeners = /* @__PURE__ */ new Map();
|
|
8027
|
+
var activeClickUpWebhookLifecycleRegistry = /* @__PURE__ */ new Map();
|
|
8028
|
+
var CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS = 8e3;
|
|
8029
|
+
var CLICKUP_WEBHOOK_SIGNAL_STATE = Symbol.for("opencode-optima.clickup-webhook.signal-state");
|
|
8027
8030
|
var activeClickUpTaskRoutes = /* @__PURE__ */ new Map();
|
|
8028
8031
|
var objectIdentityMap = /* @__PURE__ */ new WeakMap();
|
|
8029
8032
|
var objectIdentitySequence = 0;
|
|
@@ -9048,8 +9051,13 @@ async function ensureClickUpWebhookSubscription({ validation, worktree, clickupC
|
|
|
9048
9051
|
const existingValidation = await validateClickUpWebhookState(existing, config, clickupClient);
|
|
9049
9052
|
if (existingValidation.valid) {
|
|
9050
9053
|
const state = writeClickUpWebhookState(worktree, { ...existingValidation.state, recentEventKeys: existing.recentEventKeys || [] }, config);
|
|
9054
|
+
clickUpWebhookLifecycleLog(worktree, { type: "remote_webhook_reused", webhookId: state.webhookId, mode: existingValidation.mode });
|
|
9051
9055
|
return { active: true, valid: true, mode: existingValidation.mode, limitation: existingValidation.limitation, state };
|
|
9052
9056
|
}
|
|
9057
|
+
if (existing.webhookId && clickupClient?.deleteWebhook) {
|
|
9058
|
+
await deleteClickUpWebhookBestEffort({ webhookId: existing.webhookId, clickupClient, worktree, reason: existingValidation.reason || "startup_self_heal" });
|
|
9059
|
+
markClickUpWebhookInactive(worktree, existing, config);
|
|
9060
|
+
}
|
|
9053
9061
|
if (!clickupClient?.createWebhook) {
|
|
9054
9062
|
return { active: false, valid: false, reason: "clickup_client_unavailable", state: existing };
|
|
9055
9063
|
}
|
|
@@ -9069,15 +9077,12 @@ async function ensureClickUpWebhookSubscription({ validation, worktree, clickupC
|
|
|
9069
9077
|
}
|
|
9070
9078
|
}
|
|
9071
9079
|
if (!createdValidation.valid) {
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
await clickupClient.deleteWebhook(stateForValidation.webhookId);
|
|
9075
|
-
} catch {
|
|
9076
|
-
}
|
|
9077
|
-
}
|
|
9080
|
+
await deleteClickUpWebhookBestEffort({ webhookId: stateForValidation.webhookId, clickupClient, worktree, reason: "created_state_invalid" });
|
|
9081
|
+
clickUpWebhookLifecycleLog(worktree, { type: "remote_webhook_create_invalid", webhookId: stateForValidation.webhookId, reason: createdValidation.reason });
|
|
9078
9082
|
return { active: false, valid: false, reason: "created_state_invalid", validation: createdValidation, state: stateForValidation };
|
|
9079
9083
|
}
|
|
9080
9084
|
const next = writeClickUpWebhookState(worktree, createdValidation.state || stateForValidation, config);
|
|
9085
|
+
clickUpWebhookLifecycleLog(worktree, { type: "remote_webhook_created", webhookId: next.webhookId, mode: createdValidation.mode || "created" });
|
|
9081
9086
|
const mode = createdValidation.mode === "created_pending_remote_validation" ? "created_pending_remote_validation" : clickupClient?.listWebhooks ? "created_remote_validated" : "created";
|
|
9082
9087
|
return { active: true, valid: true, mode, limitation: createdValidation.limitation, state: next };
|
|
9083
9088
|
}
|
|
@@ -9260,6 +9265,93 @@ function appendClickUpWebhookLocalLog(worktree, entry) {
|
|
|
9260
9265
|
fs2.appendFileSync(logPath, `${JSON.stringify(safeEntry)}
|
|
9261
9266
|
`, "utf8");
|
|
9262
9267
|
}
|
|
9268
|
+
function clickUpWebhookLifecycleLog(worktree, entry) {
|
|
9269
|
+
try {
|
|
9270
|
+
appendClickUpWebhookLocalLog(worktree, { scope: "lifecycle", ...entry });
|
|
9271
|
+
} catch {
|
|
9272
|
+
}
|
|
9273
|
+
}
|
|
9274
|
+
function promiseWithTimeout(promise, timeoutMs, timeoutValue) {
|
|
9275
|
+
let timeout;
|
|
9276
|
+
return Promise.race([
|
|
9277
|
+
Promise.resolve(promise),
|
|
9278
|
+
new Promise((resolve) => {
|
|
9279
|
+
timeout = setTimeout(() => resolve(timeoutValue), Math.max(1, Number(timeoutMs) || CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS));
|
|
9280
|
+
})
|
|
9281
|
+
]).finally(() => clearTimeout(timeout));
|
|
9282
|
+
}
|
|
9283
|
+
function closeClickUpWebhookServer(server) {
|
|
9284
|
+
if (!server || typeof server.close !== "function") return Promise.resolve({ ok: true, skipped: true });
|
|
9285
|
+
return new Promise((resolve) => {
|
|
9286
|
+
try {
|
|
9287
|
+
server.close((error) => resolve(error ? { ok: false, error: error.message } : { ok: true }));
|
|
9288
|
+
} catch (error) {
|
|
9289
|
+
resolve({ ok: false, error: error.message });
|
|
9290
|
+
}
|
|
9291
|
+
});
|
|
9292
|
+
}
|
|
9293
|
+
function managedClickUpWebhookKey({ worktree, state, config } = {}) {
|
|
9294
|
+
return [path2.resolve(worktree || process.cwd()), state?.webhookId || "", config?.webhook?.publicUrl || ""].join("|");
|
|
9295
|
+
}
|
|
9296
|
+
async function deleteClickUpWebhookBestEffort({ webhookId, clickupClient, worktree, reason = "cleanup" } = {}) {
|
|
9297
|
+
const id = String(webhookId || "").trim();
|
|
9298
|
+
if (!id || !clickupClient?.deleteWebhook) return { ok: false, skipped: true, reason: "delete_unavailable" };
|
|
9299
|
+
try {
|
|
9300
|
+
await clickupClient.deleteWebhook(id);
|
|
9301
|
+
clickUpWebhookLifecycleLog(worktree, { type: "remote_webhook_deleted", reason, webhookId: id });
|
|
9302
|
+
return { ok: true };
|
|
9303
|
+
} catch (error) {
|
|
9304
|
+
clickUpWebhookLifecycleLog(worktree, { type: "remote_webhook_delete_failed", reason, webhookId: id, message: error.message });
|
|
9305
|
+
return { ok: false, error: error.message };
|
|
9306
|
+
}
|
|
9307
|
+
}
|
|
9308
|
+
function markClickUpWebhookInactive(worktree, state = {}, config = null) {
|
|
9309
|
+
if (!worktree || !state?.webhookId) return null;
|
|
9310
|
+
return writeClickUpWebhookState(worktree, { ...state, active: false, listener: {}, lastValidatedAt: (/* @__PURE__ */ new Date()).toISOString() }, config);
|
|
9311
|
+
}
|
|
9312
|
+
async function cleanupManagedClickUpWebhook(entry = {}, { timeoutMs = CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS, reason = "shutdown" } = {}) {
|
|
9313
|
+
if (!entry || entry.cleaning) return { ok: true, skipped: true, reason: "already_cleaning" };
|
|
9314
|
+
entry.cleaning = true;
|
|
9315
|
+
const cleanup = (async () => {
|
|
9316
|
+
clickUpWebhookLifecycleLog(entry.worktree, { type: "cleanup_started", reason, key: entry.key, webhookId: entry.state?.webhookId });
|
|
9317
|
+
const closeResult = await closeClickUpWebhookServer(entry.listener?.server);
|
|
9318
|
+
if (entry.listenerRegistry && entry.listener?.key) entry.listenerRegistry.delete(entry.listener.key);
|
|
9319
|
+
const deleteResult = await deleteClickUpWebhookBestEffort({ webhookId: entry.state?.webhookId, clickupClient: entry.clickupClient, worktree: entry.worktree, reason });
|
|
9320
|
+
if (deleteResult.ok) markClickUpWebhookInactive(entry.worktree, entry.state, entry.config);
|
|
9321
|
+
activeClickUpWebhookLifecycleRegistry.delete(entry.key);
|
|
9322
|
+
clickUpWebhookLifecycleLog(entry.worktree, { type: "cleanup_finished", reason, close_ok: closeResult.ok, delete_ok: deleteResult.ok, delete_reason: deleteResult.reason });
|
|
9323
|
+
return { ok: closeResult.ok !== false && deleteResult.ok !== false, closeResult, deleteResult };
|
|
9324
|
+
})();
|
|
9325
|
+
const result = await promiseWithTimeout(cleanup, timeoutMs, { ok: false, timeout: true, reason: "cleanup_timeout" });
|
|
9326
|
+
if (result?.timeout) clickUpWebhookLifecycleLog(entry.worktree, { type: "cleanup_timeout", reason, webhookId: entry.state?.webhookId });
|
|
9327
|
+
return result;
|
|
9328
|
+
}
|
|
9329
|
+
function registerClickUpWebhookLifecycle({ config, state, worktree, clickupClient, listener, listenerRegistry = activeClickUpWebhookListeners } = {}) {
|
|
9330
|
+
if (!isClickUpWebhookStateActive(state, config)) return null;
|
|
9331
|
+
const key = managedClickUpWebhookKey({ worktree, state, config });
|
|
9332
|
+
const entry = { key, config, state, worktree, clickupClient, listener, listenerRegistry, registeredAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
9333
|
+
activeClickUpWebhookLifecycleRegistry.set(key, entry);
|
|
9334
|
+
installClickUpWebhookSignalHandlers();
|
|
9335
|
+
clickUpWebhookLifecycleLog(worktree, { type: "lifecycle_registered", key, webhookId: state.webhookId });
|
|
9336
|
+
return entry;
|
|
9337
|
+
}
|
|
9338
|
+
function installClickUpWebhookSignalHandlers() {
|
|
9339
|
+
const globalState = globalThis[CLICKUP_WEBHOOK_SIGNAL_STATE] || { installed: false, running: false };
|
|
9340
|
+
if (globalState.installed) return;
|
|
9341
|
+
const handler = (signal) => {
|
|
9342
|
+
if (globalState.running) return;
|
|
9343
|
+
globalState.running = true;
|
|
9344
|
+
const timeoutMs = CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS;
|
|
9345
|
+
const cleanup = Promise.allSettled([...activeClickUpWebhookLifecycleRegistry.values()].map((entry) => cleanupManagedClickUpWebhook(entry, { timeoutMs, reason: signal })));
|
|
9346
|
+
promiseWithTimeout(cleanup, timeoutMs + 500, { timeout: true }).finally(() => {
|
|
9347
|
+
process.exit(signal === "SIGINT" ? 130 : 143);
|
|
9348
|
+
});
|
|
9349
|
+
};
|
|
9350
|
+
process.once("SIGTERM", handler);
|
|
9351
|
+
process.once("SIGINT", handler);
|
|
9352
|
+
globalState.installed = true;
|
|
9353
|
+
globalThis[CLICKUP_WEBHOOK_SIGNAL_STATE] = globalState;
|
|
9354
|
+
}
|
|
9263
9355
|
function redactClickUpWebhookAuditValue(value, secretValues = []) {
|
|
9264
9356
|
if (typeof value === "string") {
|
|
9265
9357
|
return secretValues.reduce((next, secret) => secret ? next.split(secret).join(CLICKUP_WEBHOOK_REDACTED) : next, value);
|
|
@@ -10573,25 +10665,35 @@ async function OptimaPlugin(input = {}, pluginOptions = {}) {
|
|
|
10573
10665
|
let clickUpWebhookActive = clickUpWebhookRuntime.active === true && clickUpWebhookRuntime.valid === true;
|
|
10574
10666
|
if (clickUpWebhookActive && input.startClickUpWebhookListener !== false) {
|
|
10575
10667
|
try {
|
|
10668
|
+
const lifecycleClickUpClient = input.clickupClient || createClickUpApiClient(clickUpWebhookValidation.config, input.fetch);
|
|
10669
|
+
const listenerRegistry = input.clickUpWebhookListenerRegistry || activeClickUpWebhookListeners;
|
|
10670
|
+
const listenerState = clickUpWebhookRuntime.state || readClickUpWebhookState(worktree, clickUpWebhookValidation.config);
|
|
10576
10671
|
const listener = startClickUpWebhookListener({
|
|
10577
10672
|
config: clickUpWebhookValidation.config,
|
|
10578
|
-
state:
|
|
10673
|
+
state: listenerState,
|
|
10579
10674
|
worktree,
|
|
10580
|
-
clickupClient:
|
|
10675
|
+
clickupClient: lifecycleClickUpClient,
|
|
10581
10676
|
openCodeClient: input.client,
|
|
10582
|
-
listenerRegistry
|
|
10677
|
+
listenerRegistry
|
|
10583
10678
|
});
|
|
10584
10679
|
const readyListener = listener.readyPromise ? await listener.readyPromise : listener;
|
|
10585
10680
|
if (readyListener.active && readyListener.ready !== false) {
|
|
10586
|
-
writeClickUpWebhookState(worktree, {
|
|
10587
|
-
...
|
|
10681
|
+
const activeState = writeClickUpWebhookState(worktree, {
|
|
10682
|
+
...listenerState,
|
|
10588
10683
|
listener: { bindHost: clickUpWebhookValidation.config.webhook.bindHost, bindPort: clickUpWebhookValidation.config.webhook.bindPort, startedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
10589
10684
|
}, clickUpWebhookValidation.config);
|
|
10685
|
+
registerClickUpWebhookLifecycle({ config: clickUpWebhookValidation.config, state: activeState, worktree, clickupClient: lifecycleClickUpClient, listener: readyListener, listenerRegistry });
|
|
10590
10686
|
} else {
|
|
10687
|
+
await deleteClickUpWebhookBestEffort({ webhookId: listenerState.webhookId, clickupClient: lifecycleClickUpClient, worktree, reason: readyListener.reason || "listener_unavailable" });
|
|
10688
|
+
markClickUpWebhookInactive(worktree, listenerState, clickUpWebhookValidation.config);
|
|
10591
10689
|
clickUpWebhookActive = false;
|
|
10592
10690
|
clickUpWebhookRuntime = { ...clickUpWebhookRuntime, active: false, valid: false, reason: readyListener.reason || "listener_unavailable" };
|
|
10593
10691
|
}
|
|
10594
10692
|
} catch (error) {
|
|
10693
|
+
const failureState = clickUpWebhookRuntime.state || readClickUpWebhookState(worktree, clickUpWebhookValidation.config);
|
|
10694
|
+
const failureClient = input.clickupClient || createClickUpApiClient(clickUpWebhookValidation.config, input.fetch);
|
|
10695
|
+
await deleteClickUpWebhookBestEffort({ webhookId: failureState.webhookId, clickupClient: failureClient, worktree, reason: "listener_failed" });
|
|
10696
|
+
markClickUpWebhookInactive(worktree, failureState, clickUpWebhookValidation.config);
|
|
10595
10697
|
clickUpWebhookActive = false;
|
|
10596
10698
|
clickUpWebhookRuntime = { ...clickUpWebhookRuntime, active: false, valid: false, reason: "listener_failed", error: error.message };
|
|
10597
10699
|
appendClickUpWebhookLocalLog(worktree, { type: "listener_failed", message: error.message });
|
|
@@ -11146,7 +11248,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
|
|
|
11146
11248
|
}
|
|
11147
11249
|
};
|
|
11148
11250
|
}
|
|
11149
|
-
OptimaPlugin.__internals = { buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, readClickUpWebhookState, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, 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 };
|
|
11251
|
+
OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, readClickUpWebhookState, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, 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 };
|
|
11150
11252
|
|
|
11151
11253
|
// src/sanitize_cli.js
|
|
11152
11254
|
var { migrateLegacyOptimaLayout: migrateLegacyOptimaLayout2 } = OptimaPlugin.__internals;
|