@defend-tech/opencode-optima 0.1.58 → 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.
- package/assets/agents/workflow_product_manager.md +2 -2
- package/dist/index.js +158 -106
- package/dist/sanitize_cli.js +158 -106
- package/docs/core/agent_orchestration.md +2 -2
- package/docs/core/agent_orchestration.prompt.md +1 -1
- package/docs/core/task_model.md +1 -1
- package/docs/core/task_model.prompt.md +1 -1
- package/package.json +1 -1
|
@@ -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
|
|
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
|
-
|
|
1710
|
-
if (identity.isSeq(
|
|
1711
|
-
for (const it of
|
|
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(
|
|
1714
|
-
for (const it of
|
|
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,
|
|
1714
|
+
mergeValue(ctx, map, value);
|
|
1718
1715
|
}
|
|
1719
1716
|
function mergeValue(ctx, map, value) {
|
|
1720
|
-
const source =
|
|
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
|
-
|
|
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") &&
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
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
|
-
|
|
5185
|
-
|
|
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
|
|
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
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
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
|
|
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
|
-
|
|
6387
|
+
Array.prototype.push.apply(it.value.end, it.sep);
|
|
6426
6388
|
else
|
|
6427
6389
|
it.value.end = it.sep;
|
|
6428
6390
|
} else
|
|
6429
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
9251
|
-
|
|
9252
|
-
|
|
9253
|
-
|
|
9254
|
-
|
|
9255
|
-
|
|
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
|
-
|
|
9259
|
-
|
|
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
|
|
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
|
|
9311
|
+
startFrom,
|
|
9308
9312
|
branch,
|
|
9309
9313
|
worktree,
|
|
9310
|
-
|
|
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
|
|
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,
|
|
@@ -10563,6 +10568,16 @@ async function probeOpenCodeSessionControl(client, { directory, agent, omitAgent
|
|
|
10563
10568
|
const rawMessages = await readOpenCodeSessionMessages(client, { sessionId: create.session_id, directory, limit: 50 });
|
|
10564
10569
|
if (!rawMessages) throw new Error("OpenCode client does not expose session.messages.");
|
|
10565
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;
|
|
10566
10581
|
const messages = {
|
|
10567
10582
|
ok: true,
|
|
10568
10583
|
session_id: create.session_id,
|
|
@@ -10580,8 +10595,11 @@ async function probeOpenCodeSessionControl(client, { directory, agent, omitAgent
|
|
|
10580
10595
|
marker_length: marker.length,
|
|
10581
10596
|
marker_truncated: requestedMarker.length > marker.length,
|
|
10582
10597
|
marker_hash: hashOpenCodeSessionText(marker),
|
|
10583
|
-
marker_visible:
|
|
10584
|
-
assistant_visible:
|
|
10598
|
+
marker_visible: markerVisible,
|
|
10599
|
+
assistant_visible: assistantVisible,
|
|
10600
|
+
delivery_verified: deliveryVerified,
|
|
10601
|
+
requested_agent_verified: requestedAgentVerified,
|
|
10602
|
+
responding_agents: respondingAgents,
|
|
10585
10603
|
create,
|
|
10586
10604
|
prompt,
|
|
10587
10605
|
messages
|
|
@@ -10981,8 +10999,13 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
10981
10999
|
}
|
|
10982
11000
|
const deliveryEvidencePath = deliveryEvidencePathForClickUpTask(taskId);
|
|
10983
11001
|
const routingMetadata = {
|
|
11002
|
+
parent_task_id: subtaskId ? parentTaskId : void 0,
|
|
11003
|
+
parent_branch: taskRoute.parentBranch,
|
|
10984
11004
|
branch: taskRoute.branch,
|
|
11005
|
+
subtask_branch: subtaskId ? taskRoute.branch : void 0,
|
|
10985
11006
|
worktree: taskRoute.worktree,
|
|
11007
|
+
subtask_worktree: subtaskId ? taskRoute.worktree : void 0,
|
|
11008
|
+
pr_target: taskRoute.prTarget || (subtaskId ? taskRoute.parentBranch : "dev"),
|
|
10986
11009
|
delivery_evidence_path: deliveryEvidencePath,
|
|
10987
11010
|
evidence_path: `.optima/evidences/${branchSafeClickUpId(taskId)}/SUMMARY.md`
|
|
10988
11011
|
};
|
|
@@ -12254,7 +12277,33 @@ function getModePromptFragment(agentId, operatingTeamMode, worktree) {
|
|
|
12254
12277
|
function shouldRegisterWorkflowProductManager(options = {}, worktree = process.cwd()) {
|
|
12255
12278
|
if (options.clickUpWebhookActive === true) return true;
|
|
12256
12279
|
const validation = options.clickUpWebhookValidation;
|
|
12257
|
-
|
|
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
|
+
}
|
|
12258
12307
|
}
|
|
12259
12308
|
function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktree, clickUpWebhookValidation } = {}) {
|
|
12260
12309
|
const safe = safeWorktreeOrFailure(context, pluginWorktree);
|
|
@@ -12266,6 +12315,9 @@ function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktr
|
|
|
12266
12315
|
if (clickUpBasePath && isSameOrNestedPath(requested, clickUpBasePath)) {
|
|
12267
12316
|
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path5.resolve(clickUpBasePath) };
|
|
12268
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
|
+
}
|
|
12269
12321
|
return {
|
|
12270
12322
|
ok: false,
|
|
12271
12323
|
error: `Directory '${requested}' is outside the safe worktree '${safe.worktree}' and configured ClickUp base path.`
|
|
@@ -13097,7 +13149,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
|
|
|
13097
13149
|
}
|
|
13098
13150
|
};
|
|
13099
13151
|
}
|
|
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 };
|
|
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 };
|
|
13101
13153
|
export {
|
|
13102
13154
|
OptimaPlugin as default
|
|
13103
13155
|
};
|
package/dist/sanitize_cli.js
CHANGED
|
@@ -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
|
-
|
|
1711
|
-
if (identity.isSeq(
|
|
1712
|
-
for (const it of
|
|
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(
|
|
1715
|
-
for (const it of
|
|
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,
|
|
1715
|
+
mergeValue(ctx, map, value);
|
|
1719
1716
|
}
|
|
1720
1717
|
function mergeValue(ctx, map, value) {
|
|
1721
|
-
const source =
|
|
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
|
-
|
|
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") &&
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
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
|
-
|
|
5186
|
-
|
|
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
|
|
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
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
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
|
|
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
|
-
|
|
6388
|
+
Array.prototype.push.apply(it.value.end, it.sep);
|
|
6427
6389
|
else
|
|
6428
6390
|
it.value.end = it.sep;
|
|
6429
6391
|
} else
|
|
6430
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
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
|
-
|
|
9266
|
-
|
|
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
|
|
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
|
|
9318
|
+
startFrom,
|
|
9315
9319
|
branch,
|
|
9316
9320
|
worktree,
|
|
9317
|
-
|
|
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
|
|
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,
|
|
@@ -10570,6 +10575,16 @@ async function probeOpenCodeSessionControl(client, { directory, agent, omitAgent
|
|
|
10570
10575
|
const rawMessages = await readOpenCodeSessionMessages(client, { sessionId: create.session_id, directory, limit: 50 });
|
|
10571
10576
|
if (!rawMessages) throw new Error("OpenCode client does not expose session.messages.");
|
|
10572
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;
|
|
10573
10588
|
const messages = {
|
|
10574
10589
|
ok: true,
|
|
10575
10590
|
session_id: create.session_id,
|
|
@@ -10587,8 +10602,11 @@ async function probeOpenCodeSessionControl(client, { directory, agent, omitAgent
|
|
|
10587
10602
|
marker_length: marker.length,
|
|
10588
10603
|
marker_truncated: requestedMarker.length > marker.length,
|
|
10589
10604
|
marker_hash: hashOpenCodeSessionText(marker),
|
|
10590
|
-
marker_visible:
|
|
10591
|
-
assistant_visible:
|
|
10605
|
+
marker_visible: markerVisible,
|
|
10606
|
+
assistant_visible: assistantVisible,
|
|
10607
|
+
delivery_verified: deliveryVerified,
|
|
10608
|
+
requested_agent_verified: requestedAgentVerified,
|
|
10609
|
+
responding_agents: respondingAgents,
|
|
10592
10610
|
create,
|
|
10593
10611
|
prompt,
|
|
10594
10612
|
messages
|
|
@@ -10988,8 +11006,13 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
|
|
|
10988
11006
|
}
|
|
10989
11007
|
const deliveryEvidencePath = deliveryEvidencePathForClickUpTask(taskId);
|
|
10990
11008
|
const routingMetadata = {
|
|
11009
|
+
parent_task_id: subtaskId ? parentTaskId : void 0,
|
|
11010
|
+
parent_branch: taskRoute.parentBranch,
|
|
10991
11011
|
branch: taskRoute.branch,
|
|
11012
|
+
subtask_branch: subtaskId ? taskRoute.branch : void 0,
|
|
10992
11013
|
worktree: taskRoute.worktree,
|
|
11014
|
+
subtask_worktree: subtaskId ? taskRoute.worktree : void 0,
|
|
11015
|
+
pr_target: taskRoute.prTarget || (subtaskId ? taskRoute.parentBranch : "dev"),
|
|
10993
11016
|
delivery_evidence_path: deliveryEvidencePath,
|
|
10994
11017
|
evidence_path: `.optima/evidences/${branchSafeClickUpId(taskId)}/SUMMARY.md`
|
|
10995
11018
|
};
|
|
@@ -12261,7 +12284,33 @@ function getModePromptFragment(agentId, operatingTeamMode, worktree) {
|
|
|
12261
12284
|
function shouldRegisterWorkflowProductManager(options = {}, worktree = process.cwd()) {
|
|
12262
12285
|
if (options.clickUpWebhookActive === true) return true;
|
|
12263
12286
|
const validation = options.clickUpWebhookValidation;
|
|
12264
|
-
|
|
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
|
+
}
|
|
12265
12314
|
}
|
|
12266
12315
|
function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktree, clickUpWebhookValidation } = {}) {
|
|
12267
12316
|
const safe = safeWorktreeOrFailure(context, pluginWorktree);
|
|
@@ -12273,6 +12322,9 @@ function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktr
|
|
|
12273
12322
|
if (clickUpBasePath && isSameOrNestedPath(requested, clickUpBasePath)) {
|
|
12274
12323
|
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path5.resolve(clickUpBasePath) };
|
|
12275
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
|
+
}
|
|
12276
12328
|
return {
|
|
12277
12329
|
ok: false,
|
|
12278
12330
|
error: `Directory '${requested}' is outside the safe worktree '${safe.worktree}' and configured ClickUp base path.`
|
|
@@ -13104,7 +13156,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
|
|
|
13104
13156
|
}
|
|
13105
13157
|
};
|
|
13106
13158
|
}
|
|
13107
|
-
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 };
|
|
13108
13160
|
|
|
13109
13161
|
// src/sanitize_cli.js
|
|
13110
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
|
|
37
|
-
- Subtask
|
|
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
|
|
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.
|
package/docs/core/task_model.md
CHANGED
|
@@ -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.
|