@defend-tech/opencode-optima 0.1.12 → 0.1.13

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
@@ -7929,6 +7929,8 @@ var CLICKUP_PM_MENTION_NAME = "Defend Tech Product Manager";
7929
7929
  var CLICKUP_WEBHOOK_RUNTIME_VERSION = 1;
7930
7930
  var CLICKUP_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
7931
7931
  var CLICKUP_WEBHOOK_REQUEST_TIMEOUT_MS = 1e4;
7932
+ var CLICKUP_WEBHOOK_LOG_LEVELS = /* @__PURE__ */ new Set(["error", "info", "verbose"]);
7933
+ var CLICKUP_WEBHOOK_REDACTED = "[REDACTED]";
7932
7934
  var DISCUSSION_BACKFILL_FETCH_LIMIT = 100;
7933
7935
  var DEFAULT_PRESERVE_EXISTING_AGENTS = true;
7934
7936
  var SAFE_WORKTREE_FAILURE = "FAIL: Optima needs a writable project directory. Open/add a project in OpenChamber first. Refusing to use '/'.";
@@ -8793,6 +8795,22 @@ function clickUpWebhookStatePath(worktree) {
8793
8795
  function clickUpWebhookLogPath(worktree) {
8794
8796
  return path2.join(optimaRuntimeDir(worktree), "clickup-webhook.log.jsonl");
8795
8797
  }
8798
+ function normalizeClickUpWebhookLogLevel(value) {
8799
+ const level = String(value || "info").trim().toLowerCase();
8800
+ return CLICKUP_WEBHOOK_LOG_LEVELS.has(level) ? level : "info";
8801
+ }
8802
+ function clickUpWebhookAuditLogDir() {
8803
+ const dataHome = process.env.XDG_DATA_HOME && path2.isAbsolute(process.env.XDG_DATA_HOME) ? process.env.XDG_DATA_HOME : path2.join(os.homedir(), ".local", "share", "opencode");
8804
+ return path2.join(dataHome, "opencode-optima");
8805
+ }
8806
+ function clickUpWebhookAuditLogPath(at = /* @__PURE__ */ new Date(), logDir = clickUpWebhookAuditLogDir()) {
8807
+ return path2.join(logDir, `clickup-webhook-${at.toISOString().slice(0, 10)}.jsonl`);
8808
+ }
8809
+ function clickUpWebhookRequestFilePath(at = /* @__PURE__ */ new Date(), logDir = clickUpWebhookAuditLogDir()) {
8810
+ const stamp = at.toISOString().replace(/:/g, "-").replace(/\./g, "-");
8811
+ const shortId = crypto.randomBytes(4).toString("hex");
8812
+ return path2.join(logDir, "requests", `clickup-webhook-${stamp}-${shortId}.json`);
8813
+ }
8796
8814
  function findOptimaPluginTupleOptions(pluginEntries = []) {
8797
8815
  if (!Array.isArray(pluginEntries)) return null;
8798
8816
  for (const entry of pluginEntries) {
@@ -8822,6 +8840,7 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
8822
8840
  basePath: String(raw.base_path || raw.basePath || worktree || "").trim(),
8823
8841
  teamId: String(raw.team_id || raw.teamId || "").trim(),
8824
8842
  apiToken: String(raw.api_token || raw.apiToken || "").trim(),
8843
+ log: normalizeClickUpWebhookLogLevel(raw.log),
8825
8844
  webhook: {
8826
8845
  publicUrl: String(webhook.public_url || webhook.publicUrl || "").trim(),
8827
8846
  bindHost: String(webhook.bind_host || webhook.bindHost || "127.0.0.1").trim(),
@@ -9212,6 +9231,74 @@ function appendClickUpWebhookLocalLog(worktree, entry) {
9212
9231
  fs2.appendFileSync(logPath, `${JSON.stringify(safeEntry)}
9213
9232
  `, "utf8");
9214
9233
  }
9234
+ function redactClickUpWebhookAuditValue(value, secretValues = []) {
9235
+ if (typeof value === "string") {
9236
+ return secretValues.reduce((next, secret) => secret ? next.split(secret).join(CLICKUP_WEBHOOK_REDACTED) : next, value);
9237
+ }
9238
+ if (Array.isArray(value)) return value.map((item) => redactClickUpWebhookAuditValue(item, secretValues));
9239
+ if (!isPlainObject(value)) return value;
9240
+ return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => {
9241
+ const normalizedKey = normalizeLooseToken(key);
9242
+ const secretKey = normalizedKey.includes("signature") || normalizedKey.includes("authorization") || normalizedKey.includes("cookie") || normalizedKey.includes("token") || normalizedKey.includes("secret") || normalizedKey.includes("api-key") || normalizedKey.includes("apikey");
9243
+ return [key, secretKey ? CLICKUP_WEBHOOK_REDACTED : redactClickUpWebhookAuditValue(entryValue, secretValues)];
9244
+ }));
9245
+ }
9246
+ function buildClickUpWebhookAuditSummary({ method, url, config, handled, error, payload, requestFile, at = /* @__PURE__ */ new Date() } = {}) {
9247
+ const result = handled?.result || {};
9248
+ const summary = {
9249
+ at: at.toISOString(),
9250
+ method,
9251
+ path: url === null ? null : new URL(String(url || "/"), config?.webhook?.publicUrl || "http://localhost").pathname,
9252
+ status: handled?.status || 500,
9253
+ ok: Boolean(handled?.ok),
9254
+ reason: handled?.reason || result.reason || (error ? "handler_error" : void 0),
9255
+ action: result.action,
9256
+ event: payload ? clickUpEventType(payload) : void 0,
9257
+ task: result.taskId || clickUpTaskIdFromPayload(payload || {}),
9258
+ comment: clickUpCommentFromPayload(payload || {})?.id || payload?.comment_id || payload?.commentId,
9259
+ session: result.sessionId,
9260
+ base_path: config?.basePath || "",
9261
+ request_file: requestFile || void 0
9262
+ };
9263
+ return Object.fromEntries(Object.entries(summary).filter(([, value]) => value !== void 0 && value !== ""));
9264
+ }
9265
+ function writeClickUpWebhookAuditLog({ method, url, headers = {}, rawBody = "", config, state = {}, handled = null, error = null, payload = null, at = /* @__PURE__ */ new Date() } = {}) {
9266
+ try {
9267
+ const level = normalizeClickUpWebhookLogLevel(config?.log);
9268
+ const failed = Boolean(error || !handled?.ok || (handled?.status || 500) >= 400);
9269
+ if (level === "error" && !failed) return;
9270
+ const logDir = clickUpWebhookAuditLogDir();
9271
+ fs2.mkdirSync(logDir, { recursive: true });
9272
+ const secretValues = [resolveSecretReference(config?.apiToken), state?.secret, config?.webhook?.secret].filter(Boolean);
9273
+ let requestFile;
9274
+ if (level === "verbose") {
9275
+ const absoluteRequestFile = clickUpWebhookRequestFilePath(at, logDir);
9276
+ fs2.mkdirSync(path2.dirname(absoluteRequestFile), { recursive: true });
9277
+ requestFile = path2.relative(logDir, absoluteRequestFile).split(path2.sep).join("/");
9278
+ const parsedBody = payload || (() => {
9279
+ try {
9280
+ return JSON.parse(Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : String(rawBody || ""));
9281
+ } catch {
9282
+ return void 0;
9283
+ }
9284
+ })();
9285
+ const requestArtifact = redactClickUpWebhookAuditValue({
9286
+ at: at.toISOString(),
9287
+ method,
9288
+ url,
9289
+ path: url === null ? null : new URL(String(url || "/"), config?.webhook?.publicUrl || "http://localhost").pathname,
9290
+ headers,
9291
+ body: parsedBody === void 0 ? Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : String(rawBody || "") : parsedBody
9292
+ }, secretValues);
9293
+ fs2.writeFileSync(absoluteRequestFile, `${JSON.stringify(requestArtifact, null, 2)}
9294
+ `, "utf8");
9295
+ }
9296
+ const summary = redactClickUpWebhookAuditValue(buildClickUpWebhookAuditSummary({ method, url, config, handled, error, payload, requestFile, at }), secretValues);
9297
+ fs2.appendFileSync(clickUpWebhookAuditLogPath(at, logDir), `${JSON.stringify(summary)}
9298
+ `, "utf8");
9299
+ } catch {
9300
+ }
9301
+ }
9215
9302
  async function withClickUpTaskRouteLock(taskId, operation) {
9216
9303
  const key = String(taskId || "");
9217
9304
  if (!key) return operation();
@@ -9309,25 +9396,36 @@ function clickUpWebhookExpectedPath(config) {
9309
9396
  return "/";
9310
9397
  }
9311
9398
  }
9312
- async function handleClickUpWebhookRequest({ method = "POST", url = null, headers = {}, rawBody = "", config, state, worktree, clickupClient, openCodeClient, saveState } = {}) {
9313
- if (method !== "POST") return { ok: false, status: 405, reason: "method_not_allowed" };
9314
- if (url !== null) {
9315
- const requestPath = new URL(String(url), config?.webhook?.publicUrl || "http://localhost").pathname;
9316
- if (requestPath !== clickUpWebhookExpectedPath(config)) return { ok: false, status: 404, reason: "wrong_path" };
9317
- }
9318
- const maxBodyBytes = Number(config?.webhook?.maxBodyBytes || CLICKUP_WEBHOOK_MAX_BODY_BYTES);
9319
- const bodyBytes = Buffer.isBuffer(rawBody) ? rawBody.length : Buffer.byteLength(String(rawBody || ""));
9320
- if (bodyBytes > maxBodyBytes) return { ok: false, status: 413, reason: "body_too_large" };
9321
- const signature = headers["x-signature"] || headers["X-Signature"];
9322
- if (!verifyClickUpSignature(rawBody, signature, state?.secret)) return { ok: false, status: 401, reason: "invalid_signature" };
9323
- let payload;
9399
+ async function handleClickUpWebhookRequest({ method = "POST", url = null, headers = {}, rawBody = "", config, state, worktree, clickupClient, openCodeClient, saveState, now = () => /* @__PURE__ */ new Date() } = {}) {
9400
+ let payload = null;
9401
+ let handled = null;
9402
+ const finish = (result) => {
9403
+ handled = result;
9404
+ writeClickUpWebhookAuditLog({ method, url, headers, rawBody, config, state, handled, payload, at: now() });
9405
+ return result;
9406
+ };
9324
9407
  try {
9325
- payload = JSON.parse(Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : String(rawBody));
9326
- } catch {
9327
- return { ok: false, status: 400, reason: "invalid_json" };
9408
+ if (method !== "POST") return finish({ ok: false, status: 405, reason: "method_not_allowed" });
9409
+ if (url !== null) {
9410
+ const requestPath = new URL(String(url), config?.webhook?.publicUrl || "http://localhost").pathname;
9411
+ if (requestPath !== clickUpWebhookExpectedPath(config)) return finish({ ok: false, status: 404, reason: "wrong_path" });
9412
+ }
9413
+ const maxBodyBytes = Number(config?.webhook?.maxBodyBytes || CLICKUP_WEBHOOK_MAX_BODY_BYTES);
9414
+ const bodyBytes = Buffer.isBuffer(rawBody) ? rawBody.length : Buffer.byteLength(String(rawBody || ""));
9415
+ if (bodyBytes > maxBodyBytes) return finish({ ok: false, status: 413, reason: "body_too_large" });
9416
+ const signature = headers["x-signature"] || headers["X-Signature"];
9417
+ if (!verifyClickUpSignature(rawBody, signature, state?.secret)) return finish({ ok: false, status: 401, reason: "invalid_signature" });
9418
+ try {
9419
+ payload = JSON.parse(Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : String(rawBody));
9420
+ } catch {
9421
+ return finish({ ok: false, status: 400, reason: "invalid_json" });
9422
+ }
9423
+ const result = await routeClickUpWebhookEvent({ payload, config, state, worktree, clickupClient, openCodeClient, saveState });
9424
+ return finish({ ok: result.ok, status: result.ok ? 200 : 422, result });
9425
+ } catch (error) {
9426
+ writeClickUpWebhookAuditLog({ method, url, headers, rawBody, config, state, handled, error, payload, at: now() });
9427
+ throw error;
9328
9428
  }
9329
- const result = await routeClickUpWebhookEvent({ payload, config, state, worktree, clickupClient, openCodeClient, saveState });
9330
- return { ok: result.ok, status: result.ok ? 200 : 422, result };
9331
9429
  }
9332
9430
  function clickUpListenerKey(config) {
9333
9431
  return `${config?.webhook?.bindHost || "127.0.0.1"}:${config?.webhook?.bindPort || 0}`;
@@ -11019,7 +11117,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
11019
11117
  }
11020
11118
  };
11021
11119
  }
11022
- OptimaPlugin.__internals = { buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentMentionsProductManager, createClickUpApiClient, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, readClickUpWebhookState, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, 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 };
11120
+ OptimaPlugin.__internals = { buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, readClickUpWebhookState, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, 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 };
11023
11121
  export {
11024
11122
  OptimaPlugin as default
11025
11123
  };
@@ -7936,6 +7936,8 @@ var CLICKUP_PM_MENTION_NAME = "Defend Tech Product Manager";
7936
7936
  var CLICKUP_WEBHOOK_RUNTIME_VERSION = 1;
7937
7937
  var CLICKUP_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
7938
7938
  var CLICKUP_WEBHOOK_REQUEST_TIMEOUT_MS = 1e4;
7939
+ var CLICKUP_WEBHOOK_LOG_LEVELS = /* @__PURE__ */ new Set(["error", "info", "verbose"]);
7940
+ var CLICKUP_WEBHOOK_REDACTED = "[REDACTED]";
7939
7941
  var DISCUSSION_BACKFILL_FETCH_LIMIT = 100;
7940
7942
  var DEFAULT_PRESERVE_EXISTING_AGENTS = true;
7941
7943
  var SAFE_WORKTREE_FAILURE = "FAIL: Optima needs a writable project directory. Open/add a project in OpenChamber first. Refusing to use '/'.";
@@ -8800,6 +8802,22 @@ function clickUpWebhookStatePath(worktree) {
8800
8802
  function clickUpWebhookLogPath(worktree) {
8801
8803
  return path2.join(optimaRuntimeDir(worktree), "clickup-webhook.log.jsonl");
8802
8804
  }
8805
+ function normalizeClickUpWebhookLogLevel(value) {
8806
+ const level = String(value || "info").trim().toLowerCase();
8807
+ return CLICKUP_WEBHOOK_LOG_LEVELS.has(level) ? level : "info";
8808
+ }
8809
+ function clickUpWebhookAuditLogDir() {
8810
+ const dataHome = process.env.XDG_DATA_HOME && path2.isAbsolute(process.env.XDG_DATA_HOME) ? process.env.XDG_DATA_HOME : path2.join(os.homedir(), ".local", "share", "opencode");
8811
+ return path2.join(dataHome, "opencode-optima");
8812
+ }
8813
+ function clickUpWebhookAuditLogPath(at = /* @__PURE__ */ new Date(), logDir = clickUpWebhookAuditLogDir()) {
8814
+ return path2.join(logDir, `clickup-webhook-${at.toISOString().slice(0, 10)}.jsonl`);
8815
+ }
8816
+ function clickUpWebhookRequestFilePath(at = /* @__PURE__ */ new Date(), logDir = clickUpWebhookAuditLogDir()) {
8817
+ const stamp = at.toISOString().replace(/:/g, "-").replace(/\./g, "-");
8818
+ const shortId = crypto.randomBytes(4).toString("hex");
8819
+ return path2.join(logDir, "requests", `clickup-webhook-${stamp}-${shortId}.json`);
8820
+ }
8803
8821
  function findOptimaPluginTupleOptions(pluginEntries = []) {
8804
8822
  if (!Array.isArray(pluginEntries)) return null;
8805
8823
  for (const entry of pluginEntries) {
@@ -8829,6 +8847,7 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
8829
8847
  basePath: String(raw.base_path || raw.basePath || worktree || "").trim(),
8830
8848
  teamId: String(raw.team_id || raw.teamId || "").trim(),
8831
8849
  apiToken: String(raw.api_token || raw.apiToken || "").trim(),
8850
+ log: normalizeClickUpWebhookLogLevel(raw.log),
8832
8851
  webhook: {
8833
8852
  publicUrl: String(webhook.public_url || webhook.publicUrl || "").trim(),
8834
8853
  bindHost: String(webhook.bind_host || webhook.bindHost || "127.0.0.1").trim(),
@@ -9219,6 +9238,74 @@ function appendClickUpWebhookLocalLog(worktree, entry) {
9219
9238
  fs2.appendFileSync(logPath, `${JSON.stringify(safeEntry)}
9220
9239
  `, "utf8");
9221
9240
  }
9241
+ function redactClickUpWebhookAuditValue(value, secretValues = []) {
9242
+ if (typeof value === "string") {
9243
+ return secretValues.reduce((next, secret) => secret ? next.split(secret).join(CLICKUP_WEBHOOK_REDACTED) : next, value);
9244
+ }
9245
+ if (Array.isArray(value)) return value.map((item) => redactClickUpWebhookAuditValue(item, secretValues));
9246
+ if (!isPlainObject(value)) return value;
9247
+ return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => {
9248
+ const normalizedKey = normalizeLooseToken(key);
9249
+ const secretKey = normalizedKey.includes("signature") || normalizedKey.includes("authorization") || normalizedKey.includes("cookie") || normalizedKey.includes("token") || normalizedKey.includes("secret") || normalizedKey.includes("api-key") || normalizedKey.includes("apikey");
9250
+ return [key, secretKey ? CLICKUP_WEBHOOK_REDACTED : redactClickUpWebhookAuditValue(entryValue, secretValues)];
9251
+ }));
9252
+ }
9253
+ function buildClickUpWebhookAuditSummary({ method, url, config, handled, error, payload, requestFile, at = /* @__PURE__ */ new Date() } = {}) {
9254
+ const result = handled?.result || {};
9255
+ const summary = {
9256
+ at: at.toISOString(),
9257
+ method,
9258
+ path: url === null ? null : new URL(String(url || "/"), config?.webhook?.publicUrl || "http://localhost").pathname,
9259
+ status: handled?.status || 500,
9260
+ ok: Boolean(handled?.ok),
9261
+ reason: handled?.reason || result.reason || (error ? "handler_error" : void 0),
9262
+ action: result.action,
9263
+ event: payload ? clickUpEventType(payload) : void 0,
9264
+ task: result.taskId || clickUpTaskIdFromPayload(payload || {}),
9265
+ comment: clickUpCommentFromPayload(payload || {})?.id || payload?.comment_id || payload?.commentId,
9266
+ session: result.sessionId,
9267
+ base_path: config?.basePath || "",
9268
+ request_file: requestFile || void 0
9269
+ };
9270
+ return Object.fromEntries(Object.entries(summary).filter(([, value]) => value !== void 0 && value !== ""));
9271
+ }
9272
+ function writeClickUpWebhookAuditLog({ method, url, headers = {}, rawBody = "", config, state = {}, handled = null, error = null, payload = null, at = /* @__PURE__ */ new Date() } = {}) {
9273
+ try {
9274
+ const level = normalizeClickUpWebhookLogLevel(config?.log);
9275
+ const failed = Boolean(error || !handled?.ok || (handled?.status || 500) >= 400);
9276
+ if (level === "error" && !failed) return;
9277
+ const logDir = clickUpWebhookAuditLogDir();
9278
+ fs2.mkdirSync(logDir, { recursive: true });
9279
+ const secretValues = [resolveSecretReference(config?.apiToken), state?.secret, config?.webhook?.secret].filter(Boolean);
9280
+ let requestFile;
9281
+ if (level === "verbose") {
9282
+ const absoluteRequestFile = clickUpWebhookRequestFilePath(at, logDir);
9283
+ fs2.mkdirSync(path2.dirname(absoluteRequestFile), { recursive: true });
9284
+ requestFile = path2.relative(logDir, absoluteRequestFile).split(path2.sep).join("/");
9285
+ const parsedBody = payload || (() => {
9286
+ try {
9287
+ return JSON.parse(Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : String(rawBody || ""));
9288
+ } catch {
9289
+ return void 0;
9290
+ }
9291
+ })();
9292
+ const requestArtifact = redactClickUpWebhookAuditValue({
9293
+ at: at.toISOString(),
9294
+ method,
9295
+ url,
9296
+ path: url === null ? null : new URL(String(url || "/"), config?.webhook?.publicUrl || "http://localhost").pathname,
9297
+ headers,
9298
+ body: parsedBody === void 0 ? Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : String(rawBody || "") : parsedBody
9299
+ }, secretValues);
9300
+ fs2.writeFileSync(absoluteRequestFile, `${JSON.stringify(requestArtifact, null, 2)}
9301
+ `, "utf8");
9302
+ }
9303
+ const summary = redactClickUpWebhookAuditValue(buildClickUpWebhookAuditSummary({ method, url, config, handled, error, payload, requestFile, at }), secretValues);
9304
+ fs2.appendFileSync(clickUpWebhookAuditLogPath(at, logDir), `${JSON.stringify(summary)}
9305
+ `, "utf8");
9306
+ } catch {
9307
+ }
9308
+ }
9222
9309
  async function withClickUpTaskRouteLock(taskId, operation) {
9223
9310
  const key = String(taskId || "");
9224
9311
  if (!key) return operation();
@@ -9316,25 +9403,36 @@ function clickUpWebhookExpectedPath(config) {
9316
9403
  return "/";
9317
9404
  }
9318
9405
  }
9319
- async function handleClickUpWebhookRequest({ method = "POST", url = null, headers = {}, rawBody = "", config, state, worktree, clickupClient, openCodeClient, saveState } = {}) {
9320
- if (method !== "POST") return { ok: false, status: 405, reason: "method_not_allowed" };
9321
- if (url !== null) {
9322
- const requestPath = new URL(String(url), config?.webhook?.publicUrl || "http://localhost").pathname;
9323
- if (requestPath !== clickUpWebhookExpectedPath(config)) return { ok: false, status: 404, reason: "wrong_path" };
9324
- }
9325
- const maxBodyBytes = Number(config?.webhook?.maxBodyBytes || CLICKUP_WEBHOOK_MAX_BODY_BYTES);
9326
- const bodyBytes = Buffer.isBuffer(rawBody) ? rawBody.length : Buffer.byteLength(String(rawBody || ""));
9327
- if (bodyBytes > maxBodyBytes) return { ok: false, status: 413, reason: "body_too_large" };
9328
- const signature = headers["x-signature"] || headers["X-Signature"];
9329
- if (!verifyClickUpSignature(rawBody, signature, state?.secret)) return { ok: false, status: 401, reason: "invalid_signature" };
9330
- let payload;
9406
+ async function handleClickUpWebhookRequest({ method = "POST", url = null, headers = {}, rawBody = "", config, state, worktree, clickupClient, openCodeClient, saveState, now = () => /* @__PURE__ */ new Date() } = {}) {
9407
+ let payload = null;
9408
+ let handled = null;
9409
+ const finish = (result) => {
9410
+ handled = result;
9411
+ writeClickUpWebhookAuditLog({ method, url, headers, rawBody, config, state, handled, payload, at: now() });
9412
+ return result;
9413
+ };
9331
9414
  try {
9332
- payload = JSON.parse(Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : String(rawBody));
9333
- } catch {
9334
- return { ok: false, status: 400, reason: "invalid_json" };
9415
+ if (method !== "POST") return finish({ ok: false, status: 405, reason: "method_not_allowed" });
9416
+ if (url !== null) {
9417
+ const requestPath = new URL(String(url), config?.webhook?.publicUrl || "http://localhost").pathname;
9418
+ if (requestPath !== clickUpWebhookExpectedPath(config)) return finish({ ok: false, status: 404, reason: "wrong_path" });
9419
+ }
9420
+ const maxBodyBytes = Number(config?.webhook?.maxBodyBytes || CLICKUP_WEBHOOK_MAX_BODY_BYTES);
9421
+ const bodyBytes = Buffer.isBuffer(rawBody) ? rawBody.length : Buffer.byteLength(String(rawBody || ""));
9422
+ if (bodyBytes > maxBodyBytes) return finish({ ok: false, status: 413, reason: "body_too_large" });
9423
+ const signature = headers["x-signature"] || headers["X-Signature"];
9424
+ if (!verifyClickUpSignature(rawBody, signature, state?.secret)) return finish({ ok: false, status: 401, reason: "invalid_signature" });
9425
+ try {
9426
+ payload = JSON.parse(Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : String(rawBody));
9427
+ } catch {
9428
+ return finish({ ok: false, status: 400, reason: "invalid_json" });
9429
+ }
9430
+ const result = await routeClickUpWebhookEvent({ payload, config, state, worktree, clickupClient, openCodeClient, saveState });
9431
+ return finish({ ok: result.ok, status: result.ok ? 200 : 422, result });
9432
+ } catch (error) {
9433
+ writeClickUpWebhookAuditLog({ method, url, headers, rawBody, config, state, handled, error, payload, at: now() });
9434
+ throw error;
9335
9435
  }
9336
- const result = await routeClickUpWebhookEvent({ payload, config, state, worktree, clickupClient, openCodeClient, saveState });
9337
- return { ok: result.ok, status: result.ok ? 200 : 422, result };
9338
9436
  }
9339
9437
  function clickUpListenerKey(config) {
9340
9438
  return `${config?.webhook?.bindHost || "127.0.0.1"}:${config?.webhook?.bindPort || 0}`;
@@ -11026,7 +11124,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
11026
11124
  }
11027
11125
  };
11028
11126
  }
11029
- OptimaPlugin.__internals = { buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentMentionsProductManager, createClickUpApiClient, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, readClickUpWebhookState, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, 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 };
11127
+ OptimaPlugin.__internals = { buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, readClickUpWebhookState, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, 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 };
11030
11128
 
11031
11129
  // src/sanitize_cli.js
11032
11130
  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.12",
3
+ "version": "0.1.13",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+ssh://git@github.com/defend-tech/opencode-optima.git"