@defend-tech/opencode-optima 0.1.59 → 0.1.60

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.
@@ -51,7 +51,9 @@ You are Workflow_Product_Manager, Optima's ClickUp-first delivery orchestrator.
51
51
 
52
52
  - Principal workspace stays on `dev`; never use `main` for delivery and never push directly to `main`.
53
53
  - Do not implement, plan, or write ClickUp task mirrors in the principal workspace. Use task-specific worktrees/branches.
54
- - To plan a ClickUp task, first create or reuse that task's branch/worktree with `optima_clickup_start_task`, then do Definition planning and local `.optima` mirror writes inside that task worktree.
54
+ - To plan a ClickUp task, first create or reuse that task's branch/worktree with `optima_clickup_start_task`; webhook-created worktrees must be provisioned or registered through the configured OpenChamber Git API (`clickup.openchamber.base_url` `/api/git/worktrees`) before local `.optima` mirror writes.
55
+ - Use `clickup.opencode.base_url` for legacy OpenCode session/prompt delivery, not as the preferred worktree creation API when `clickup.openchamber.base_url` is configured.
56
+ - If OpenChamber cannot create or verify the required branch/worktree (especially subtask start-from-parent semantics), fail closed with a ClickUp blocker comment instead of silently using raw `git worktree add`.
55
57
  - Do not update the principal `dev` workspace `.optima/tasks/current.md` for ClickUp task planning.
56
58
  - Unrelated active tasks in `.optima/tasks/current.md` must not block planning; move to/create the correct task worktree instead.
57
59
  - Parent setup pulls remote once; after parent branch creation, subtasks can trust the parent local branch without continuous remote polling.
package/dist/index.js CHANGED
@@ -9224,6 +9224,215 @@ function addClickUpWorktreeForBranch({ baseWorktree, branch, worktreePath, start
9224
9224
  runGitFn(baseWorktree, ["worktree", "add", "-b", branch, worktreePath, startPoint]);
9225
9225
  }
9226
9226
  }
