@defend-tech/opencode-optima 0.1.57 → 0.1.59

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.
@@ -55,8 +55,8 @@ You are Workflow_Product_Manager, Optima's ClickUp-first delivery orchestrator.
55
55
  - Do not update the principal `dev` workspace `.optima/tasks/current.md` for ClickUp task planning.
56
56
  - Unrelated active tasks in `.optima/tasks/current.md` must not block planning; move to/create the correct task worktree instead.
57
57
  - Parent setup pulls remote once; after parent branch creation, subtasks can trust the parent local branch without continuous remote polling.
58
- - Branches: parent `<clickup-task-type>/<parent-task-id>`; subtask `<clickup-task-type>/<parent-task-id>/<subtask-id>`; PoC always `poc/<clickup-task-id>` and remains there unless productized later.
59
- - PR targets: subtask -> parent branch; parent -> `dev` only after Tech Lead + Validator/QA pass and `CTO`/`PO` move to `merge`; release -> `dev` to `main` only after explicit approval.
58
+ - Branches: parent `<clickup-task-type>/<parent-task-id>`; subtask `<clickup-task-type>/<parent-task-id>-subtask-<subtask-id>`; pending planned subtasks `<clickup-task-type>/<parent-task-id>-pending-<title-slug>`; PoC always `poc/<clickup-task-id>` and remains there unless productized later.
59
+ - PR targets/start points: subtask -> parent branch and starts from the parent branch; if parent branch/worktree is missing, bootstrap the parent from `dev`/`origin/dev` first; parent -> `dev` only after Tech Lead + Validator/QA pass and `CTO`/`PO` move to `merge`; release -> `dev` to `main` only after explicit approval.
60
60
  - Preserve user work and unrelated dirty files. Stop and ask if unexpected changes appear.
61
61
 
62
62
  ## Operating Style