9227
+ function clickUpOpenChamberWorktreeName(branch = "") {
9228
+ return String(branch || "").trim().replace(/\//g, "-");
9229
+ }
9230
+ function openChamberUrl(baseUrl, pathname, query = {}) {
9231
+ const url = new URL(pathname, normalizeOpenCodeBaseUrl(baseUrl));
9232
+ for (const [key, value] of Object.entries(query)) {
9233
+ if (value !== void 0 && value !== null && String(value).trim()) url.searchParams.set(key, String(value));
9234
+ }
9235
+ return url.toString();
9236
+ }
9237
+ async function readOpenChamberJson(response, endpoint) {
9238
+ const text = await response.text();
9239
+ let data = null;
9240
+ if (text.trim()) {
9241
+ try {
9242
+ data = JSON.parse(text);
9243
+ } catch {
9244
+ throw new Error(`OpenChamber ${endpoint} returned non-JSON response.`);
9245
+ }
9246
+ }
9247
+ if (!response.ok) {
9248
+ const message = data?.error?.message || data?.message || data?.data?.message || text.slice(0, 200) || `HTTP ${response.status}`;
9249
+ throw new Error(`OpenChamber ${endpoint} failed: ${response.status} ${message}`);
9250
+ }
9251
+ return data;
9252
+ }
9253
+ async function requestOpenChamberJson({ baseUrl, endpoint, method = "GET", directory, body, fetchImpl = globalThis.fetch } = {}) {
9254
+ if (typeof fetchImpl !== "function") throw new Error("OpenChamber worktree provisioning requires fetch.");
9255
+ const response = await fetchImpl(openChamberUrl(baseUrl, endpoint, { directory }), {
9256
+ method,
9257
+ headers: body ? { "content-type": "application/json" } : void 0,
9258
+ body: body ? JSON.stringify(body) : void 0
9259
+ });
9260
+ return readOpenChamberJson(response, endpoint);
9261
+ }
9262
+ function normalizeOpenChamberCollection(value) {
9263
+ if (Array.isArray(value)) return value;
9264
+ if (!isPlainObject(value)) return [];
9265
+ for (const key of ["worktrees", "items", "data", "result", "results", "directories", "sandboxes"]) {
9266
+ const nested = value[key];
9267
+ if (Array.isArray(nested)) return nested;
9268
+ if (isPlainObject(nested)) {
9269
+ const normalized = normalizeOpenChamberCollection(nested);
9270
+ if (normalized.length > 0) return normalized;
9271
+ }
9272
+ }
9273
+ return [];
9274
+ }
9275
+ function openChamberEntryDirectory(entry) {
9276
+ if (typeof entry === "string") return entry;
9277
+ return String(entry?.directory || entry?.path || entry?.worktreePath || entry?.worktree_path || entry?.worktree?.path || entry?.worktree?.directory || "");
9278
+ }
9279
+ function openChamberEntryBranch(entry) {
9280
+ if (typeof entry === "string") return "";
9281
+ return String(entry?.branch || entry?.branchName || entry?.branch_name || entry?.worktree?.branch || "").replace(/^refs\/heads\//, "");
9282
+ }
9283
+ function openChamberListIncludesDirectory(list, directory) {
9284
+ const resolved = path5.resolve(directory);
9285
+ return normalizeOpenChamberCollection(list).some((entry) => {
9286
+ const entryDirectory = openChamberEntryDirectory(entry);
9287
+ return entryDirectory && path5.resolve(entryDirectory) === resolved;
9288
+ });
9289
+ }
9290
+ function openChamberListIncludesBranch(list, directory, branch) {
9291
+ const resolved = path5.resolve(directory);
9292
+ return normalizeOpenChamberCollection(list).some((entry) => {
9293
+ const entryDirectory = openChamberEntryDirectory(entry);
9294
+ if (!entryDirectory || path5.resolve(entryDirectory) !== resolved) return false;
9295
+ const entryBranch = openChamberEntryBranch(entry);
9296
+ return !entryBranch || entryBranch === branch;
9297
+ });
9298
+ }
9299
+ async function findOpenChamberProject({ baseUrl, baseWorktree, fetchImpl = globalThis.fetch } = {}) {
9300
+ const projects = await requestOpenChamberJson({ baseUrl, endpoint: "/project", directory: baseWorktree, fetchImpl });
9301
+ if (!Array.isArray(projects)) return null;
9302
+ const resolvedBase = path5.resolve(baseWorktree);
9303
+ return projects.find((project) => path5.resolve(String(project?.worktree || project?.path || "")) === resolvedBase) || null;
9304
+ }
9305
+ async function refreshOpenChamberProjectCopy({ baseUrl, baseWorktree, projectId, fetchImpl = globalThis.fetch } = {}) {
9306
+ if (!projectId) return { refreshed: false, reason: "project_id_unavailable" };
9307
+ const response = await fetchImpl(openChamberUrl(baseUrl, `/experimental/project/${encodeURIComponent(projectId)}/copy/refresh`, {}), { method: "POST" });
9308
+ await readOpenChamberJson(response, "/experimental/project/{projectID}/copy/refresh");
9309
+ return { refreshed: true, projectId };
9310
+ }
9311
+ async function listOpenChamberGitWorktrees({ baseUrl, baseWorktree, fetchImpl = globalThis.fetch } = {}) {
9312
+ return requestOpenChamberJson({ baseUrl, endpoint: "/api/git/worktrees", directory: baseWorktree, fetchImpl });
9313
+ }
9314
+ async function verifyOpenChamberGitWorktree({ baseUrl, baseWorktree, worktreePath, branch, fetchImpl = globalThis.fetch } = {}) {
9315
+ const worktrees = await listOpenChamberGitWorktrees({ baseUrl, baseWorktree, fetchImpl });
9316
+ const verified = openChamberListIncludesBranch(worktrees, worktreePath, branch);
9317
+ if (!verified) {
9318
+ throw new Error(`OpenChamber Git worktree verification failed for ${worktreePath} on ${branch}.`);
9319
+ }
9320
+ return { worktree: true, branch: true };
9321
+ }
9322
+ async function syncOpenChamberWorktreeVisibility({ baseUrl, baseWorktree, worktreePath, branch, fetchImpl = globalThis.fetch } = {}) {
9323
+ const gitWorktree = await verifyOpenChamberGitWorktree({ baseUrl, baseWorktree, worktreePath, branch, fetchImpl });
9324
+ await requestOpenChamberJson({ baseUrl, endpoint: "/experimental/workspace/sync-list", method: "POST", directory: baseWorktree, fetchImpl });
9325
+ const project = await findOpenChamberProject({ baseUrl, baseWorktree, fetchImpl });
9326
+ if (!project?.id) throw new Error("OpenChamber project was not found after workspace sync; refusing to treat worktree as visible.");
9327
+ await refreshOpenChamberProjectCopy({ baseUrl, baseWorktree, projectId: project.id, fetchImpl });
9328
+ const [worktrees, workspaces, directories] = await Promise.all([
9329
+ listOpenChamberGitWorktrees({ baseUrl, baseWorktree, fetchImpl }),
9330
+ requestOpenChamberJson({ baseUrl, endpoint: "/experimental/workspace", directory: baseWorktree, fetchImpl }),
9331
+ requestOpenChamberJson({ baseUrl, endpoint: `/project/${encodeURIComponent(project.id)}/directories`, directory: baseWorktree, fetchImpl })
9332
+ ]);
9333
+ const visibility = {
9334
+ worktree: openChamberListIncludesBranch(worktrees, worktreePath, branch),
9335
+ workspace: openChamberListIncludesBranch(workspaces, worktreePath, branch),
9336
+ projectDirectory: openChamberListIncludesDirectory(directories, worktreePath),
9337
+ gitWorktree,
9338
+ projectId: project.id
9339
+ };
9340
+ if (!visibility.worktree || !visibility.workspace || !visibility.projectDirectory) {
9341
+ throw new Error(`OpenChamber visibility verification failed for ${worktreePath}: ${JSON.stringify(visibility)}`);
9342
+ }
9343
+ return visibility;
9344
+ }
9345
+ function assertOpenChamberClickUpWorktreePath({ baseWorktree, worktreePath } = {}) {
9346
+ if (!isClickUpDerivedWorktreeSibling(worktreePath, baseWorktree)) {
9347
+ throw new Error(`OpenChamber worktree path is outside the configured ClickUp sibling scope: ${worktreePath}`);
9348
+ }
9349
+ }
9350
+ async function createOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch, worktreePath, startPoint, branchExists = false, fetchImpl = globalThis.fetch } = {}) {
9351
+ const worktreeName = clickUpOpenChamberWorktreeName(branch);
9352
+ const body = { name: worktreeName, mode: branchExists ? "existing" : "new", worktreeName, branchName: branch, startRef: branchExists ? branch : startPoint };
9353
+ let created;
9354
+ try {
9355
+ created = await requestOpenChamberJson({ baseUrl, endpoint: "/api/git/worktrees", method: "POST", directory: baseWorktree, body, fetchImpl });
9356
+ } catch (error) {
9357
+ throw new Error(`OpenChamber could not create ${branch} from ${branchExists ? branch : startPoint}; API may not support required branch/startRef semantics. Fail-closed: ${error.message}`);
9358
+ }
9359
+ const createdDirectory = openChamberEntryDirectory(created);
9360
+ const createdBranch = openChamberEntryBranch(created);
9361
+ if (!createdDirectory || !path5.isAbsolute(createdDirectory)) {
9362
+ throw new Error(`OpenChamber did not return an absolute worktree path for ${branch}.`);
9363
+ }
9364
+ if (createdBranch !== branch) {
9365
+ throw new Error(`OpenChamber created unexpected branch ${createdBranch || "<unknown>"}; expected ${branch}.`);
9366
+ }
9367
+ const verified = await verifyOpenChamberGitWorktree({ baseUrl, baseWorktree, worktreePath: createdDirectory, branch, fetchImpl });
9368
+ return { created, worktree: path5.resolve(createdDirectory), branch: createdBranch, verified };
9369
+ }
9370
+ async function registerOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch, worktreePath, fetchImpl = globalThis.fetch, source = "reuse" } = {}) {
9371
+ assertOpenChamberClickUpWorktreePath({ baseWorktree, worktreePath });
9372
+ const visibility = await syncOpenChamberWorktreeVisibility({ baseUrl, baseWorktree, worktreePath, branch, fetchImpl });
9373
+ return { branch, worktree: path5.resolve(worktreePath), reused: true, provider: "openchamber", openChamber: { source, visibility } };
9374
+ }
9375
+ async function ensureClickUpTaskWorktreeOpenChamber({ baseWorktree = "", taskId, taskType = "Tarea", parentTaskId = "", subtaskId = "", existingMetadata = {}, runGitFn = runGit, baseUrl = "", fetchImpl = globalThis.fetch, log = null } = {}) {
9376
+ const effectiveParent = parentTaskId || taskId;
9377
+ const isSubtask = isClickUpSubtaskRoute({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9378
+ const parentBranch = isSubtask ? deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent }) : "";
9379
+ const branch = deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9380
+ const prTarget = parentBranch || "dev";
9381
+ const existing = safeExistingClickUpWorktree({ metadata: existingMetadata, branch });
9382
+ if (existing) {
9383
+ const registered = await registerOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch, worktreePath: existing.worktree, fetchImpl, source: "metadata_reuse" });
9384
+ log?.({ type: "openchamber_worktree_registered", taskId, branch, worktree: registered.worktree, source: "metadata_reuse", visibility: registered.openChamber.visibility });
9385
+ return { ...registered, parentBranch: parentBranch || void 0, prTarget };
9386
+ }
9387
+ const worktreePath = deriveClickUpWorktree({ baseWorktree, taskId, taskType, parentTaskId: effectiveParent, subtaskId });
9388
+ if (fs5.existsSync(worktreePath)) {
9389
+ const registered = await registerOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch, worktreePath, fetchImpl, source: "existing_directory" });
9390
+ log?.({ type: "openchamber_worktree_registered", taskId, branch, worktree: registered.worktree, source: "existing_directory", visibility: registered.openChamber.visibility });
9391
+ return { ...registered, parentBranch: parentBranch || void 0, prTarget };
9392
+ }
9393
+ let parentBootstrap = null;
9394
+ if (isSubtask) {
9395
+ const parentWorktree = deriveClickUpWorktree({ baseWorktree, taskId: effectiveParent, taskType, parentTaskId: effectiveParent });
9396
+ if (fs5.existsSync(parentWorktree)) {
9397
+ const registeredParent = await registerOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch: parentBranch, worktreePath: parentWorktree, fetchImpl, source: "parent_existing_directory" });
9398
+ parentBootstrap = { branch: parentBranch, worktree: registeredParent.worktree, reused: true, provider: "openchamber", visibility: registeredParent.openChamber.visibility };
9399
+ } else {
9400
+ const parentStartPoint = resolveClickUpDevStartPoint(baseWorktree, runGitFn);
9401
+ const parentBranchExists = clickUpGitRefExists(baseWorktree, parentBranch, runGitFn);
9402
+ const createdParent = await createOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch: parentBranch, worktreePath: parentWorktree, startPoint: parentStartPoint, branchExists: parentBranchExists, fetchImpl });
9403
+ const parentVisibility = await syncOpenChamberWorktreeVisibility({ baseUrl, baseWorktree, worktreePath: createdParent.worktree, branch: parentBranch, fetchImpl });
9404
+ parentBootstrap = { branch: parentBranch, worktree: createdParent.worktree, startPoint: parentBranchExists ? parentBranch : parentStartPoint, reused: parentBranchExists, provider: "openchamber", visibility: parentVisibility };
9405
+ log?.({ type: "openchamber_worktree_created", taskId: effectiveParent, branch: parentBranch, worktree: parentBootstrap.worktree, startPoint: parentBootstrap.startPoint, visibility: parentVisibility });
9406
+ }
9407
+ }
9408
+ const startPoint = isSubtask ? parentBranch : resolveClickUpDevStartPoint(baseWorktree, runGitFn);
9409
+ const branchExists = clickUpGitRefExists(baseWorktree, branch, runGitFn);
9410
+ const created = await createOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch, worktreePath, startPoint, branchExists, fetchImpl });
9411
+ const visibility = await syncOpenChamberWorktreeVisibility({ baseUrl, baseWorktree, worktreePath: created.worktree, branch, fetchImpl });
9412
+ log?.({ type: "openchamber_worktree_created", taskId, branch, worktree: created.worktree, startPoint: branchExists ? branch : startPoint, visibility });
9413
+ return { branch, worktree: created.worktree, reused: false, startPoint, parentBranch: parentBranch || void 0, prTarget, parentBootstrap: parentBootstrap || void 0, provider: "openchamber", openChamber: { source: "created", visibility } };
9414
+ }
9415
+ async function ensureClickUpTaskWorktreeForWebhook({ opencodeBaseUrl = "", opencodeBaseUrlConfigured = false, openchamberBaseUrl = "", openchamberBaseUrlConfigured = false, clickupClient = null, webhookWorktree = process.cwd(), fetchImpl = globalThis.fetch, ...options } = {}) {
9416
+ void opencodeBaseUrl;
9417
+ void opencodeBaseUrlConfigured;
9418
+ if (!openchamberBaseUrlConfigured || !openchamberBaseUrl) return ensureClickUpTaskWorktree(options);
9419
+ try {
9420
+ return await ensureClickUpTaskWorktreeOpenChamber({ ...options, baseUrl: openchamberBaseUrl, fetchImpl, log: (entry) => appendClickUpWebhookLocalLog(webhookWorktree, entry) });
9421
+ } catch (error) {
9422
+ const message = `OpenChamber worktree provisioning failed for ${options.taskId || "unknown task"}; raw git fallback is disabled to avoid invisible worktrees. ${error.message}`;
9423
+ appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_failed", taskId: options.taskId || null, message });
9424
+ if (typeof clickupClient?.postTaskComment === "function") {
9425
+ try {
9426
+ await clickupClient.postTaskComment({ taskId: options.taskId, comment: `${message}
9427
+
9428
+ Optima did not run raw git worktree fallback. Please verify clickup.openchamber.base_url and OpenChamber Git API compatibility.` });
9429
+ } catch (commentError) {
9430
+ appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_blocker_comment_failed", taskId: options.taskId || null, message: commentError.message });
9431
+ }
9432
+ }
9433
+ throw new Error(message);
9434
+ }
9435
+ }
9227
9436
  function ensureClickUpTaskWorktree({ baseWorktree = "", taskId, taskType = "Tarea", parentTaskId = "", subtaskId = "", existingMetadata = {}, runGitFn = runGit, allowNonGitFallback = false } = {}) {
9228
9437
  const effectiveParent = parentTaskId || taskId;
9229
9438
  const isSubtask = isClickUpSubtaskRoute({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
@@ -9585,6 +9794,11 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
9585
9794
  const webhook = isPlainObject(raw.webhook) ? raw.webhook : {};
9586
9795
  const routing = isPlainObject(raw.routing) ? raw.routing : {};
9587
9796
  const opencode = isPlainObject(raw.opencode) ? raw.opencode : {};
9797
+ const openchamber = isPlainObject(raw.openchamber) ? raw.openchamber : {};
9798
+ const rawOpenCodeBaseUrl = opencode.base_url ?? opencode.baseUrl ?? raw.opencode_base_url ?? raw.opencodeBaseUrl;
9799
+ const rawOpenChamberBaseUrl = openchamber.base_url ?? openchamber.baseUrl ?? raw.openchamber_base_url ?? raw.openchamberBaseUrl;
9800
+ const openCodeBaseUrlConfigured = rawOpenCodeBaseUrl !== void 0 && rawOpenCodeBaseUrl !== null && String(rawOpenCodeBaseUrl).trim() !== "";
9801
+ const openChamberBaseUrlConfigured = rawOpenChamberBaseUrl !== void 0 && rawOpenChamberBaseUrl !== null && String(rawOpenChamberBaseUrl).trim() !== "";
9588
9802
  const location = isPlainObject(webhook.location) ? webhook.location : {};
9589
9803
  const events = Array.isArray(webhook.events) && webhook.events.length > 0 ? [...new Set(webhook.events.map((event) => String(event || "").trim()).filter(Boolean))] : [...CLICKUP_WEBHOOK_EVENTS];
9590
9804
  const ignoredStatuses = Array.isArray(routing.ignored_statuses) && routing.ignored_statuses.length > 0 ? routing.ignored_statuses : CLICKUP_WEBHOOK_TERMINAL_STATUSES;
@@ -9596,7 +9810,8 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
9596
9810
  apiToken: String(raw.api_token || raw.apiToken || "").trim(),
9597
9811
  log: normalizeClickUpWebhookLogLevel(raw.log),
9598
9812
  opencode: {
9599
- baseUrl: normalizeOpenCodeBaseUrl(opencode.base_url || opencode.baseUrl || raw.opencode_base_url || raw.opencodeBaseUrl),
9813
+ baseUrl: normalizeOpenCodeBaseUrl(rawOpenCodeBaseUrl),
9814
+ baseUrlConfigured: openCodeBaseUrlConfigured,
9600
9815
  promptDelivery: ["http", "direct"].includes(String(opencode.prompt_delivery || opencode.promptDelivery || raw.prompt_delivery || raw.promptDelivery || "").trim().toLowerCase()) ? "http" : "sdk",
9601
9816
  acceptPromptAdmission: opencode.accept_prompt_admission === true || opencode.acceptPromptAdmission === true || raw.accept_prompt_admission === true || raw.acceptPromptAdmission === true,
9602
9817
  startupReconciliationDelayMs: normalizeNonNegativeInteger(
@@ -9604,6 +9819,10 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
9604
9819
  CLICKUP_WEBHOOK_STARTUP_RECONCILIATION_DELAY_MS
9605
9820
  )
9606
9821
  },
9822
+ openchamber: {
9823
+ baseUrl: normalizeOpenCodeBaseUrl(rawOpenChamberBaseUrl, ""),
9824
+ baseUrlConfigured: openChamberBaseUrlConfigured
9825
+ },
9607
9826
  webhook: {
9608
9827
  publicUrl: String(webhook.public_url || webhook.publicUrl || "").trim(),
9609
9828
  bindHost: String(webhook.bind_host || webhook.bindHost || "127.0.0.1").trim(),
@@ -9645,6 +9864,13 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
9645
9864
  errors.push("clickup.opencode.base_url must be a valid URL");
9646
9865
  }
9647
9866
  }
9867
+ if (config.openchamber.baseUrl) {
9868
+ try {
9869
+ new URL(config.openchamber.baseUrl);
9870
+ } catch {
9871
+ errors.push("clickup.openchamber.base_url must be a valid URL");
9872
+ }
9873
+ }
9648
9874
  const missingEvents = CLICKUP_WEBHOOK_EVENTS.filter((event) => !config.webhook.events.includes(event));
9649
9875
  if (missingEvents.length > 0) errors.push(`clickup.webhook.events missing: ${missingEvents.join(", ")}`);
9650
9876
  if (config.routing.targetAgent !== "workflow_product_manager") errors.push("clickup.routing.target_agent must be workflow_product_manager");
@@ -10934,7 +11160,7 @@ async function withClickUpTaskRouteLock(taskId, operation) {
10934
11160
  if (activeClickUpTaskRoutes.get(key) === current) activeClickUpTaskRoutes.delete(key);
10935
11161
  }
10936
11162
  }
10937
- 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) } = {}) {
11163
+ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, worktree = process.cwd(), clickupClient, openCodeClient, sessionExists = openCodeSessionExists, createSession = createOpenCodeSession, sendSessionEvent = sendOpenCodeSessionEvent, ensureTaskWorktree = ensureClickUpTaskWorktreeForWebhook, verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, saveState = null, now = () => /* @__PURE__ */ new Date(), host = os.hostname(), commentLedgerPath = clickUpCommentLedgerPath(worktree) } = {}) {
10938
11164
  const eventType = clickUpEventType(payload);
10939
11165
  const eventKey = clickUpWebhookEventKey(payload);
10940
11166
  const isStartupAssignmentReconciliation = payload?.startup_reconciliation === true && eventType === "taskAssigneeUpdated";
@@ -10990,7 +11216,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
10990
11216
  const subtaskId = parentTaskId && parentTaskId !== taskId ? taskId : "";
10991
11217
  let taskRoute;
10992
11218
  try {
10993
- taskRoute = ensureTaskWorktree({ baseWorktree: config.basePath, taskId, taskType, parentTaskId, subtaskId, existingMetadata: metadata, allowNonGitFallback: process.env.NODE_ENV === "test" || config.test === true });
11219
+ taskRoute = await ensureTaskWorktree({ baseWorktree: config.basePath, taskId, taskType, parentTaskId, subtaskId, existingMetadata: metadata, allowNonGitFallback: process.env.NODE_ENV === "test" || config.test === true, opencodeBaseUrl: config.opencode?.baseUrl, opencodeBaseUrlConfigured: config.opencode?.baseUrlConfigured === true, openchamberBaseUrl: config.openchamber?.baseUrl, openchamberBaseUrlConfigured: config.openchamber?.baseUrlConfigured === true, clickupClient, webhookWorktree: worktree });
10994
11220
  } catch (error) {
10995
11221
  const message = `Optima webhook could not create or reuse a task worktree for ${taskId}: ${error.message}`;
10996
11222
  appendClickUpWebhookLocalLog(worktree, { type: "task_worktree_failed", taskId, message });
@@ -13149,7 +13375,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
13149
13375
  }
13150
13376
  };
13151
13377
  }
13152
- 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, compactPromptPath, createClickUpApiClient, createTestClickUpApiClient, createOpenCodeSession, createOpenCodeSessionControl, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpDerivedWorktreeSibling, isClickUpSubtaskRoute, isClickUpWebhookStateActive, isSameOrNestedPath, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, openCodeSessionExists, promptOpenCodeSessionControl, probeOpenCodeSessionControl, readClickUpCommentLedger, readClickUpWebhookState, readOpenCodeSessionControl, readOpenCodeSessionMessages, reconcileClickUpStartup, scheduleClickUpStartupReconciliation, waitForOpenCodeReadiness, recordClickUpCommentVersionProcessed, resyncClickUpWebhookForSignatureDrift, resolveIncludeFile, resolveIncludes, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, summarizeOpenCodeMessages, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatRepairResult, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, optimaRepairDependencies, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, planOptimaRepair, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
13378
+ 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, compactPromptPath, createClickUpApiClient, createTestClickUpApiClient, createOpenCodeSession, createOpenCodeSessionControl, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpTaskWorktreeForWebhook, ensureClickUpTaskWorktreeOpenChamber, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpDerivedWorktreeSibling, isClickUpSubtaskRoute, isClickUpWebhookStateActive, isSameOrNestedPath, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, openCodeSessionExists, promptOpenCodeSessionControl, probeOpenCodeSessionControl, readClickUpCommentLedger, readClickUpWebhookState, readOpenCodeSessionControl, readOpenCodeSessionMessages, reconcileClickUpStartup, registerOpenChamberClickUpWorktree, scheduleClickUpStartupReconciliation, syncOpenChamberWorktreeVisibility, waitForOpenCodeReadiness, recordClickUpCommentVersionProcessed, resyncClickUpWebhookForSignatureDrift, resolveIncludeFile, resolveIncludes, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, summarizeOpenCodeMessages, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatRepairResult, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, optimaRepairDependencies, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, planOptimaRepair, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
13153
13379
  export {
13154
13380
  OptimaPlugin as default
13155
13381
  };