package/dist/index.js CHANGED
@@ -632,8 +632,6 @@ var require_Alias = __commonJS({
632
632
  * instance of the `source` anchor before this node.
633
633
  */
634
634
  resolve(doc, ctx) {
635
- if (ctx?.maxAliasCount === 0)
636
- throw new ReferenceError("Alias resolution is disabled");
637
635
  let nodes;
638
636
  if (ctx?.aliasResolveCache) {
639
637
  nodes = ctx.aliasResolveCache;
@@ -1433,7 +1431,6 @@ var require_stringify = __commonJS({
1433
1431
  nullStr: "null",
1434
1432
  simpleKeys: false,
1435
1433
  singleQuote: null,
1436
- trailingComma: false,
1437
1434
  trueStr: "true",
1438
1435
  verifyAliasOrder: true
1439
1436
  }, doc.schema.toStringOptions, options);
@@ -1706,18 +1703,18 @@ var require_merge = __commonJS({
1706
1703
  };
1707
1704
  var isMergeKey = (ctx, key) => (merge.identify(key) || identity.isScalar(key) && (!key.type || key.type === Scalar.Scalar.PLAIN) && merge.identify(key.value)) && ctx?.doc.schema.tags.some((tag) => tag.tag === merge.tag && tag.default);
1708
1705
  function addMergeToJSMap(ctx, map, value) {
1709
- const source = resolveAliasValue(ctx, value);
1710
- if (identity.isSeq(source))
1711
- for (const it of source.items)
1706
+ value = ctx && identity.isAlias(value) ? value.resolve(ctx.doc) : value;
1707
+ if (identity.isSeq(value))
1708
+ for (const it of value.items)
1712
1709
  mergeValue(ctx, map, it);
1713
- else if (Array.isArray(source))
1714
- for (const it of source)
1710
+ else if (Array.isArray(value))
1711
+ for (const it of value)
1715
1712
  mergeValue(ctx, map, it);
1716
1713
  else
1717
- mergeValue(ctx, map, source);
1714
+ mergeValue(ctx, map, value);
1718
1715
  }
1719
1716
  function mergeValue(ctx, map, value) {
1720
- const source = resolveAliasValue(ctx, value);
1717
+ const source = ctx && identity.isAlias(value) ? value.resolve(ctx.doc) : value;
1721
1718
  if (!identity.isMap(source))
1722
1719
  throw new Error("Merge sources must be maps or map aliases");
1723
1720
  const srcMap = source.toJSON(null, ctx, Map);
@@ -1738,9 +1735,6 @@ var require_merge = __commonJS({
1738
1735
  }
1739
1736
  return map;
1740
1737
  }
1741
- function resolveAliasValue(ctx, value) {
1742
- return ctx && identity.isAlias(value) ? value.resolve(ctx.doc, ctx) : value;
1743
- }
1744
1738
  exports.addMergeToJSMap = addMergeToJSMap;
1745
1739
  exports.isMergeKey = isMergeKey;
1746
1740
  exports.merge = merge;
@@ -1954,19 +1948,12 @@ ${indent}${line}` : "\n";
1954
1948
  if (comment)
1955
1949
  reqNewline = true;
1956
1950
  let str = stringify.stringify(item, itemCtx, () => comment = null);
1957
- reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
1958
- if (i < items.length - 1) {
1951
+ if (i < items.length - 1)
1959
1952
  str += ",";
1960
- } else if (ctx.options.trailingComma) {
1961
- if (ctx.options.lineWidth > 0) {
1962
- reqNewline || (reqNewline = lines.reduce((sum, line) => sum + line.length + 2, 2) + (str.length + 2) > ctx.options.lineWidth);
1963
- }
1964
- if (reqNewline) {
1965
- str += ",";
1966
- }
1967
- }
1968
1953
  if (comment)
1969
1954
  str += stringifyComment.lineComment(str, itemIndent, commentString(comment));
1955
+ if (!reqNewline && (lines.length > linesAtValue || str.includes("\n")))
1956
+ reqNewline = true;
1970
1957
  lines.push(str);
1971
1958
  linesAtValue = lines.length;
1972
1959
  }
@@ -2378,7 +2365,7 @@ var require_stringifyNumber = __commonJS({
2378
2365
  if (!isFinite(num))
2379
2366
  return isNaN(num) ? ".nan" : num < 0 ? "-.inf" : ".inf";
2380
2367
  let n = Object.is(value, -0) ? "-0" : JSON.stringify(value);
2381
- if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^-?\d/.test(n) && !n.includes("e")) {
2368
+ if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^\d/.test(n)) {
2382
2369
  let i = n.indexOf(".");
2383
2370
  if (i < 0) {
2384
2371
  i = n.length;
@@ -4750,7 +4737,7 @@ var require_resolve_flow_scalar = __commonJS({
4750
4737
  while (next === " " || next === " ")
4751
4738
  next = source[++i + 1];
4752
4739
  } else if (next === "x" || next === "u" || next === "U") {
4753
- const length = next === "x" ? 2 : next === "u" ? 4 : 8;
4740
+ const length = { x: 2, u: 4, U: 8 }[next];
4754
4741
  res += parseCharCode(source, i + 1, length, onError);
4755
4742
  i += length;
4756
4743
  } else {
@@ -4825,13 +4812,12 @@ var require_resolve_flow_scalar = __commonJS({
4825
4812
  const cc = source.substr(offset, length);
4826
4813
  const ok = cc.length === length && /^[0-9a-fA-F]+$/.test(cc);
4827
4814
  const code = ok ? parseInt(cc, 16) : NaN;
4828
- try {
4829
- return String.fromCodePoint(code);
4830
- } catch {
4815
+ if (isNaN(code)) {
4831
4816
  const raw = source.substr(offset - 2, length + 2);
4832
4817
  onError(offset - 2, "BAD_DQ_ESCAPE", `Invalid escape sequence ${raw}`);
4833
4818
  return raw;
4834
4819
  }
4820
+ return String.fromCodePoint(code);
4835
4821
  }
4836
4822
  exports.resolveFlowScalar = resolveFlowScalar;
4837
4823
  }
@@ -4981,22 +4967,17 @@ var require_compose_node = __commonJS({
4981
4967
  case "block-map":
4982
4968
  case "block-seq":
4983
4969
  case "flow-collection":
4984
- try {
4985
- node = composeCollection.composeCollection(CN, ctx, token, props, onError);
4986
- if (anchor)
4987
- node.anchor = anchor.source.substring(1);
4988
- } catch (error) {
4989
- const message = error instanceof Error ? error.message : String(error);
4990
- onError(token, "RESOURCE_EXHAUSTION", message);
4991
- }
4970
+ node = composeCollection.composeCollection(CN, ctx, token, props, onError);
4971
+ if (anchor)
4972
+ node.anchor = anchor.source.substring(1);
4992
4973
  break;
4993
4974
  default: {
4994
4975
  const message = token.type === "error" ? token.message : `Unsupported token (type: ${token.type})`;
4995
4976
  onError(token, "UNEXPECTED_TOKEN", message);
4977
+ node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError);
4996
4978
  isSrcToken = false;
4997
4979
  }
4998
4980
  }
4999
- node ?? (node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError));
5000
4981
  if (anchor && node.anchor === "")
5001
4982
  onError(anchor, "BAD_ALIAS", "Anchor cannot be an empty string");
5002
4983
  if (atKey && ctx.options.stringKeys && (!identity.isScalar(node) || typeof node.value !== "string" || node.tag && node.tag !== "tag:yaml.org,2002:str")) {
@@ -5181,10 +5162,8 @@ ${cb}` : comment;
5181
5162
  }
5182
5163
  }
5183
5164
  if (afterDoc) {
5184
- for (let i = 0; i < this.errors.length; ++i)
5185
- doc.errors.push(this.errors[i]);
5186
- for (let i = 0; i < this.warnings.length; ++i)
5187
- doc.warnings.push(this.warnings[i]);
5165
+ Array.prototype.push.apply(doc.errors, this.errors);
5166
+ Array.prototype.push.apply(doc.warnings, this.warnings);
5188
5167
  } else {
5189
5168
  doc.errors = this.errors;
5190
5169
  doc.warnings = this.warnings;
@@ -5917,7 +5896,7 @@ var require_lexer = __commonJS({
5917
5896
  const n = (yield* this.pushCount(1)) + (yield* this.pushSpaces(true));
5918
5897
  this.indentNext = this.indentValue + 1;
5919
5898
  this.indentValue += n;
5920
- return "block-start";
5899
+ return yield* this.parseBlockStart();
5921
5900
  }
5922
5901
  return "doc";
5923
5902
  }
@@ -6216,38 +6195,28 @@ var require_lexer = __commonJS({
6216
6195
  return 0;
6217
6196
  }
6218
6197
  *pushIndicators() {
6219
- let n = 0;
6220
- loop: while (true) {
6221
- switch (this.charAt(0)) {
6222
- case "!":
6223
- n += yield* this.pushTag();
6224
- n += yield* this.pushSpaces(true);
6225
- continue loop;
6226
- case "&":
6227
- n += yield* this.pushUntil(isNotAnchorChar);
6228
- n += yield* this.pushSpaces(true);
6229
- continue loop;
6230
- case "-":
6231
- // this is an error
6232
- case "?":
6233
- // this is an error outside flow collections
6234
- case ":": {
6235
- const inFlow = this.flowLevel > 0;
6236
- const ch1 = this.charAt(1);
6237
- if (isEmpty(ch1) || inFlow && flowIndicatorChars.has(ch1)) {
6238
- if (!inFlow)
6239
- this.indentNext = this.indentValue + 1;
6240
- else if (this.flowKey)
6241
- this.flowKey = false;
6242
- n += yield* this.pushCount(1);
6243
- n += yield* this.pushSpaces(true);
6244
- continue loop;
6245
- }
6198
+ switch (this.charAt(0)) {
6199
+ case "!":
6200
+ return (yield* this.pushTag()) + (yield* this.pushSpaces(true)) + (yield* this.pushIndicators());
6201
+ case "&":
6202
+ return (yield* this.pushUntil(isNotAnchorChar)) + (yield* this.pushSpaces(true)) + (yield* this.pushIndicators());
6203
+ case "-":
6204
+ // this is an error
6205
+ case "?":
6206
+ // this is an error outside flow collections
6207
+ case ":": {
6208
+ const inFlow = this.flowLevel > 0;
6209
+ const ch1 = this.charAt(1);
6210
+ if (isEmpty(ch1) || inFlow && flowIndicatorChars.has(ch1)) {
6211
+ if (!inFlow)
6212
+ this.indentNext = this.indentValue + 1;
6213
+ else if (this.flowKey)
6214
+ this.flowKey = false;
6215
+ return (yield* this.pushCount(1)) + (yield* this.pushSpaces(true)) + (yield* this.pushIndicators());
6246
6216
  }
6247
6217
  }
6248
- break loop;
6249
6218
  }
6250
- return n;
6219
+ return 0;
6251
6220
  }
6252
6221
  *pushTag() {
6253
6222
  if (this.charAt(1) === "<") {
@@ -6406,13 +6375,6 @@ var require_parser = __commonJS({
6406
6375
  }
6407
6376
  return prev.splice(i, prev.length);
6408
6377
  }
6409
- function arrayPushArray(target, source) {
6410
- if (source.length < 1e5)
6411
- Array.prototype.push.apply(target, source);
6412
- else
6413
- for (let i = 0; i < source.length; ++i)
6414
- target.push(source[i]);
6415
- }
6416
6378
  function fixFlowSeqItems(fc) {
6417
6379
  if (fc.start.type === "flow-seq-start") {
6418
6380
  for (const it of fc.items) {
@@ -6422,11 +6384,11 @@ var require_parser = __commonJS({
6422
6384
  delete it.key;
6423
6385
  if (isFlowToken(it.value)) {
6424
6386
  if (it.value.end)
6425
- arrayPushArray(it.value.end, it.sep);
6387
+ Array.prototype.push.apply(it.value.end, it.sep);
6426
6388
  else
6427
6389
  it.value.end = it.sep;
6428
6390
  } else
6429
- arrayPushArray(it.start, it.sep);
6391
+ Array.prototype.push.apply(it.start, it.sep);
6430
6392
  delete it.sep;
6431
6393
  }
6432
6394
  }
@@ -6781,7 +6743,7 @@ var require_parser = __commonJS({
6781
6743
  const prev = map.items[map.items.length - 2];
6782
6744
  const end = prev?.value?.end;
6783
6745
  if (Array.isArray(end)) {
6784
- arrayPushArray(end, it.start);
6746
+ Array.prototype.push.apply(end, it.start);
6785
6747
  end.push(this.sourceToken);
6786
6748
  map.items.pop();
6787
6749
  return;
@@ -6969,7 +6931,7 @@ var require_parser = __commonJS({
6969
6931
  const prev = seq.items[seq.items.length - 2];
6970
6932
  const end = prev?.value?.end;
6971
6933
  if (Array.isArray(end)) {
6972
- arrayPushArray(end, it.start);
6934
+ Array.prototype.push.apply(end, it.start);
6973
6935
  end.push(this.sourceToken);
6974
6936
  seq.items.pop();
6975
6937
  return;
@@ -8841,7 +8803,13 @@ function deriveClickUpBranchName({ taskType, parentTaskId, subtaskId, taskId } =
8841
8803
  throw new Error("taskType and parentTaskId/taskId are required to derive a ClickUp branch name.");
8842
8804
  }
8843
8805
  if (typeSlug === "poc") return ["poc", parentSlug].join("/");
8844
- return [typeSlug, parentSlug, subtaskSlug].filter(Boolean).join("/");
8806
+ if (subtaskSlug) return `${typeSlug}/${parentSlug}-subtask-${subtaskSlug}`;
8807
+ return [typeSlug, parentSlug].join("/");
8808
+ }
8809
+ function isClickUpSubtaskRoute({ taskType, parentTaskId, subtaskId, taskId } = {}) {
8810
+ return Boolean(
8811
+ normalizeClickUpTaskType(taskType) !== "poc" && subtaskId && parentTaskId && String(parentTaskId) !== String(taskId || subtaskId)
8812
+ );
8845
8813
  }
8846
8814
  function deriveClickUpPrTarget({ isRelease = false, parentTaskId, parentBranch, parentTaskType, taskType, devBranch = "dev", mainBranch = "main" } = {}) {
8847
8815
  if (isRelease) return mainBranch;
@@ -9030,15 +8998,17 @@ function deriveClickUpPendingSubtaskBranch({ taskType, parentTaskId, title } = {
9030
8998
  const parentSlug = branchSafeClickUpId(parentTaskId);
9031
8999
  if (!typeSlug || !parentSlug) throw new Error("taskType and parentTaskId are required to derive a pending subtask branch name.");
9032
9000
  if (typeSlug === "poc") return ["poc", parentSlug].join("/");
9033
- return [typeSlug, parentSlug, `pending-${normalizeLooseToken(title) || "subtask"}`].join("/");
9001
+ return `${typeSlug}/${parentSlug}-pending-${normalizeLooseToken(title) || "subtask"}`;
9034
9002
  }
9035
- function buildClickUpSubtaskAgentMetadata({ parentTaskId, subtask, branch, prTarget, titleSlug } = {}) {
9003
+ function buildClickUpSubtaskAgentMetadata({ parentTaskId, subtask, branch, prTarget, titleSlug, parentBranch } = {}) {
9036
9004
  return mergeClickUpAgentMetadata("", {
9037
9005
  subtask: {
9038
9006
  parent_task_id: parentTaskId,
9007
+ parent_branch: parentBranch || prTarget,
9039
9008
  title: subtask.title,
9040
9009
  title_slug: titleSlug,
9041
9010
  branch,
9011
+ subtask_branch: branch,
9042
9012
  pr_target: prTarget,
9043
9013
  pending_clickup_subtask_id: true,
9044
9014
  owner_role: subtask.ownerRole,
@@ -9058,7 +9028,7 @@ function buildClickUpCreateSubtasksPayload({ parentTaskId, markdown = "", source
9058
9028
  const titleSlug = normalizeLooseToken(subtask.title) || "subtask";
9059
9029
  const branch = subtask.branch || deriveClickUpPendingSubtaskBranch({ taskType: subtask.type, parentTaskId: parentId, title: subtask.title });
9060
9030
  const prTarget = normalizeClickUpTaskType(subtask.type) === "poc" ? "dev" : parentBranchValue;
9061
- const agentMetadata = buildClickUpSubtaskAgentMetadata({ parentTaskId: parentId, subtask, branch, prTarget, titleSlug });
9031
+ const agentMetadata = buildClickUpSubtaskAgentMetadata({ parentTaskId: parentId, subtask, branch, prTarget, titleSlug, parentBranch: parentBranchValue });
9062
9032
  const descriptionParts = [
9063
9033
  subtask.description,
9064
9034
  subtask.acceptanceCriteria.length ? ["Acceptance Criteria:", ...subtask.acceptanceCriteria.map((item) => `- ${item}`)].join("\n") : ""
@@ -9236,27 +9206,52 @@ function safeExistingClickUpWorktree({ metadata = {}, branch = "" } = {}) {
9236
9206
  return null;
9237
9207
  }
9238
9208
  }
9209
+ function clickUpGitRefExists(baseWorktree, ref, runGitFn = runGit) {
9210
+ try {
9211
+ runGitFn(baseWorktree, ["rev-parse", "--verify", ref]);
9212
+ return true;
9213
+ } catch {
9214
+ return false;
9215
+ }
9216
+ }
9217
+ function resolveClickUpDevStartPoint(baseWorktree, runGitFn = runGit) {
9218
+ return clickUpGitRefExists(baseWorktree, "dev", runGitFn) ? "dev" : "origin/dev";
9219
+ }
9220
+ function addClickUpWorktreeForBranch({ baseWorktree, branch, worktreePath, startPoint, runGitFn = runGit } = {}) {
9221
+ if (clickUpGitRefExists(baseWorktree, branch, runGitFn)) {
9222
+ runGitFn(baseWorktree, ["worktree", "add", worktreePath, branch]);
9223
+ } else {
9224
+ runGitFn(baseWorktree, ["worktree", "add", "-b", branch, worktreePath, startPoint]);
9225
+ }
9226
+ }
9239
9227
  function ensureClickUpTaskWorktree({ baseWorktree = "", taskId, taskType = "Tarea", parentTaskId = "", subtaskId = "", existingMetadata = {}, runGitFn = runGit, allowNonGitFallback = false } = {}) {
9240
9228
  const effectiveParent = parentTaskId || taskId;
9229
+ const isSubtask = isClickUpSubtaskRoute({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9230
+ const parentBranch = isSubtask ? deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent }) : "";
9241
9231
  const branch = deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9242
9232
  const existing = safeExistingClickUpWorktree({ metadata: existingMetadata, branch });
9243
- if (existing) return { ...existing, branch };
9233
+ if (existing) return { ...existing, branch, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev" };
9244
9234
  const worktreePath = deriveClickUpWorktree({ baseWorktree, taskId, taskType, parentTaskId: effectiveParent, subtaskId });
9245
- if (fs5.existsSync(worktreePath)) return { branch, worktree: path5.resolve(worktreePath), reused: true };
9235
+ if (fs5.existsSync(worktreePath)) return { branch, worktree: path5.resolve(worktreePath), reused: true, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev" };
9246
9236
  if (allowNonGitFallback) {
9247
9237
  fs5.mkdirSync(worktreePath, { recursive: true });
9248
- return { branch, worktree: path5.resolve(worktreePath), reused: false, fallback: "non_git" };
9238
+ return { branch, worktree: path5.resolve(worktreePath), reused: false, fallback: "non_git", parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev", startPoint: parentBranch || "dev" };
9249
9239
  }
9250
- const startPoint = (() => {
9251
- try {
9252
- runGitFn(baseWorktree, ["rev-parse", "--verify", "dev"]);
9253
- return "dev";
9254
- } catch {
9255
- return "origin/dev";
9240
+ let parentBootstrap = null;
9241
+ if (isSubtask) {
9242
+ const parentWorktree = deriveClickUpWorktree({ baseWorktree, taskId: effectiveParent, taskType, parentTaskId: effectiveParent });
9243
+ if (!fs5.existsSync(parentWorktree)) {
9244
+ const parentStartPoint = resolveClickUpDevStartPoint(baseWorktree, runGitFn);
9245
+ const parentBranchExists = clickUpGitRefExists(baseWorktree, parentBranch, runGitFn);
9246
+ addClickUpWorktreeForBranch({ baseWorktree, branch: parentBranch, worktreePath: parentWorktree, startPoint: parentStartPoint, runGitFn });
9247
+ parentBootstrap = { branch: parentBranch, worktree: path5.resolve(parentWorktree), startPoint: parentBranchExists ? parentBranch : parentStartPoint, reused: parentBranchExists };
9248
+ } else {
9249
+ parentBootstrap = { branch: parentBranch, worktree: path5.resolve(parentWorktree), reused: true };
9256
9250
  }
9257
- })();
9258
- runGitFn(baseWorktree, ["worktree", "add", "-b", branch, worktreePath, startPoint]);
9259
- return { branch, worktree: path5.resolve(worktreePath), reused: false, startPoint };
9251
+ }
9252
+ const startPoint = isSubtask ? parentBranch : resolveClickUpDevStartPoint(baseWorktree, runGitFn);
9253
+ addClickUpWorktreeForBranch({ baseWorktree, branch, worktreePath, startPoint, runGitFn });
9254
+ return { branch, worktree: path5.resolve(worktreePath), reused: false, startPoint, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev", parentBootstrap: parentBootstrap || void 0 };
9260
9255
  }
9261
9256
  function normalizeClickUpDefinitionDocParent(parent = {}) {
9262
9257
  const docId = String(parent.doc_id || parent.docId || CLICKUP_DEFINITION_DOC_PARENT.doc_id).trim();
@@ -9278,13 +9273,22 @@ function buildClickUpStartTaskPayload({ taskId, taskType = "Tarea", parentTaskId
9278
9273
  if (!description) errors.push("taskDescription is required for the initial ClickUp task description rewrite.");
9279
9274
  if (errors.length > 0) return clickUpPayloadValidationError(errors);
9280
9275
  const effectiveParent = parentTaskId || taskId;
9276
+ const isSubtask = isClickUpSubtaskRoute({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9277
+ const parentBranch = isSubtask ? deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent }) : "";
9281
9278
  const branch = deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9282
9279
  const worktree = deriveClickUpWorktree({ baseWorktree, taskId, taskType, parentTaskId: effectiveParent, subtaskId });
9280
+ const prTarget = isSubtask ? parentBranch : "dev";
9281
+ const startFrom = isSubtask ? parentBranch : "dev";
9283
9282
  const estimate = preEstimateClickUpWork({ complexity, filesChanged, acceptanceCriteria, unknowns });
9284
9283
  const metadata = mergeClickUpAgentMetadata(existingAgentMetadata, {
9285
9284
  task: {
9285
+ parent_task_id: isSubtask ? effectiveParent : void 0,
9286
+ parent_branch: parentBranch || void 0,
9286
9287
  branch,
9288
+ subtask_branch: isSubtask ? branch : void 0,
9287
9289
  worktree,
9290
+ subtask_worktree: isSubtask ? worktree : void 0,
9291
+ pr_target: prTarget,
9288
9292
  mirror_task_path: `.optima/tasks/${branchSafeClickUpId(taskId || subtaskId || effectiveParent)}.md`,
9289
9293
  evidence_path: `.optima/evidences/${branchSafeClickUpId(taskId || subtaskId || effectiveParent)}/SUMMARY.md`,
9290
9294
  delivery_evidence_path: deliveryEvidencePathForClickUpTask(taskId || subtaskId || effectiveParent),
@@ -9297,17 +9301,18 @@ function buildClickUpStartTaskPayload({ taskId, taskType = "Tarea", parentTaskId
9297
9301
  dryRun: true,
9298
9302
  required_first_actions: [
9299
9303
  "Create or reuse the task-specific branch/worktree before planning or writing local .optima mirrors.",
9300
- `Use branch ${branch} from dev and worktree ${worktree} for this task workspace.`,
9304
+ `Use branch ${branch} from ${startFrom} and worktree ${worktree} for this task workspace.`,
9301
9305
  "Write planning state, .optima/tasks/current.md, task mirrors, and local evidence only inside the task worktree.",
9302
9306
  `Write merge-trackable final evidence under ${deliveryEvidencePathForClickUpTask(taskId || subtaskId || effectiveParent)}; .optima remains local mirror/staging.`,
9303
9307
  "Do not update the principal dev workspace .optima/tasks/current.md for ClickUp task planning.",
9304
9308
  "If another active task is present in current.md, move to or create this task worktree instead of stopping."
9305
9309
  ],
9306
9310
  git: {
9307
- startFrom: "dev",
9311
+ startFrom,
9308
9312
  branch,
9309
9313
  worktree,
9310
- prTarget: subtaskId && normalizeClickUpTaskType(taskType) !== "poc" ? deriveClickUpPrTarget({ parentTaskId: effectiveParent, parentTaskType: taskType }) : "dev"
9314
+ parentBranch: parentBranch || void 0,
9315
+ prTarget
9311
9316
  },
9312
9317
  mirror: {
9313
9318
  taskPath: `.optima/tasks/${branchSafeClickUpId(taskId || subtaskId || effectiveParent)}.md`,
@@ -9319,7 +9324,7 @@ function buildClickUpStartTaskPayload({ taskId, taskType = "Tarea", parentTaskId
9319
9324
  wouldCreate: true
9320
9325
  },
9321
9326
  clickup: {
9322
- comment: `Starting task from dev. Branch: ${branch}. Worktree: ${worktree}. Delivery evidence: ${deliveryEvidencePathForClickUpTask(taskId || subtaskId || effectiveParent)}.`,
9327
+ comment: `Starting task from ${startFrom}. Branch: ${branch}. Worktree: ${worktree}. Delivery evidence: ${deliveryEvidencePathForClickUpTask(taskId || subtaskId || effectiveParent)}.`,
9323
9328
  description,
9324
9329
  fields: {
9325
9330
  Definition: definitionContent,
@@ -9592,6 +9597,8 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
9592
9597
  log: normalizeClickUpWebhookLogLevel(raw.log),
9593
9598
  opencode: {
9594
9599
  baseUrl: normalizeOpenCodeBaseUrl(opencode.base_url || opencode.baseUrl || raw.opencode_base_url || raw.opencodeBaseUrl),
9600
+ promptDelivery: ["http", "direct"].includes(String(opencode.prompt_delivery || opencode.promptDelivery || raw.prompt_delivery || raw.promptDelivery || "").trim().toLowerCase()) ? "http" : "sdk",
9601
+ acceptPromptAdmission: opencode.accept_prompt_admission === true || opencode.acceptPromptAdmission === true || raw.accept_prompt_admission === true || raw.acceptPromptAdmission === true,
9595
9602
  startupReconciliationDelayMs: normalizeNonNegativeInteger(
9596
9603
  opencode.startup_reconciliation_delay_ms ?? opencode.startupReconciliationDelayMs ?? raw.startup_reconciliation_delay_ms ?? raw.startupReconciliationDelayMs,
9597
9604
  CLICKUP_WEBHOOK_STARTUP_RECONCILIATION_DELAY_MS
@@ -10561,6 +10568,16 @@ async function probeOpenCodeSessionControl(client, { directory, agent, omitAgent
10561
10568
  const rawMessages = await readOpenCodeSessionMessages(client, { sessionId: create.session_id, directory, limit: 50 });
10562
10569
  if (!rawMessages) throw new Error("OpenCode client does not expose session.messages.");
10563
10570
  const fullMessageText = rawMessages.map(openCodeMessageText).join("\n");
10571
+ const respondingAgents = [...new Set(rawMessages.filter((message) => normalizeLooseToken(normalizeOpenCodeMessageRole(message)) === "assistant").flatMap((message) => [normalizeOpenCodeMessageAgent(message), normalizeOpenCodeMessageMode(message)]).map((value) => String(value || "").trim()).filter(Boolean))];
10572
+ const requestedAgent = normalizeLooseToken(agent);
10573
+ const assistantVisible = rawMessages.some((message) => normalizeLooseToken(normalizeOpenCodeMessageRole(message)) === "assistant");
10574
+ const markerVisible = fullMessageText.includes(marker);
10575
+ const deliveryVerified = markerVisible && assistantVisible;
10576
+ const requestedAgentVerified = requestedAgent ? deliveryVerified && rawMessages.some((message) => {
10577
+ const messageAgent = normalizeLooseToken(normalizeOpenCodeMessageAgent(message));
10578
+ const messageMode = normalizeLooseToken(normalizeOpenCodeMessageMode(message));
10579
+ return normalizeLooseToken(normalizeOpenCodeMessageRole(message)) === "assistant" && (messageAgent === requestedAgent || messageMode === requestedAgent);
10580
+ }) : null;
10564
10581
  const messages = {
10565
10582
  ok: true,
10566
10583
  session_id: create.session_id,
@@ -10578,8 +10595,11 @@ async function probeOpenCodeSessionControl(client, { directory, agent, omitAgent
10578
10595
  marker_length: marker.length,
10579
10596
  marker_truncated: requestedMarker.length > marker.length,
10580
10597
  marker_hash: hashOpenCodeSessionText(marker),
10581
- marker_visible: fullMessageText.includes(marker),
10582
- assistant_visible: rawMessages.some((message) => normalizeLooseToken(normalizeOpenCodeMessageRole(message)) === "assistant" || Boolean(normalizeOpenCodeMessageAgent(message) && openCodeMessageText(message))),
10598
+ marker_visible: markerVisible,
10599
+ assistant_visible: assistantVisible,
10600
+ delivery_verified: deliveryVerified,
10601
+ requested_agent_verified: requestedAgentVerified,
10602
+ responding_agents: respondingAgents,
10583
10603
  create,
10584
10604
  prompt,
10585
10605
  messages
@@ -10647,9 +10667,9 @@ function openCodeBlockingPromptVerification(result, sessionId) {
10647
10667
  if (parts.length > 0 || messageId) return { ok: true, method: parts.length > 0 ? "blocking_prompt_parts" : "blocking_prompt_message", messageId: messageId ? String(messageId) : null, sessionId: deliveredSessionId ? String(deliveredSessionId) : String(sessionId), parts: parts.length };
10648
10668
  return null;
10649
10669
  }
10650
- async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, applyBlockerOnFailure = true } = {}) {
10670
+ async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, directPrompt = false, acceptPromptAdmission = false, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, applyBlockerOnFailure = true } = {}) {
10651
10671
  const beforeMessages = await readOpenCodeSessionMessages(openCodeClient, { sessionId, directory, limit: 50 }).catch(() => null);
10652
- const sendResult = await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, allowDirectFallback: false });
10672
+ const sendResult = await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, direct: directPrompt, allowDirectFallback: directPrompt });
10653
10673
  let blockingPromptVerification = null;
10654
10674
  let admissionVerification = null;
10655
10675
  try {
@@ -10662,6 +10682,9 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
10662
10682
  return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2 };
10663
10683
  }
10664
10684
  if (blockingPromptVerification) return { ok: true, verification: blockingPromptVerification, admissionVerification: null, fallback: false };
10685
+ if (admissionVerification && acceptPromptAdmission) {
10686
+ return { ok: true, verification: admissionVerification, admissionVerification, fallback: false, admissionOnly: true };
10687
+ }
10665
10688
  let verification = await verifySessionEventDelivery(openCodeClient, { sessionId, directory, beforeMessages, expectedText: text, markers: eventMarkers });
10666
10689
  if (verification?.ok) return { ok: true, verification, admissionVerification, fallback: false };
10667
10690
  if (admissionVerification) {
@@ -10699,6 +10722,8 @@ async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, click
10699
10722
  text: prompt,
10700
10723
  directory: taskRoute.worktree,
10701
10724
  opencodeBaseUrl: config.opencode?.baseUrl,
10725
+ directPrompt: config.opencode?.promptDelivery === "http",
10726
+ acceptPromptAdmission: config.opencode?.acceptPromptAdmission === true,
10702
10727
  eventMarkers,
10703
10728
  verifySessionEventDelivery,
10704
10729
  applyBlockerOnFailure: false
@@ -10974,8 +10999,13 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
10974
10999
  }
10975
11000
  const deliveryEvidencePath = deliveryEvidencePathForClickUpTask(taskId);
10976
11001
  const routingMetadata = {
11002
+ parent_task_id: subtaskId ? parentTaskId : void 0,
11003
+ parent_branch: taskRoute.parentBranch,
10977
11004
  branch: taskRoute.branch,
11005
+ subtask_branch: subtaskId ? taskRoute.branch : void 0,
10978
11006
  worktree: taskRoute.worktree,
11007
+ subtask_worktree: subtaskId ? taskRoute.worktree : void 0,
11008
+ pr_target: taskRoute.prTarget || (subtaskId ? taskRoute.parentBranch : "dev"),
10979
11009
  delivery_evidence_path: deliveryEvidencePath,
10980
11010
  evidence_path: `.optima/evidences/${branchSafeClickUpId(taskId)}/SUMMARY.md`
10981
11011
  };
@@ -11001,7 +11031,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
11001
11031
  appendClickUpWebhookLocalLog(worktree, { type: "pending_session_metadata_failed", taskId, sessionId: pendingSessionId, message: error.message });
11002
11032
  throw error;
11003
11033
  }
11004
- const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId: pendingSessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, eventMarkers: [taskId, eventType], verifySessionEventDelivery });
11034
+ const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId: pendingSessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, directPrompt: config.opencode?.promptDelivery === "http", acceptPromptAdmission: config.opencode?.acceptPromptAdmission === true, eventMarkers: [taskId, eventType], verifySessionEventDelivery });
11005
11035
  if (!delivery.ok) return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
11006
11036
  const nextMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(pendingMetadata, config.routing.metadataKey, pendingSessionId), config.routing.metadataKey);
11007
11037
  await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: nextMetadata });
@@ -11012,7 +11042,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
11012
11042
  const sessionId = String(existingSessionId);
11013
11043
  if (await sessionExists(openCodeClient, sessionId)) {
11014
11044
  if (typeof clickupClient?.updateTaskMetadata === "function") await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: metadataWithRouting });
11015
- const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, eventMarkers: [taskId, eventType], verifySessionEventDelivery, applyBlockerOnFailure: false });
11045
+ const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, directPrompt: config.opencode?.promptDelivery === "http", acceptPromptAdmission: config.opencode?.acceptPromptAdmission === true, eventMarkers: [taskId, eventType], verifySessionEventDelivery, applyBlockerOnFailure: false });
11016
11046
  if (!delivery.ok) {
11017
11047
  const recovery2 = await recoverClickUpPmSession({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, staleSessionId: sessionId, sessionTitle, taskRoute, metadataWithRouting, config, prompt, eventMarkers: [taskId, eventType], deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, eventKey, createSession, verifySessionEventDelivery });
11018
11048
  return finish(recovery2);
@@ -12247,7 +12277,33 @@ function getModePromptFragment(agentId, operatingTeamMode, worktree) {
12247
12277
  function shouldRegisterWorkflowProductManager(options = {}, worktree = process.cwd()) {
12248
12278
  if (options.clickUpWebhookActive === true) return true;
12249
12279
  const validation = options.clickUpWebhookValidation;
12250
- return validation?.complete === true && validation?.ok !== false && isSameOrNestedPath(worktree, validation.config?.basePath);
12280
+ if (validation?.complete !== true || validation?.ok === false) return false;
12281
+ const basePath = validation.config?.basePath;
12282
+ return isSameOrNestedPath(worktree, basePath) || isClickUpDerivedWorktreeSibling(worktree, basePath);
12283
+ }
12284
+ function isClickUpDerivedWorktreeSibling(candidate, basePath) {
12285
+ if (typeof candidate !== "string" || typeof basePath !== "string" || !candidate.trim() || !basePath.trim()) return false;
12286
+ const resolvedCandidate = path5.resolve(candidate);
12287
+ const resolvedBase = path5.resolve(basePath);
12288
+ const baseParent = path5.dirname(resolvedBase);
12289
+ if (path5.dirname(resolvedCandidate) !== baseParent) return false;
12290
+ const baseName = path5.basename(resolvedBase);
12291
+ const candidateName = path5.basename(resolvedCandidate);
12292
+ if (!candidateName.startsWith(`${baseName}-`)) return false;
12293
+ const branchSlug = candidateName.slice(baseName.length + 1);
12294
+ const parts = branchSlug.split("-").filter(Boolean);
12295
+ if (parts.length < 2) return false;
12296
+ if (!(/* @__PURE__ */ new Set(["tarea", "bug", "doc", "poc", "idea"])).has(parts[0])) return false;
12297
+ if (!parts.slice(1).every((part) => /^[a-z0-9][a-z0-9-]*$/.test(part))) return false;
12298
+ try {
12299
+ const candidateStat = fs5.lstatSync(resolvedCandidate);
12300
+ if (!candidateStat.isDirectory() || candidateStat.isSymbolicLink()) return false;
12301
+ const realCandidate = fs5.realpathSync.native(resolvedCandidate);
12302
+ const realBaseParent = fs5.realpathSync.native(baseParent);
12303
+ return path5.dirname(realCandidate) === realBaseParent && path5.basename(realCandidate) === candidateName;
12304
+ } catch {
12305
+ return false;
12306
+ }
12251
12307
  }
12252
12308
  function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktree, clickUpWebhookValidation } = {}) {
12253
12309
  const safe = safeWorktreeOrFailure(context, pluginWorktree);
@@ -12259,6 +12315,9 @@ function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktr
12259
12315
  if (clickUpBasePath && isSameOrNestedPath(requested, clickUpBasePath)) {
12260
12316
  return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path5.resolve(clickUpBasePath) };
12261
12317
  }
12318
+ if (clickUpBasePath && isClickUpDerivedWorktreeSibling(requested, clickUpBasePath)) {
12319
+ return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath: path5.resolve(clickUpBasePath) };
12320
+ }
12262
12321
  return {
12263
12322
  ok: false,
12264
12323
  error: `Directory '${requested}' is outside the safe worktree '${safe.worktree}' and configured ClickUp base path.`
@@ -13090,7 +13149,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
13090
13149
  }
13091
13150
  };
13092
13151
  }
13093
- 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, 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 };
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 };
13094
13153
  export {
13095
13154
  OptimaPlugin as default
13096
13155
  };
@@ -633,8 +633,6 @@ var require_Alias = __commonJS({
633
633
  * instance of the `source` anchor before this node.
634
634
  */
635
635
  resolve(doc, ctx) {
636
- if (ctx?.maxAliasCount === 0)
637
- throw new ReferenceError("Alias resolution is disabled");
638
636
  let nodes;
639
637
  if (ctx?.aliasResolveCache) {
640
638
  nodes = ctx.aliasResolveCache;
@@ -1434,7 +1432,6 @@ var require_stringify = __commonJS({
1434
1432
  nullStr: "null",
1435
1433
  simpleKeys: false,
1436
1434
  singleQuote: null,
1437
- trailingComma: false,
1438
1435
  trueStr: "true",
1439
1436
  verifyAliasOrder: true
1440
1437
  }, doc.schema.toStringOptions, options);
@@ -1707,18 +1704,18 @@ var require_merge = __commonJS({
1707
1704
  };
1708
1705
  var isMergeKey = (ctx, key) => (merge.identify(key) || identity.isScalar(key) && (!key.type || key.type === Scalar.Scalar.PLAIN) && merge.identify(key.value)) && ctx?.doc.schema.tags.some((tag) => tag.tag === merge.tag && tag.default);
1709
1706
  function addMergeToJSMap(ctx, map, value) {
1710
- const source = resolveAliasValue(ctx, value);
1711
- if (identity.isSeq(source))
1712
- for (const it of source.items)
1707
+ value = ctx && identity.isAlias(value) ? value.resolve(ctx.doc) : value;
1708
+ if (identity.isSeq(value))
1709
+ for (const it of value.items)
1713
1710
  mergeValue(ctx, map, it);
1714
- else if (Array.isArray(source))
1715
- for (const it of source)
1711
+ else if (Array.isArray(value))
1712
+ for (const it of value)
1716
1713
  mergeValue(ctx, map, it);
1717
1714
  else
1718
- mergeValue(ctx, map, source);
1715
+ mergeValue(ctx, map, value);
1719
1716
  }
1720
1717
  function mergeValue(ctx, map, value) {
1721
- const source = resolveAliasValue(ctx, value);
1718
+ const source = ctx && identity.isAlias(value) ? value.resolve(ctx.doc) : value;
1722
1719
  if (!identity.isMap(source))
1723
1720
  throw new Error("Merge sources must be maps or map aliases");
1724
1721
  const srcMap = source.toJSON(null, ctx, Map);
@@ -1739,9 +1736,6 @@ var require_merge = __commonJS({
1739
1736
  }
1740
1737
  return map;
1741
1738
  }
1742
- function resolveAliasValue(ctx, value) {
1743
- return ctx && identity.isAlias(value) ? value.resolve(ctx.doc, ctx) : value;
1744
- }
1745
1739
  exports.addMergeToJSMap = addMergeToJSMap;
1746
1740
  exports.isMergeKey = isMergeKey;
1747
1741
  exports.merge = merge;
@@ -1955,19 +1949,12 @@ ${indent}${line}` : "\n";
1955
1949
  if (comment)
1956
1950
  reqNewline = true;
1957
1951
  let str = stringify.stringify(item, itemCtx, () => comment = null);
1958
- reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
1959
- if (i < items.length - 1) {
1952
+ if (i < items.length - 1)
1960
1953
  str += ",";
1961
- } else if (ctx.options.trailingComma) {
1962
- if (ctx.options.lineWidth > 0) {
1963
- reqNewline || (reqNewline = lines.reduce((sum, line) => sum + line.length + 2, 2) + (str.length + 2) > ctx.options.lineWidth);
1964
- }
1965
- if (reqNewline) {
1966
- str += ",";
1967
- }
1968
- }
1969
1954
  if (comment)
1970
1955
  str += stringifyComment.lineComment(str, itemIndent, commentString(comment));
1956
+ if (!reqNewline && (lines.length > linesAtValue || str.includes("\n")))
1957
+ reqNewline = true;
1971
1958
  lines.push(str);
1972
1959
  linesAtValue = lines.length;
1973
1960
  }
@@ -2379,7 +2366,7 @@ var require_stringifyNumber = __commonJS({
2379
2366
  if (!isFinite(num))
2380
2367
  return isNaN(num) ? ".nan" : num < 0 ? "-.inf" : ".inf";
2381
2368
  let n = Object.is(value, -0) ? "-0" : JSON.stringify(value);
2382
- if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^-?\d/.test(n) && !n.includes("e")) {
2369
+ if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^\d/.test(n)) {
2383
2370
  let i = n.indexOf(".");
2384
2371
  if (i < 0) {
2385
2372
  i = n.length;
@@ -4751,7 +4738,7 @@ var require_resolve_flow_scalar = __commonJS({
4751
4738
  while (next === " " || next === " ")
4752
4739
  next = source[++i + 1];
4753
4740
  } else if (next === "x" || next === "u" || next === "U") {
4754
- const length = next === "x" ? 2 : next === "u" ? 4 : 8;
4741
+ const length = { x: 2, u: 4, U: 8 }[next];
4755
4742
  res += parseCharCode(source, i + 1, length, onError);
4756
4743
  i += length;
4757
4744
  } else {
@@ -4826,13 +4813,12 @@ var require_resolve_flow_scalar = __commonJS({
4826
4813
  const cc = source.substr(offset, length);
4827
4814
  const ok = cc.length === length && /^[0-9a-fA-F]+$/.test(cc);
4828
4815
  const code = ok ? parseInt(cc, 16) : NaN;
4829
- try {
4830
- return String.fromCodePoint(code);
4831
- } catch {
4816
+ if (isNaN(code)) {
4832
4817
  const raw = source.substr(offset - 2, length + 2);
4833
4818
  onError(offset - 2, "BAD_DQ_ESCAPE", `Invalid escape sequence ${raw}`);
4834
4819
  return raw;
4835
4820
  }
4821
+ return String.fromCodePoint(code);
4836
4822
  }
4837
4823
  exports.resolveFlowScalar = resolveFlowScalar;
4838
4824
  }
@@ -4982,22 +4968,17 @@ var require_compose_node = __commonJS({
4982
4968
  case "block-map":
4983
4969
  case "block-seq":
4984
4970
  case "flow-collection":
4985
- try {
4986
- node = composeCollection.composeCollection(CN, ctx, token, props, onError);
4987
- if (anchor)
4988
- node.anchor = anchor.source.substring(1);
4989
- } catch (error) {
4990
- const message = error instanceof Error ? error.message : String(error);
4991
- onError(token, "RESOURCE_EXHAUSTION", message);
4992
- }
4971
+ node = composeCollection.composeCollection(CN, ctx, token, props, onError);
4972
+ if (anchor)
4973
+ node.anchor = anchor.source.substring(1);
4993
4974
  break;
4994
4975
  default: {
4995
4976
  const message = token.type === "error" ? token.message : `Unsupported token (type: ${token.type})`;
4996
4977
  onError(token, "UNEXPECTED_TOKEN", message);
4978
+ node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError);
4997
4979
  isSrcToken = false;
4998
4980
  }
4999
4981
  }
5000
- node ?? (node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError));
5001
4982
  if (anchor && node.anchor === "")
5002
4983
  onError(anchor, "BAD_ALIAS", "Anchor cannot be an empty string");
5003
4984
  if (atKey && ctx.options.stringKeys && (!identity.isScalar(node) || typeof node.value !== "string" || node.tag && node.tag !== "tag:yaml.org,2002:str")) {
@@ -5182,10 +5163,8 @@ ${cb}` : comment;
5182
5163
  }
5183
5164
  }
5184
5165
  if (afterDoc) {
5185
- for (let i = 0; i < this.errors.length; ++i)
5186
- doc.errors.push(this.errors[i]);
5187
- for (let i = 0; i < this.warnings.length; ++i)
5188
- doc.warnings.push(this.warnings[i]);
5166
+ Array.prototype.push.apply(doc.errors, this.errors);
5167
+ Array.prototype.push.apply(doc.warnings, this.warnings);
5189
5168
  } else {
5190
5169
  doc.errors = this.errors;
5191
5170
  doc.warnings = this.warnings;
@@ -5918,7 +5897,7 @@ var require_lexer = __commonJS({
5918
5897
  const n = (yield* this.pushCount(1)) + (yield* this.pushSpaces(true));
5919
5898
  this.indentNext = this.indentValue + 1;
5920
5899
  this.indentValue += n;
5921
- return "block-start";
5900
+ return yield* this.parseBlockStart();
5922
5901
  }
5923
5902
  return "doc";
5924
5903
  }
@@ -6217,38 +6196,28 @@ var require_lexer = __commonJS({
6217
6196
  return 0;
6218
6197
  }
6219
6198
  *pushIndicators() {
6220
- let n = 0;
6221
- loop: while (true) {
6222
- switch (this.charAt(0)) {
6223
- case "!":
6224
- n += yield* this.pushTag();
6225
- n += yield* this.pushSpaces(true);
6226
- continue loop;
6227
- case "&":
6228
- n += yield* this.pushUntil(isNotAnchorChar);
6229
- n += yield* this.pushSpaces(true);
6230
- continue loop;
6231
- case "-":
6232
- // this is an error
6233
- case "?":
6234
- // this is an error outside flow collections
6235
- case ":": {
6236
- const inFlow = this.flowLevel > 0;
6237
- const ch1 = this.charAt(1);
6238
- if (isEmpty(ch1) || inFlow && flowIndicatorChars.has(ch1)) {
6239
- if (!inFlow)
6240
- this.indentNext = this.indentValue + 1;
6241
- else if (this.flowKey)
6242
- this.flowKey = false;
6243
- n += yield* this.pushCount(1);
6244
- n += yield* this.pushSpaces(true);
6245
- continue loop;
6246
- }
6199
+ switch (this.charAt(0)) {
6200
+ case "!":
6201
+ return (yield* this.pushTag()) + (yield* this.pushSpaces(true)) + (yield* this.pushIndicators());
6202
+ case "&":
6203
+ return (yield* this.pushUntil(isNotAnchorChar)) + (yield* this.pushSpaces(true)) + (yield* this.pushIndicators());
6204
+ case "-":
6205
+ // this is an error
6206
+ case "?":
6207
+ // this is an error outside flow collections
6208
+ case ":": {
6209
+ const inFlow = this.flowLevel > 0;
6210
+ const ch1 = this.charAt(1);
6211
+ if (isEmpty(ch1) || inFlow && flowIndicatorChars.has(ch1)) {
6212
+ if (!inFlow)
6213
+ this.indentNext = this.indentValue + 1;
6214
+ else if (this.flowKey)
6215
+ this.flowKey = false;
6216
+ return (yield* this.pushCount(1)) + (yield* this.pushSpaces(true)) + (yield* this.pushIndicators());
6247
6217
  }
6248
6218
  }
6249
- break loop;
6250
6219
  }
6251
- return n;
6220
+ return 0;
6252
6221
  }
6253
6222
  *pushTag() {
6254
6223
  if (this.charAt(1) === "<") {
@@ -6407,13 +6376,6 @@ var require_parser = __commonJS({
6407
6376
  }
6408
6377
  return prev.splice(i, prev.length);
6409
6378
  }
6410
- function arrayPushArray(target, source) {
6411
- if (source.length < 1e5)
6412
- Array.prototype.push.apply(target, source);
6413
- else
6414
- for (let i = 0; i < source.length; ++i)
6415
- target.push(source[i]);
6416
- }
6417
6379
  function fixFlowSeqItems(fc) {
6418
6380
  if (fc.start.type === "flow-seq-start") {
6419
6381
  for (const it of fc.items) {
@@ -6423,11 +6385,11 @@ var require_parser = __commonJS({
6423
6385
  delete it.key;
6424
6386
  if (isFlowToken(it.value)) {
6425
6387
  if (it.value.end)
6426
- arrayPushArray(it.value.end, it.sep);
6388
+ Array.prototype.push.apply(it.value.end, it.sep);
6427
6389
  else
6428
6390
  it.value.end = it.sep;
6429
6391
  } else
6430
- arrayPushArray(it.start, it.sep);
6392
+ Array.prototype.push.apply(it.start, it.sep);
6431
6393
  delete it.sep;
6432
6394
  }
6433
6395
  }
@@ -6782,7 +6744,7 @@ var require_parser = __commonJS({
6782
6744
  const prev = map.items[map.items.length - 2];
6783
6745
  const end = prev?.value?.end;
6784
6746
  if (Array.isArray(end)) {
6785
- arrayPushArray(end, it.start);
6747
+ Array.prototype.push.apply(end, it.start);
6786
6748
  end.push(this.sourceToken);
6787
6749
  map.items.pop();
6788
6750
  return;
@@ -6970,7 +6932,7 @@ var require_parser = __commonJS({
6970
6932
  const prev = seq.items[seq.items.length - 2];
6971
6933
  const end = prev?.value?.end;
6972
6934
  if (Array.isArray(end)) {
6973
- arrayPushArray(end, it.start);
6935
+ Array.prototype.push.apply(end, it.start);
6974
6936
  end.push(this.sourceToken);
6975
6937
  seq.items.pop();
6976
6938
  return;
@@ -8848,7 +8810,13 @@ function deriveClickUpBranchName({ taskType, parentTaskId, subtaskId, taskId } =
8848
8810
  throw new Error("taskType and parentTaskId/taskId are required to derive a ClickUp branch name.");
8849
8811
  }
8850
8812
  if (typeSlug === "poc") return ["poc", parentSlug].join("/");
8851
- return [typeSlug, parentSlug, subtaskSlug].filter(Boolean).join("/");
8813
+ if (subtaskSlug) return `${typeSlug}/${parentSlug}-subtask-${subtaskSlug}`;
8814
+ return [typeSlug, parentSlug].join("/");
8815
+ }
8816
+ function isClickUpSubtaskRoute({ taskType, parentTaskId, subtaskId, taskId } = {}) {
8817
+ return Boolean(
8818
+ normalizeClickUpTaskType(taskType) !== "poc" && subtaskId && parentTaskId && String(parentTaskId) !== String(taskId || subtaskId)
8819
+ );
8852
8820
  }
8853
8821
  function deriveClickUpPrTarget({ isRelease = false, parentTaskId, parentBranch, parentTaskType, taskType, devBranch = "dev", mainBranch = "main" } = {}) {
8854
8822
  if (isRelease) return mainBranch;
@@ -9037,15 +9005,17 @@ function deriveClickUpPendingSubtaskBranch({ taskType, parentTaskId, title } = {
9037
9005
  const parentSlug = branchSafeClickUpId(parentTaskId);
9038
9006
  if (!typeSlug || !parentSlug) throw new Error("taskType and parentTaskId are required to derive a pending subtask branch name.");
9039
9007
  if (typeSlug === "poc") return ["poc", parentSlug].join("/");
9040
- return [typeSlug, parentSlug, `pending-${normalizeLooseToken(title) || "subtask"}`].join("/");
9008
+ return `${typeSlug}/${parentSlug}-pending-${normalizeLooseToken(title) || "subtask"}`;
9041
9009
  }
9042
- function buildClickUpSubtaskAgentMetadata({ parentTaskId, subtask, branch, prTarget, titleSlug } = {}) {
9010
+ function buildClickUpSubtaskAgentMetadata({ parentTaskId, subtask, branch, prTarget, titleSlug, parentBranch } = {}) {
9043
9011
  return mergeClickUpAgentMetadata("", {
9044
9012
  subtask: {
9045
9013
  parent_task_id: parentTaskId,
9014
+ parent_branch: parentBranch || prTarget,
9046
9015
  title: subtask.title,
9047
9016
  title_slug: titleSlug,
9048
9017
  branch,
9018
+ subtask_branch: branch,
9049
9019
  pr_target: prTarget,
9050
9020
  pending_clickup_subtask_id: true,
9051
9021
  owner_role: subtask.ownerRole,
@@ -9065,7 +9035,7 @@ function buildClickUpCreateSubtasksPayload({ parentTaskId, markdown = "", source
9065
9035
  const titleSlug = normalizeLooseToken(subtask.title) || "subtask";
9066
9036
  const branch = subtask.branch || deriveClickUpPendingSubtaskBranch({ taskType: subtask.type, parentTaskId: parentId, title: subtask.title });
9067
9037
  const prTarget = normalizeClickUpTaskType(subtask.type) === "poc" ? "dev" : parentBranchValue;
9068
- const agentMetadata = buildClickUpSubtaskAgentMetadata({ parentTaskId: parentId, subtask, branch, prTarget, titleSlug });
9038
+ const agentMetadata = buildClickUpSubtaskAgentMetadata({ parentTaskId: parentId, subtask, branch, prTarget, titleSlug, parentBranch: parentBranchValue });
9069
9039
  const descriptionParts = [
9070
9040
  subtask.description,
9071
9041
  subtask.acceptanceCriteria.length ? ["Acceptance Criteria:", ...subtask.acceptanceCriteria.map((item) => `- ${item}`)].join("\n") : ""
@@ -9243,27 +9213,52 @@ function safeExistingClickUpWorktree({ metadata = {}, branch = "" } = {}) {
9243
9213
  return null;
9244
9214
  }
9245
9215
  }
9216
+ function clickUpGitRefExists(baseWorktree, ref, runGitFn = runGit) {
9217
+ try {
9218
+ runGitFn(baseWorktree, ["rev-parse", "--verify", ref]);
9219
+ return true;
9220
+ } catch {
9221
+ return false;
9222
+ }
9223
+ }
9224
+ function resolveClickUpDevStartPoint(baseWorktree, runGitFn = runGit) {
9225
+ return clickUpGitRefExists(baseWorktree, "dev", runGitFn) ? "dev" : "origin/dev";
9226
+ }
9227
+ function addClickUpWorktreeForBranch({ baseWorktree, branch, worktreePath, startPoint, runGitFn = runGit } = {}) {
9228
+ if (clickUpGitRefExists(baseWorktree, branch, runGitFn)) {
9229
+ runGitFn(baseWorktree, ["worktree", "add", worktreePath, branch]);
9230
+ } else {
9231
+ runGitFn(baseWorktree, ["worktree", "add", "-b", branch, worktreePath, startPoint]);
9232
+ }
9233
+ }
9246
9234
  function ensureClickUpTaskWorktree({ baseWorktree = "", taskId, taskType = "Tarea", parentTaskId = "", subtaskId = "", existingMetadata = {}, runGitFn = runGit, allowNonGitFallback = false } = {}) {
9247
9235
  const effectiveParent = parentTaskId || taskId;
9236
+ const isSubtask = isClickUpSubtaskRoute({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9237
+ const parentBranch = isSubtask ? deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent }) : "";
9248
9238
  const branch = deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9249
9239
  const existing = safeExistingClickUpWorktree({ metadata: existingMetadata, branch });
9250
- if (existing) return { ...existing, branch };
9240
+ if (existing) return { ...existing, branch, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev" };
9251
9241
  const worktreePath = deriveClickUpWorktree({ baseWorktree, taskId, taskType, parentTaskId: effectiveParent, subtaskId });
9252
- if (fs5.existsSync(worktreePath)) return { branch, worktree: path5.resolve(worktreePath), reused: true };
9242
+ if (fs5.existsSync(worktreePath)) return { branch, worktree: path5.resolve(worktreePath), reused: true, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev" };
9253
9243
  if (allowNonGitFallback) {
9254
9244
  fs5.mkdirSync(worktreePath, { recursive: true });
9255
- return { branch, worktree: path5.resolve(worktreePath), reused: false, fallback: "non_git" };
9245
+ return { branch, worktree: path5.resolve(worktreePath), reused: false, fallback: "non_git", parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev", startPoint: parentBranch || "dev" };
9256
9246
  }
9257
- const startPoint = (() => {
9258
- try {
9259
- runGitFn(baseWorktree, ["rev-parse", "--verify", "dev"]);
9260
- return "dev";
9261
- } catch {
9262
- return "origin/dev";
9247
+ let parentBootstrap = null;
9248
+ if (isSubtask) {
9249
+ const parentWorktree = deriveClickUpWorktree({ baseWorktree, taskId: effectiveParent, taskType, parentTaskId: effectiveParent });
9250
+ if (!fs5.existsSync(parentWorktree)) {
9251
+ const parentStartPoint = resolveClickUpDevStartPoint(baseWorktree, runGitFn);
9252
+ const parentBranchExists = clickUpGitRefExists(baseWorktree, parentBranch, runGitFn);
9253
+ addClickUpWorktreeForBranch({ baseWorktree, branch: parentBranch, worktreePath: parentWorktree, startPoint: parentStartPoint, runGitFn });
9254
+ parentBootstrap = { branch: parentBranch, worktree: path5.resolve(parentWorktree), startPoint: parentBranchExists ? parentBranch : parentStartPoint, reused: parentBranchExists };
9255
+ } else {
9256
+ parentBootstrap = { branch: parentBranch, worktree: path5.resolve(parentWorktree), reused: true };
9263
9257
  }
9264
- })();
9265
- runGitFn(baseWorktree, ["worktree", "add", "-b", branch, worktreePath, startPoint]);
9266
- return { branch, worktree: path5.resolve(worktreePath), reused: false, startPoint };
9258
+ }
9259
+ const startPoint = isSubtask ? parentBranch : resolveClickUpDevStartPoint(baseWorktree, runGitFn);
9260
+ addClickUpWorktreeForBranch({ baseWorktree, branch, worktreePath, startPoint, runGitFn });
9261
+ return { branch, worktree: path5.resolve(worktreePath), reused: false, startPoint, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev", parentBootstrap: parentBootstrap || void 0 };
9267
9262
  }
9268
9263
  function normalizeClickUpDefinitionDocParent(parent = {}) {
9269
9264
  const docId = String(parent.doc_id || parent.docId || CLICKUP_DEFINITION_DOC_PARENT.doc_id).trim();
@@ -9285,13 +9280,22 @@ function buildClickUpStartTaskPayload({ taskId, taskType = "Tarea", parentTaskId
9285
9280
  if (!description) errors.push("taskDescription is required for the initial ClickUp task description rewrite.");
9286
9281
  if (errors.length > 0) return clickUpPayloadValidationError(errors);
9287
9282
  const effectiveParent = parentTaskId || taskId;
9283
+ const isSubtask = isClickUpSubtaskRoute({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9284
+ const parentBranch = isSubtask ? deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent }) : "";
9288
9285
  const branch = deriveClickUpBranchName({ taskType, parentTaskId: effectiveParent, subtaskId, taskId });
9289
9286
  const worktree = deriveClickUpWorktree({ baseWorktree, taskId, taskType, parentTaskId: effectiveParent, subtaskId });
9287
+ const prTarget = isSubtask ? parentBranch : "dev";
9288
+ const startFrom = isSubtask ? parentBranch : "dev";
9290
9289
  const estimate = preEstimateClickUpWork({ complexity, filesChanged, acceptanceCriteria, unknowns });
9291
9290
  const metadata = mergeClickUpAgentMetadata(existingAgentMetadata, {
9292
9291
  task: {
9292
+ parent_task_id: isSubtask ? effectiveParent : void 0,
9293
+ parent_branch: parentBranch || void 0,
9293
9294
  branch,
9295
+ subtask_branch: isSubtask ? branch : void 0,
9294
9296
  worktree,
9297
+ subtask_worktree: isSubtask ? worktree : void 0,
9298
+ pr_target: prTarget,
9295
9299
  mirror_task_path: `.optima/tasks/${branchSafeClickUpId(taskId || subtaskId || effectiveParent)}.md`,
9296
9300
  evidence_path: `.optima/evidences/${branchSafeClickUpId(taskId || subtaskId || effectiveParent)}/SUMMARY.md`,
9297
9301
  delivery_evidence_path: deliveryEvidencePathForClickUpTask(taskId || subtaskId || effectiveParent),
@@ -9304,17 +9308,18 @@ function buildClickUpStartTaskPayload({ taskId, taskType = "Tarea", parentTaskId
9304
9308
  dryRun: true,
9305
9309
  required_first_actions: [
9306
9310
  "Create or reuse the task-specific branch/worktree before planning or writing local .optima mirrors.",
9307
- `Use branch ${branch} from dev and worktree ${worktree} for this task workspace.`,
9311
+ `Use branch ${branch} from ${startFrom} and worktree ${worktree} for this task workspace.`,
9308
9312
  "Write planning state, .optima/tasks/current.md, task mirrors, and local evidence only inside the task worktree.",
9309
9313
  `Write merge-trackable final evidence under ${deliveryEvidencePathForClickUpTask(taskId || subtaskId || effectiveParent)}; .optima remains local mirror/staging.`,
9310
9314
  "Do not update the principal dev workspace .optima/tasks/current.md for ClickUp task planning.",
9311
9315
  "If another active task is present in current.md, move to or create this task worktree instead of stopping."
9312
9316
  ],
9313
9317
  git: {
9314
- startFrom: "dev",
9318
+ startFrom,
9315
9319
  branch,
9316
9320
  worktree,
9317
- prTarget: subtaskId && normalizeClickUpTaskType(taskType) !== "poc" ? deriveClickUpPrTarget({ parentTaskId: effectiveParent, parentTaskType: taskType }) : "dev"
9321
+ parentBranch: parentBranch || void 0,
9322
+ prTarget
9318
9323
  },
9319
9324
  mirror: {
9320
9325
  taskPath: `.optima/tasks/${branchSafeClickUpId(taskId || subtaskId || effectiveParent)}.md`,
@@ -9326,7 +9331,7 @@ function buildClickUpStartTaskPayload({ taskId, taskType = "Tarea", parentTaskId
9326
9331
  wouldCreate: true
9327
9332
  },
9328
9333
  clickup: {
9329
- comment: `Starting task from dev. Branch: ${branch}. Worktree: ${worktree}. Delivery evidence: ${deliveryEvidencePathForClickUpTask(taskId || subtaskId || effectiveParent)}.`,
9334
+ comment: `Starting task from ${startFrom}. Branch: ${branch}. Worktree: ${worktree}. Delivery evidence: ${deliveryEvidencePathForClickUpTask(taskId || subtaskId || effectiveParent)}.`,
9330
9335
  description,
9331
9336
  fields: {
9332
9337
  Definition: definitionContent,
@@ -9599,6 +9604,8 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
9599
9604
  log: normalizeClickUpWebhookLogLevel(raw.log),
9600
9605
  opencode: {
9601
9606
  baseUrl: normalizeOpenCodeBaseUrl(opencode.base_url || opencode.baseUrl || raw.opencode_base_url || raw.opencodeBaseUrl),
9607
+ promptDelivery: ["http", "direct"].includes(String(opencode.prompt_delivery || opencode.promptDelivery || raw.prompt_delivery || raw.promptDelivery || "").trim().toLowerCase()) ? "http" : "sdk",
9608
+ acceptPromptAdmission: opencode.accept_prompt_admission === true || opencode.acceptPromptAdmission === true || raw.accept_prompt_admission === true || raw.acceptPromptAdmission === true,
9602
9609
  startupReconciliationDelayMs: normalizeNonNegativeInteger(
9603
9610
  opencode.startup_reconciliation_delay_ms ?? opencode.startupReconciliationDelayMs ?? raw.startup_reconciliation_delay_ms ?? raw.startupReconciliationDelayMs,
9604
9611
  CLICKUP_WEBHOOK_STARTUP_RECONCILIATION_DELAY_MS
@@ -10568,6 +10575,16 @@ async function probeOpenCodeSessionControl(client, { directory, agent, omitAgent
10568
10575
  const rawMessages = await readOpenCodeSessionMessages(client, { sessionId: create.session_id, directory, limit: 50 });
10569
10576
  if (!rawMessages) throw new Error("OpenCode client does not expose session.messages.");
10570
10577
  const fullMessageText = rawMessages.map(openCodeMessageText).join("\n");
10578
+ const respondingAgents = [...new Set(rawMessages.filter((message) => normalizeLooseToken(normalizeOpenCodeMessageRole(message)) === "assistant").flatMap((message) => [normalizeOpenCodeMessageAgent(message), normalizeOpenCodeMessageMode(message)]).map((value) => String(value || "").trim()).filter(Boolean))];
10579
+ const requestedAgent = normalizeLooseToken(agent);
10580
+ const assistantVisible = rawMessages.some((message) => normalizeLooseToken(normalizeOpenCodeMessageRole(message)) === "assistant");
10581
+ const markerVisible = fullMessageText.includes(marker);
10582
+ const deliveryVerified = markerVisible && assistantVisible;
10583
+ const requestedAgentVerified = requestedAgent ? deliveryVerified && rawMessages.some((message) => {
10584
+ const messageAgent = normalizeLooseToken(normalizeOpenCodeMessageAgent(message));
10585
+ const messageMode = normalizeLooseToken(normalizeOpenCodeMessageMode(message));
10586
+ return normalizeLooseToken(normalizeOpenCodeMessageRole(message)) === "assistant" && (messageAgent === requestedAgent || messageMode === requestedAgent);
10587
+ }) : null;
10571
10588
  const messages = {
10572
10589
  ok: true,
10573
10590
  session_id: create.session_id,
@@ -10585,8 +10602,11 @@ async function probeOpenCodeSessionControl(client, { directory, agent, omitAgent
10585
10602
  marker_length: marker.length,
10586
10603
  marker_truncated: requestedMarker.length > marker.length,
10587
10604
  marker_hash: hashOpenCodeSessionText(marker),
10588
- marker_visible: fullMessageText.includes(marker),
10589
- assistant_visible: rawMessages.some((message) => normalizeLooseToken(normalizeOpenCodeMessageRole(message)) === "assistant" || Boolean(normalizeOpenCodeMessageAgent(message) && openCodeMessageText(message))),
10605
+ marker_visible: markerVisible,
10606
+ assistant_visible: assistantVisible,
10607
+ delivery_verified: deliveryVerified,
10608
+ requested_agent_verified: requestedAgentVerified,
10609
+ responding_agents: respondingAgents,
10590
10610
  create,
10591
10611
  prompt,
10592
10612
  messages
@@ -10654,9 +10674,9 @@ function openCodeBlockingPromptVerification(result, sessionId) {
10654
10674
  if (parts.length > 0 || messageId) return { ok: true, method: parts.length > 0 ? "blocking_prompt_parts" : "blocking_prompt_message", messageId: messageId ? String(messageId) : null, sessionId: deliveredSessionId ? String(deliveredSessionId) : String(sessionId), parts: parts.length };
10655
10675
  return null;
10656
10676
  }
10657
- async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, applyBlockerOnFailure = true } = {}) {
10677
+ async function deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent, text, directory, opencodeBaseUrl, directPrompt = false, acceptPromptAdmission = false, eventMarkers = [], verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, applyBlockerOnFailure = true } = {}) {
10658
10678
  const beforeMessages = await readOpenCodeSessionMessages(openCodeClient, { sessionId, directory, limit: 50 }).catch(() => null);
10659
- const sendResult = await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, allowDirectFallback: false });
10679
+ const sendResult = await sendSessionEvent(openCodeClient, { sessionId, agent, text, directory, opencodeBaseUrl, direct: directPrompt, allowDirectFallback: directPrompt });
10660
10680
  let blockingPromptVerification = null;
10661
10681
  let admissionVerification = null;
10662
10682
  try {
@@ -10669,6 +10689,9 @@ async function deliverClickUpSessionEventWithVerification({ openCodeClient, send
10669
10689
  return { ok: false, action: "message_delivery_failed", reason: error.message, taskId, sessionId, fallbackAttempted: false, blockerTag: blocker2 };
10670
10690
  }
10671
10691
  if (blockingPromptVerification) return { ok: true, verification: blockingPromptVerification, admissionVerification: null, fallback: false };
10692
+ if (admissionVerification && acceptPromptAdmission) {
10693
+ return { ok: true, verification: admissionVerification, admissionVerification, fallback: false, admissionOnly: true };
10694
+ }
10672
10695
  let verification = await verifySessionEventDelivery(openCodeClient, { sessionId, directory, beforeMessages, expectedText: text, markers: eventMarkers });
10673
10696
  if (verification?.ok) return { ok: true, verification, admissionVerification, fallback: false };
10674
10697
  if (admissionVerification) {
@@ -10706,6 +10729,8 @@ async function recoverClickUpPmSession({ openCodeClient, sendSessionEvent, click
10706
10729
  text: prompt,
10707
10730
  directory: taskRoute.worktree,
10708
10731
  opencodeBaseUrl: config.opencode?.baseUrl,
10732
+ directPrompt: config.opencode?.promptDelivery === "http",
10733
+ acceptPromptAdmission: config.opencode?.acceptPromptAdmission === true,
10709
10734
  eventMarkers,
10710
10735
  verifySessionEventDelivery,
10711
10736
  applyBlockerOnFailure: false
@@ -10981,8 +11006,13 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
10981
11006
  }
10982
11007
  const deliveryEvidencePath = deliveryEvidencePathForClickUpTask(taskId);
10983
11008
  const routingMetadata = {
11009
+ parent_task_id: subtaskId ? parentTaskId : void 0,
11010
+ parent_branch: taskRoute.parentBranch,
10984
11011
  branch: taskRoute.branch,
11012
+ subtask_branch: subtaskId ? taskRoute.branch : void 0,
10985
11013
  worktree: taskRoute.worktree,
11014
+ subtask_worktree: subtaskId ? taskRoute.worktree : void 0,
11015
+ pr_target: taskRoute.prTarget || (subtaskId ? taskRoute.parentBranch : "dev"),
10986
11016
  delivery_evidence_path: deliveryEvidencePath,
10987
11017
  evidence_path: `.optima/evidences/${branchSafeClickUpId(taskId)}/SUMMARY.md`
10988
11018
  };
@@ -11008,7 +11038,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
11008
11038
  appendClickUpWebhookLocalLog(worktree, { type: "pending_session_metadata_failed", taskId, sessionId: pendingSessionId, message: error.message });
11009
11039
  throw error;
11010
11040
  }
11011
- const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId: pendingSessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, eventMarkers: [taskId, eventType], verifySessionEventDelivery });
11041
+ const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId: pendingSessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, directPrompt: config.opencode?.promptDelivery === "http", acceptPromptAdmission: config.opencode?.acceptPromptAdmission === true, eventMarkers: [taskId, eventType], verifySessionEventDelivery });
11012
11042
  if (!delivery.ok) return finish({ ...delivery, eventKey, branch: taskRoute.branch, worktree: taskRoute.worktree, deliveryEvidencePath, evidencePath: routingMetadata.evidence_path });
11013
11043
  const nextMetadata = clearClickUpPendingSessionMetadata(setClickUpSessionMetadata(pendingMetadata, config.routing.metadataKey, pendingSessionId), config.routing.metadataKey);
11014
11044
  await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: nextMetadata });
@@ -11019,7 +11049,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
11019
11049
  const sessionId = String(existingSessionId);
11020
11050
  if (await sessionExists(openCodeClient, sessionId)) {
11021
11051
  if (typeof clickupClient?.updateTaskMetadata === "function") await clickupClient.updateTaskMetadata({ taskId, fieldId: config.routing.metadataFieldId, value: metadataWithRouting });
11022
- const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, eventMarkers: [taskId, eventType], verifySessionEventDelivery, applyBlockerOnFailure: false });
11052
+ const delivery = await deliverClickUpSessionEventWithVerification({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, sessionId, agent: config.routing.targetAgent, text: prompt, directory: taskRoute.worktree, opencodeBaseUrl: config.opencode?.baseUrl, directPrompt: config.opencode?.promptDelivery === "http", acceptPromptAdmission: config.opencode?.acceptPromptAdmission === true, eventMarkers: [taskId, eventType], verifySessionEventDelivery, applyBlockerOnFailure: false });
11023
11053
  if (!delivery.ok) {
11024
11054
  const recovery2 = await recoverClickUpPmSession({ openCodeClient, sendSessionEvent, clickupClient, worktree, taskId, staleSessionId: sessionId, sessionTitle, taskRoute, metadataWithRouting, config, prompt, eventMarkers: [taskId, eventType], deliveryEvidencePath, evidencePath: routingMetadata.evidence_path, eventKey, createSession, verifySessionEventDelivery });
11025
11055
  return finish(recovery2);
@@ -12254,7 +12284,33 @@ function getModePromptFragment(agentId, operatingTeamMode, worktree) {
12254
12284
  function shouldRegisterWorkflowProductManager(options = {}, worktree = process.cwd()) {
12255
12285
  if (options.clickUpWebhookActive === true) return true;
12256
12286
  const validation = options.clickUpWebhookValidation;
12257
- return validation?.complete === true && validation?.ok !== false && isSameOrNestedPath(worktree, validation.config?.basePath);
12287
+ if (validation?.complete !== true || validation?.ok === false) return false;
12288
+ const basePath = validation.config?.basePath;
12289
+ return isSameOrNestedPath(worktree, basePath) || isClickUpDerivedWorktreeSibling(worktree, basePath);
12290
+ }
12291
+ function isClickUpDerivedWorktreeSibling(candidate, basePath) {
12292
+ if (typeof candidate !== "string" || typeof basePath !== "string" || !candidate.trim() || !basePath.trim()) return false;
12293
+ const resolvedCandidate = path5.resolve(candidate);
12294
+ const resolvedBase = path5.resolve(basePath);
12295
+ const baseParent = path5.dirname(resolvedBase);
12296
+ if (path5.dirname(resolvedCandidate) !== baseParent) return false;
12297
+ const baseName = path5.basename(resolvedBase);
12298
+ const candidateName = path5.basename(resolvedCandidate);
12299
+ if (!candidateName.startsWith(`${baseName}-`)) return false;
12300
+ const branchSlug = candidateName.slice(baseName.length + 1);
12301
+ const parts = branchSlug.split("-").filter(Boolean);
12302
+ if (parts.length < 2) return false;
12303
+ if (!(/* @__PURE__ */ new Set(["tarea", "bug", "doc", "poc", "idea"])).has(parts[0])) return false;
12304
+ if (!parts.slice(1).every((part) => /^[a-z0-9][a-z0-9-]*$/.test(part))) return false;
12305
+ try {
12306
+ const candidateStat = fs5.lstatSync(resolvedCandidate);
12307
+ if (!candidateStat.isDirectory() || candidateStat.isSymbolicLink()) return false;
12308
+ const realCandidate = fs5.realpathSync.native(resolvedCandidate);
12309
+ const realBaseParent = fs5.realpathSync.native(baseParent);
12310
+ return path5.dirname(realCandidate) === realBaseParent && path5.basename(realCandidate) === candidateName;
12311
+ } catch {
12312
+ return false;
12313
+ }
12258
12314
  }
12259
12315
  function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktree, clickUpWebhookValidation } = {}) {
12260
12316
  const safe = safeWorktreeOrFailure(context, pluginWorktree);
@@ -12266,6 +12322,9 @@ function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktr
12266
12322
  if (clickUpBasePath && isSameOrNestedPath(requested, clickUpBasePath)) {
12267
12323
  return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path5.resolve(clickUpBasePath) };
12268
12324
  }
12325
+ if (clickUpBasePath && isClickUpDerivedWorktreeSibling(requested, clickUpBasePath)) {
12326
+ return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath: path5.resolve(clickUpBasePath) };
12327
+ }
12269
12328
  return {
12270
12329
  ok: false,
12271
12330
  error: `Directory '${requested}' is outside the safe worktree '${safe.worktree}' and configured ClickUp base path.`
@@ -13097,7 +13156,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
13097
13156
  }
13098
13157
  };
13099
13158
  }
13100
- 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, 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 };
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 };
13101
13160
 
13102
13161
  // src/sanitize_cli.js
13103
13162
  var { migrateLegacyOptimaLayout: migrateLegacyOptimaLayout2 } = OptimaPlugin.__internals;
@@ -33,8 +33,8 @@
33
33
  - Only one shared-worktree `implementation` task may be active.
34
34
  - ClickUp-first delivery should use task-specific worktrees/branches; the principal workspace must remain on `dev` and never on `main`.
35
35
  - Parent task start pulls remote once; after branch creation, subtasks trust the parent local branch instead of continuous remote polling.
36
- - Parent branch format is `<clickup-task-type>/<parent-task-id>`; subtask branch format is `<clickup-task-type>/<parent-task-id>/<subtask-id>`; PoC branch format is always `poc/<clickup-task-id>` and stays there until a later productization task.
37
- - Subtask PRs target the parent branch, parent task PRs target `dev`, and release PRs target `main` from `dev` only after explicit approval.
36
+ - Parent branch format is `<clickup-task-type>/<parent-task-id>`; subtask branch format is the non-nested sibling ref `<clickup-task-type>/<parent-task-id>-subtask-<subtask-id>`; pending planned subtasks use `<clickup-task-type>/<parent-task-id>-pending-<title-slug>`; PoC branch format is always `poc/<clickup-task-id>` and stays there until a later productization task.
37
+ - Subtask worktrees start from the parent branch and PR to the parent branch; if the parent branch/worktree is missing, bootstrap the parent from `dev`/`origin/dev` first. Parent task PRs target `dev`, and release PRs target `main` from `dev` only after explicit approval.
38
38
  - After successful subtask validation, Validator/QA merges the subtask PR into the parent branch/workspace without `CTO`/`PO` approval.
39
39
  - After parent Tech Lead and Validator/QA validation passes, the parent task stays in `validation`, `CTO`/`PO` are assigned and marked as approval owners, and they approve by moving it to `merge`; only then does Validator/QA attempt the parent PR merge into `dev`.
40
40
  - If any subtask or parent merge conflicts or fails, Validator/QA returns the affected ClickUp item to `in progress` and routes it to the coding owner.
@@ -16,7 +16,7 @@
16
16
  - Human role registry: resolve `CTO` and `PO` from `docs/core/humans.md` when present; if missing in a task worktree, use Optima-provided fallback role context/configured ClickUp IDs instead of blocking solely on the missing file.
17
17
  - ClickUp-first statuses: `backlog` ignore, `plan` plan with `Story Points`, `Definition`, test strategy, and `CTO`/`PO` assignment, `in progress` execute, `validation` split Tech Lead + Validator/QA gates; Validator/QA may merge validated subtasks directly into the parent branch; validated parents stay in `validation` for `CTO`/`PO` approval; `merge` means `CTO`/`PO` approved the parent and Validator/QA may attempt parent merge into `dev`; `completed`/`Closed` ignore unless reopened.
18
18
  - Shared-worktree rule: one active `implementation` task at a time; isolated `investigation`/`spec` may run in parallel if non-conflicting.
19
- - Git rules: principal workspace stays on `dev`, never `main`; parent task pulls remote once at start; subtasks trust parent local branch; PoC branches stay `poc/<clickup-task-id>`; subtasks PR to parent branch, parents PR to `dev`, releases PR `dev` -> `main`; failed/conflicted subtask or parent merges return the affected item to `in progress` for the coding owner; no direct `main` pushes.
19
+ - Git rules: principal workspace stays on `dev`, never `main`; parent branches use `<type>/<parent-id>`; subtask branches use non-nested `<type>/<parent-id>-subtask-<subtask-id>` and pending subtasks use `<type>/<parent-id>-pending-<title-slug>`; parent task pulls remote once at start; subtasks start from and PR to the parent local branch, bootstrapping the parent from `dev`/`origin/dev` first when missing; PoC branches stay `poc/<clickup-task-id>`; parents PR to `dev`, releases PR `dev` -> `main`; failed/conflicted subtask or parent merges return the affected item to `in progress` for the coding owner; no direct `main` pushes.
20
20
  - Store `agent_metadata` session JSON; `Definition` is the plan contract, final Documentation is delivered behavior docs.
21
21
  - `workflow_product_manager` is registered only when opt-in ClickUp webhook mode is complete and active/valid.
22
22
  - Webhook mode validates `X-Signature` HMAC SHA-256, routes only PM-assigned non-terminal status/assignee events, routes comments only on `@Defend Tech Product Manager`, writes new `ses_...` ids to `agent_metadata`, and reports stale/missing sessions to ClickUp without replacement.
@@ -23,7 +23,7 @@
23
23
  - `complex + implementation` normally uses `workflow_runner` in full mode.
24
24
  - While one shared-worktree implementation task is active, parallel work is limited to non-conflicting `investigation` or `spec`.
25
25
  - WPM estimates `Story Points` during `plan`, re-estimates on material plan changes, links the `Definition` plan contract when needed, and records `agent_metadata` session IDs.
26
- - In ClickUp-first mode, work should be decomposed into parent/subtask branches: parent tasks pull remote once at start, parent branches merge to `dev`, subtasks trust the parent local branch and merge to parent branches, PoC branches stay `poc/<clickup-task-id>`, and release branches merge `dev` to `main` only after approval.
26
+ - In ClickUp-first mode, work should be decomposed into parent/subtask branches: parent tasks pull remote once at start, parent branches use `<type>/<parent-id>` and merge to `dev`, subtasks use non-nested `<type>/<parent-id>-subtask-<subtask-id>` branches that start from/trust the parent local branch and merge to parent branches, missing parent branches/worktrees are bootstrapped from `dev`/`origin/dev` before subtask worktree creation, PoC branches stay `poc/<clickup-task-id>`, and release branches merge `dev` to `main` only after approval.
27
27
  - Validator/QA owns merge execution after the correct gate: validated subtask PRs merge directly into the parent branch/workspace, while parent PRs merge into `dev` only after `CTO`/`PO` move the parent task to `merge`. Merge conflicts or failed attempts return the affected task/subtask to `in progress` for the coding owner.
28
28
 
29
29
  ## Pre-Sync Defaults
@@ -11,6 +11,6 @@
11
11
  - Routing: keep `tiny` to one slice and usually one specialist; keep `standard` bounded; decompose `complex` into slice-based subtasks.
12
12
  - `complex + implementation` normally uses `workflow_runner` in full mode.
13
13
  - WPM stores `agent_metadata`, re-estimates `Story Points` on material plan changes, and keeps `Definition` plan contract separate from final Documentation.
14
- - Shared worktree permits only one active implementation task; isolated investigation/spec work may run in parallel; PoC branches remain `poc/<clickup-task-id>`; merge conflicts or failed merge attempts return the affected task/subtask to `in progress` for the coding owner.
14
+ - Shared worktree permits only one active implementation task; isolated investigation/spec work may run in parallel; parent branches use `<type>/<parent-id>`, subtasks use non-nested `<type>/<parent-id>-subtask-<subtask-id>` from the parent branch with parent bootstrap from `dev`/`origin/dev` when needed; PoC branches remain `poc/<clickup-task-id>`; merge conflicts or failed merge attempts return the affected task/subtask to `in progress` for the coding owner.
15
15
  - Pre-sync defaults: `tiny` -> developer + tech_lead; `standard` -> business_analyst + technical_architect; `complex` -> business_analyst + technical_architect + tech_lead + Validator/QA.
16
16
  - Add UI/UX for user-facing interface impact; add BA when product behavior, copy intent, or requirements are affected; add Tech Lead to standard work with elevated technical risk.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defend-tech/opencode-optima",
3
- "version": "0.1.57",
3
+ "version": "0.1.59",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+ssh://git@github.com/defend-tech/opencode-optima.git"