@@ -9231,6 +9231,215 @@ function addClickUpWorktreeForBranch({ baseWorktree, branch, worktreePath, start
9231
9231
  runGitFn(baseWorktree, ["worktree", "add", "-b", branch, worktreePath, startPoint]);
9232
9232
  }
9233
9233
  }
9234
+ function clickUpOpenChamberWorktreeName(branch = "") {
9235
+ return String(branch || "").trim().replace(/\//g, "-");
9236
+ }
9237
+ function openChamberUrl(baseUrl, pathname, query = {}) {
9238
+ const url = new URL(pathname, normalizeOpenCodeBaseUrl(baseUrl));
9239
+ for (const [key, value] of Object.entries(query)) {
9240
+ if (value !== void 0 && value !== null && String(value).trim()) url.searchParams.set(key, String(value));
9241
+ }
9242
+ return url.toString();
9243
+ }
9244
+ async function readOpenChamberJson(response, endpoint) {
9245
+ const text = await response.text();
9246
+ let data = null;
9247
+ if (text.trim()) {
9248
+ try {
9249
+ data = JSON.parse(text);
9250
+ } catch {
9251
+ throw new Error(`OpenChamber ${endpoint} returned non-JSON response.`);
9252
+ }
9253
+ }
9254
+ if (!response.ok) {
9255
+ const message = data?.error?.message || data?.message || data?.data?.message || text.slice(0, 200) || `HTTP ${response.status}`;
9256
+ throw new Error(`OpenChamber ${endpoint} failed: ${response.status} ${message}`);
9257
+ }
9258
+ return data;
9259
+ }
9260
+ async function requestOpenChamberJson({ baseUrl, endpoint, method = "GET", directory, body, fetchImpl = globalThis.fetch } = {}) {
9261
+ if (typeof fetchImpl !== "function") throw new Error("OpenChamber worktree provisioning requires fetch.");
9262
+ const response = await fetchImpl(openChamberUrl(baseUrl, endpoint, { directory }), {
9263
+ method,
9264
+ headers: body ? { "content-type": "application/json" } : void 0,
9265
+ body: body ? JSON.stringify(body) : void 0
9266
+ });
9267
+ return readOpenChamberJson(response, endpoint);
9268
+ }
9269
+ function normalizeOpenChamberCollection(value) {
9270
+ if (Array.isArray(value)) return value;
9271
+ if (!isPlainObject(value)) return [];
9272
+ for (const key of ["worktrees", "items", "data", "result", "results", "directories", "sandboxes"]) {
9273
+ const nested = value[key];
9274
+ if (Array.isArray(nested)) return nested;
9275
+ if (isPlainObject(nested)) {
9276
+ const normalized = normalizeOpenChamberCollection(nested);
9277
+ if (normalized.length > 0) return normalized;
9278
+ }
9279
+ }
9280
+ return [];
9281
+ }
9282
+ function openChamberEntryDirectory(entry) {
9283
+ if (typeof entry === "string") return entry;
9284
+ return String(entry?.directory || entry?.path || entry?.worktreePath || entry?.worktree_path || entry?.worktree?.path || entry?.worktree?.directory || "");
9285
+ }
9286
+ function openChamberEntryBranch(entry) {
9287
+ if (typeof entry === "string") return "";
9288
+ return String(entry?.branch || entry?.branchName || entry?.branch_name || entry?.worktree?.branch || "").replace(/^refs\/heads\//, "");
9289
+ }
9290
+ function openChamberListIncludesDirectory(list, directory) {
9291
+ const resolved = path5.resolve(directory);
9292
+ return normalizeOpenChamberCollection(list).some((entry) => {
9293
+ const entryDirectory = openChamberEntryDirectory(entry);
9294
+ return entryDirectory && path5.resolve(entryDirectory) === resolved;
9295
+ });
9296
+ }
9297
+ function openChamberListIncludesBranch(list, directory, branch) {
9298
+ const resolved = path5.resolve(directory);
9299
+ return normalizeOpenChamberCollection(list).some((entry) => {
9300
+ const entryDirectory = openChamberEntryDirectory(entry);
9301
+ if (!entryDirectory || path5.resolve(entryDirectory) !== resolved) return false;
9302
+ const entryBranch = openChamberEntryBranch(entry);
9303
+ return !entryBranch || entryBranch === branch;
9304
+ });
9305
+ }
9306
+ async function findOpenChamberProject({ baseUrl, baseWorktree, fetchImpl = globalThis.fetch } = {}) {
9307
+ const projects = await requestOpenChamberJson({ baseUrl, endpoint: "/project", directory: baseWorktree, fetchImpl });
9308
+ if (!Array.isArray(projects)) return null;
9309
+ const resolvedBase = path5.resolve(baseWorktree);
9310
+ return projects.find((project) => path5.resolve(String(project?.worktree || project?.path || "")) === resolvedBase) || null;
9311
+ }
9312
+ async function refreshOpenChamberProjectCopy({ baseUrl, baseWorktree, projectId, fetchImpl = globalThis.fetch } = {}) {
9313
+ if (!projectId) return { refreshed: false, reason: "project_id_unavailable" };
9314
+ const response = await fetchImpl(openChamberUrl(baseUrl, `/experimental/project/${encodeURIComponent(projectId)}/copy/refresh`, {}), { method: "POST" });
9315
+ await readOpenChamberJson(response, "/experimental/project/{projectID}/copy/refresh");
9316
+ return { refreshed: true, projectId };
9317
+ }
9318
+ async function listOpenChamberGitWorktrees({ baseUrl, baseWorktree, fetchImpl = globalThis.fetch } = {}) {
9319
+ return requestOpenChamberJson({ baseUrl, endpoint: "/api/git/worktrees", directory: baseWorktree, fetchImpl });
9320
+ }
9321
+ async function verifyOpenChamberGitWorktree({ baseUrl, baseWorktree, worktreePath, branch, fetchImpl = globalThis.fetch } = {}) {
9322
+ const worktrees = await listOpenChamberGitWorktrees({ baseUrl, baseWorktree, fetchImpl });
9323
+ const verified = openChamberListIncludesBranch(worktrees, worktreePath, branch);
9324
+ if (!verified) {
9325
+ throw new Error(`OpenChamber Git worktree verification failed for ${worktreePath} on ${branch}.`);
9326
+ }
9327
+ return { worktree: true, branch: true };
9328
+ }
9329
+ async function syncOpenChamberWorktreeVisibility({ baseUrl, baseWorktree, worktreePath, branch, fetchImpl = globalThis.fetch } = {}) {
9330
+ const gitWorktree = await verifyOpenChamberGitWorktree({ baseUrl, baseWorktree, worktreePath, branch, fetchImpl });
9331
+ await requestOpenChamberJson({ baseUrl, endpoint: "/experimental/workspace/sync-list", method: "POST", directory: baseWorktree, fetchImpl });
9332
+ const project = await findOpenChamberProject({ baseUrl, baseWorktree, fetchImpl });
9333
+ if (!project?.id) throw new Error("OpenChamber project was not found after workspace sync; refusing to treat worktree as visible.");
9334
+ await refreshOpenChamberProjectCopy({ baseUrl, baseWorktree, projectId: project.id, fetchImpl });
9335
+ const [worktrees, workspaces, directories] = await Promise.all([
9336
+ listOpenChamberGitWorktrees({ baseUrl, baseWorktree, fetchImpl }),
9337
+ requestOpenChamberJson({ baseUrl, endpoint: "/experimental/workspace", directory: baseWorktree, fetchImpl }),
9338
+ requestOpenChamberJson({ baseUrl, endpoint: `/project/${encodeURIComponent(project.id)}/directories`, directory: baseWorktree, fetchImpl })
9339
+ ]);
9340
+ const visibility = {
9341
+ worktree: openChamberListIncludesBranch(worktrees, worktreePath, branch),
9342
+ workspace: openChamberListIncludesBranch(workspaces, worktreePath, branch),
9343
+ projectDirectory: openChamberListIncludesDirectory(directories, worktreePath),
9344
+ gitWorktree,
9345
+ projectId: project.id
9346
+ };
9347
+ if (!visibility.worktree || !visibility.workspace || !visibility.projectDirectory) {
9348
+ throw new Error(`OpenChamber visibility verification failed for ${worktreePath}: ${JSON.stringify(visibility)}`);
9349
+ }
9350
+ return visibility;
9351
+ }
9352
+ function assertOpenChamberClickUpWorktreePath({ baseWorktree, worktreePath } = {}) {
9353
+ if (!isClickUpDerivedWorktreeSibling(worktreePath, baseWorktree)) {
9354
+ throw new Error(`OpenChamber worktree path is outside the configured ClickUp sibling scope: ${worktreePath}`);
9355
+ }
9356
+ }
9357
+ async function createOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch, worktreePath, startPoint, branchExists = false, fetchImpl = globalThis.fetch } = {}) {
9358
+ const worktreeName = clickUpOpenChamberWorktreeName(branch);
9359
+ const body = { name: worktreeName, mode: branchExists ? "existing" : "new", worktreeName, branchName: branch, startRef: branchExists ? branch : startPoint };
9360
+ let created;
9361
+ try {
9362
+ created = await requestOpenChamberJson({ baseUrl, endpoint: "/api/git/worktrees", method: "POST", directory: baseWorktree, body, fetchImpl });
9363
+ } catch (error) {
9364
+ throw new Error(`OpenChamber could not create ${branch} from ${branchExists ? branch : startPoint}; API may not support required branch/startRef semantics. Fail-closed: ${error.message}`);
9365
+ }
9366
+ const createdDirectory = openChamberEntryDirectory(created);
9367
+ const createdBranch = openChamberEntryBranch(created);
9368
+ if (!createdDirectory || !path5.isAbsolute(createdDirectory)) {
9369
+ throw new Error(`OpenChamber did not return an absolute worktree path for ${branch}.`);
9370
+ }
9371
+ if (createdBranch !== branch) {
9372
+ throw new Error(`OpenChamber created unexpected branch ${createdBranch || "<unknown>"}; expected ${branch}.`);
9373
+ }
9374
+ const verified = await verifyOpenChamberGitWorktree({ baseUrl, baseWorktree, worktreePath: createdDirectory, branch, fetchImpl });
9375
+ return { created, worktree: path5.resolve(createdDirectory), branch: createdBranch, verified };
9376
+ }
9377
+ async function registerOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch, worktreePath, fetchImpl = globalThis.fetch, source = "reuse" } = {}) {
9378
+ assertOpenChamberClickUpWorktreePath({ baseWorktree, worktreePath });
9379
+ const visibility = await syncOpenChamberWorktreeVisibility({ baseUrl, baseWorktree, worktreePath, branch, fetchImpl });
9380
+ return { branch, worktree: path5.resolve(worktreePath), reused: true, provider: "openchamber", openChamber: { source, visibility } };
9381
+ }
9382
+ async function ensureClickUpTaskWorktreeOpenChamber({ baseWorktree = "", taskId, taskType = "Tarea", parentTaskId = "", subtaskId = "", existingMetadata = {}, runGitFn = runGit, baseUrl = "", fetchImpl = globalThis.fetch, log = null } = {}) {
9383
+ const effectiveParent = parentTaskId || taskId;
9384
+ const isSubtask = isClickUpSubtaskRoute({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9385
+ const parentBranch = isSubtask ? deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent }) : "";
9386
+ const branch = deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9387
+ const prTarget = parentBranch || "dev";
9388
+ const existing = safeExistingClickUpWorktree({ metadata: existingMetadata, branch });
9389
+ if (existing) {
9390
+ const registered = await registerOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch, worktreePath: existing.worktree, fetchImpl, source: "metadata_reuse" });
9391
+ log?.({ type: "openchamber_worktree_registered", taskId, branch, worktree: registered.worktree, source: "metadata_reuse", visibility: registered.openChamber.visibility });
9392
+ return { ...registered, parentBranch: parentBranch || void 0, prTarget };
9393
+ }
9394
+ const worktreePath = deriveClickUpWorktree({ baseWorktree, taskId, taskType, parentTaskId: effectiveParent, subtaskId });
9395
+ if (fs5.existsSync(worktreePath)) {
9396
+ const registered = await registerOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch, worktreePath, fetchImpl, source: "existing_directory" });
9397
+ log?.({ type: "openchamber_worktree_registered", taskId, branch, worktree: registered.worktree, source: "existing_directory", visibility: registered.openChamber.visibility });
9398
+ return { ...registered, parentBranch: parentBranch || void 0, prTarget };
9399
+ }
9400
+ let parentBootstrap = null;
9401
+ if (isSubtask) {
9402
+ const parentWorktree = deriveClickUpWorktree({ baseWorktree, taskId: effectiveParent, taskType, parentTaskId: effectiveParent });
9403
+ if (fs5.existsSync(parentWorktree)) {
9404
+ const registeredParent = await registerOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch: parentBranch, worktreePath: parentWorktree, fetchImpl, source: "parent_existing_directory" });
9405
+ parentBootstrap = { branch: parentBranch, worktree: registeredParent.worktree, reused: true, provider: "openchamber", visibility: registeredParent.openChamber.visibility };
9406
+ } else {
9407
+ const parentStartPoint = resolveClickUpDevStartPoint(baseWorktree, runGitFn);
9408
+ const parentBranchExists = clickUpGitRefExists(baseWorktree, parentBranch, runGitFn);
9409
+ const createdParent = await createOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch: parentBranch, worktreePath: parentWorktree, startPoint: parentStartPoint, branchExists: parentBranchExists, fetchImpl });
9410
+ const parentVisibility = await syncOpenChamberWorktreeVisibility({ baseUrl, baseWorktree, worktreePath: createdParent.worktree, branch: parentBranch, fetchImpl });
9411
+ parentBootstrap = { branch: parentBranch, worktree: createdParent.worktree, startPoint: parentBranchExists ? parentBranch : parentStartPoint, reused: parentBranchExists, provider: "openchamber", visibility: parentVisibility };
9412
+ log?.({ type: "openchamber_worktree_created", taskId: effectiveParent, branch: parentBranch, worktree: parentBootstrap.worktree, startPoint: parentBootstrap.startPoint, visibility: parentVisibility });
9413
+ }
9414
+ }
9415
+ const startPoint = isSubtask ? parentBranch : resolveClickUpDevStartPoint(baseWorktree, runGitFn);
9416
+ const branchExists = clickUpGitRefExists(baseWorktree, branch, runGitFn);
9417
+ const created = await createOpenChamberClickUpWorktree({ baseUrl, baseWorktree, branch, worktreePath, startPoint, branchExists, fetchImpl });
9418
+ const visibility = await syncOpenChamberWorktreeVisibility({ baseUrl, baseWorktree, worktreePath: created.worktree, branch, fetchImpl });
9419
+ log?.({ type: "openchamber_worktree_created", taskId, branch, worktree: created.worktree, startPoint: branchExists ? branch : startPoint, visibility });
9420
+ return { branch, worktree: created.worktree, reused: false, startPoint, parentBranch: parentBranch || void 0, prTarget, parentBootstrap: parentBootstrap || void 0, provider: "openchamber", openChamber: { source: "created", visibility } };
9421
+ }
9422
+ async function ensureClickUpTaskWorktreeForWebhook({ opencodeBaseUrl = "", opencodeBaseUrlConfigured = false, openchamberBaseUrl = "", openchamberBaseUrlConfigured = false, clickupClient = null, webhookWorktree = process.cwd(), fetchImpl = globalThis.fetch, ...options } = {}) {
9423
+ void opencodeBaseUrl;
9424
+ void opencodeBaseUrlConfigured;
9425
+ if (!openchamberBaseUrlConfigured || !openchamberBaseUrl) return ensureClickUpTaskWorktree(options);
9426
+ try {
9427
+ return await ensureClickUpTaskWorktreeOpenChamber({ ...options, baseUrl: openchamberBaseUrl, fetchImpl, log: (entry) => appendClickUpWebhookLocalLog(webhookWorktree, entry) });
9428
+ } catch (error) {
9429
+ const message = `OpenChamber worktree provisioning failed for ${options.taskId || "unknown task"}; raw git fallback is disabled to avoid invisible worktrees. ${error.message}`;
9430
+ appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_failed", taskId: options.taskId || null, message });
9431
+ if (typeof clickupClient?.postTaskComment === "function") {
9432
+ try {
9433
+ await clickupClient.postTaskComment({ taskId: options.taskId, comment: `${message}
9434
+
9435
+ Optima did not run raw git worktree fallback. Please verify clickup.openchamber.base_url and OpenChamber Git API compatibility.` });
9436
+ } catch (commentError) {
9437
+ appendClickUpWebhookLocalLog(webhookWorktree, { type: "openchamber_worktree_blocker_comment_failed", taskId: options.taskId || null, message: commentError.message });
9438
+ }
9439
+ }
9440
+ throw new Error(message);
9441
+ }
9442
+ }
9234
9443
  function ensureClickUpTaskWorktree({ baseWorktree = "", taskId, taskType = "Tarea", parentTaskId = "", subtaskId = "", existingMetadata = {}, runGitFn = runGit, allowNonGitFallback = false } = {}) {
9235
9444
  const effectiveParent = parentTaskId || taskId;
9236
9445
  const isSubtask = isClickUpSubtaskRoute({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
@@ -9592,6 +9801,11 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
9592
9801
  const webhook = isPlainObject(raw.webhook) ? raw.webhook : {};
9593
9802
  const routing = isPlainObject(raw.routing) ? raw.routing : {};
9594
9803
  const opencode = isPlainObject(raw.opencode) ? raw.opencode : {};
9804
+ const openchamber = isPlainObject(raw.openchamber) ? raw.openchamber : {};
9805
+ const rawOpenCodeBaseUrl = opencode.base_url ?? opencode.baseUrl ?? raw.opencode_base_url ?? raw.opencodeBaseUrl;
9806
+ const rawOpenChamberBaseUrl = openchamber.base_url ?? openchamber.baseUrl ?? raw.openchamber_base_url ?? raw.openchamberBaseUrl;
9807
+ const openCodeBaseUrlConfigured = rawOpenCodeBaseUrl !== void 0 && rawOpenCodeBaseUrl !== null && String(rawOpenCodeBaseUrl).trim() !== "";
9808
+ const openChamberBaseUrlConfigured = rawOpenChamberBaseUrl !== void 0 && rawOpenChamberBaseUrl !== null && String(rawOpenChamberBaseUrl).trim() !== "";
9595
9809
  const location = isPlainObject(webhook.location) ? webhook.location : {};
9596
9810
  const events = Array.isArray(webhook.events) && webhook.events.length > 0 ? [...new Set(webhook.events.map((event) => String(event || "").trim()).filter(Boolean))] : [...CLICKUP_WEBHOOK_EVENTS];
9597
9811
  const ignoredStatuses = Array.isArray(routing.ignored_statuses) && routing.ignored_statuses.length > 0 ? routing.ignored_statuses : CLICKUP_WEBHOOK_TERMINAL_STATUSES;
@@ -9603,7 +9817,8 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
9603
9817
  apiToken: String(raw.api_token || raw.apiToken || "").trim(),
9604
9818
  log: normalizeClickUpWebhookLogLevel(raw.log),
9605
9819
  opencode: {
9606
- baseUrl: normalizeOpenCodeBaseUrl(opencode.base_url || opencode.baseUrl || raw.opencode_base_url || raw.opencodeBaseUrl),
9820
+ baseUrl: normalizeOpenCodeBaseUrl(rawOpenCodeBaseUrl),
9821
+ baseUrlConfigured: openCodeBaseUrlConfigured,
9607
9822
  promptDelivery: ["http", "direct"].includes(String(opencode.prompt_delivery || opencode.promptDelivery || raw.prompt_delivery || raw.promptDelivery || "").trim().toLowerCase()) ? "http" : "sdk",
9608
9823
  acceptPromptAdmission: opencode.accept_prompt_admission === true || opencode.acceptPromptAdmission === true || raw.accept_prompt_admission === true || raw.acceptPromptAdmission === true,
9609
9824
  startupReconciliationDelayMs: normalizeNonNegativeInteger(
@@ -9611,6 +9826,10 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
9611
9826
  CLICKUP_WEBHOOK_STARTUP_RECONCILIATION_DELAY_MS
9612
9827
  )
9613
9828
  },
9829
+ openchamber: {
9830
+ baseUrl: normalizeOpenCodeBaseUrl(rawOpenChamberBaseUrl, ""),
9831
+ baseUrlConfigured: openChamberBaseUrlConfigured
9832
+ },
9614
9833
  webhook: {
9615
9834
  publicUrl: String(webhook.public_url || webhook.publicUrl || "").trim(),
9616
9835
  bindHost: String(webhook.bind_host || webhook.bindHost || "127.0.0.1").trim(),
@@ -9652,6 +9871,13 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
9652
9871
  errors.push("clickup.opencode.base_url must be a valid URL");
9653
9872
  }
9654
9873
  }
9874
+ if (config.openchamber.baseUrl) {
9875
+ try {
9876
+ new URL(config.openchamber.baseUrl);
9877
+ } catch {
9878
+ errors.push("clickup.openchamber.base_url must be a valid URL");
9879
+ }
9880
+ }
9655
9881
  const missingEvents = CLICKUP_WEBHOOK_EVENTS.filter((event) => !config.webhook.events.includes(event));
9656
9882
  if (missingEvents.length > 0) errors.push(`clickup.webhook.events missing: ${missingEvents.join(", ")}`);
9657
9883
  if (config.routing.targetAgent !== "workflow_product_manager") errors.push("clickup.routing.target_agent must be workflow_product_manager");
@@ -10941,7 +11167,7 @@ async function withClickUpTaskRouteLock(taskId, operation) {
10941
11167
  if (activeClickUpTaskRoutes.get(key) === current) activeClickUpTaskRoutes.delete(key);
10942
11168
  }
10943
11169
  }
10944
- 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) } = {}) {
11170
+ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, worktree = process.cwd(), clickupClient, openCodeClient, sessionExists = openCodeSessionExists, createSession = createOpenCodeSession, sendSessionEvent = sendOpenCodeSessionEvent, ensureTaskWorktree = ensureClickUpTaskWorktreeForWebhook, verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, saveState = null, now = () => /* @__PURE__ */ new Date(), host = os.hostname(), commentLedgerPath = clickUpCommentLedgerPath(worktree) } = {}) {
10945
11171
  const eventType = clickUpEventType(payload);
10946
11172
  const eventKey = clickUpWebhookEventKey(payload);
10947
11173
  const isStartupAssignmentReconciliation = payload?.startup_reconciliation === true && eventType === "taskAssigneeUpdated";
@@ -10997,7 +11223,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
10997
11223
  const subtaskId = parentTaskId && parentTaskId !== taskId ? taskId : "";
10998
11224
  let taskRoute;
10999
11225
  try {
11000
- taskRoute = ensureTaskWorktree({ baseWorktree: config.basePath, taskId, taskType, parentTaskId, subtaskId, existingMetadata: metadata, allowNonGitFallback: process.env.NODE_ENV === "test" || config.test === true });
11226
+ taskRoute = await ensureTaskWorktree({ baseWorktree: config.basePath, taskId, taskType, parentTaskId, subtaskId, existingMetadata: metadata, allowNonGitFallback: process.env.NODE_ENV === "test" || config.test === true, opencodeBaseUrl: config.opencode?.baseUrl, opencodeBaseUrlConfigured: config.opencode?.baseUrlConfigured === true, openchamberBaseUrl: config.openchamber?.baseUrl, openchamberBaseUrlConfigured: config.openchamber?.baseUrlConfigured === true, clickupClient, webhookWorktree: worktree });
11001
11227
  } catch (error) {
11002
11228
  const message = `Optima webhook could not create or reuse a task worktree for ${taskId}: ${error.message}`;
11003
11229
  appendClickUpWebhookLocalLog(worktree, { type: "task_worktree_failed", taskId, message });
@@ -13156,7 +13382,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
13156
13382
  }
13157
13383
  };
13158
13384
  }
13159
- 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, compactPromptPath, createClickUpApiClient, createTestClickUpApiClient, createOpenCodeSession, createOpenCodeSessionControl, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpDerivedWorktreeSibling, isClickUpSubtaskRoute, isClickUpWebhookStateActive, isSameOrNestedPath, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, openCodeSessionExists, promptOpenCodeSessionControl, probeOpenCodeSessionControl, readClickUpCommentLedger, readClickUpWebhookState, readOpenCodeSessionControl, readOpenCodeSessionMessages, reconcileClickUpStartup, scheduleClickUpStartupReconciliation, waitForOpenCodeReadiness, recordClickUpCommentVersionProcessed, resyncClickUpWebhookForSignatureDrift, resolveIncludeFile, resolveIncludes, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, summarizeOpenCodeMessages, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatRepairResult, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, optimaRepairDependencies, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, planOptimaRepair, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
13385
+ 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, compactPromptPath, createClickUpApiClient, createTestClickUpApiClient, createOpenCodeSession, createOpenCodeSessionControl, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpTaskWorktreeForWebhook, ensureClickUpTaskWorktreeOpenChamber, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpDerivedWorktreeSibling, isClickUpSubtaskRoute, isClickUpWebhookStateActive, isSameOrNestedPath, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, openCodeSessionExists, promptOpenCodeSessionControl, probeOpenCodeSessionControl, readClickUpCommentLedger, readClickUpWebhookState, readOpenCodeSessionControl, readOpenCodeSessionMessages, reconcileClickUpStartup, registerOpenChamberClickUpWorktree, scheduleClickUpStartupReconciliation, syncOpenChamberWorktreeVisibility, waitForOpenCodeReadiness, recordClickUpCommentVersionProcessed, resyncClickUpWebhookForSignatureDrift, resolveIncludeFile, resolveIncludes, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, summarizeOpenCodeMessages, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatRepairResult, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, optimaRepairDependencies, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, planOptimaRepair, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
13160
13386
 
13161
13387
  // src/sanitize_cli.js
13162
13388
  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.59",
3
+ "version": "0.1.60",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+ssh://git@github.com/defend-tech/opencode-optima.git"